18 #include "llvm/ADT/Sequence.h" 19 #include "llvm/ADT/StringExtras.h" 20 #include "llvm/Support/Debug.h" 24 #define DEBUG_TYPE "mlir-spirv-conversion" 38 template <
typename LabelT>
42 for (
const auto &ors : candidates) {
48 for (spirv::Extension ext : ors)
49 extStrings.push_back(spirv::stringifyExtension(ext));
51 llvm::dbgs() << label <<
" illegal: requires at least one extension in [" 52 << llvm::join(extStrings,
", ")
53 <<
"] but none allowed in target environment\n";
66 template <
typename LabelT>
70 for (
const auto &ors : candidates) {
76 for (spirv::Capability cap : ors)
77 capStrings.push_back(spirv::stringifyCapability(cap));
79 llvm::dbgs() << label <<
" illegal: requires at least one capability in [" 80 << llvm::join(capStrings,
", ")
81 <<
"] but none allowed in target environment\n";
91 switch (storageClass) {
92 case spirv::StorageClass::PhysicalStorageBuffer:
93 case spirv::StorageClass::PushConstant:
94 case spirv::StorageClass::StorageBuffer:
95 case spirv::StorageClass::Uniform:
117 return IntegerType::get(getContext(), options.
use64bitIndex ? 64 : 32);
129 #define STORAGE_SPACE_MAP_LIST(MAP_FN) \ 130 MAP_FN(spirv::StorageClass::Generic, 1) \ 131 MAP_FN(spirv::StorageClass::StorageBuffer, 0) \ 132 MAP_FN(spirv::StorageClass::Workgroup, 3) \ 133 MAP_FN(spirv::StorageClass::Uniform, 4) \ 134 MAP_FN(spirv::StorageClass::Private, 5) \ 135 MAP_FN(spirv::StorageClass::Function, 6) \ 136 MAP_FN(spirv::StorageClass::PushConstant, 7) \ 137 MAP_FN(spirv::StorageClass::UniformConstant, 8) \ 138 MAP_FN(spirv::StorageClass::Input, 9) \ 139 MAP_FN(spirv::StorageClass::Output, 10) \ 140 MAP_FN(spirv::StorageClass::CrossWorkgroup, 11) \ 141 MAP_FN(spirv::StorageClass::AtomicCounter, 12) \ 142 MAP_FN(spirv::StorageClass::Image, 13) \ 143 MAP_FN(spirv::StorageClass::CallableDataKHR, 14) \ 144 MAP_FN(spirv::StorageClass::IncomingCallableDataKHR, 15) \ 145 MAP_FN(spirv::StorageClass::RayPayloadKHR, 16) \ 146 MAP_FN(spirv::StorageClass::HitAttributeKHR, 17) \ 147 MAP_FN(spirv::StorageClass::IncomingRayPayloadKHR, 18) \ 148 MAP_FN(spirv::StorageClass::ShaderRecordBufferKHR, 19) \ 149 MAP_FN(spirv::StorageClass::PhysicalStorageBuffer, 20) \ 150 MAP_FN(spirv::StorageClass::CodeSectionINTEL, 21) \ 151 MAP_FN(spirv::StorageClass::DeviceOnlyINTEL, 22) \ 152 MAP_FN(spirv::StorageClass::HostOnlyINTEL, 23) 156 #define STORAGE_SPACE_MAP_FN(storage, space) \ 161 #undef STORAGE_SPACE_MAP_FN 162 llvm_unreachable(
"unhandled storage class!");
167 #define STORAGE_SPACE_MAP_FN(storage, space) \ 176 #undef STORAGE_SPACE_MAP_FN 183 MLIRContext *SPIRVTypeConverter::getContext()
const {
184 return targetEnv.
getAttr().getContext();
187 #undef STORAGE_SPACE_MAP_LIST 206 if (
auto vecType = type.
dyn_cast<VectorType>()) {
210 return vecType.getNumElements() * *elementSize;
213 if (
auto memRefType = type.
dyn_cast<MemRefType>()) {
218 if (!memRefType.hasStaticShape() ||
225 auto elementSize =
getTypeNumBytes(options, memRefType.getElementType());
229 if (memRefType.getRank() == 0)
232 auto dims = memRefType.getShape();
233 if (llvm::is_contained(dims, ShapedType::kDynamicSize) ||
234 offset == MemRefType::getDynamicStrideOrOffset() ||
235 llvm::is_contained(strides, MemRefType::getDynamicStrideOrOffset()))
238 int64_t memrefSize = -1;
239 for (
const auto &shape :
enumerate(dims))
240 memrefSize =
std::max(memrefSize, shape.value() * strides[shape.index()]);
242 return (offset + memrefSize) * *elementSize;
246 if (!tensorType.hasStaticShape())
249 auto elementSize =
getTypeNumBytes(options, tensorType.getElementType());
253 int64_t size = *elementSize;
254 for (
auto shape : tensorType.getShape())
287 LLVM_DEBUG(llvm::dbgs() << type <<
" converted to 32-bit for SPIR-V\n");
291 auto intType = type.
cast<IntegerType>();
292 LLVM_DEBUG(llvm::dbgs() << type <<
" converted to 32-bit for SPIR-V\n");
293 return IntegerType::get(targetEnv.
getContext(), 32,
294 intType.getSignedness());
302 if (type.getRank() == 1 && type.getNumElements() == 1)
303 return type.getElementType();
308 LLVM_DEBUG(llvm::dbgs() << type <<
" illegal: > 4-element unimplemented\n");
327 return VectorType::get(type.getShape(), elementType);
341 if (!type.hasStaticShape()) {
342 LLVM_DEBUG(llvm::dbgs()
343 << type <<
" illegal: dynamic shape unimplemented\n");
349 LLVM_DEBUG(llvm::dbgs()
350 << type <<
" illegal: cannot convert non-scalar element type\n");
356 if (!scalarSize || !tensorSize) {
357 LLVM_DEBUG(llvm::dbgs()
358 << type <<
" illegal: cannot deduce element count\n");
362 auto arrayElemCount = *tensorSize / *scalarSize;
367 if (!arrayElemSize) {
368 LLVM_DEBUG(llvm::dbgs()
369 << type <<
" illegal: cannot deduce converted element size\n");
381 type.getMemorySpaceAsInt());
383 LLVM_DEBUG(llvm::dbgs()
384 << type <<
" illegal: cannot convert memory space\n");
389 if (numBoolBits != 8) {
390 LLVM_DEBUG(llvm::dbgs()
391 <<
"using non-8-bit storage for bool types unimplemented");
394 auto elementType = IntegerType::get(type.getContext(), numBoolBits)
395 .dyn_cast<spirv::ScalarType>();
403 if (!arrayElemSize) {
404 LLVM_DEBUG(llvm::dbgs()
405 << type <<
" illegal: cannot deduce converted element size\n");
409 if (!type.hasStaticShape()) {
415 int64_t memrefSize = (type.getNumElements() * numBoolBits + 7) / 8;
416 auto arrayElemCount = llvm::divideCeil(memrefSize, *arrayElemSize);
426 if (type.getElementType().isa<IntegerType>() &&
427 type.getElementTypeBitWidth() == 1) {
433 type.getMemorySpaceAsInt());
435 LLVM_DEBUG(llvm::dbgs()
436 << type <<
" illegal: cannot convert memory space\n");
441 Type elementType = type.getElementType();
442 if (
auto vecType = elementType.
dyn_cast<VectorType>()) {
452 <<
" unhandled: can only convert scalar or vector element type\n");
459 if (!arrayElemSize) {
460 LLVM_DEBUG(llvm::dbgs()
461 << type <<
" illegal: cannot deduce converted element size\n");
465 if (!type.hasStaticShape()) {
473 LLVM_DEBUG(llvm::dbgs()
474 << type <<
" illegal: cannot deduce element count\n");
478 auto arrayElemCount = llvm::divideCeil(*memrefSize, *arrayElemSize);
487 : targetEnv(targetAttr), options(options) {
539 matchAndRewrite(func::FuncOp funcOp, OpAdaptor adaptor,
545 FuncOpConversion::matchAndRewrite(func::FuncOp funcOp, OpAdaptor adaptor,
547 auto fnType = funcOp.getFunctionType();
548 if (fnType.getNumResults() > 1)
552 for (
const auto &argType :
enumerate(fnType.getInputs())) {
553 auto convertedType = getTypeConverter()->convertType(argType.value());
556 signatureConverter.addInputs(argType.index(), convertedType);
560 if (fnType.getNumResults() == 1) {
561 resultType = getTypeConverter()->convertType(fnType.getResult(0));
567 auto newFuncOp = rewriter.
create<spirv::FuncOp>(
568 funcOp.getLoc(), funcOp.getName(),
574 for (
const auto &namedAttr : funcOp->getAttrs()) {
577 newFuncOp->setAttr(namedAttr.getName(), namedAttr.getValue());
583 &newFuncOp.getBody(), *getTypeConverter(), &signatureConverter)))
591 patterns.
add<FuncOpConversion>(typeConverter, patterns.
getContext());
599 spirv::BuiltIn builtin) {
602 for (
auto varOp : body.
getOps<spirv::GlobalVariableOp>()) {
603 if (
auto builtinAttr = varOp->getAttrOfType<StringAttr>(
604 spirv::SPIRVDialect::getAttributeName(
605 spirv::Decoration::BuiltIn))) {
606 auto varBuiltIn = spirv::symbolizeBuiltIn(builtinAttr.getValue());
607 if (varBuiltIn && *varBuiltIn == builtin) {
617 return std::string(
"__builtin_var_") + stringifyBuiltIn(builtin).str() +
"__";
621 static spirv::GlobalVariableOp
630 spirv::GlobalVariableOp newVarOp;
632 case spirv::BuiltIn::NumWorkgroups:
633 case spirv::BuiltIn::WorkgroupSize:
634 case spirv::BuiltIn::WorkgroupId:
635 case spirv::BuiltIn::LocalInvocationId:
636 case spirv::BuiltIn::GlobalInvocationId: {
638 spirv::StorageClass::Input);
641 builder.
create<spirv::GlobalVariableOp>(loc, ptrType, name, builtin);
644 case spirv::BuiltIn::SubgroupId:
645 case spirv::BuiltIn::NumSubgroups:
646 case spirv::BuiltIn::SubgroupSize: {
651 builder.
create<spirv::GlobalVariableOp>(loc, ptrType, name, builtin);
655 emitError(loc,
"unimplemented builtin variable generation for ")
656 << stringifyBuiltIn(builtin);
662 spirv::BuiltIn builtin,
667 op->
emitError(
"expected operation to be within a module-like op");
671 spirv::GlobalVariableOp varOp =
673 builtin, integerType, builder);
675 return builder.
create<spirv::LoadOp>(op->
getLoc(), ptr);
696 unsigned elementCount) {
697 for (
auto varOp : body.
getOps<spirv::GlobalVariableOp>()) {
705 if (ptrType.getStorageClass() == spirv::StorageClass::PushConstant) {
711 if (numElements == elementCount)
720 static spirv::GlobalVariableOp
729 const char *name =
"__push_constant_var__";
730 return builder.
create<spirv::GlobalVariableOp>(loc, type, name,
735 unsigned offset,
Type integerType,
740 op->
emitError(
"expected operation to be within a module-like op");
745 loc, parent->
getRegion(0).
front(), elementCount, builder, integerType);
747 Value zeroOp = spirv::ConstantOp::getZero(integerType, loc, builder);
748 Value offsetOp = builder.create<spirv::ConstantOp>(
749 loc, integerType, builder.getI32IntegerAttr(offset));
750 auto addrOp = builder.create<spirv::AddressOfOp>(loc, varOp);
751 auto acOp = builder.create<spirv::AccessChainOp>(
752 loc, addrOp, llvm::makeArrayRef({zeroOp, offsetOp}));
753 return builder.create<spirv::LoadOp>(loc, acOp);
761 int64_t offset,
Type integerType,
763 assert(indices.size() == strides.size() &&
764 "must provide indices for all dimensions");
771 Value linearizedIndex = builder.
create<spirv::ConstantOp>(
772 loc, integerType, IntegerAttr::get(integerType, offset));
774 Value strideVal = builder.
create<spirv::ConstantOp>(
776 IntegerAttr::get(integerType, strides[index.index()]));
777 Value update = builder.
create<spirv::IMulOp>(loc, strideVal, index.value());
779 builder.
create<spirv::IAddOp>(loc, linearizedIndex, update);
781 return linearizedIndex;
792 llvm::is_contained(strides, MemRefType::getDynamicStrideOrOffset()) ||
793 offset == MemRefType::getDynamicStrideOrOffset()) {
800 auto zero = spirv::ConstantOp::getZero(indexType, loc, builder);
803 linearizedIndices.push_back(zero);
805 if (baseType.getRank() == 0) {
806 linearizedIndices.push_back(zero);
808 linearizedIndices.push_back(
809 linearizeIndex(indices, strides, offset, indexType, loc, builder));
811 return builder.
create<spirv::AccessChainOp>(loc, basePtr, linearizedIndices);
818 std::unique_ptr<SPIRVConversionTarget>
820 std::unique_ptr<SPIRVConversionTarget> target(
824 target->addDynamicallyLegalDialect<spirv::SPIRVDialect>(
827 [targetPtr](
Operation *op) {
return targetPtr->isLegalOp(op); });
834 bool SPIRVConversionTarget::isLegalOp(
Operation *op) {
838 if (
auto minVersionIfx = dyn_cast<spirv::QueryMinVersionInterface>(op)) {
840 if (minVersion && *minVersion > this->targetEnv.
getVersion()) {
841 LLVM_DEBUG(llvm::dbgs()
842 << op->
getName() <<
" illegal: requiring min version " 843 << spirv::stringifyVersion(*minVersion) <<
"\n");
847 if (
auto maxVersionIfx = dyn_cast<spirv::QueryMaxVersionInterface>(op)) {
849 if (maxVersion && *maxVersion < this->targetEnv.
getVersion()) {
850 LLVM_DEBUG(llvm::dbgs()
851 << op->
getName() <<
" illegal: requiring max version " 852 << spirv::stringifyVersion(*maxVersion) <<
"\n");
860 if (
auto extensions = dyn_cast<spirv::QueryExtensionInterface>(op))
862 extensions.getExtensions())))
868 if (
auto capabilities = dyn_cast<spirv::QueryCapabilityInterface>(op))
870 capabilities.getCapabilities())))
878 if (llvm::any_of(valueTypes,
884 if (
auto globalVar = dyn_cast<spirv::GlobalVariableOp>(op))
885 valueTypes.push_back(globalVar.type());
891 for (
Type valueType : valueTypes) {
892 typeExtensions.clear();
898 typeCapabilities.clear();
TODO: Remove this file when SCCP and integer range analysis have been ported to the new framework...
Type getIndexType() const
Gets the SPIR-V correspondence for the standard index type.
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
Operation is a basic unit of execution within MLIR.
const Options & getOptions() const
Returns the options controlling the SPIR-V type converter.
Type getPointeeType() const
Block represents an ordered list of Operations.
bool use64bitIndex
Use 64-bit integers to convert index types.
void getExtensions(SPIRVType::ExtensionArrayRefVector &extensions, Optional< StorageClass > storage=llvm::None)
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity...
static Type convertMemrefType(const spirv::TargetEnv &targetEnv, const SPIRVTypeConverter::Options &options, MemRefType type)
static unsigned getMemorySpaceForStorageClass(spirv::StorageClass)
Returns the corresponding memory space for memref given a SPIR-V storage class.
TargetEnvAttr getAttr() const
static Type convertTensorType(const spirv::TargetEnv &targetEnv, const SPIRVTypeConverter::Options &options, TensorType type)
Converts a tensor type to a suitable type under the given targetEnv.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value...
static RuntimeArrayType get(Type elementType)
SPIRVTypeConverter(spirv::TargetEnvAttr targetAttr, Options options={})
StringRef getTypeAttrName()
Return the name of the attribute used for function types.
static OpBuilder atBlockBegin(Block *block, Listener *listener=nullptr)
Create a builder and set the insertion point to before the first operation in the block but still ins...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
static spirv::GlobalVariableOp getOrInsertBuiltinVariable(Block &body, Location loc, spirv::BuiltIn builtin, Type integerType, OpBuilder &builder)
Gets or inserts a global variable for a builtin within body block.
bool allows(Capability) const
Returns true if the given capability is allowed.
static StructType get(ArrayRef< Type > memberTypes, ArrayRef< OffsetInfo > offsetInfo={}, ArrayRef< MemberDecorationInfo > memberDecorations={})
Construct a literal StructType with at least one member.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
This class represents an efficient way to signal success or failure.
static Type convertVectorType(const spirv::TargetEnv &targetEnv, const SPIRVTypeConverter::Options &options, VectorType type, Optional< spirv::StorageClass > storageClass={})
Converts a vector type to a suitable type under the given targetEnv.
LogicalResult getStridesAndOffset(MemRefType t, SmallVectorImpl< int64_t > &strides, int64_t &offset)
Returns the strides of the MemRef if the layout map is in strided form.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
This class provides all of the information necessary to convert a type signature. ...
#define STORAGE_SPACE_MAP_LIST(MAP_FN)
Mapping between SPIR-V storage classes to memref memory spaces.
Value getBuiltinVariableValue(Operation *op, BuiltIn builtin, Type integerType, OpBuilder &builder)
Returns the value for the given builtin variable.
static ArrayType get(Type elementType, unsigned elementCount)
static spirv::GlobalVariableOp getPushConstantVariable(Block &body, unsigned elementCount)
Returns the push constant varible containing elementCount 32-bit integer values in body...
MLIRContext * getContext() const
Returns the MLIRContext.
void populateBuiltinFuncToSPIRVPatterns(SPIRVTypeConverter &typeConverter, RewritePatternSet &patterns)
Appends to a pattern list additional patterns for translating the builtin func op to the SPIR-V diale...
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
static std::unique_ptr< SPIRVConversionTarget > get(spirv::TargetEnvAttr targetAttr)
Creates a SPIR-V conversion target for the given target environment.
This class provides an abstraction over the various different ranges of value types.
Location getLoc()
The source location the operation was defined or derived from.
Listener * getListener() const
Returns the current listener of this builder, or nullptr if this builder doesn't have a listener...
result_type_iterator result_type_end()
operand_type_iterator operand_type_begin()
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
void inlineRegionBefore(Region ®ion, Region &parent, Region::iterator before) override
PatternRewriter hook for moving blocks out of a region.
OpConversionPattern is a wrapper around ConversionPattern that allows for matching and rewriting agai...
A wrapper class around a spirv::TargetEnvAttr to provide query methods for allowed version/capabiliti...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
static PointerType get(Type pointeeType, StorageClass storageClass)
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
operand_type_iterator operand_type_end()
static std::string getBuiltinVarName(spirv::BuiltIn builtin)
Gets name of global variable for a builtin.
static spirv::GlobalVariableOp getOrInsertPushConstantVariable(Location loc, Block &block, unsigned elementCount, OpBuilder &b, Type indexType)
Gets or inserts a global variable for push constant storage containing elementCount 32-bit integer va...
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
static Optional< int64_t > getTypeNumBytes(const SPIRVTypeConverter::Options &options, Type type)
RAII guard to reset the insertion point of the builder when destroyed.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
void addConversion(FnT &&callback)
Register a conversion function.
Value getPushConstantValue(Operation *op, unsigned elementCount, unsigned offset, Type integerType, OpBuilder &builder)
Gets the value at the given offset of the push constant storage with a total of elementCount integerT...
This class is a general helper class for creating context-global objects like types, attributes, and affine expressions.
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&... args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments...
result_type_iterator result_type_begin()
static spirv::PointerType getPushConstantStorageType(unsigned elementCount, Builder &builder, Type indexType)
Returns the pointer type for the push constant storage containing elementCount 32-bit integer values...
static spirv::GlobalVariableOp getBuiltinVariable(Block &body, spirv::BuiltIn builtin)
static int64_t getNumElements(ShapedType type)
Value linearizeIndex(ValueRange indices, ArrayRef< int64_t > strides, int64_t offset, Type integerType, Location loc, OpBuilder &builder)
Generates IR to perform index linearization with the given indices and their corresponding strides...
spirv::AccessChainOp getElementPtr(SPIRVTypeConverter &typeConverter, MemRefType baseType, Value basePtr, ValueRange indices, Location loc, OpBuilder &builder)
Performs the index computation to get to the element at indices of the memory pointed to by basePtr...
void getCapabilities(SPIRVType::CapabilityArrayRefVector &capabilities, Optional< StorageClass > storage=llvm::None)
iterator_range< op_iterator< OpT > > getOps()
Return an iterator range over the operations within this block that are of 'OpT'. ...
static VectorType vectorType(CodeGen &codegen, Type etp)
Constructs vector type.
MLIRContext is the top-level object for a collection of MLIR operations.
Type getElementType() const
Returns the element type of this tensor type.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class implements a pattern rewriter for use with ConversionPatterns.
static spirv::PointerType wrapInStructAndGetPointer(Type elementType, spirv::StorageClass storageClass)
Wraps the given elementType in a struct and gets the pointer to the struct.
static Operation * getNearestSymbolTable(Operation *from)
Returns the nearest symbol table from a given operation from.
void eraseOp(Operation *op) override
PatternRewriter hook for erasing a dead operation.
#define STORAGE_SPACE_MAP_FN(storage, space)
unsigned boolNumBits
The number of bits to store a boolean value.
This class describes a specific conversion target.
FunctionType getFunctionType(TypeRange inputs, TypeRange results)
static Optional< spirv::StorageClass > getStorageClassForMemorySpace(unsigned space)
Returns the SPIR-V storage class given a memory space for memref.
static Type convertBoolMemrefType(const spirv::TargetEnv &targetEnv, const SPIRVTypeConverter::Options &options, MemRefType type)
static Type convertScalarType(const spirv::TargetEnv &targetEnv, const SPIRVTypeConverter::Options &options, spirv::ScalarType type, Optional< spirv::StorageClass > storageClass={})
Converts a scalar type to a suitable type under the given targetEnv.
OperationName getName()
The name of an operation is the key identifier for it.
Version getVersion() const
static bool needsExplicitLayout(spirv::StorageClass storageClass)
Returns true if the given storageClass needs explicit layout when used in Shader environments.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
This class helps build Operations.
This class provides an abstraction over the different types of ranges over Values.
static LogicalResult checkCapabilityRequirements(LabelT label, const spirv::TargetEnv &targetEnv, const spirv::SPIRVType::CapabilityArrayRefVector &candidates)
Checks that candidatescapability requirements are possible to be satisfied with the given isAllowedFn...
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
MLIRContext * getContext() const
bool emulateNon32BitScalarTypes
Whether to emulate non-32-bit scalar types with 32-bit scalar types if no native support.
An attribute that specifies the target version, allowed extensions and capabilities, and resource limits.
Type conversion from builtin types to SPIR-V types for shader interface.
FailureOr< Block * > convertRegionTypes(Region *region, TypeConverter &converter, TypeConverter::SignatureConversion *entryConversion=nullptr)
Convert the types of block arguments within the given region.
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static LogicalResult checkExtensionRequirements(LabelT label, const spirv::TargetEnv &targetEnv, const spirv::SPIRVType::ExtensionArrayRefVector &candidates)
Checks that candidates extension requirements are possible to be satisfied with the given targetEnv...
static bool isValid(VectorType)
Returns true if the given vector type is valid for the SPIR-V dialect.