21#include "llvm/ADT/APInt.h"
22#include "llvm/ADT/ArrayRef.h"
23#include "llvm/ADT/STLExtras.h"
24#include "llvm/Support/Debug.h"
25#include "llvm/Support/MathExtras.h"
30#define GEN_PASS_DEF_CONVERTARITHTOSPIRVPASS
31#include "mlir/Conversion/Passes.h.inc"
34#define DEBUG_TYPE "arith-to-spirv-pattern"
45 if (
auto boolAttr = dyn_cast<BoolAttr>(srcAttr))
47 if (
auto intAttr = dyn_cast<IntegerAttr>(srcAttr))
48 return builder.
getBoolAttr(intAttr.getValue().getBoolValue());
58 if (srcAttr.getValue().isIntN(dstType.getWidth()))
66 if (srcAttr.getValue().isSignedIntN(dstType.getWidth())) {
68 LLVM_DEBUG(llvm::dbgs() <<
"attribute '" << srcAttr <<
"' converted to '"
69 << dstAttr <<
"' for type '" << dstType <<
"'\n");
73 LLVM_DEBUG(llvm::dbgs() <<
"attribute '" << srcAttr
74 <<
"' illegal: cannot fit into target type '"
88 APFloat dstVal = srcAttr.getValue();
89 bool losesInfo =
false;
90 APFloat::opStatus status =
91 dstVal.convert(APFloat::IEEEsingle(), APFloat::rmTowardZero, &losesInfo);
92 if (status != APFloat::opOK || losesInfo) {
93 LLVM_DEBUG(llvm::dbgs()
94 << srcAttr <<
" illegal: cannot fit into converted type '"
108 APInt intVal = floatAttr.getValue().bitcastToAPInt();
109 auto srcType = IntegerType::get(dstType.getContext(), intVal.getBitWidth());
116 assert(type &&
"Not a valid type");
120 if (
auto vecType = dyn_cast<VectorType>(type))
121 return vecType.getElementType().isInteger(1);
129 if (
auto vectorType = dyn_cast<VectorType>(type)) {
130 Attribute element = IntegerAttr::get(vectorType.getElementType(), value);
132 return spirv::ConstantOp::create(builder, loc, vectorType, attr);
135 if (
auto intType = dyn_cast<IntegerType>(type))
136 return spirv::ConstantOp::create(builder, loc, type,
145 auto getNumBitwidth = [](
Type type) {
147 if (type.isIntOrFloat())
148 bw = type.getIntOrFloatBitWidth();
149 else if (
auto vecType = dyn_cast<VectorType>(type))
150 bw = vecType.getElementTypeBitWidth() * vecType.getNumElements();
153 unsigned aBW = getNumBitwidth(a);
154 unsigned bBW = getNumBitwidth(
b);
155 return aBW != 0 && bBW != 0 && aBW == bBW;
162 return rewriter.notifyMatchFailure(
164 llvm::formatv(
"failed to convert source type '{0}'", srcType));
178template <
typename Op,
typename SPIRVOp>
179struct ElementwiseArithOpPattern final : OpConversionPattern<Op> {
180 using OpConversionPattern<
Op>::OpConversionPattern;
183 matchAndRewrite(Op op,
typename Op::Adaptor adaptor,
184 ConversionPatternRewriter &rewriter)
const override {
185 assert(adaptor.getOperands().size() <= 3);
188 if (!adaptor.getOperands().empty() &&
191 auto converter = this->
template getTypeConverter<SPIRVTypeConverter>();
192 Type dstType = converter->convertType(op.getType());
194 return rewriter.notifyMatchFailure(
196 llvm::formatv(
"failed to convert type {0} for SPIR-V", op.getType()));
199 if (SPIRVOp::template hasTrait<OpTrait::spirv::UnsignedOp>() &&
201 dstType != op.getType()) {
202 return op.
emitError(
"bitwidth emulation is not implemented yet on "
203 "unsigned op pattern version");
206 auto overflowFlags = arith::IntegerOverflowFlags::none;
207 if (
auto overflowIface =
208 dyn_cast<arith::ArithIntegerOverflowFlagsInterface>(*op)) {
209 if (converter->getTargetEnv().allows(
210 spirv::Extension::SPV_KHR_no_integer_wrap_decoration))
211 overflowFlags = overflowIface.getOverflowAttr().getValue();
214 auto newOp = rewriter.template replaceOpWithNewOp<SPIRVOp>(
215 op, dstType, adaptor.getOperands());
217 if (bitEnumContainsAny(overflowFlags, arith::IntegerOverflowFlags::nsw))
218 newOp->setDiscardableAttr(
220 rewriter.getUnitAttr());
222 if (bitEnumContainsAny(overflowFlags, arith::IntegerOverflowFlags::nuw))
223 newOp->setDiscardableAttr(
225 rewriter.getUnitAttr());
236struct ConstantCompositeOpPattern final
237 :
public OpConversionPattern<arith::ConstantOp> {
241 matchAndRewrite(arith::ConstantOp constOp, OpAdaptor adaptor,
242 ConversionPatternRewriter &rewriter)
const override {
243 auto srcType = dyn_cast<ShapedType>(constOp.getType());
244 if (!srcType || srcType.getNumElements() == 1)
249 if (!isa<VectorType, RankedTensorType>(srcType))
250 return rewriter.notifyMatchFailure(constOp,
"unsupported ShapedType");
252 Type dstType = getTypeConverter()->convertType(srcType);
259 if (
auto denseElementsAttr =
260 dyn_cast<DenseElementsAttr>(constOp.getValue())) {
261 dstElementsAttr = denseElementsAttr;
262 }
else if (
auto resourceAttr =
263 dyn_cast<DenseResourceElementsAttr>(constOp.getValue())) {
267 return constOp->emitError(
"could not find resource blob");
274 return constOp->emitError(
"resource is not a valid buffer");
279 return constOp->emitError(
"unsupported elements attribute");
282 ShapedType dstAttrType = dstElementsAttr.
getType();
286 if (srcType.getRank() > 1) {
287 if (isa<RankedTensorType>(srcType)) {
288 dstAttrType = RankedTensorType::get(srcType.getNumElements(),
289 srcType.getElementType());
290 dstElementsAttr = dstElementsAttr.
reshape(dstAttrType);
297 Type srcElemType = srcType.getElementType();
301 if (
auto arrayType = dyn_cast<spirv::ArrayType>(dstType))
302 dstElemType = arrayType.getElementType();
304 dstElemType = cast<VectorType>(dstType).getElementType();
308 if (srcElemType != dstElemType) {
310 if (isa<FloatType>(srcElemType)) {
311 for (FloatAttr srcAttr : dstElementsAttr.
getValues<FloatAttr>()) {
314 auto *typeConverter = getTypeConverter<SPIRVTypeConverter>();
315 if (typeConverter->getOptions().emulateUnsupportedFloatTypes &&
317 isa<IntegerType>(dstElemType)) {
319 srcAttr, cast<IntegerType>(dstElemType), rewriter);
326 elements.push_back(dstAttr);
331 for (IntegerAttr srcAttr : dstElementsAttr.
getValues<IntegerAttr>()) {
333 srcAttr, cast<IntegerType>(dstElemType), rewriter);
336 elements.push_back(dstAttr);
344 if (isa<RankedTensorType>(dstAttrType))
346 RankedTensorType::get(dstAttrType.getShape(), dstElemType);
348 dstAttrType = VectorType::get(dstAttrType.getShape(), dstElemType);
353 rewriter.replaceOpWithNewOp<spirv::ConstantOp>(constOp, dstType,
360struct ConstantScalarOpPattern final
361 :
public OpConversionPattern<arith::ConstantOp> {
365 matchAndRewrite(arith::ConstantOp constOp, OpAdaptor adaptor,
366 ConversionPatternRewriter &rewriter)
const override {
367 Type srcType = constOp.getType();
368 if (
auto shapedType = dyn_cast<ShapedType>(srcType)) {
369 if (shapedType.getNumElements() != 1)
371 srcType = shapedType.getElementType();
376 Attribute cstAttr = constOp.getValue();
377 if (
auto elementsAttr = dyn_cast<DenseElementsAttr>(cstAttr))
378 cstAttr = elementsAttr.getSplatValue<Attribute>();
380 Type dstType = getTypeConverter()->convertType(srcType);
385 if (isa<FloatType>(srcType)) {
386 auto srcAttr = cast<FloatAttr>(cstAttr);
387 Attribute dstAttr = srcAttr;
391 auto *typeConverter = getTypeConverter<SPIRVTypeConverter>();
392 if (typeConverter->getOptions().emulateUnsupportedFloatTypes &&
396 srcAttr, cast<IntegerType>(dstType), rewriter);
399 }
else if (srcType != dstType) {
405 rewriter.replaceOpWithNewOp<spirv::ConstantOp>(constOp, dstType, dstAttr);
416 rewriter.replaceOpWithNewOp<spirv::ConstantOp>(constOp, dstType, dstAttr);
422 auto srcAttr = cast<IntegerAttr>(cstAttr);
423 IntegerAttr dstAttr =
427 rewriter.replaceOpWithNewOp<spirv::ConstantOp>(constOp, dstType, dstAttr);
443template <
typename SignedAbsOp>
446 assert(lhs.getType() == rhs.getType());
447 assert(lhs == signOperand || rhs == signOperand);
449 Type type = lhs.getType();
452 Value lhsAbs = SignedAbsOp::create(builder, loc, type, lhs);
453 Value rhsAbs = SignedAbsOp::create(builder, loc, type, rhs);
454 Value abs = spirv::UModOp::create(builder, loc, lhsAbs, rhsAbs);
458 if (lhs == signOperand)
459 isPositive = spirv::IEqualOp::create(builder, loc, lhs, lhsAbs);
461 isPositive = spirv::IEqualOp::create(builder, loc, rhs, rhsAbs);
462 Value absNegate = spirv::SNegateOp::create(builder, loc, type, abs);
463 return spirv::SelectOp::create(builder, loc, type, isPositive, abs,
471struct RemSIOpGLPattern final :
public OpConversionPattern<arith::RemSIOp> {
475 matchAndRewrite(arith::RemSIOp op, OpAdaptor adaptor,
476 ConversionPatternRewriter &rewriter)
const override {
477 Value
result = emulateSignedRemainder<spirv::GLSAbsOp>(
478 op.getLoc(), adaptor.getOperands()[0], adaptor.getOperands()[1],
479 adaptor.getOperands()[0], rewriter);
480 rewriter.replaceOp(op,
result);
487struct RemSIOpCLPattern final :
public OpConversionPattern<arith::RemSIOp> {
491 matchAndRewrite(arith::RemSIOp op, OpAdaptor adaptor,
492 ConversionPatternRewriter &rewriter)
const override {
493 Value
result = emulateSignedRemainder<spirv::CLSAbsOp>(
494 op.getLoc(), adaptor.getOperands()[0], adaptor.getOperands()[1],
495 adaptor.getOperands()[0], rewriter);
496 rewriter.replaceOp(op,
result);
509struct CeilDivUIOpPattern final : OpConversionPattern<arith::CeilDivUIOp> {
513 matchAndRewrite(arith::CeilDivUIOp op, OpAdaptor adaptor,
514 ConversionPatternRewriter &rewriter)
const override {
515 Type dstType = getTypeConverter()->convertType(op.getType());
520 dstType != op.getType())
521 return op.emitError(
"bitwidth emulation is not implemented yet on "
522 "unsigned op pattern version");
524 Location loc = op.getLoc();
525 Value n = adaptor.getLhs();
526 Value m = adaptor.getRhs();
528 Value zero = spirv::ConstantOp::getZero(dstType, loc, rewriter);
529 Value one = spirv::ConstantOp::getOne(dstType, loc, rewriter);
531 Value minusOne = spirv::ISubOp::create(rewriter, loc, n, one);
532 Value quotient = spirv::UDivOp::create(rewriter, loc, minusOne, m);
533 Value plusOne = spirv::IAddOp::create(rewriter, loc, quotient, one);
535 Value cmp = spirv::IEqualOp::create(rewriter, loc, n, zero);
536 rewriter.replaceOpWithNewOp<spirv::SelectOp>(op, cmp, zero, plusOne);
548struct CeilDivSIOpPattern final : OpConversionPattern<arith::CeilDivSIOp> {
552 matchAndRewrite(arith::CeilDivSIOp op, OpAdaptor adaptor,
553 ConversionPatternRewriter &rewriter)
const override {
554 Type dstType = getTypeConverter()->convertType(op.getType());
558 Location loc = op.getLoc();
559 Value a = adaptor.getLhs();
560 Value
b = adaptor.getRhs();
562 Value zero = spirv::ConstantOp::getZero(dstType, loc, rewriter);
563 Value one = spirv::ConstantOp::getOne(dstType, loc, rewriter);
565 Value quotient = spirv::SDivOp::create(rewriter, loc, a,
b);
566 Value
product = spirv::IMulOp::create(rewriter, loc, quotient,
b);
567 Value notEqual = spirv::INotEqualOp::create(rewriter, loc, a,
product);
569 Value aNeg = spirv::SLessThanOp::create(rewriter, loc, a, zero);
570 Value bNeg = spirv::SLessThanOp::create(rewriter, loc,
b, zero);
571 Value sameSign = spirv::LogicalEqualOp::create(rewriter, loc, aNeg, bNeg);
572 Value cond = spirv::LogicalAndOp::create(rewriter, loc, notEqual, sameSign);
574 Value quotientPlusOne = spirv::IAddOp::create(rewriter, loc, quotient, one);
575 rewriter.replaceOpWithNewOp<spirv::SelectOp>(op, cond, quotientPlusOne,
588struct FloorDivSIOpPattern final : OpConversionPattern<arith::FloorDivSIOp> {
592 matchAndRewrite(arith::FloorDivSIOp op, OpAdaptor adaptor,
593 ConversionPatternRewriter &rewriter)
const override {
594 Type dstType = getTypeConverter()->convertType(op.getType());
598 Location loc = op.getLoc();
599 Value a = adaptor.getLhs();
600 Value
b = adaptor.getRhs();
602 Value zero = spirv::ConstantOp::getZero(dstType, loc, rewriter);
604 dstType,
static_cast<uint64_t
>(-1), rewriter, loc);
606 Value quotient = spirv::SDivOp::create(rewriter, loc, a,
b);
607 Value
product = spirv::IMulOp::create(rewriter, loc, quotient,
b);
608 Value notEqual = spirv::INotEqualOp::create(rewriter, loc, a,
product);
610 Value aNeg = spirv::SLessThanOp::create(rewriter, loc, a, zero);
611 Value bNeg = spirv::SLessThanOp::create(rewriter, loc,
b, zero);
613 spirv::LogicalNotEqualOp::create(rewriter, loc, aNeg, bNeg);
614 Value cond = spirv::LogicalAndOp::create(rewriter, loc, notEqual, diffSign);
616 Value quotientMinusOne =
617 spirv::IAddOp::create(rewriter, loc, quotient, minusOne);
618 rewriter.replaceOpWithNewOp<spirv::SelectOp>(op, cond, quotientMinusOne,
632template <
typename Op,
typename SPIRVLogicalOp,
typename SPIRVBitwiseOp>
633struct BitwiseOpPattern final :
public OpConversionPattern<Op> {
634 using OpConversionPattern<
Op>::OpConversionPattern;
637 matchAndRewrite(Op op,
typename Op::Adaptor adaptor,
638 ConversionPatternRewriter &rewriter)
const override {
639 assert(adaptor.getOperands().size() == 2);
640 Type dstType = this->getTypeConverter()->convertType(op.getType());
645 rewriter.template replaceOpWithNewOp<SPIRVLogicalOp>(
646 op, dstType, adaptor.getOperands());
648 rewriter.template replaceOpWithNewOp<SPIRVBitwiseOp>(
649 op, dstType, adaptor.getOperands());
660struct XOrIOpLogicalPattern final :
public OpConversionPattern<arith::XOrIOp> {
664 matchAndRewrite(arith::XOrIOp op, OpAdaptor adaptor,
665 ConversionPatternRewriter &rewriter)
const override {
666 assert(adaptor.getOperands().size() == 2);
671 Type dstType = getTypeConverter()->convertType(op.getType());
675 rewriter.replaceOpWithNewOp<spirv::BitwiseXorOp>(op, dstType,
676 adaptor.getOperands());
684struct XOrIOpBooleanPattern final :
public OpConversionPattern<arith::XOrIOp> {
688 matchAndRewrite(arith::XOrIOp op, OpAdaptor adaptor,
689 ConversionPatternRewriter &rewriter)
const override {
690 assert(adaptor.getOperands().size() == 2);
695 Type dstType = getTypeConverter()->convertType(op.getType());
699 rewriter.replaceOpWithNewOp<spirv::LogicalNotEqualOp>(
700 op, dstType, adaptor.getOperands());
723template <
typename ArithOp,
typename SPIRVOp>
724struct BoolIOpPattern final :
public OpConversionPattern<ArithOp> {
725 BoolIOpPattern(
const TypeConverter &converter, MLIRContext *context)
728 : OpConversionPattern<ArithOp>(converter, context, 2) {}
731 matchAndRewrite(ArithOp op,
typename ArithOp::Adaptor adaptor,
732 ConversionPatternRewriter &rewriter)
const override {
736 Type dstType = this->getTypeConverter()->convertType(op.getType());
740 rewriter.replaceOpWithNewOp<SPIRVOp>(op, dstType, adaptor.getOperands());
754template <
typename ArithOp>
755struct BoolIOpAndNotPattern final :
public OpConversionPattern<ArithOp> {
756 BoolIOpAndNotPattern(
const TypeConverter &converter, MLIRContext *context)
759 : OpConversionPattern<ArithOp>(converter, context, 2) {}
762 matchAndRewrite(ArithOp op,
typename ArithOp::Adaptor adaptor,
763 ConversionPatternRewriter &rewriter)
const override {
767 Type dstType = this->getTypeConverter()->convertType(op.getType());
771 Location loc = op.getLoc();
772 Value notRhs = spirv::LogicalNotOp::create(rewriter, loc, dstType,
773 adaptor.getOperands()[1]);
774 rewriter.replaceOpWithNewOp<spirv::LogicalAndOp>(
775 op, dstType, adaptor.getOperands()[0], notRhs);
782struct ShRSIBoolPattern final :
public OpConversionPattern<arith::ShRSIOp> {
783 ShRSIBoolPattern(
const TypeConverter &converter, MLIRContext *context)
786 : OpConversionPattern<arith::ShRSIOp>(converter, context,
790 matchAndRewrite(arith::ShRSIOp op, OpAdaptor adaptor,
791 ConversionPatternRewriter &rewriter)
const override {
795 rewriter.replaceOp(op, adaptor.getOperands().front());
807template <
typename ArithOp>
808struct BoolToValuePattern final :
public OpConversionPattern<ArithOp> {
809 using OpConversionPattern<ArithOp>::OpConversionPattern;
812 matchAndRewrite(ArithOp op,
typename ArithOp::Adaptor adaptor,
813 ConversionPatternRewriter &rewriter)
const override {
814 Type srcType = adaptor.getOperands().front().getType();
818 Type dstType = this->getTypeConverter()->convertType(op.getType());
822 Location loc = op.getLoc();
823 Value zero = spirv::ConstantOp::getZero(dstType, loc, rewriter);
824 Value one = spirv::ConstantOp::getOne(dstType, loc, rewriter);
825 rewriter.replaceOpWithNewOp<spirv::SelectOp>(
826 op, dstType, adaptor.getOperands().front(), one, zero);
842template <
typename ArithOp,
typename SPIRVOp,
bool IsSigned>
843struct IntToFPPattern final :
public OpConversionPattern<ArithOp> {
844 using OpConversionPattern<ArithOp>::OpConversionPattern;
847 matchAndRewrite(ArithOp op,
typename ArithOp::Adaptor adaptor,
848 ConversionPatternRewriter &rewriter)
const override {
849 Type srcType = adaptor.getOperands().front().getType();
853 Type dstType = this->getTypeConverter()->convertType(op.getType());
858 unsigned originalBitwidth =
863 return rewriter.notifyMatchFailure(op,
864 "unsupported type for uitofp/sitofp");
869 if (originalBitwidth >= convertedBitwidth) {
870 rewriter.replaceOpWithNewOp<SPIRVOp>(op, dstType, adaptor.getOperands());
877 if constexpr (IsSigned) {
879 unsigned shiftAmount = convertedBitwidth - originalBitwidth;
882 Value shifted = spirv::ShiftLeftLogicalOp::create(
883 rewriter, loc, srcType, adaptor.getIn(), shiftSize);
884 cleaned = spirv::ShiftRightArithmeticOp::create(rewriter, loc, srcType,
889 srcType, llvm::maskTrailingOnes<uint64_t>(originalBitwidth), rewriter,
891 cleaned = spirv::BitwiseAndOp::create(rewriter, loc, srcType,
892 adaptor.getIn(), mask);
894 rewriter.replaceOpWithNewOp<SPIRVOp>(op, dstType, cleaned);
904struct IndexCastIndexI1Pattern final
905 :
public OpConversionPattern<arith::IndexCastOp> {
909 matchAndRewrite(arith::IndexCastOp op, OpAdaptor adaptor,
910 ConversionPatternRewriter &rewriter)
const override {
914 Type dstType = getTypeConverter()->convertType(op.getType());
918 Location loc = op.getLoc();
920 spirv::ConstantOp::getZero(adaptor.getIn().getType(), loc, rewriter);
921 rewriter.replaceOpWithNewOp<spirv::INotEqualOp>(op, dstType, zeroIdx,
933struct ExtSII1Pattern final :
public OpConversionPattern<arith::ExtSIOp> {
937 matchAndRewrite(arith::ExtSIOp op, OpAdaptor adaptor,
938 ConversionPatternRewriter &rewriter)
const override {
939 Value operand = adaptor.getIn();
943 Location loc = op.getLoc();
944 Type dstType = getTypeConverter()->convertType(op.getType());
949 if (
auto intTy = dyn_cast<IntegerType>(dstType)) {
950 unsigned componentBitwidth = intTy.getWidth();
951 allOnes = spirv::ConstantOp::create(
952 rewriter, loc, intTy,
953 rewriter.getIntegerAttr(intTy, APInt::getAllOnes(componentBitwidth)));
954 }
else if (
auto vectorTy = dyn_cast<VectorType>(dstType)) {
955 unsigned componentBitwidth = vectorTy.getElementTypeBitWidth();
956 allOnes = spirv::ConstantOp::create(
957 rewriter, loc, vectorTy,
958 SplatElementsAttr::get(vectorTy,
959 APInt::getAllOnes(componentBitwidth)));
961 return rewriter.notifyMatchFailure(
962 loc, llvm::formatv(
"unhandled type: {0}", dstType));
965 Value zero = spirv::ConstantOp::getZero(dstType, loc, rewriter);
966 rewriter.replaceOpWithNewOp<spirv::SelectOp>(op, dstType, operand, allOnes,
974struct ExtSIPattern final :
public OpConversionPattern<arith::ExtSIOp> {
978 matchAndRewrite(arith::ExtSIOp op, OpAdaptor adaptor,
979 ConversionPatternRewriter &rewriter)
const override {
980 Type srcType = adaptor.getIn().getType();
984 Type dstType = getTypeConverter()->convertType(op.getType());
988 if (dstType == srcType) {
996 assert(srcBW < dstBW);
998 rewriter, op.getLoc());
1000 return rewriter.notifyMatchFailure(op,
"unsupported type for shift");
1005 auto shiftLOp = spirv::ShiftLeftLogicalOp::create(
1006 rewriter, op.getLoc(), dstType, adaptor.getIn(), shiftSize);
1010 rewriter.replaceOpWithNewOp<spirv::ShiftRightArithmeticOp>(
1011 op, dstType, shiftLOp, shiftSize);
1013 rewriter.replaceOpWithNewOp<spirv::SConvertOp>(op, dstType,
1014 adaptor.getOperands());
1027struct ExtUIPattern final :
public OpConversionPattern<arith::ExtUIOp> {
1031 matchAndRewrite(arith::ExtUIOp op, OpAdaptor adaptor,
1032 ConversionPatternRewriter &rewriter)
const override {
1033 Type srcType = adaptor.getIn().getType();
1037 Type dstType = getTypeConverter()->convertType(op.getType());
1041 if (dstType == srcType) {
1049 dstType, llvm::maskTrailingOnes<uint64_t>(bitwidth), rewriter,
1052 return rewriter.notifyMatchFailure(op,
"unsupported type for mask");
1053 rewriter.replaceOpWithNewOp<spirv::BitwiseAndOp>(op, dstType,
1054 adaptor.getIn(), mask);
1056 rewriter.replaceOpWithNewOp<spirv::UConvertOp>(op, dstType,
1057 adaptor.getOperands());
1069struct TruncII1Pattern final :
public OpConversionPattern<arith::TruncIOp> {
1073 matchAndRewrite(arith::TruncIOp op, OpAdaptor adaptor,
1074 ConversionPatternRewriter &rewriter)
const override {
1075 Type dstType = getTypeConverter()->convertType(op.getType());
1082 Location loc = op.getLoc();
1083 auto srcType = adaptor.getOperands().front().getType();
1085 Value mask = spirv::ConstantOp::getOne(srcType, loc, rewriter);
1086 Value maskedSrc = spirv::BitwiseAndOp::create(
1087 rewriter, loc, srcType, adaptor.getOperands()[0], mask);
1088 Value isOne = spirv::IEqualOp::create(rewriter, loc, maskedSrc, mask);
1090 Value zero = spirv::ConstantOp::getZero(dstType, loc, rewriter);
1091 Value one = spirv::ConstantOp::getOne(dstType, loc, rewriter);
1092 rewriter.replaceOpWithNewOp<spirv::SelectOp>(op, dstType, isOne, one, zero);
1099struct TruncIPattern final :
public OpConversionPattern<arith::TruncIOp> {
1103 matchAndRewrite(arith::TruncIOp op, OpAdaptor adaptor,
1104 ConversionPatternRewriter &rewriter)
const override {
1105 Type srcType = adaptor.getIn().getType();
1106 Type dstType = getTypeConverter()->convertType(op.getType());
1113 if (dstType == srcType) {
1120 dstType, llvm::maskTrailingOnes<uint64_t>(bw), rewriter, op.getLoc());
1122 return rewriter.notifyMatchFailure(op,
"unsupported type for mask");
1123 rewriter.replaceOpWithNewOp<spirv::BitwiseAndOp>(op, dstType,
1124 adaptor.getIn(), mask);
1127 rewriter.replaceOpWithNewOp<spirv::SConvertOp>(op, dstType,
1128 adaptor.getOperands());
1138static std::optional<spirv::FPRoundingMode>
1139convertArithRoundingModeToSPIRV(arith::RoundingMode roundingMode) {
1140 switch (roundingMode) {
1141 case arith::RoundingMode::downward:
1142 return spirv::FPRoundingMode::RTN;
1143 case arith::RoundingMode::to_nearest_even:
1144 return spirv::FPRoundingMode::RTE;
1145 case arith::RoundingMode::toward_zero:
1146 return spirv::FPRoundingMode::RTZ;
1147 case arith::RoundingMode::upward:
1148 return spirv::FPRoundingMode::RTP;
1149 case arith::RoundingMode::to_nearest_away:
1152 return std::nullopt;
1154 llvm_unreachable(
"Unhandled rounding mode");
1158template <
typename Op,
typename SPIRVOp>
1159struct TypeCastingOpPattern final :
public OpConversionPattern<Op> {
1160 using OpConversionPattern<
Op>::OpConversionPattern;
1163 matchAndRewrite(Op op,
typename Op::Adaptor adaptor,
1164 ConversionPatternRewriter &rewriter)
const override {
1165 Type srcType = llvm::getSingleElement(adaptor.getOperands()).getType();
1166 Type dstType = this->getTypeConverter()->convertType(op.getType());
1173 if (dstType == srcType) {
1176 rewriter.replaceOp(op, adaptor.getOperands().front());
1179 std::optional<spirv::FPRoundingMode> rm = std::nullopt;
1180 if (
auto roundingModeOp =
1181 dyn_cast<arith::ArithRoundingModeInterface>(*op)) {
1182 if (arith::RoundingModeAttr roundingMode =
1183 roundingModeOp.getRoundingModeAttr()) {
1185 convertArithRoundingModeToSPIRV(roundingMode.getValue()))) {
1186 return rewriter.notifyMatchFailure(
1188 llvm::formatv(
"unsupported rounding mode '{0}'", roundingMode));
1193 auto newOp = rewriter.template replaceOpWithNewOp<SPIRVOp>(
1194 op, dstType, adaptor.getOperands());
1196 newOp->setDiscardableAttr(
1198 spirv::FPRoundingModeAttr::get(rewriter.getContext(), *rm));
1210class CmpIOpBooleanPattern final :
public OpConversionPattern<arith::CmpIOp> {
1215 matchAndRewrite(arith::CmpIOp op, OpAdaptor adaptor,
1216 ConversionPatternRewriter &rewriter)
const override {
1217 Type srcType = op.getLhs().getType();
1220 Type dstType = getTypeConverter()->convertType(srcType);
1224 switch (op.getPredicate()) {
1225 case arith::CmpIPredicate::eq: {
1226 rewriter.replaceOpWithNewOp<spirv::LogicalEqualOp>(op, adaptor.getLhs(),
1230 case arith::CmpIPredicate::ne: {
1231 rewriter.replaceOpWithNewOp<spirv::LogicalNotEqualOp>(
1232 op, adaptor.getLhs(), adaptor.getRhs());
1235 case arith::CmpIPredicate::uge:
1236 case arith::CmpIPredicate::ugt:
1237 case arith::CmpIPredicate::ule:
1238 case arith::CmpIPredicate::ult: {
1241 Type type = rewriter.getI32Type();
1242 if (
auto vectorType = dyn_cast<VectorType>(dstType))
1243 type = VectorType::get(vectorType.getShape(), type);
1245 arith::ExtUIOp::create(rewriter, op.getLoc(), type, adaptor.getLhs());
1247 arith::ExtUIOp::create(rewriter, op.getLoc(), type, adaptor.getRhs());
1249 rewriter.replaceOpWithNewOp<arith::CmpIOp>(op, op.getPredicate(), extLhs,
1261class CmpIOpPattern final :
public OpConversionPattern<arith::CmpIOp> {
1266 matchAndRewrite(arith::CmpIOp op, OpAdaptor adaptor,
1267 ConversionPatternRewriter &rewriter)
const override {
1268 Type srcType = op.getLhs().getType();
1271 Type dstType = getTypeConverter()->convertType(srcType);
1275 switch (op.getPredicate()) {
1276#define DISPATCH(cmpPredicate, spirvOp) \
1277 case cmpPredicate: \
1278 if (spirvOp::template hasTrait<OpTrait::spirv::UnsignedOp>() && \
1279 !getElementTypeOrSelf(srcType).isIndex() && srcType != dstType && \
1280 !hasSameBitwidth(srcType, dstType)) { \
1281 return op.emitError( \
1282 "bitwidth emulation is not implemented yet on unsigned op"); \
1284 rewriter.replaceOpWithNewOp<spirvOp>(op, adaptor.getLhs(), \
1285 adaptor.getRhs()); \
1288 DISPATCH(arith::CmpIPredicate::eq, spirv::IEqualOp);
1289 DISPATCH(arith::CmpIPredicate::ne, spirv::INotEqualOp);
1290 DISPATCH(arith::CmpIPredicate::slt, spirv::SLessThanOp);
1291 DISPATCH(arith::CmpIPredicate::sle, spirv::SLessThanEqualOp);
1292 DISPATCH(arith::CmpIPredicate::sgt, spirv::SGreaterThanOp);
1293 DISPATCH(arith::CmpIPredicate::sge, spirv::SGreaterThanEqualOp);
1294 DISPATCH(arith::CmpIPredicate::ult, spirv::ULessThanOp);
1295 DISPATCH(arith::CmpIPredicate::ule, spirv::ULessThanEqualOp);
1296 DISPATCH(arith::CmpIPredicate::ugt, spirv::UGreaterThanOp);
1297 DISPATCH(arith::CmpIPredicate::uge, spirv::UGreaterThanEqualOp);
1310class CmpFOpPattern final :
public OpConversionPattern<arith::CmpFOp> {
1315 matchAndRewrite(arith::CmpFOp op, OpAdaptor adaptor,
1316 ConversionPatternRewriter &rewriter)
const override {
1317 switch (op.getPredicate()) {
1318#define DISPATCH(cmpPredicate, spirvOp) \
1319 case cmpPredicate: \
1320 rewriter.replaceOpWithNewOp<spirvOp>(op, adaptor.getLhs(), \
1321 adaptor.getRhs()); \
1325 DISPATCH(arith::CmpFPredicate::OEQ, spirv::FOrdEqualOp);
1326 DISPATCH(arith::CmpFPredicate::OGT, spirv::FOrdGreaterThanOp);
1327 DISPATCH(arith::CmpFPredicate::OGE, spirv::FOrdGreaterThanEqualOp);
1328 DISPATCH(arith::CmpFPredicate::OLT, spirv::FOrdLessThanOp);
1329 DISPATCH(arith::CmpFPredicate::OLE, spirv::FOrdLessThanEqualOp);
1330 DISPATCH(arith::CmpFPredicate::ONE, spirv::FOrdNotEqualOp);
1332 DISPATCH(arith::CmpFPredicate::UEQ, spirv::FUnordEqualOp);
1333 DISPATCH(arith::CmpFPredicate::UGT, spirv::FUnordGreaterThanOp);
1334 DISPATCH(arith::CmpFPredicate::UGE, spirv::FUnordGreaterThanEqualOp);
1335 DISPATCH(arith::CmpFPredicate::ULT, spirv::FUnordLessThanOp);
1336 DISPATCH(arith::CmpFPredicate::ULE, spirv::FUnordLessThanEqualOp);
1337 DISPATCH(arith::CmpFPredicate::UNE, spirv::FUnordNotEqualOp);
1350class CmpFOpNanKernelPattern final :
public OpConversionPattern<arith::CmpFOp> {
1355 matchAndRewrite(arith::CmpFOp op, OpAdaptor adaptor,
1356 ConversionPatternRewriter &rewriter)
const override {
1357 if (op.getPredicate() == arith::CmpFPredicate::ORD) {
1358 rewriter.replaceOpWithNewOp<spirv::OrderedOp>(op, adaptor.getLhs(),
1363 if (op.getPredicate() == arith::CmpFPredicate::UNO) {
1364 rewriter.replaceOpWithNewOp<spirv::UnorderedOp>(op, adaptor.getLhs(),
1375class CmpFOpNanNonePattern final :
public OpConversionPattern<arith::CmpFOp> {
1380 matchAndRewrite(arith::CmpFOp op, OpAdaptor adaptor,
1381 ConversionPatternRewriter &rewriter)
const override {
1382 if (op.getPredicate() != arith::CmpFPredicate::ORD &&
1383 op.getPredicate() != arith::CmpFPredicate::UNO)
1386 Location loc = op.getLoc();
1389 if (bitEnumContainsAll(op.getFastmath(), arith::FastMathFlags::nnan)) {
1390 if (op.getPredicate() == arith::CmpFPredicate::ORD) {
1392 replace = spirv::ConstantOp::getOne(op.getType(), loc, rewriter);
1395 replace = spirv::ConstantOp::getZero(op.getType(), loc, rewriter);
1398 Value lhsIsNan = spirv::IsNanOp::create(rewriter, loc, adaptor.getLhs());
1399 Value rhsIsNan = spirv::IsNanOp::create(rewriter, loc, adaptor.getRhs());
1401 replace = spirv::LogicalOrOp::create(rewriter, loc, lhsIsNan, rhsIsNan);
1402 if (op.getPredicate() == arith::CmpFPredicate::ORD)
1403 replace = spirv::LogicalNotOp::create(rewriter, loc, replace);
1406 rewriter.replaceOp(op, replace);
1417template <
typename ArithExtendedOp,
typename SPIRVExtendedOp>
1418class BinaryExtendedOpPattern final
1419 :
public OpConversionPattern<ArithExtendedOp> {
1421 using OpConversionPattern<ArithExtendedOp>::OpConversionPattern;
1423 matchAndRewrite(ArithExtendedOp op,
typename ArithExtendedOp::Adaptor adaptor,
1424 ConversionPatternRewriter &rewriter)
const override {
1425 Type dstElemTy = adaptor.getLhs().getType();
1426 Location loc = op->getLoc();
1427 Value
result = SPIRVExtendedOp::create(rewriter, loc, adaptor.getLhs(),
1430 Value valueResult = spirv::CompositeExtractOp::create(rewriter, loc,
result,
1432 Value flagValue = spirv::CompositeExtractOp::create(rewriter, loc,
result,
1436 Value one = spirv::ConstantOp::getOne(dstElemTy, loc, rewriter);
1437 Value flagResult = spirv::IEqualOp::create(rewriter, loc, flagValue, one);
1439 rewriter.replaceOp(op, {valueResult, flagResult});
1449template <
typename ArithMulOp,
typename SPIRVMulOp>
1450class MulIExtendedOpPattern final :
public OpConversionPattern<ArithMulOp> {
1452 using OpConversionPattern<ArithMulOp>::OpConversionPattern;
1454 matchAndRewrite(ArithMulOp op,
typename ArithMulOp::Adaptor adaptor,
1455 ConversionPatternRewriter &rewriter)
const override {
1456 Location loc = op->getLoc();
1458 SPIRVMulOp::create(rewriter, loc, adaptor.getLhs(), adaptor.getRhs());
1460 Value low = spirv::CompositeExtractOp::create(rewriter, loc,
result,
1462 Value high = spirv::CompositeExtractOp::create(rewriter, loc,
result,
1465 rewriter.replaceOp(op, {low, high});
1475class SelectOpPattern final :
public OpConversionPattern<arith::SelectOp> {
1479 matchAndRewrite(arith::SelectOp op, OpAdaptor adaptor,
1480 ConversionPatternRewriter &rewriter)
const override {
1481 rewriter.replaceOpWithNewOp<spirv::SelectOp>(op, adaptor.getCondition(),
1482 adaptor.getTrueValue(),
1483 adaptor.getFalseValue());
1494template <
typename Op,
typename SPIRVOp>
1495class MinimumMaximumFOpPattern final :
public OpConversionPattern<Op> {
1497 using OpConversionPattern<
Op>::OpConversionPattern;
1499 matchAndRewrite(Op op,
typename Op::Adaptor adaptor,
1500 ConversionPatternRewriter &rewriter)
const override {
1501 auto *converter = this->
template getTypeConverter<SPIRVTypeConverter>();
1502 Type dstType = converter->convertType(op.getType());
1514 Location loc = op.
getLoc();
1516 SPIRVOp::create(rewriter, loc, dstType, adaptor.getOperands());
1518 if (bitEnumContainsAll(op.getFastmath(), arith::FastMathFlags::nnan)) {
1519 rewriter.replaceOp(op, spirvOp);
1523 Value lhsIsNan = spirv::IsNanOp::create(rewriter, loc, adaptor.getLhs());
1524 Value rhsIsNan = spirv::IsNanOp::create(rewriter, loc, adaptor.getRhs());
1526 Value select1 = spirv::SelectOp::create(rewriter, loc, dstType, lhsIsNan,
1527 adaptor.getLhs(), spirvOp);
1528 Value select2 = spirv::SelectOp::create(rewriter, loc, dstType, rhsIsNan,
1529 adaptor.getRhs(), select1);
1531 rewriter.replaceOp(op, select2);
1542template <
typename Op,
typename SPIRVOp>
1543class MinNumMaxNumFOpPattern final :
public OpConversionPattern<Op> {
1544 template <
typename TargetOp>
1545 constexpr bool shouldInsertNanGuards()
const {
1546 return llvm::is_one_of<TargetOp, spirv::GLFMaxOp, spirv::GLFMinOp>::value;
1550 using OpConversionPattern<
Op>::OpConversionPattern;
1552 matchAndRewrite(
Op op,
typename Op::Adaptor adaptor,
1553 ConversionPatternRewriter &rewriter)
const override {
1554 auto *converter = this->
template getTypeConverter<SPIRVTypeConverter>();
1555 Type dstType = converter->convertType(op.getType());
1570 SPIRVOp::create(rewriter, loc, dstType, adaptor.getOperands());
1572 if (!shouldInsertNanGuards<SPIRVOp>() ||
1573 bitEnumContainsAll(op.getFastmath(), arith::FastMathFlags::nnan)) {
1574 rewriter.replaceOp(op, spirvOp);
1578 Value lhsIsNan = spirv::IsNanOp::create(rewriter, loc, adaptor.getLhs());
1579 Value rhsIsNan = spirv::IsNanOp::create(rewriter, loc, adaptor.getRhs());
1581 Value select1 = spirv::SelectOp::create(rewriter, loc, dstType, lhsIsNan,
1582 adaptor.getRhs(), spirvOp);
1583 Value select2 = spirv::SelectOp::create(rewriter, loc, dstType, rhsIsNan,
1584 adaptor.getLhs(), select1);
1586 rewriter.replaceOp(op, select2);
1601 ConstantCompositeOpPattern,
1602 ConstantScalarOpPattern,
1603 BoolIOpPattern<arith::AddIOp, spirv::LogicalNotEqualOp>,
1604 ElementwiseArithOpPattern<arith::AddIOp, spirv::IAddOp>,
1605 BoolIOpPattern<arith::SubIOp, spirv::LogicalNotEqualOp>,
1606 ElementwiseArithOpPattern<arith::SubIOp, spirv::ISubOp>,
1607 BoolIOpPattern<arith::MulIOp, spirv::LogicalAndOp>,
1608 ElementwiseArithOpPattern<arith::MulIOp, spirv::IMulOp>,
1609 BoolIOpPattern<arith::DivUIOp, spirv::LogicalAndOp>,
1611 BoolIOpPattern<arith::DivSIOp, spirv::LogicalAndOp>,
1613 BoolIOpPattern<arith::CeilDivUIOp, spirv::LogicalAndOp>,
1615 BoolIOpPattern<arith::CeilDivSIOp, spirv::LogicalAndOp>,
1617 BoolIOpPattern<arith::FloorDivSIOp, spirv::LogicalAndOp>,
1618 FloorDivSIOpPattern,
1619 BoolIOpAndNotPattern<arith::RemUIOp>,
1621 BoolIOpAndNotPattern<arith::RemSIOp>,
1622 RemSIOpGLPattern, RemSIOpCLPattern,
1623 BitwiseOpPattern<arith::AndIOp, spirv::LogicalAndOp, spirv::BitwiseAndOp>,
1624 BitwiseOpPattern<arith::OrIOp, spirv::LogicalOrOp, spirv::BitwiseOrOp>,
1625 XOrIOpLogicalPattern, XOrIOpBooleanPattern,
1626 BoolIOpAndNotPattern<arith::ShLIOp>,
1627 ElementwiseArithOpPattern<arith::ShLIOp, spirv::ShiftLeftLogicalOp>,
1628 BoolIOpAndNotPattern<arith::ShRUIOp>,
1638 ExtUIPattern, BoolToValuePattern<arith::ExtUIOp>,
1639 ExtSIPattern, ExtSII1Pattern,
1640 TypeCastingOpPattern<arith::ExtFOp, spirv::FConvertOp>,
1641 TruncIPattern, TruncII1Pattern,
1642 TypeCastingOpPattern<arith::TruncFOp, spirv::FConvertOp>,
1643 TypeCastingOpPattern<arith::ConvertFOp, spirv::FConvertOp>,
1644 IntToFPPattern<arith::UIToFPOp, spirv::ConvertUToFOp, false>,
1645 BoolToValuePattern<arith::UIToFPOp>,
1646 IntToFPPattern<arith::SIToFPOp, spirv::ConvertSToFOp, true>,
1647 TypeCastingOpPattern<arith::FPToUIOp, spirv::ConvertFToUOp>,
1648 TypeCastingOpPattern<arith::FPToSIOp, spirv::ConvertFToSOp>,
1649 TypeCastingOpPattern<arith::IndexCastOp, spirv::SConvertOp>,
1650 IndexCastIndexI1Pattern, BoolToValuePattern<arith::IndexCastOp>,
1651 TypeCastingOpPattern<arith::IndexCastUIOp, spirv::UConvertOp>,
1652 TypeCastingOpPattern<arith::BitcastOp, spirv::BitcastOp>,
1653 CmpIOpBooleanPattern, CmpIOpPattern,
1654 CmpFOpNanNonePattern, CmpFOpPattern,
1655 BinaryExtendedOpPattern<arith::AddUIExtendedOp, spirv::IAddCarryOp>,
1656 BinaryExtendedOpPattern<arith::SubUIExtendedOp, spirv::ISubBorrowOp>,
1657 MulIExtendedOpPattern<arith::MulSIExtendedOp, spirv::SMulExtendedOp>,
1658 MulIExtendedOpPattern<arith::MulUIExtendedOp, spirv::UMulExtendedOp>,
1661 MinimumMaximumFOpPattern<arith::MaximumFOp, spirv::GLFMaxOp>,
1662 MinimumMaximumFOpPattern<arith::MinimumFOp, spirv::GLFMinOp>,
1663 MinNumMaxNumFOpPattern<arith::MaxNumFOp, spirv::GLNMaxOp>,
1664 MinNumMaxNumFOpPattern<arith::MinNumFOp, spirv::GLNMinOp>,
1665 BoolIOpPattern<arith::MaxSIOp, spirv::LogicalAndOp>,
1666 BoolIOpPattern<arith::MaxUIOp, spirv::LogicalOrOp>,
1667 BoolIOpPattern<arith::MinSIOp, spirv::LogicalOrOp>,
1668 BoolIOpPattern<arith::MinUIOp, spirv::LogicalAndOp>,
1674 MinimumMaximumFOpPattern<arith::MaximumFOp, spirv::CLFMaxOp>,
1675 MinimumMaximumFOpPattern<arith::MinimumFOp, spirv::CLFMinOp>,
1676 MinNumMaxNumFOpPattern<arith::MaxNumFOp, spirv::CLFMaxOp>,
1677 MinNumMaxNumFOpPattern<arith::MinNumFOp, spirv::CLFMinOp>,
1687 patterns.
add<CmpFOpNanKernelPattern>(typeConverter, patterns.
getContext(),
1696struct ConvertArithToSPIRVPass
1700 void runOnOperation()
override {
1703 std::unique_ptr<SPIRVConversionTarget>
target =
1707 options.emulateLT32BitScalarTypes = this->emulateLT32BitScalarTypes;
1708 options.emulateUnsupportedFloatTypes = this->emulateUnsupportedFloatTypes;
1713 target->addLegalOp<UnrealizedConversionCastOp>();
1716 target->addIllegalDialect<arith::ArithDialect>();
1721 if (failed(applyPartialConversion(op, *
target, std::move(patterns))))
1722 signalPassFailure();
static bool hasSameBitwidth(Type a, Type b)
Returns true if scalar/vector type a and b have the same number of bitwidth.
static Value getScalarOrVectorConstInt(Type type, uint64_t value, OpBuilder &builder, Location loc)
Creates a scalar/vector integer constant.
static LogicalResult getTypeConversionFailure(ConversionPatternRewriter &rewriter, Operation *op, Type srcType)
Returns a source type conversion failure for srcType and operation op.
static IntegerAttr getIntegerAttrFromFloatAttr(FloatAttr floatAttr, IntegerType dstType, Builder builder)
static FloatAttr convertFloatAttr(FloatAttr srcAttr, FloatType dstType, Builder builder)
Converts the given srcAttr to a new attribute of the given dstType.
static BoolAttr convertBoolAttr(Attribute srcAttr, Builder builder)
Converts the given srcAttr into a boolean attribute if it holds an integral value.
static bool isBoolScalarOrVector(Type type)
Returns true if the given type is a boolean scalar or vector type.
#define DISPATCH(cmpPredicate, spirvOp)
static IntegerAttr convertIntegerAttr(IntegerAttr srcAttr, IntegerType dstType, Builder builder)
Converts the given srcAttr to a new attribute of the given dstType.
static int64_t product(ArrayRef< int64_t > vals)
static llvm::ManagedStatic< PassManagerOptions > options
This class represents a processed binary blob of data.
ArrayRef< char > getData() const
Return the raw underlying data of this blob.
Attributes are known-constant values of operations.
Special case of IntegerAttr to represent boolean integers, i.e., signless i1 integers.
This class is a general helper class for creating context-global objects like types,...
IntegerAttr getIntegerAttr(Type type, int64_t value)
BoolAttr getBoolAttr(bool value)
FloatAttr getF32FloatAttr(float value)
An attribute that represents a reference to a dense vector or tensor object.
auto getValues() const
Return the held element values as a range of the given type.
static DenseElementsAttr getFromRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Construct a dense elements attribute from a raw buffer representing the data for this attribute.
static bool isValidRawBuffer(ShapedType type, ArrayRef< char > rawBuffer)
Returns true if the given buffer is a valid raw buffer for the given type.
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
ShapedType getType() const
Return the type of this ElementsAttr, guaranteed to be a vector or tensor with static shape.
DenseElementsAttr reshape(ShapedType newType)
Return a new DenseElementsAttr that has the same data as the current attribute, but has been reshaped...
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
This class helps build Operations.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Location getLoc()
The source location the operation was defined or derived from.
This provides public APIs that all operations should have.
Operation is the basic unit of execution within MLIR.
Location getLoc()
The source location the operation was defined or derived from.
result_type_range getResultTypes()
unsigned getNumResults()
Return the number of results held by this operation.
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.
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.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isIntOrIndexOrFloat() const
Return true if this is an integer (of any signedness), index, or float type.
bool isInteger() const
Return true if this is an integer type (with the specified width).
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Type front()
Return first type in the range.
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.
An attribute that specifies the target version, allowed extensions and capabilities,...
NestedPattern Op(FilterFunctionType filter=defaultFilterFunction)
void populateArithToSPIRVPatterns(const SPIRVTypeConverter &typeConverter, RewritePatternSet &patterns)
TargetEnvAttr lookupTargetEnvOrDefault(Operation *op)
Queries the target environment recursively from enclosing symbol table ops containing the given op or...
std::string getDecorationString(Decoration decoration)
Converts a SPIR-V Decoration enum value to its snake_case string representation for use in MLIR attri...
Include the generated interface declarations.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
Converts elementwise unary, binary and ternary standard operations to SPIR-V operations.