Skip to content

Commit

Permalink
Replacing descriptor set layout usage with a flag bitfield.
Browse files Browse the repository at this point in the history
Descriptor sets are only used in layouts and the usage is now
always push-only today. As we support things like binding tables
we may want to indicate which bindings may come from tables and
if we want to carry access information (which bindings are read-only,
etc) we'll need somewhere for that too: instead of having 4 enums
with 2 options each we'll just mash them together for now.

This also adds a per-descriptor flag that can be used for indicating
binding behavior. Today it's got a placeholder read-only value but we
can add more in the future controlling cache behavior and such.

Progress on #10144.
  • Loading branch information
benvanik committed Aug 23, 2022
1 parent 88795f5 commit 886855e
Show file tree
Hide file tree
Showing 37 changed files with 281 additions and 169 deletions.
36 changes: 18 additions & 18 deletions compiler/src/iree/compiler/Dialect/HAL/Analysis/BindingLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ void PipelineLayout::print(llvm::raw_ostream &os) const {
os << " sets:\n";
for (auto &setLayout : setLayouts) {
os << " set[" << setLayout.ordinal
<< "]: " << stringifyDescriptorSetLayoutUsageType(setLayout.usage)
<< "\n";
<< "]: " << stringifyDescriptorSetLayoutFlags(setLayout.flags) << "\n";
for (auto &binding : setLayout.bindings) {
os << " binding[" << binding.ordinal
<< "]: " << stringifyDescriptorType(binding.type) << "\n";
Expand Down Expand Up @@ -87,20 +86,22 @@ static PipelineLayout deriveExportLayout(
}
}

// In lieu of actual analysis we just check per dispatch-site which bindings
// need to be dynamic vs those that are at a constant uniform offset.
// The number of dynamic storage buffer bindings available is limited:
// https://vulkan.gpuinfo.org/displaydevicelimit.php?name=maxDescriptorSetStorageBuffersDynamic&platform=all
// Earlier optimizations in the stream dialect try to rebase bindings to 0 to
// make this possible.
// NOTE: we could check the actual constant values being uniform within a
// single command buffer (as that's all that really matters) but this is all
// just a temporary hack so ¯\_(ツ)_/¯.
llvm::BitVector staticBindings(bindingCount, /*t=*/true);
// Check the usage of each binding at each dispatch site.
SmallVector<DescriptorFlags> bindingFlags(bindingCount);
for (auto dispatchOp : dispatchOps) {
auto resourceOffsets = dispatchOp.getResourceOffsets();
auto resourceAccessesAttrs = dispatchOp.getResourceAccesses().getValue();
for (unsigned i = 0; i < bindingCount; ++i) {
if (!matchPattern(resourceOffsets[i], m_Zero())) staticBindings.reset(i);
auto resourceAccessAttr =
resourceAccessesAttrs[i]
.cast<IREE::Stream::ResourceAccessBitfieldAttr>();
auto resourceAccess = static_cast<IREE::Stream::ResourceAccessBitfield>(
resourceAccessAttr.getInt());
if (!bitEnumContains(resourceAccess,
IREE::Stream::ResourceAccessBitfield::Write)) {
// Read-only.
bindingFlags[i] =
bindingFlags[i] | IREE::HAL::DescriptorFlags::ReadOnly;
}
}
}

Expand All @@ -112,14 +113,13 @@ static PipelineLayout deriveExportLayout(
// on once interfaces are materialized.
DescriptorSetLayout setLayout;
setLayout.ordinal = 0;
setLayout.usage = IREE::HAL::DescriptorSetLayoutUsageType::PushOnly;
setLayout.flags = IREE::HAL::DescriptorSetLayoutFlags::None;
setLayout.bindings.resize(bindingCount);
for (unsigned i = 0; i < bindingCount; ++i) {
DescriptorSetLayoutBinding setBinding;
setBinding.ordinal = i;
setBinding.type = staticBindings.test(i)
? IREE::HAL::DescriptorType::StorageBuffer
: IREE::HAL::DescriptorType::StorageBufferDynamic;
setBinding.type = IREE::HAL::DescriptorType::StorageBuffer;
setBinding.flags = bindingFlags[i];
setLayout.bindings[i] = setBinding;
pipelineLayout.resourceMap[i] =
std::make_pair(setLayout.ordinal, setBinding.ordinal);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ struct DescriptorSetLayoutBinding {
unsigned ordinal;
// Storage type of the descriptor resource.
IREE::HAL::DescriptorType type;
// Flags defining how the descriptor behaves.
IREE::HAL::DescriptorFlags flags;
};

struct DescriptorSetLayout {
// Ordinal of the set within the parent pipeline layout.
unsigned ordinal;
// Usage of the descriptor set (such as whether it is persistent or push).
IREE::HAL::DescriptorSetLayoutUsageType usage;
IREE::HAL::DescriptorSetLayoutFlags flags;
// Bindings within the layout. Ordinals may be sparse.
SmallVector<DescriptorSetLayoutBinding> bindings;
};
Expand Down
33 changes: 20 additions & 13 deletions compiler/src/iree/compiler/Dialect/HAL/IR/HALBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -125,24 +125,30 @@ def HAL_CommandCategoryBitfieldAttr :

def HAL_DescriptorType_UniformBuffer : I32EnumAttrCase<"UniformBuffer", 6, "uniform_buffer">;
def HAL_DescriptorType_StorageBuffer : I32EnumAttrCase<"StorageBuffer", 7, "storage_buffer">;
def HAL_DescriptorType_UniformBufferDynamic : I32EnumAttrCase<"UniformBufferDynamic", 8, "uniform_buffer_dynamic">;
def HAL_DescriptorType_StorageBufferDynamic : I32EnumAttrCase<"StorageBufferDynamic", 9, "storage_buffer_dynamic">;
def HAL_DescriptorTypeAttr :
I32EnumAttr<"DescriptorType", "IREE HAL DescriptorType", [
I32EnumAttr<"DescriptorType", "valid DescriptorType", [
HAL_DescriptorType_UniformBuffer,
HAL_DescriptorType_StorageBuffer,
HAL_DescriptorType_UniformBufferDynamic,
HAL_DescriptorType_StorageBufferDynamic,
]> {
let cppNamespace = "::mlir::iree_compiler::IREE::HAL";
}

def HAL_DescriptorSetLayoutUsageType_Immutable : I32EnumAttrCase<"Immutable", 0, "immutable">;
def HAL_DescriptorSetLayoutUsageType_PushOnly : I32EnumAttrCase<"PushOnly", 1, "push_only">;
def HAL_DescriptorSetLayoutUsageTypeAttr :
I32EnumAttr<"DescriptorSetLayoutUsageType", "IREE HAL DescriptorSetLayoutType", [
HAL_DescriptorSetLayoutUsageType_Immutable,
HAL_DescriptorSetLayoutUsageType_PushOnly,
def HAL_DescriptorFlags_None : I32BitEnumAttrCase<"None", 0x0000>;
def HAL_DescriptorFlags_ReadOnly : I32BitEnumAttrCase<"ReadOnly", 0x0001>;
def HAL_DescriptorFlagsAttr :
I32BitEnumAttr<"DescriptorFlags", "valid Descriptor flags", [
HAL_DescriptorFlags_None,
HAL_DescriptorFlags_ReadOnly,
]> {
let cppNamespace = "::mlir::iree_compiler::IREE::HAL";
}

def HAL_DescriptorSetLayoutFlags_None : I32BitEnumAttrCase<"None", 0x0000>;
def HAL_DescriptorSetLayoutFlags_Reserved : I32BitEnumAttrCase<"Reserved", 0x0001>;
def HAL_DescriptorSetLayoutFlagsAttr :
I32BitEnumAttr<"DescriptorSetLayoutFlags", "valid DescriptorSetLayout flags", [
HAL_DescriptorSetLayoutFlags_None,
HAL_DescriptorSetLayoutFlags_Reserved, // to make tblgen happy
]> {
let cppNamespace = "::mlir::iree_compiler::IREE::HAL";
}
Expand Down Expand Up @@ -438,10 +444,11 @@ def HAL_DescriptorSetBindingAttr :
}];
let parameters = (ins
AttrParameter<"int64_t", "">:$ordinal,
AttrParameter<"DescriptorType", "">:$type
AttrParameter<"DescriptorType", "">:$type,
OptionalParameter<"mlir::Optional<DescriptorFlags>">:$flags
);
let assemblyFormat = [{
`<` $ordinal `,` $type `>`
`<` $ordinal `,` $type (`,` $flags^)? `>`
}];
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/src/iree/compiler/Dialect/HAL/IR/HALDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ class HALToVMConversionInterface : public VMConversionDialectInterface {
APInt(64, bindingAttr.getOrdinal())));
fn(IREE::HAL::DescriptorTypeAttr::get(attr.getContext(),
bindingAttr.getType()));
fn(IREE::HAL::DescriptorFlagsAttr::get(
attr.getContext(),
bindingAttr.getFlags().value_or(IREE::HAL::DescriptorFlags::None)));
}
}
};
Expand Down
8 changes: 4 additions & 4 deletions compiler/src/iree/compiler/Dialect/HAL/IR/HALOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1062,7 +1062,7 @@ def HAL_DescriptorSetLayoutCreateOp :

let arguments = (ins
HAL_Device:$device,
HAL_DescriptorSetLayoutUsageTypeAttr:$usage_type,
HAL_DescriptorSetLayoutFlagsAttr:$flags,
HAL_DescriptorSetLayoutBindingArrayAttr:$bindings
);
let results = (outs
Expand All @@ -1071,7 +1071,7 @@ def HAL_DescriptorSetLayoutCreateOp :

let assemblyFormat = [{
`device` `(` $device `:` type($device) `)`
`usage` `(` $usage_type `)`
`flags` `(` $flags `)`
`bindings` `(` $bindings `)`
`:` type($result)
attr-dict-with-keyword
Expand All @@ -1089,7 +1089,7 @@ def HAL_DescriptorSetLayoutLookupOp : HAL_PureOp<"descriptor_set_layout.lookup",

let arguments = (ins
HAL_Device:$device,
HAL_DescriptorSetLayoutUsageTypeAttr:$usage_type,
HAL_DescriptorSetLayoutFlagsAttr:$flags,
HAL_DescriptorSetLayoutBindingArrayAttr:$bindings
);
let results = (outs
Expand All @@ -1098,7 +1098,7 @@ def HAL_DescriptorSetLayoutLookupOp : HAL_PureOp<"descriptor_set_layout.lookup",

let assemblyFormat = [{
`device` `(` $device `:` type($device) `)`
`usage` `(` $usage_type `)`
`flags` `(` $flags `)`
`bindings` `(` $bindings `)`
`:` type($result)
attr-dict-with-keyword
Expand Down
21 changes: 21 additions & 0 deletions compiler/src/iree/compiler/Dialect/HAL/IR/HALTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,27 @@ static inline AsmPrinter &operator<<(
printer << mlir::iree_compiler::IREE::HAL::stringifyEnum(param);
return printer;
}
template <>
struct FieldParser<
mlir::Optional<mlir::iree_compiler::IREE::HAL::DescriptorFlags>> {
static FailureOr<mlir::iree_compiler::IREE::HAL::DescriptorFlags> parse(
AsmParser &parser) {
std::string value;
if (parser.parseKeywordOrString(&value)) return failure();
auto result = mlir::iree_compiler::IREE::HAL::symbolizeEnum<
mlir::iree_compiler::IREE::HAL::DescriptorFlags>(value);
if (!result.has_value()) return failure();
return result.value();
}
};
static inline AsmPrinter &operator<<(
AsmPrinter &printer,
mlir::Optional<mlir::iree_compiler::IREE::HAL::DescriptorFlags> param) {
printer << (param.has_value()
? mlir::iree_compiler::IREE::HAL::stringifyEnum(param.value())
: StringRef{""});
return printer;
}
} // namespace mlir

// clang-format off: must be included after all LLVM/MLIR headers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
func.func @descriptor_set_layout_create(%device: !hal.device) {
// CHECK: = hal.descriptor_set_layout.create
// CHECK-SAME: device(%[[DEVICE]] : !hal.device)
// CHECK-SAME: usage(push_only)
// CHECK-SAME: flags("None")
// CHECK-SAME: bindings([
// CHECK-SAME: #hal.descriptor_set.binding<0, storage_buffer>,
// CHECK-SAME: #hal.descriptor_set.binding<1, storage_buffer>
// CHECK-SAME: ]) : !hal.descriptor_set_layout
%0 = hal.descriptor_set_layout.create device(%device : !hal.device)
usage(push_only)
flags("None")
bindings([
#hal.descriptor_set.binding<0, storage_buffer>,
#hal.descriptor_set.binding<1, storage_buffer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,10 @@ static IREE::HAL::PipelineLayoutAttr makePipelineLayoutAttr(
SmallVector<IREE::HAL::DescriptorSetBindingAttr> bindingAttrs;
for (const auto &binding : setLayout.bindings) {
bindingAttrs.push_back(IREE::HAL::DescriptorSetBindingAttr::get(
builder.getContext(), binding.ordinal, binding.type));
builder.getContext(), binding.ordinal, binding.type,
binding.flags != IREE::HAL::DescriptorFlags::None
? binding.flags
: Optional<IREE::HAL::DescriptorFlags>{}));
}
setLayoutAttrs.push_back(IREE::HAL::DescriptorSetLayoutAttr::get(
builder.getContext(), setLayout.ordinal, bindingAttrs));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ class MaterializeResourceCachesPass
OpBuilder blockBuilder =
OpBuilder::atBlockEnd(initializerOp.addEntryBlock());
auto deviceValue = blockBuilder.createOrFold<ExSharedDeviceOp>(loc);
auto layoutUsage = IREE::HAL::DescriptorSetLayoutUsageType::PushOnly;
auto layoutFlags = IREE::HAL::DescriptorSetLayoutFlags::None;
auto layoutValue = blockBuilder.createOrFold<DescriptorSetLayoutCreateOp>(
loc, layoutType, deviceValue, layoutUsage, bindingAttrs);
loc, layoutType, deviceValue, layoutFlags, bindingAttrs);
blockBuilder.create<IREE::Util::GlobalStoreOp>(loc, layoutValue,
globalOp.getName());
blockBuilder.create<IREE::Util::InitializerReturnOp>(loc);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,61 @@ module attributes {hal.device.targets = [
}>
]} {

// CHECK: hal.executable private @ex_workgroups
// CHECK: hal.executable.variant public @embedded_elf_arm_64, target = #executable_target_embedded_elf_arm_64
// CHECK: hal.executable.export public @entry ordinal(0) layout(#pipeline_layout) {
// CHECK-NEXT: ^bb0(%[[DEVICE:.+]]: !hal.device, %[[ARG0:.+]]: index, %[[ARG1:.+]]: index):
// CHECK-NEXT: hal.return %[[ARG0]], %[[ARG1]], %[[ARG0]] : index, index, index
// CHECK-NEXT: }
// CHECK: builtin.module
// CHECK-NEXT: func.func @entry()
// CHECK: hal.executable.variant public @embedded_elf_x86_64, target = #executable_target_embedded_elf_x86_64
// CHECK: hal.executable.export public @entry ordinal(0) layout(#pipeline_layout) {
// CHECK-NEXT: ^bb0(%[[DEVICE:.+]]: !hal.device, %[[ARG0:.+]]: index, %[[ARG1:.+]]: index):
// CHECK-NEXT: hal.return %[[ARG0]], %[[ARG1]], %[[ARG0]] : index, index, index
// CHECK-NEXT: }
// CHECK: builtin.module
// CHECK-NEXT: func.func @entry()
// CHECK: #pipeline_layout = #hal.pipeline.layout<
// CHECK-SAME: push_constants = 1
// CHECK-SAME: sets = [
// CHECK-SAME: <0, bindings = [
// CHECK-SAME: <0, storage_buffer, ReadOnly>
// CHECK-SAME: <1, storage_buffer, ReadOnly>
// CHECK-SAME: <2, storage_buffer>

stream.executable private @ex_workgroups {
stream.executable.export public @entry workgroups(%arg0: index, %arg1: index) -> (index, index, index) {
stream.return %arg0, %arg1, %arg0 : index, index, index
}
builtin.module {
func.func @entry() {
return
// CHECK: hal.executable private @ex_workgroups
// CHECK: hal.executable.variant public @embedded_elf_arm_64, target = #executable_target_embedded_elf_arm_64
// CHECK: hal.executable.export public @entry ordinal(0) layout(#pipeline_layout) {
// CHECK-NEXT: ^bb0(%[[DEVICE:.+]]: !hal.device, %[[ARG0:.+]]: index, %[[ARG1:.+]]: index):
// CHECK-NEXT: hal.return %[[ARG0]], %[[ARG1]], %[[ARG0]] : index, index, index
// CHECK-NEXT: }
// CHECK: builtin.module
// CHECK-NEXT: func.func @entry
// CHECK: hal.executable.variant public @embedded_elf_x86_64, target = #executable_target_embedded_elf_x86_64
// CHECK: hal.executable.export public @entry ordinal(0) layout(#pipeline_layout) {
// CHECK-NEXT: ^bb0(%[[DEVICE:.+]]: !hal.device, %[[ARG0:.+]]: index, %[[ARG1:.+]]: index):
// CHECK-NEXT: hal.return %[[ARG0]], %[[ARG1]], %[[ARG0]] : index, index, index
// CHECK-NEXT: }
// CHECK: builtin.module
// CHECK-NEXT: func.func @entry

stream.executable private @ex_workgroups {
stream.executable.export public @entry workgroups(%arg0: index, %arg1: index) -> (index, index, index) {
stream.return %arg0, %arg1, %arg0 : index, index, index
}
builtin.module {
func.func @entry(%operand: i32, %arg0: !stream.binding {stream.alignment = 64 : index}, %arg1: !stream.binding {stream.alignment = 64 : index}, %arg2: !stream.binding {stream.alignment = 64 : index}) {
return
}
}
}
}

// CHECK-LABEL: @main
func.func @main(%arg0: !stream.resource<external>, %arg1: index) -> !stream.resource<external> {
%c1 = arith.constant 1 : index
%c2 = arith.constant 2 : index
%c4 = arith.constant 4 : index
%0 = stream.async.dispatch @ex_workgroups::@entry[%c1, %c2](%arg0, %c4) : (!stream.resource<external>{%arg1}, index) -> %arg0{%arg1}
return %0 : !stream.resource<external>
}

func.func @main(%arg0: !stream.resource<constant>, %arg1: !stream.resource<transient>, %arg2: index, %arg3: i32) -> !stream.resource<transient> {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c2 = arith.constant 2 : index
%0 = stream.resource.alloc uninitialized : !stream.resource<transient>{%arg2}
%1 = stream.cmd.execute with(%arg0 as %arg4: !stream.resource<constant>{%arg2}, %arg1 as %arg5: !stream.resource<transient>{%arg2}, %0 as %arg6: !stream.resource<transient>{%arg2}) {
// CHECK: stream.cmd.dispatch @ex_workgroups::@entry
// CHECK: attributes {
// CHECK-SAME: hal.interface.bindings = [
// CHECK-SAME: #hal.interface.binding<0, 0>,
// CHECK-SAME: #hal.interface.binding<0, 1>,
// CHECK-SAME: #hal.interface.binding<0, 2>
stream.cmd.dispatch @ex_workgroups::@entry[%c1, %c2](%arg3 : i32) {
ro %arg4[%c0 for %arg2] : !stream.resource<constant>{%arg2},
ro %arg5[%c0 for %arg2] : !stream.resource<transient>{%arg2},
wo %arg6[%c0 for %arg2] : !stream.resource<transient>{%arg2}
}
} => !stream.timepoint
%2 = stream.timepoint.await %1 => %0 : !stream.resource<transient>{%arg2}
return %2 : !stream.resource<transient>
}
}

// -----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// CHECK-NEXT: %device = hal.ex.shared_device : !hal.device
// CHECK-NEXT: %descriptor_set_layout = hal.descriptor_set_layout.create
// CHECK-SAME: device(%device : !hal.device)
// CHECK-SAME: usage(push_only)
// CHECK-SAME: flags("None")
// CHECK-SAME: bindings([
// CHECK-SAME: #hal.descriptor_set.binding<0, storage_buffer>,
// CHECK-SAME: #hal.descriptor_set.binding<1, storage_buffer>
Expand All @@ -16,7 +16,7 @@
func.func @descriptorSetLayoutLookup(%device : !hal.device) -> !hal.descriptor_set_layout {
// CHECK-NEXT: %[[LAYOUT:.+]] = util.global.load @_descriptor_set_layout_0 : !hal.descriptor_set_layout
%0 = hal.descriptor_set_layout.lookup device(%device : !hal.device)
usage(push_only)
flags("None")
bindings([
#hal.descriptor_set.binding<0, storage_buffer>,
#hal.descriptor_set.binding<1, storage_buffer>
Expand Down Expand Up @@ -91,7 +91,7 @@ func.func @sharedLayoutLookup(%device : !hal.device) -> !hal.pipeline_layout {
func.func @otherDescriptorSetLayoutLookup(%device : !hal.device) -> !hal.descriptor_set_layout {
// CHECK: %[[LAYOUT:.+]] = util.global.load @_descriptor_set_layout_0 : !hal.descriptor_set_layout
%0 = hal.descriptor_set_layout.lookup device(%device : !hal.device)
usage(push_only)
flags(None)
bindings([
#hal.descriptor_set.binding<0, storage_buffer>,
#hal.descriptor_set.binding<1, storage_buffer>
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/iree/compiler/Dialect/HAL/hal.imports.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,9 @@ vm.import @command_buffer.dispatch.indirect(
// Creates a descriptor set layout that defines the bindings used within a set.
vm.import @descriptor_set_layout.create(
%device : !vm.ref<!hal.device>,
%usage_type : i32,
// <binding, type>
%bindings : tuple<i32, i32>...
%flags : i32,
// <binding, type, flags>
%bindings : tuple<i32, i32, i32>...
) -> !vm.ref<!hal.descriptor_set_layout>
attributes {nosideeffects}

Expand Down
2 changes: 1 addition & 1 deletion experimental/rocm/pipeline_layout.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ iree_hal_rocm_descriptor_set_layout_cast(

iree_status_t iree_hal_rocm_descriptor_set_layout_create(
iree_hal_rocm_context_wrapper_t* context,
iree_hal_descriptor_set_layout_usage_type_t usage_type,
iree_hal_descriptor_set_layout_flags_t flags,
iree_host_size_t binding_count,
const iree_hal_descriptor_set_layout_binding_t* bindings,
iree_hal_descriptor_set_layout_t** out_descriptor_set_layout) {
Expand Down
Loading

0 comments on commit 886855e

Please sign in to comment.