31#include "llvm/ADT/APInt.h"
32#include "llvm/ADT/STLExtras.h"
33#include "llvm/ADT/SmallVector.h"
34#include "llvm/ADT/StringExtras.h"
35#include "llvm/Support/CheckedArithmetic.h"
36#include "llvm/Support/Debug.h"
37#include "llvm/Support/MathExtras.h"
41#define DEBUG_TYPE "mlir-spirv-conversion"
51static std::optional<SmallVector<int64_t>>
getTargetShape(VectorType vecType) {
52 LLVM_DEBUG(llvm::dbgs() <<
"Get target shape\n");
53 if (vecType.isScalable()) {
54 LLVM_DEBUG(llvm::dbgs()
55 <<
"--scalable vectors are not supported -> BAIL\n");
58 if (vecType.getRank() == 0) {
59 LLVM_DEBUG(llvm::dbgs() <<
"--0-D vectors are not supported -> BAIL\n");
66 LLVM_DEBUG(llvm::dbgs() <<
"--no unrolling target shape defined\n");
70 if (!maybeShapeRatio) {
71 LLVM_DEBUG(llvm::dbgs()
72 <<
"--could not compute integral shape ratio -> BAIL\n");
75 if (llvm::all_of(*maybeShapeRatio, [](
int64_t v) {
return v == 1; })) {
76 LLVM_DEBUG(llvm::dbgs() <<
"--no unrolling needed -> SKIP\n");
79 LLVM_DEBUG(llvm::dbgs()
80 <<
"--found an integral shape ratio to unroll to -> SUCCESS\n");
90template <
typename LabelT>
91static LogicalResult checkExtensionRequirements(
94 for (
const auto &ors : candidates) {
100 for (spirv::Extension ext : ors)
101 extStrings.push_back(spirv::stringifyExtension(ext));
103 llvm::dbgs() << label <<
" illegal: requires at least one extension in ["
104 << llvm::join(extStrings,
", ")
105 <<
"] but none allowed in target environment\n";
118template <
typename LabelT>
119static LogicalResult checkCapabilityRequirements(
122 for (
const auto &ors : candidates) {
123 if (targetEnv.
allows(ors))
128 for (spirv::Capability cap : ors)
129 capStrings.push_back(spirv::stringifyCapability(cap));
131 llvm::dbgs() << label <<
" illegal: requires at least one capability in ["
132 << llvm::join(capStrings,
", ")
133 <<
"] but none allowed in target environment\n";
142static bool needsExplicitLayout(spirv::StorageClass storageClass) {
143 switch (storageClass) {
144 case spirv::StorageClass::PhysicalStorageBuffer:
145 case spirv::StorageClass::PushConstant:
146 case spirv::StorageClass::StorageBuffer:
147 case spirv::StorageClass::Uniform:
157wrapInStructAndGetPointer(
Type elementType, spirv::StorageClass storageClass) {
158 auto structType = needsExplicitLayout(storageClass)
170 return cast<spirv::ScalarType>(
171 IntegerType::get(ctx,
options.use64bitIndex ? 64 : 32));
176static std::optional<int64_t>
178 if (isa<spirv::ScalarType>(type)) {
192 if (
options.emulateUnsupportedFloatTypes && isa<FloatType>(type)) {
199 if (
auto complexType = dyn_cast<ComplexType>(type)) {
200 auto elementSize = getTypeNumBytes(
options, complexType.getElementType());
203 return 2 * *elementSize;
206 if (
auto vecType = dyn_cast<VectorType>(type)) {
207 auto elementSize = getTypeNumBytes(
options, vecType.getElementType());
210 return vecType.getNumElements() * *elementSize;
213 if (
auto memRefType = dyn_cast<MemRefType>(type)) {
218 if (!memRefType.hasStaticShape() ||
219 failed(memRefType.getStridesAndOffset(strides, offset)))
225 auto elementSize = getTypeNumBytes(
options, memRefType.getElementType());
229 if (memRefType.getRank() == 0)
232 auto dims = memRefType.getShape();
233 if (llvm::is_contained(dims, ShapedType::kDynamic) ||
234 ShapedType::isDynamic(offset) ||
235 llvm::is_contained(strides, ShapedType::kDynamic))
239 for (
const auto &
shape : enumerate(dims))
240 memrefSize = std::max(memrefSize,
shape.value() * strides[
shape.index()]);
242 return (offset + memrefSize) * *elementSize;
245 if (
auto tensorType = dyn_cast<TensorType>(type)) {
246 if (!tensorType.hasStaticShape())
249 auto elementSize = getTypeNumBytes(
options, tensorType.getElementType());
254 for (
auto shape : tensorType.getShape())
268 std::optional<spirv::StorageClass> storageClass = {}) {
272 type.getExtensions(extensions, storageClass);
273 type.getCapabilities(capabilities, storageClass);
276 if (succeeded(checkCapabilityRequirements(type, targetEnv, capabilities)) &&
277 succeeded(checkExtensionRequirements(type, targetEnv, extensions)))
282 if (!
options.emulateLT32BitScalarTypes)
287 LLVM_DEBUG(llvm::dbgs()
289 <<
" not converted to 32-bit for SPIR-V to avoid truncation\n");
293 if (
auto floatType = dyn_cast<FloatType>(type)) {
294 LLVM_DEBUG(llvm::dbgs() << type <<
" converted to 32-bit for SPIR-V\n");
298 auto intType = cast<IntegerType>(type);
299 LLVM_DEBUG(llvm::dbgs() << type <<
" converted to 32-bit for SPIR-V\n");
300 return IntegerType::get(targetEnv.
getContext(), 32,
301 intType.getSignedness());
314 if (type.getWidth() > 8) {
315 LLVM_DEBUG(llvm::dbgs() <<
"not a subbyte type\n");
319 LLVM_DEBUG(llvm::dbgs() <<
"unsupported sub-byte storage kind\n");
323 if (!llvm::isPowerOf2_32(type.getWidth())) {
324 LLVM_DEBUG(llvm::dbgs()
325 <<
"unsupported non-power-of-two bitwidth in sub-byte" << type
330 LLVM_DEBUG(llvm::dbgs() << type <<
" converted to 32-bit for SPIR-V\n");
331 return IntegerType::get(type.getContext(), 32,
332 type.getSignedness());
339 if (!
options.emulateUnsupportedFloatTypes)
342 if (isa<Float8E5M2Type, Float8E4M3Type, Float8E4M3FNType, Float8E5M2FNUZType,
343 Float8E4M3FNUZType, Float8E4M3B11FNUZType, Float8E3M4Type,
344 Float8E8M0FNUType>(type))
345 return IntegerType::get(type.getContext(), type.getWidth());
346 LLVM_DEBUG(llvm::dbgs() <<
"unsupported 8-bit float type: " << type <<
"\n");
354convertShaped8BitFloatType(ShapedType type,
356 if (!
options.emulateUnsupportedFloatTypes)
358 Type srcElementType = type.getElementType();
359 Type convertedElementType =
nullptr;
361 if (isa<Float8E5M2Type, Float8E4M3Type, Float8E4M3FNType, Float8E5M2FNUZType,
362 Float8E4M3FNUZType, Float8E4M3B11FNUZType, Float8E3M4Type,
363 Float8E8M0FNUType>(srcElementType))
364 convertedElementType = IntegerType::get(
367 if (!convertedElementType)
370 return type.clone(convertedElementType);
377convertIndexElementType(ShapedType type,
379 Type indexType = dyn_cast<IndexType>(type.getElementType());
390 std::optional<spirv::StorageClass> storageClass = {}) {
391 type = cast<VectorType>(convertIndexElementType(type,
options));
392 type = cast<VectorType>(convertShaped8BitFloatType(type,
options));
393 auto scalarType = dyn_cast_or_null<spirv::ScalarType>(type.getElementType());
397 auto intType = dyn_cast<IntegerType>(type.getElementType());
399 LLVM_DEBUG(llvm::dbgs()
401 <<
" illegal: cannot convert non-scalar element type\n");
405 Type elementType = convertSubByteIntegerType(
options, intType);
409 if (type.getRank() <= 1 && type.getNumElements() == 1)
412 if (type.getNumElements() > 4) {
413 LLVM_DEBUG(llvm::dbgs()
414 << type <<
" illegal: > 4-element unimplemented\n");
418 return VectorType::get(type.getShape(), elementType);
421 if (type.getRank() <= 1 && type.getNumElements() == 1)
422 return convertScalarType(targetEnv,
options, scalarType, storageClass);
425 LLVM_DEBUG(llvm::dbgs()
426 << type <<
" illegal: not a valid composite type\n");
433 cast<spirv::CompositeType>(type).getExtensions(extensions, storageClass);
434 cast<spirv::CompositeType>(type).getCapabilities(capabilities, storageClass);
437 if (succeeded(checkCapabilityRequirements(type, targetEnv, capabilities)) &&
438 succeeded(checkExtensionRequirements(type, targetEnv, extensions)))
442 convertScalarType(targetEnv,
options, scalarType, storageClass);
444 return VectorType::get(type.getShape(), elementType);
451 std::optional<spirv::StorageClass> storageClass = {}) {
452 auto scalarType = dyn_cast_or_null<spirv::ScalarType>(type.getElementType());
454 LLVM_DEBUG(llvm::dbgs()
455 << type <<
" illegal: cannot convert non-scalar element type\n");
460 convertScalarType(targetEnv,
options, scalarType, storageClass);
463 if (elementType != type.getElementType()) {
464 LLVM_DEBUG(llvm::dbgs()
465 << type <<
" illegal: complex type emulation unsupported\n");
469 return VectorType::get(2, elementType);
482 if (!type.hasStaticShape()) {
483 LLVM_DEBUG(llvm::dbgs()
484 << type <<
" illegal: dynamic shape unimplemented\n");
488 type = cast<TensorType>(convertIndexElementType(type,
options));
489 type = cast<TensorType>(convertShaped8BitFloatType(type,
options));
490 auto scalarType = dyn_cast_or_null<spirv::ScalarType>(type.
getElementType());
492 LLVM_DEBUG(llvm::dbgs()
493 << type <<
" illegal: cannot convert non-scalar element type\n");
497 std::optional<int64_t> scalarSize = getTypeNumBytes(
options, scalarType);
498 std::optional<int64_t> tensorSize = getTypeNumBytes(
options, type);
499 if (!scalarSize || !tensorSize) {
500 LLVM_DEBUG(llvm::dbgs()
501 << type <<
" illegal: cannot deduce element count\n");
505 int64_t arrayElemCount = *tensorSize / *scalarSize;
506 if (arrayElemCount == 0) {
507 LLVM_DEBUG(llvm::dbgs()
508 << type <<
" illegal: cannot handle zero-element tensors\n");
511 if (arrayElemCount > std::numeric_limits<unsigned>::max()) {
512 LLVM_DEBUG(llvm::dbgs()
513 << type <<
" illegal: cannot fit tensor into target type\n");
517 Type arrayElemType = convertScalarType(targetEnv,
options, scalarType);
520 std::optional<int64_t> arrayElemSize =
521 getTypeNumBytes(
options, arrayElemType);
522 if (!arrayElemSize) {
523 LLVM_DEBUG(llvm::dbgs()
524 << type <<
" illegal: cannot deduce converted element size\n");
534 spirv::StorageClass storageClass) {
535 unsigned numBoolBits =
options.boolNumBits;
536 if (numBoolBits != 8) {
537 LLVM_DEBUG(llvm::dbgs()
538 <<
"using non-8-bit storage for bool types unimplemented");
541 auto elementType = dyn_cast<spirv::ScalarType>(
542 IntegerType::get(type.
getContext(), numBoolBits));
546 convertScalarType(targetEnv,
options, elementType, storageClass);
549 std::optional<int64_t> arrayElemSize =
550 getTypeNumBytes(
options, arrayElemType);
551 if (!arrayElemSize) {
552 LLVM_DEBUG(llvm::dbgs()
553 << type <<
" illegal: cannot deduce converted element size\n");
557 if (!type.hasStaticShape()) {
560 if (targetEnv.
allows(spirv::Capability::Kernel))
562 int64_t stride = needsExplicitLayout(storageClass) ? *arrayElemSize : 0;
566 return wrapInStructAndGetPointer(arrayType, storageClass);
569 if (type.getNumElements() == 0) {
570 LLVM_DEBUG(llvm::dbgs()
571 << type <<
" illegal: zero-element memrefs are not supported\n");
575 int64_t memrefSize = llvm::divideCeil(type.getNumElements() * numBoolBits, 8);
576 int64_t arrayElemCount = llvm::divideCeil(memrefSize, *arrayElemSize);
577 int64_t stride = needsExplicitLayout(storageClass) ? *arrayElemSize : 0;
579 if (targetEnv.
allows(spirv::Capability::Kernel))
581 return wrapInStructAndGetPointer(arrayType, storageClass);
587 spirv::StorageClass storageClass) {
588 IntegerType elementType = cast<IntegerType>(type.getElementType());
589 Type arrayElemType = convertSubByteIntegerType(
options, elementType);
594 if (!type.hasStaticShape()) {
597 if (targetEnv.
allows(spirv::Capability::Kernel))
599 int64_t stride = needsExplicitLayout(storageClass) ? arrayElemSize : 0;
603 return wrapInStructAndGetPointer(arrayType, storageClass);
606 if (type.getNumElements() == 0) {
607 LLVM_DEBUG(llvm::dbgs()
608 << type <<
" illegal: zero-element memrefs are not supported\n");
613 llvm::divideCeil(type.getNumElements() * elementType.getWidth(), 8);
614 int64_t arrayElemCount = llvm::divideCeil(memrefSize, arrayElemSize);
615 int64_t stride = needsExplicitLayout(storageClass) ? arrayElemSize : 0;
617 if (targetEnv.
allows(spirv::Capability::Kernel))
619 return wrapInStructAndGetPointer(arrayType, storageClass);
622static spirv::Dim convertRank(
int64_t rank) {
625 return spirv::Dim::Dim1D;
627 return spirv::Dim::Dim2D;
629 return spirv::Dim::Dim3D;
631 llvm_unreachable(
"Invalid memref rank!");
635static spirv::ImageFormat getImageFormat(
Type elementType) {
637 .Case([](Float16Type) {
return spirv::ImageFormat::R16f; })
638 .Case([](Float32Type) {
return spirv::ImageFormat::R32f; })
639 .Case([](IntegerType intType) {
640 auto const isSigned = intType.isSigned() || intType.isSignless();
641#define BIT_WIDTH_CASE(BIT_WIDTH) \
643 return isSigned ? spirv::ImageFormat::R##BIT_WIDTH##i \
644 : spirv::ImageFormat::R##BIT_WIDTH##ui
646 switch (intType.getWidth()) {
650 llvm_unreachable(
"Unhandled integer type!");
653 .DefaultUnreachable(
"Unhandled element type!");
660 auto attr = dyn_cast_or_null<spirv::StorageClassAttr>(type.getMemorySpace());
665 <<
" illegal: expected memory space to be a SPIR-V storage class "
666 "attribute; please use MemorySpaceToStorageClassConverter to map "
667 "numeric memory spaces beforehand\n");
670 spirv::StorageClass storageClass = attr.getValue();
675 if (storageClass == spirv::StorageClass::Image) {
676 const int64_t rank = type.getRank();
677 if (rank < 1 || rank > 3) {
678 LLVM_DEBUG(llvm::dbgs()
679 << type <<
" illegal: cannot lower memref of rank " << rank
680 <<
" to a SPIR-V Image\n");
686 auto elementType = type.getElementType();
687 if (!isa<spirv::ScalarType>(elementType)) {
688 LLVM_DEBUG(llvm::dbgs() << type <<
" illegal: cannot lower memref of "
689 << elementType <<
" to a SPIR-V Image\n");
697 elementType, convertRank(rank), spirv::ImageDepthInfo::DepthUnknown,
698 spirv::ImageArrayedInfo::NonArrayed,
699 spirv::ImageSamplingInfo::SingleSampled,
700 spirv::ImageSamplerUseInfo::NeedSampler, getImageFormat(elementType));
703 spvSampledImageType, spirv::StorageClass::UniformConstant);
707 if (isa<IntegerType>(type.getElementType())) {
708 if (type.getElementTypeBitWidth() == 1)
709 return convertBoolMemrefType(targetEnv,
options, type, storageClass);
710 if (type.getElementTypeBitWidth() < 8)
711 return convertSubByteMemrefType(targetEnv,
options, type, storageClass);
715 Type elementType = type.getElementType();
716 if (
auto vecType = dyn_cast<VectorType>(elementType)) {
718 convertVectorType(targetEnv,
options, vecType, storageClass);
719 }
else if (
auto complexType = dyn_cast<ComplexType>(elementType)) {
721 convertComplexType(targetEnv,
options, complexType, storageClass);
722 }
else if (
auto scalarType = dyn_cast<spirv::ScalarType>(elementType)) {
724 convertScalarType(targetEnv,
options, scalarType, storageClass);
725 }
else if (
auto indexType = dyn_cast<IndexType>(elementType)) {
726 type = cast<MemRefType>(convertIndexElementType(type,
options));
727 arrayElemType = type.getElementType();
728 }
else if (
auto floatType = dyn_cast<FloatType>(elementType)) {
730 type = cast<MemRefType>(convertShaped8BitFloatType(type,
options));
731 arrayElemType = type.getElementType();
736 <<
" unhandled: can only convert scalar or vector element type\n");
742 std::optional<int64_t> arrayElemSize =
743 getTypeNumBytes(
options, arrayElemType);
744 if (!arrayElemSize) {
745 LLVM_DEBUG(llvm::dbgs()
746 << type <<
" illegal: cannot deduce converted element size\n");
750 if (!type.hasStaticShape()) {
753 if (targetEnv.
allows(spirv::Capability::Kernel))
755 int64_t stride = needsExplicitLayout(storageClass) ? *arrayElemSize : 0;
759 return wrapInStructAndGetPointer(arrayType, storageClass);
762 std::optional<int64_t> memrefSize = getTypeNumBytes(
options, type);
764 LLVM_DEBUG(llvm::dbgs()
765 << type <<
" illegal: cannot deduce element count\n");
769 if (*memrefSize == 0) {
770 LLVM_DEBUG(llvm::dbgs()
771 << type <<
" illegal: zero-element memrefs are not supported\n");
775 int64_t arrayElemCount = llvm::divideCeil(*memrefSize, *arrayElemSize);
776 int64_t stride = needsExplicitLayout(storageClass) ? *arrayElemSize : 0;
778 if (targetEnv.
allows(spirv::Capability::Kernel))
780 return wrapInStructAndGetPointer(arrayType, storageClass);
804 if (inputs.size() != 1) {
806 UnrealizedConversionCastOp::create(builder, loc, type, inputs);
807 return castOp.getResult(0);
809 Value input = inputs.front();
812 if (!isa<IntegerType>(type)) {
814 UnrealizedConversionCastOp::create(builder, loc, type, inputs);
815 return castOp.getResult(0);
817 auto inputType = cast<IntegerType>(input.
getType());
819 auto scalarType = dyn_cast<spirv::ScalarType>(type);
822 UnrealizedConversionCastOp::create(builder, loc, type, inputs);
823 return castOp.getResult(0);
829 if (inputType.getIntOrFloatBitWidth() < scalarType.getIntOrFloatBitWidth()) {
831 UnrealizedConversionCastOp::create(builder, loc, type, inputs);
832 return castOp.getResult(0);
837 Value one = spirv::ConstantOp::getOne(inputType, loc, builder);
838 return spirv::IEqualOp::create(builder, loc, input, one);
844 scalarType.getExtensions(exts);
845 scalarType.getCapabilities(caps);
846 if (failed(checkCapabilityRequirements(type, targetEnv, caps)) ||
847 failed(checkExtensionRequirements(type, targetEnv, exts))) {
849 UnrealizedConversionCastOp::create(builder, loc, type, inputs);
850 return castOp.getResult(0);
857 return spirv::SConvertOp::create(builder, loc, type, input);
859 return spirv::UConvertOp::create(builder, loc, type, input);
866static spirv::GlobalVariableOp getBuiltinVariable(
Block &body,
870 for (
auto varOp : body.
getOps<spirv::GlobalVariableOp>()) {
871 if (StringAttr builtinAttr = varOp.getBuiltInAttr()) {
872 auto varBuiltIn = spirv::symbolizeBuiltIn(builtinAttr.getValue());
882std::string getBuiltinVarName(spirv::BuiltIn
builtin, StringRef prefix,
884 return Twine(prefix).concat(stringifyBuiltIn(
builtin)).concat(suffix).str();
888static spirv::GlobalVariableOp
891 StringRef prefix, StringRef suffix) {
892 if (
auto varOp = getBuiltinVariable(body,
builtin))
898 spirv::GlobalVariableOp newVarOp;
900 case spirv::BuiltIn::NumWorkgroups:
901 case spirv::BuiltIn::WorkgroupSize:
902 case spirv::BuiltIn::WorkgroupId:
903 case spirv::BuiltIn::LocalInvocationId:
904 case spirv::BuiltIn::GlobalInvocationId: {
906 spirv::StorageClass::Input);
907 std::string name = getBuiltinVarName(
builtin, prefix, suffix);
909 spirv::GlobalVariableOp::create(builder, loc, ptrType, name,
builtin);
912 case spirv::BuiltIn::SubgroupId:
913 case spirv::BuiltIn::NumSubgroups:
914 case spirv::BuiltIn::SubgroupSize:
915 case spirv::BuiltIn::SubgroupLocalInvocationId: {
918 std::string name = getBuiltinVarName(
builtin, prefix, suffix);
920 spirv::GlobalVariableOp::create(builder, loc, ptrType, name,
builtin);
924 emitError(loc,
"unimplemented builtin variable generation for ")
947static spirv::GlobalVariableOp getPushConstantVariable(
Block &body,
948 unsigned elementCount) {
949 for (
auto varOp : body.
getOps<spirv::GlobalVariableOp>()) {
950 auto ptrType = dyn_cast<spirv::PointerType>(varOp.getType());
957 if (ptrType.getStorageClass() == spirv::StorageClass::PushConstant) {
958 auto numElements = cast<spirv::ArrayType>(
959 cast<spirv::StructType>(ptrType.getPointeeType())
962 if (numElements == elementCount)
971static spirv::GlobalVariableOp
975 if (
auto varOp = getPushConstantVariable(block, elementCount))
979 auto type = getPushConstantStorageType(elementCount, builder, indexType);
980 const char *name =
"__push_constant_var__";
981 return spirv::GlobalVariableOp::create(builder, loc, type, name,
991struct FuncOpConversion final : OpConversionPattern<func::FuncOp> {
995 matchAndRewrite(func::FuncOp funcOp, OpAdaptor adaptor,
996 ConversionPatternRewriter &rewriter)
const override {
997 FunctionType fnType = funcOp.getFunctionType();
998 if (fnType.getNumResults() > 1)
1001 TypeConverter::SignatureConversion signatureConverter(
1002 fnType.getNumInputs());
1003 for (
const auto &argType : enumerate(fnType.getInputs())) {
1004 auto convertedType = getTypeConverter()->convertType(argType.value());
1007 signatureConverter.addInputs(argType.index(), convertedType);
1011 if (fnType.getNumResults() == 1) {
1012 resultType = getTypeConverter()->convertType(fnType.getResult(0));
1018 auto newFuncOp = spirv::FuncOp::create(
1019 rewriter, funcOp.getLoc(), funcOp.getName(),
1020 rewriter.getFunctionType(signatureConverter.getConvertedTypes(),
1024 newFuncOp.setArgAttrsAttr(funcOp.getArgAttrsAttr());
1025 newFuncOp.setResAttrsAttr(funcOp.getResAttrsAttr());
1026 cast<SymbolOpInterface>(newFuncOp.getOperation())
1028 cast<SymbolOpInterface>(funcOp.getOperation()).getVisibility());
1032 funcOp->getDiscardableAttrDictionary().
getValue()) {
1033 if (namedAttr.getName() != funcOp.getFunctionTypeAttrName() &&
1035 newFuncOp->setDiscardableAttr(namedAttr.getName(),
1036 namedAttr.getValue());
1039 rewriter.inlineRegionBefore(funcOp.getBody(), newFuncOp.getBody(),
1041 if (failed(rewriter.convertRegionTypes(
1042 &newFuncOp.getBody(), *getTypeConverter(), &signatureConverter)))
1044 rewriter.eraseOp(funcOp);
1054 LogicalResult matchAndRewrite(func::FuncOp funcOp,
1056 FunctionType fnType = funcOp.getFunctionType();
1059 if (funcOp.isDeclaration()) {
1060 LLVM_DEBUG(llvm::dbgs()
1061 << fnType <<
" illegal: declarations are unsupported\n");
1068 if (llvm::any_of(fnType.getInputs(), [](
Type argType) {
1069 auto shapedType = dyn_cast<ShapedType>(argType);
1070 return shapedType && !shapedType.hasStaticShape();
1075 auto newFuncOp = func::FuncOp::create(rewriter, funcOp.getLoc(),
1076 funcOp.getName(), fnType);
1080 Location loc = newFuncOp.getBody().getLoc();
1082 Block &entryBlock = newFuncOp.getBlocks().
front();
1086 TypeConverter::SignatureConversion oneToNTypeMapping(
1087 fnType.getInputs().size());
1093 size_t newInputNo = 0;
1099 llvm::SmallDenseMap<Operation *, size_t> tmpOps;
1102 size_t newOpCount = 0;
1105 for (
auto [origInputNo, origType] : enumerate(fnType.getInputs())) {
1107 auto origVecType = dyn_cast<VectorType>(origType);
1111 rewriter, loc, origType, rewriter.
getZeroAttr(origType));
1113 tmpOps.insert({
result.getDefiningOp(), newInputNo});
1114 oneToNTypeMapping.addInputs(origInputNo, origType);
1124 rewriter, loc, origType, rewriter.
getZeroAttr(origType));
1126 tmpOps.insert({
result.getDefiningOp(), newInputNo});
1127 oneToNTypeMapping.addInputs(origInputNo, origType);
1132 VectorType unrolledType =
1133 VectorType::get(*targetShape, origVecType.getElementType());
1134 auto originalShape =
1135 llvm::to_vector_of<int64_t, 4>(origVecType.getShape());
1139 rewriter, loc, origVecType, rewriter.
getZeroAttr(origVecType));
1142 Value dummy = arith::ConstantOp::create(
1143 rewriter, loc, unrolledType, rewriter.
getZeroAttr(unrolledType));
1151 result = vector::InsertStridedSliceOp::create(rewriter, loc, dummy,
1152 result, offsets, strides);
1153 newTypes.push_back(unrolledType);
1154 unrolledInputNums.push_back(newInputNo);
1159 oneToNTypeMapping.addInputs(origInputNo, newTypes);
1163 auto convertedTypes = oneToNTypeMapping.getConvertedTypes();
1164 auto newFnType = fnType.clone(convertedTypes, fnType.getResults());
1166 [&] { newFuncOp.setFunctionType(newFnType); });
1175 for (
auto &[placeholderOp, argIdx] : tmpOps) {
1186 size_t unrolledInputIdx = 0;
1187 for (
auto [count, op] : enumerate(entryBlock.
getOperations())) {
1192 if (count >= newOpCount)
1194 if (
auto vecOp = dyn_cast<vector::InsertStridedSliceOp>(op)) {
1195 size_t unrolledInputNo = unrolledInputNums[unrolledInputIdx];
1197 curOp.
setOperand(0, newFuncOp.getArgument(unrolledInputNo));
1219 LogicalResult matchAndRewrite(func::ReturnOp returnOp,
1222 auto funcOp = dyn_cast<func::FuncOp>(returnOp->getParentOp());
1226 FunctionType fnType = funcOp.getFunctionType();
1227 TypeConverter::SignatureConversion oneToNTypeMapping(
1228 fnType.getResults().size());
1235 for (
auto [origResultNo, origType] : enumerate(fnType.getResults())) {
1237 auto origVecType = dyn_cast<VectorType>(origType);
1239 oneToNTypeMapping.addInputs(origResultNo, origType);
1240 newOperands.push_back(returnOp.getOperand(origResultNo));
1247 oneToNTypeMapping.addInputs(origResultNo, origType);
1248 newOperands.push_back(returnOp.getOperand(origResultNo));
1251 VectorType unrolledType =
1252 VectorType::get(*targetShape, origVecType.getElementType());
1256 auto originalShape =
1257 llvm::to_vector_of<int64_t, 4>(origVecType.getShape());
1260 extractShape.back() = targetShape->back();
1262 Value returnValue = returnOp.getOperand(origResultNo);
1265 Value result = vector::ExtractStridedSliceOp::create(
1266 rewriter, loc, returnValue, offsets, extractShape, strides);
1267 if (originalShape.size() > 1) {
1270 vector::ExtractOp::create(rewriter, loc,
result, extractIndices);
1272 newOperands.push_back(
result);
1273 newTypes.push_back(unrolledType);
1275 oneToNTypeMapping.addInputs(origResultNo, newTypes);
1281 TypeRange(oneToNTypeMapping.getConvertedTypes()));
1283 [&] { funcOp.setFunctionType(newFnType); });
1288 func::ReturnOp::create(rewriter, loc, newOperands));
1294static void addNoWrapDecorations(
Operation *op,
1310 if (
shape.size() != strides.size() || offset < 0)
1311 return std::nullopt;
1313 uint64_t maxLinearIndex = offset;
1314 for (
auto [dimension, stride] : llvm::zip(
shape, strides)) {
1315 if (dimension <= 0 || stride < 0)
1316 return std::nullopt;
1317 std::optional<uint64_t> nextMaxLinearIndex = llvm::checkedMulAddUnsigned(
1318 static_cast<uint64_t
>(dimension - 1),
static_cast<uint64_t
>(stride),
1320 if (!nextMaxLinearIndex)
1321 return std::nullopt;
1322 maxLinearIndex = *nextMaxLinearIndex;
1324 return maxLinearIndex;
1327static std::optional<uint64_t> getStorageBufferElementCount(
Value basePtr) {
1328 auto pointerType = dyn_cast<spirv::PointerType>(basePtr.
getType());
1330 pointerType.getStorageClass() != spirv::StorageClass::StorageBuffer)
1331 return std::nullopt;
1333 Type pointeeType = pointerType.getPointeeType();
1334 if (
auto structType = dyn_cast<spirv::StructType>(pointeeType)) {
1335 if (structType.getNumElements() != 1)
1336 return std::nullopt;
1337 pointeeType = structType.getElementType(0);
1339 auto arrayType = dyn_cast<spirv::ArrayType>(pointeeType);
1341 return std::nullopt;
1342 return arrayType.getNumElements();
1345static bool shouldEmitInBoundsAccessChain(MemRefType baseType,
Value basePtr,
1348 uint64_t accessElementCount) {
1352 if (
auto integerType = dyn_cast<IntegerType>(baseType.getElementType()))
1353 if (integerType.getWidth() < 16)
1356 std::optional<uint64_t> maxSourceElementIndex =
1357 getMaxLinearizedIndex(baseType.getShape(), strides, offset);
1358 std::optional<uint64_t> storageElementCount =
1359 getStorageBufferElementCount(basePtr);
1360 if (!maxSourceElementIndex || !storageElementCount)
1363 if (accessElementCount == 0 || accessElementCount > *storageElementCount)
1372 return *maxSourceElementIndex < *storageElementCount;
1384 StringRef prefix, StringRef suffix) {
1387 op->
emitError(
"expected operation to be within a module-like op");
1391 spirv::GlobalVariableOp varOp =
1393 builtin, integerType, builder, prefix, suffix);
1394 Value ptr = spirv::AddressOfOp::create(builder, op->
getLoc(), varOp);
1395 return spirv::LoadOp::create(builder, op->
getLoc(),
ptr);
1403 unsigned offset,
Type integerType,
1408 op->
emitError(
"expected operation to be within a module-like op");
1412 spirv::GlobalVariableOp varOp = getOrInsertPushConstantVariable(
1413 loc, parent->
getRegion(0).
front(), elementCount, builder, integerType);
1415 Value zeroOp = spirv::ConstantOp::getZero(integerType, loc, builder);
1416 Value offsetOp = spirv::ConstantOp::create(builder, loc, integerType,
1418 auto addrOp = spirv::AddressOfOp::create(builder, loc, varOp);
1419 auto acOp = spirv::AccessChainOp::create(builder, loc, addrOp,
1421 return spirv::LoadOp::create(builder, loc, acOp);
1434 if (!targetEnv.
allows(Extension::SPV_KHR_no_integer_wrap_decoration))
1437 auto integer = dyn_cast<IntegerType>(integerType);
1441 std::optional<uint64_t> maxLinearIndex =
1442 getMaxLinearizedIndex(
shape, strides, offset);
1443 if (!maxLinearIndex)
1448 APInt::getSignedMaxValue(integer.getWidth()).getZExtValue();
1450 *maxLinearIndex <= APInt::getMaxValue(integer.getWidth()).getZExtValue();
1458 assert(
indices.size() == strides.size() &&
1459 "must provide indices for all dimensions");
1467 loc, integerType, IntegerAttr::get(integerType, offset));
1471 IntegerAttr::get(integerType, strides[
index.index()]));
1475 if (
auto mul = update.getDefiningOp<spirv::IMulOp>())
1476 addNoWrapDecorations(
mul, noWrapFlags, builder);
1479 builder.
createOrFold<spirv::IAddOp>(loc, update, linearizedIndex);
1482 addNoWrapDecorations(
add, noWrapFlags, builder);
1484 return linearizedIndex;
1488 MemRefType baseType,
Value basePtr,
1491 uint64_t accessElementCount) {
1496 if (failed(baseType.getStridesAndOffset(strides, offset)) ||
1497 llvm::is_contained(strides, ShapedType::kDynamic) ||
1498 ShapedType::isDynamic(offset)) {
1504 typeConverter.
getTargetEnv(), baseType.getShape(), strides, offset,
1508 auto zero = spirv::ConstantOp::getZero(indexType, loc, builder);
1510 if (baseType.getRank() == 0) {
1511 linearizedIndices.push_back(zero);
1514 indices, strides, offset, indexType, loc, builder, noWrapFlags));
1517 const Type pointeeType =
1518 cast<spirv::PointerType>(basePtr.
getType()).getPointeeType();
1520 if (isa<spirv::StructType>(pointeeType))
1521 linearizedIndices.insert(linearizedIndices.begin(), zero);
1522 if (shouldEmitInBoundsAccessChain(baseType, basePtr, strides, offset,
1523 accessElementCount))
1524 return spirv::InBoundsAccessChainOp::create(builder, loc, basePtr,
1526 return spirv::AccessChainOp::create(builder, loc, basePtr, linearizedIndices);
1530 MemRefType baseType,
Value basePtr,
1538 MemRefType baseType,
Value basePtr,
1545 if (failed(baseType.getStridesAndOffset(strides, offset)) ||
1546 llvm::is_contained(strides, ShapedType::kDynamic) ||
1547 ShapedType::isDynamic(offset)) {
1553 typeConverter.
getTargetEnv(), baseType.getShape(), strides, offset,
1558 if (baseType.getRank() == 0) {
1559 linearIndex = spirv::ConstantOp::getZero(indexType, loc, builder);
1562 builder, noWrapFlags);
1565 cast<spirv::PointerType>(basePtr.
getType()).getPointeeType();
1566 if (isa<spirv::ArrayType>(pointeeType)) {
1567 linearizedIndices.push_back(linearIndex);
1568 return spirv::AccessChainOp::create(builder, loc, basePtr,
1571 return spirv::PtrAccessChainOp::create(builder, loc, basePtr, linearIndex,
1576 MemRefType baseType,
Value basePtr,
1579 uint64_t accessElementCount) {
1581 if (typeConverter.
allows(spirv::Capability::Kernel)) {
1587 builder, accessElementCount);
1591 MemRefType baseType,
Value basePtr,
1603 for (
int i : {4, 3, 2}) {
1612 VectorType srcVectorType = op.getSourceVectorType();
1613 assert(srcVectorType.getRank() == 1);
1616 return {vectorSize};
1621 VectorType vectorType = op.getResultVectorType();
1628std::optional<SmallVector<int64_t>>
1631 if (
auto vecType = dyn_cast<VectorType>(op->
getResultTypes()[0])) {
1632 if (vecType.getRank() == 0)
1633 return std::nullopt;
1642 .Case<vector::ReductionOp, vector::TransposeOp>(
1644 .Default(std::nullopt);
1668 populateVectorUnrollPatterns(patterns,
options);
1678 patterns, vector::VectorTransposeLowering::EltWise);
1689 vector::populateCastAwayVectorLeadingOneDimPatterns(patterns);
1690 vector::ReductionOp::getCanonicalizationPatterns(patterns, context);
1691 vector::TransposeOp::getCanonicalizationPatterns(patterns, context);
1695 vector::populateVectorInsertExtractStridedSliceDecompositionPatterns(
1697 vector::InsertOp::getCanonicalizationPatterns(patterns, context);
1698 vector::ExtractOp::getCanonicalizationPatterns(patterns, context);
1702 vector::BroadcastOp::getCanonicalizationPatterns(patterns, context);
1703 vector::ShapeCastOp::getCanonicalizationPatterns(patterns, context);
1717 : targetEnv(targetAttr), options(options) {
1730 addConversion([
this](IndexType ) {
return getIndexType(); });
1732 addConversion([
this](IntegerType intType) -> std::optional<Type> {
1733 if (
auto scalarType = dyn_cast<spirv::ScalarType>(intType))
1734 return convertScalarType(this->targetEnv, this->options, scalarType);
1735 if (intType.getWidth() < 8)
1736 return convertSubByteIntegerType(this->options, intType);
1740 addConversion([
this](FloatType floatType) -> std::optional<Type> {
1741 if (
auto scalarType = dyn_cast<spirv::ScalarType>(floatType))
1742 return convertScalarType(this->targetEnv, this->options, scalarType);
1743 if (floatType.getWidth() == 8)
1744 return convert8BitFloatType(this->options, floatType);
1748 addConversion([
this](ComplexType complexType) {
1749 return convertComplexType(this->targetEnv, this->options, complexType);
1752 addConversion([
this](VectorType vectorType) {
1753 return convertVectorType(this->targetEnv, this->options, vectorType);
1756 addConversion([
this](
TensorType tensorType) {
1757 return convertTensorType(this->targetEnv, this->options, tensorType);
1760 addConversion([
this](MemRefType memRefType) {
1761 return convertMemrefType(this->targetEnv, this->options, memRefType);
1765 addSourceMaterialization(
1767 return castToSourceType(this->targetEnv, builder, type, inputs, loc);
1771 auto cast = UnrealizedConversionCastOp::create(builder, loc, type, inputs);
1772 return cast.getResult(0);
1777 return ::getIndexType(
getContext(), options);
1780MLIRContext *SPIRVTypeConverter::getContext()
const {
1781 return targetEnv.
getAttr().getContext();
1785 return targetEnv.allows(capability);
1792std::unique_ptr<SPIRVConversionTarget>
1794 std::unique_ptr<SPIRVConversionTarget>
target(
1796 new SPIRVConversionTarget(targetAttr));
1797 SPIRVConversionTarget *targetPtr =
target.get();
1798 target->addDynamicallyLegalDialect<spirv::SPIRVDialect>(
1801 [targetPtr](
Operation *op) {
return targetPtr->isLegalOp(op); });
1808bool SPIRVConversionTarget::isLegalOp(
Operation *op) {
1812 if (
auto minVersionIfx = dyn_cast<spirv::QueryMinVersionInterface>(op)) {
1813 std::optional<spirv::Version> minVersion = minVersionIfx.getMinVersion();
1814 if (minVersion && *minVersion > this->targetEnv.
getVersion()) {
1815 LLVM_DEBUG(llvm::dbgs()
1816 << op->
getName() <<
" illegal: requiring min version "
1817 << spirv::stringifyVersion(*minVersion) <<
"\n");
1821 if (
auto maxVersionIfx = dyn_cast<spirv::QueryMaxVersionInterface>(op)) {
1822 std::optional<spirv::Version> maxVersion = maxVersionIfx.getMaxVersion();
1823 if (maxVersion && *maxVersion < this->targetEnv.getVersion()) {
1824 LLVM_DEBUG(llvm::dbgs()
1825 << op->
getName() <<
" illegal: requiring max version "
1826 << spirv::stringifyVersion(*maxVersion) <<
"\n");
1834 if (
auto extensions = dyn_cast<spirv::QueryExtensionInterface>(op))
1835 if (
failed(checkExtensionRequirements(op->
getName(), this->targetEnv,
1836 extensions.getExtensions())))
1842 if (
auto capabilities = dyn_cast<spirv::QueryCapabilityInterface>(op))
1843 if (
failed(checkCapabilityRequirements(op->
getName(), this->targetEnv,
1844 capabilities.getCapabilities())))
1847 SmallVector<Type, 4> valueTypes;
1852 if (llvm::any_of(valueTypes,
1853 [](Type t) {
return !isa<spirv::SPIRVType>(t); }))
1858 if (
auto globalVar = dyn_cast<spirv::GlobalVariableOp>(op))
1859 valueTypes.push_back(globalVar.getType());
1863 SmallVector<ArrayRef<spirv::Extension>, 4> typeExtensions;
1864 SmallVector<ArrayRef<spirv::Capability>, 8> typeCapabilities;
1865 for (Type valueType : valueTypes) {
1866 typeExtensions.clear();
1867 cast<spirv::SPIRVType>(valueType).getExtensions(typeExtensions);
1868 if (
failed(checkExtensionRequirements(op->
getName(), this->targetEnv,
1872 typeCapabilities.clear();
1873 cast<spirv::SPIRVType>(valueType).getCapabilities(typeCapabilities);
1874 if (
failed(checkCapabilityRequirements(op->
getName(), this->targetEnv,
1888 patterns.
add<FuncOpConversion>(typeConverter, patterns.
getContext());
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static llvm::ManagedStatic< PassManagerOptions > options
#define BIT_WIDTH_CASE(BIT_WIDTH)
static std::optional< SmallVector< int64_t > > getTargetShape(const vector::UnrollVectorOptions &options, Operation *op)
Return the target shape for unrolling for the given op.
Block represents an ordered list of Operations.
iterator_range< op_iterator< OpT > > getOps()
Return an iterator range over the operations within this block that are of 'OpT'.
iterator_range< args_iterator > addArguments(TypeRange types, ArrayRef< Location > locs)
Add one argument to the argument list for each type specified in the list.
OpListType & getOperations()
void eraseArguments(unsigned start, unsigned num)
Erases 'num' arguments from the index 'start'.
This class is a general helper class for creating context-global objects like types,...
IntegerAttr getI32IntegerAttr(int32_t value)
TypedAttr getZeroAttr(Type type)
MLIRContext * getContext() const
This class allows control over how the GreedyPatternRewriteDriver works.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttribute represents a combination of a name and an Attribute value.
Attribute getValue() const
Return the value of the attribute.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
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...
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
void createOrFold(SmallVectorImpl< Value > &results, Location location, Args &&...args)
Create an operation of specific op type at the current insertion point, and immediately try to fold i...
Operation is the basic unit of execution within MLIR.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
void setOperand(unsigned idx, Value value)
void setDiscardableAttr(StringAttr name, Attribute value)
Set a discardable attribute by name.
operand_type_iterator operand_type_end()
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
result_type_iterator result_type_end()
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
result_type_iterator result_type_begin()
OperationName getName()
The name of an operation is the key identifier for it.
result_type_range getResultTypes()
MLIRContext * getContext()
Return the context this operation is associated with.
unsigned getNumResults()
Return the number of results held by this operation.
operand_type_iterator operand_type_begin()
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
void modifyOpInPlace(Operation *root, CallableT &&callable)
This method is a utility wrapper around an in-place modification of an operation.
void inlineRegionBefore(Region ®ion, Region &parent, Region::iterator before)
Move the blocks that belong to "region" before the given position in another region "parent".
virtual void replaceAllUsesWith(Value from, Value to)
Find uses of from and replace them with to.
static std::unique_ptr< SPIRVConversionTarget > get(spirv::TargetEnvAttr targetAttr)
Creates a SPIR-V conversion target for the given target environment.
Type conversion from builtin types to SPIR-V types for shader interface.
Type getIndexType() const
Gets the SPIR-V correspondence for the standard index type.
const spirv::TargetEnv & getTargetEnv() const
SPIRVTypeConverter(spirv::TargetEnvAttr targetAttr, const SPIRVConversionOptions &options={})
bool allows(spirv::Capability capability) const
Checks if the SPIR-V capability inquired is supported.
A range-style iterator that allows for iterating over the offsets of all potential tiles of size tile...
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
static Operation * getNearestSymbolTable(Operation *from)
Returns the nearest symbol table from a given operation from.
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
Type getElementType() const
Returns the element type of this tensor type.
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
bool isSignedInteger() const
Return true if this is a signed integer type (with the specified width).
bool isInteger() const
Return true if this is an integer type (with the specified width).
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static ArrayType get(Type elementType, unsigned elementCount)
static bool isValid(VectorType)
Returns true if the given vector type is valid for the SPIR-V dialect.
static ImageType get(Type elementType, Dim dim, ImageDepthInfo depth=ImageDepthInfo::DepthUnknown, ImageArrayedInfo arrayed=ImageArrayedInfo::NonArrayed, ImageSamplingInfo samplingInfo=ImageSamplingInfo::SingleSampled, ImageSamplerUseInfo samplerUse=ImageSamplerUseInfo::SamplerUnknown, ImageFormat format=ImageFormat::Unknown)
static PointerType get(Type pointeeType, StorageClass storageClass)
static RuntimeArrayType get(Type elementType)
SmallVectorImpl< ArrayRef< Capability > > CapabilityArrayRefVector
The capability requirements for each type are following the ((Capability::A OR Extension::B) AND (Cap...
SmallVectorImpl< ArrayRef< Extension > > ExtensionArrayRefVector
The extension requirements for each type are following the ((Extension::A OR Extension::B) AND (Exten...
static SampledImageType get(Type imageType)
static StructType get(ArrayRef< Type > memberTypes, ArrayRef< OffsetInfo > offsetInfo={}, ArrayRef< MemberDecorationInfo > memberDecorations={}, ArrayRef< StructDecorationInfo > structDecorations={})
Construct a literal StructType with at least one member.
An attribute that specifies the target version, allowed extensions and capabilities,...
A wrapper class around a spirv::TargetEnvAttr to provide query methods for allowed version/capabiliti...
Version getVersion() const
bool allows(Capability) const
Returns true if the given capability is allowed.
TargetEnvAttr getAttr() const
MLIRContext * getContext() const
Returns the MLIRContext.
bool hasElementwiseMappableTraits(Operation *op)
Together, Elementwise, Scalarizable, Vectorizable, and Tensorizable provide an easy way for scalar op...
Value getBuiltinVariableValue(Operation *op, BuiltIn builtin, Type integerType, OpBuilder &builder, StringRef prefix="__builtin__", StringRef suffix="__")
Returns the value for the given builtin variable.
Value getElementPtr(const 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,...
Value getOpenCLElementPtr(const SPIRVTypeConverter &typeConverter, MemRefType baseType, Value basePtr, ValueRange indices, Location loc, OpBuilder &builder)
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...
std::optional< SmallVector< int64_t > > getNativeVectorShape(Operation *op)
LinearizedIndexNoWrapFlags getLinearizedIndexNoWrapFlags(const TargetEnv &targetEnv, ArrayRef< int64_t > shape, ArrayRef< int64_t > strides, int64_t offset, Type integerType)
Returns no-wrap guarantees for an in-bounds index into the static layout described by shape,...
LogicalResult unrollVectorsInFuncBodies(Operation *op)
Value getVulkanElementPtr(const SPIRVTypeConverter &typeConverter, MemRefType baseType, Value basePtr, ValueRange indices, Location loc, OpBuilder &builder)
SmallVector< int64_t > getNativeVectorShapeImpl(vector::ReductionOp op)
std::string getDecorationString(Decoration decoration)
Converts a SPIR-V Decoration enum value to its snake_case string representation for use in MLIR attri...
int getComputeVectorSize(int64_t size)
LogicalResult unrollVectorsInSignatures(Operation *op)
Value linearizeIndex(ValueRange indices, ArrayRef< int64_t > strides, int64_t offset, Type integerType, Location loc, OpBuilder &builder, LinearizedIndexNoWrapFlags noWrapFlags={})
Generates IR to perform index linearization with the given indices and their corresponding strides,...
void populateVectorShapeCastLoweringPatterns(RewritePatternSet &patterns, PatternBenefit benefit=1)
Populate the pattern set with the following patterns:
void populateVectorTransposeLoweringPatterns(RewritePatternSet &patterns, VectorTransposeLowering vectorTransposeLowering, PatternBenefit benefit=1)
Populate the pattern set with the following patterns:
Include the generated interface declarations.
void populateFuncOpVectorRewritePatterns(RewritePatternSet &patterns)
void populateReturnOpVectorRewritePatterns(RewritePatternSet &patterns)
@ Packed
Sub-byte values are tightly packed without any padding, e.g., 4xi2 -> i8.
LogicalResult applyPatternsGreedily(Region ®ion, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
void populateBuiltinFuncToSPIRVPatterns(const SPIRVTypeConverter &typeConverter, RewritePatternSet &patterns)
Appends to a pattern list additional patterns for translating the builtin func op to the SPIR-V diale...
llvm::TypeSwitch< T, ResultT > TypeSwitch
@ ExistingOps
Only pre-existing ops are processed.
std::optional< SmallVector< int64_t > > computeShapeRatio(ArrayRef< int64_t > shape, ArrayRef< int64_t > subShape)
Return the multi-dimensional integral ratio of subShape to the trailing dimensions of shape.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
No-wrap guarantees proven for a linearized index calculation.
Options that control the vector unrolling.
UnrollVectorOptions & setNativeShapeFn(NativeShapeFnType fn)