23#include "llvm/ADT/TypeSwitch.h"
24#include "llvm/Support/FormatVariadic.h"
26#define DEBUG_TYPE "spirv-to-llvm-pattern"
38 if (
auto vecType = dyn_cast<VectorType>(type))
39 return vecType.getElementType().isSignedInteger();
47 if (
auto vecType = dyn_cast<VectorType>(type))
48 return vecType.getElementType().isUnsignedInteger();
55 if (
auto intType = dyn_cast<IntegerType>(type))
56 return intType.getWidth();
57 if (
auto vecType = dyn_cast<VectorType>(type))
58 if (
auto intType = dyn_cast<IntegerType>(vecType.getElementType()))
59 return intType.getWidth();
66 "bitwidth is not supported for this type");
69 auto vecType = dyn_cast<VectorType>(type);
70 auto elementType = vecType.getElementType();
71 assert(elementType.isIntOrFloat() &&
72 "only integers and floats have a bitwidth");
73 return elementType.getIntOrFloatBitWidth();
78 if (
auto vecTy = dyn_cast<VectorType>(type))
79 type = vecTy.getElementType();
80 return cast<IntegerType>(type).getWidth();
87 IntegerAttr scalarAttr) {
88 if (
auto vecType = dyn_cast<VectorType>(srcType))
89 return LLVM::ConstantOp::create(
91 return LLVM::ConstantOp::create(rewriter, loc, dstType, scalarAttr);
97 auto integerType = cast<IntegerType>(
98 isa<VectorType>(srcType) ? cast<VectorType>(srcType).
getElementType()
107 if (
auto vecType = dyn_cast<VectorType>(srcType)) {
108 auto floatType = cast<FloatType>(vecType.getElementType());
109 return LLVM::ConstantOp::create(
110 rewriter, loc, dstType,
114 auto floatType = cast<FloatType>(srcType);
115 return LLVM::ConstantOp::create(rewriter, loc, dstType,
128 auto srcType = value.
getType();
134 if (valueBitWidth < targetBitWidth)
135 return LLVM::ZExtOp::create(rewriter, loc, llvmType, value);
140 if (valueBitWidth > targetBitWidth)
141 return LLVM::TruncOp::create(rewriter, loc, llvmType, value);
148 ConversionPatternRewriter &rewriter) {
149 auto vectorType = VectorType::get(numElements, toBroadcast.
getType());
150 auto llvmVectorType = typeConverter.convertType(vectorType);
151 auto llvmI32Type = typeConverter.convertType(rewriter.getIntegerType(32));
152 Value broadcasted = LLVM::PoisonOp::create(rewriter, loc, llvmVectorType);
153 for (
unsigned i = 0; i < numElements; ++i) {
154 auto index = LLVM::ConstantOp::create(rewriter, loc, llvmI32Type,
155 rewriter.getI32IntegerAttr(i));
156 broadcasted = LLVM::InsertElementOp::create(
157 rewriter, loc, llvmVectorType, broadcasted, toBroadcast,
index);
165 ConversionPatternRewriter &rewriter) {
166 if (
auto vectorType = dyn_cast<VectorType>(srcType)) {
167 unsigned numElements = vectorType.getNumElements();
168 return broadcast(loc, value, numElements, typeConverter, rewriter);
185 ConversionPatternRewriter &rewriter) {
199 if (failed(converter.convertTypes(type.
getElementTypes(), elementsVector)))
201 return LLVM::LLVMStructType::getLiteral(type.getContext(), elementsVector,
209 if (failed(converter.convertTypes(type.
getElementTypes(), elementsVector)))
211 return LLVM::LLVMStructType::getLiteral(type.getContext(), elementsVector,
218 return LLVM::ConstantOp::create(
219 rewriter, loc, IntegerType::get(rewriter.
getContext(), 32),
225 ConversionPatternRewriter &rewriter,
227 unsigned alignment,
bool isVolatile,
228 bool isNonTemporal) {
229 if (
auto loadOp = dyn_cast<spirv::LoadOp>(op)) {
230 auto dstType = typeConverter.convertType(loadOp.getType());
232 return rewriter.notifyMatchFailure(op,
"type conversion failed");
233 rewriter.replaceOpWithNewOp<LLVM::LoadOp>(
234 loadOp, dstType, spirv::LoadOpAdaptor(operands).getPtr(), alignment,
235 isVolatile, isNonTemporal);
238 auto storeOp = cast<spirv::StoreOp>(op);
239 spirv::StoreOpAdaptor adaptor(operands);
240 rewriter.replaceOpWithNewOp<LLVM::StoreOp>(storeOp, adaptor.getValue(),
241 adaptor.getPtr(), alignment,
242 isVolatile, isNonTemporal);
257 auto sizeInBytes = cast<spirv::SPIRVType>(elementType).getSizeInBytes();
258 if (stride != 0 && (!sizeInBytes || *sizeInBytes != stride))
261 auto llvmElementType = converter.convertType(elementType);
263 return LLVM::LLVMArrayType::get(llvmElementType, numElements);
270 spirv::ClientAPI clientAPI) {
271 unsigned addressSpace =
273 return LLVM::LLVMPointerType::get(type.getContext(), addressSpace);
284 return LLVM::LLVMArrayType::get(elementType, 0);
293 if (!memberDecorations.empty())
306template <
typename TargetOp,
typename SourceOp>
308collectAttrsForConversion(SourceOp op,
309 typename TargetOp::Properties &properties,
312 if (
auto sourceProperties =
313 dyn_cast_or_null<DictionaryAttr>(op->getPropertiesAsAttribute()))
314 attrs.append(sourceProperties.getValue());
316 if constexpr (std::is_same_v<
typename TargetOp::Properties,
318 llvm::append_range(discardableAttrs, attrs);
322 TargetOp::populateDefaultProperties(
323 OperationName(TargetOp::getOperationName(), op->getContext()),
325 if (
failed(TargetOp::setPropertiesFromAttr(
326 properties, attrs.getDictionary(op->getContext()),
327 [&]() { return op.emitError(
"failed to convert properties"); })))
330 auto convertedProperties = dyn_cast_or_null<DictionaryAttr>(
331 TargetOp::getPropertiesAsAttr(op->getContext(), properties));
333 StringRef name = attr.getName().getValue();
334 bool isProperty = convertedProperties && convertedProperties.contains(name);
335 if (name ==
"operand_segment_sizes")
336 isProperty |= convertedProperties &&
337 convertedProperties.contains(
"operandSegmentSizes");
338 if (name ==
"result_segment_sizes")
339 isProperty |= convertedProperties &&
340 convertedProperties.contains(
"resultSegmentSizes");
342 discardableAttrs.push_back(attr);
349 using SPIRVToLLVMConversion<spirv::AccessChainOp>::SPIRVToLLVMConversion;
352 matchAndRewrite(spirv::AccessChainOp op, OpAdaptor adaptor,
353 ConversionPatternRewriter &rewriter)
const override {
355 getTypeConverter()->convertType(op.getComponentPtr().getType());
357 return rewriter.notifyMatchFailure(op,
"type conversion failed");
359 auto indices = llvm::to_vector<4>(adaptor.getIndices());
360 Type indexType = op.getIndices().front().getType();
361 auto llvmIndexType = getTypeConverter()->convertType(indexType);
363 return rewriter.notifyMatchFailure(op,
"type conversion failed");
365 LLVM::ConstantOp::create(rewriter, op.getLoc(), llvmIndexType,
366 rewriter.getIntegerAttr(llvmIndexType, 0));
369 auto elementType = getTypeConverter()->convertType(
370 cast<spirv::PointerType>(op.getBasePtr().getType()).getPointeeType());
372 return rewriter.notifyMatchFailure(op,
"type conversion failed");
373 rewriter.replaceOpWithNewOp<LLVM::GEPOp>(op, dstType, elementType,
374 adaptor.getBasePtr(),
indices);
381 using SPIRVToLLVMConversion<spirv::AddressOfOp>::SPIRVToLLVMConversion;
384 matchAndRewrite(spirv::AddressOfOp op, OpAdaptor adaptor,
385 ConversionPatternRewriter &rewriter)
const override {
386 auto dstType = getTypeConverter()->convertType(op.getPointer().getType());
388 return rewriter.notifyMatchFailure(op,
"type conversion failed");
389 rewriter.replaceOpWithNewOp<LLVM::AddressOfOp>(op, dstType,
395class BitFieldInsertPattern
398 using SPIRVToLLVMConversion<spirv::BitFieldInsertOp>::SPIRVToLLVMConversion;
401 matchAndRewrite(spirv::BitFieldInsertOp op, OpAdaptor adaptor,
402 ConversionPatternRewriter &rewriter)
const override {
403 auto srcType = op.getType();
404 auto dstType = getTypeConverter()->convertType(srcType);
406 return rewriter.notifyMatchFailure(op,
"type conversion failed");
407 Location loc = op.getLoc();
411 *getTypeConverter(), rewriter);
413 *getTypeConverter(), rewriter);
417 Value maskShiftedByCount =
418 LLVM::ShlOp::create(rewriter, loc, dstType, minusOne, count);
419 Value negated = LLVM::XOrOp::create(rewriter, loc, dstType,
420 maskShiftedByCount, minusOne);
421 Value maskShiftedByCountAndOffset =
422 LLVM::ShlOp::create(rewriter, loc, dstType, negated, offset);
423 Value mask = LLVM::XOrOp::create(rewriter, loc, dstType,
424 maskShiftedByCountAndOffset, minusOne);
429 LLVM::AndOp::create(rewriter, loc, dstType, op.getBase(), mask);
430 Value insertShiftedByOffset =
431 LLVM::ShlOp::create(rewriter, loc, dstType, op.getInsert(), offset);
432 rewriter.replaceOpWithNewOp<LLVM::OrOp>(op, dstType, baseAndMask,
433 insertShiftedByOffset);
439class ConstantScalarAndVectorPattern
442 using SPIRVToLLVMConversion<spirv::ConstantOp>::SPIRVToLLVMConversion;
445 matchAndRewrite(spirv::ConstantOp constOp, OpAdaptor adaptor,
446 ConversionPatternRewriter &rewriter)
const override {
447 auto srcType = constOp.getType();
448 if (!isa<VectorType>(srcType) && !srcType.isIntOrFloat())
451 auto dstType = getTypeConverter()->convertType(srcType);
453 return rewriter.notifyMatchFailure(constOp,
"type conversion failed");
462 auto signlessType = rewriter.getIntegerType(
getBitWidth(srcType));
464 if (isa<VectorType>(srcType)) {
465 auto dstElementsAttr = cast<DenseIntElementsAttr>(constOp.getValue());
466 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(
468 dstElementsAttr.mapValues(
469 signlessType, [&](
const APInt &value) {
return value; }));
472 auto srcAttr = cast<IntegerAttr>(constOp.getValue());
473 auto dstAttr = rewriter.getIntegerAttr(signlessType, srcAttr.getValue());
474 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(constOp, dstType, dstAttr);
477 LLVM::ConstantOp::Properties properties{};
478 SmallVector<NamedAttribute> discardableAttrs;
479 if (
failed(collectAttrsForConversion<LLVM::ConstantOp>(constOp, properties,
482 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(
483 constOp, dstType, adaptor.getOperands(), properties, discardableAttrs);
488class BitFieldSExtractPattern
491 using SPIRVToLLVMConversion<spirv::BitFieldSExtractOp>::SPIRVToLLVMConversion;
494 matchAndRewrite(spirv::BitFieldSExtractOp op, OpAdaptor adaptor,
495 ConversionPatternRewriter &rewriter)
const override {
496 auto srcType = op.getType();
497 auto dstType = getTypeConverter()->convertType(srcType);
499 return rewriter.notifyMatchFailure(op,
"type conversion failed");
500 Location loc = op.getLoc();
504 *getTypeConverter(), rewriter);
506 *getTypeConverter(), rewriter);
509 IntegerType integerType;
510 if (
auto vecType = dyn_cast<VectorType>(srcType))
511 integerType = cast<IntegerType>(vecType.getElementType());
513 integerType = cast<IntegerType>(srcType);
515 auto baseSize = rewriter.getIntegerAttr(integerType,
getBitWidth(srcType));
517 isa<VectorType>(srcType)
518 ? LLVM::ConstantOp::create(
519 rewriter, loc, dstType,
520 SplatElementsAttr::get(cast<ShapedType>(srcType), baseSize))
521 : LLVM::ConstantOp::create(rewriter, loc, dstType, baseSize);
525 Value countPlusOffset =
526 LLVM::AddOp::create(rewriter, loc, dstType, count, offset);
527 Value amountToShiftLeft =
528 LLVM::SubOp::create(rewriter, loc, dstType, size, countPlusOffset);
529 Value baseShiftedLeft = LLVM::ShlOp::create(
530 rewriter, loc, dstType, op.getBase(), amountToShiftLeft);
533 Value amountToShiftRight =
534 LLVM::AddOp::create(rewriter, loc, dstType, offset, amountToShiftLeft);
535 rewriter.replaceOpWithNewOp<LLVM::AShrOp>(op, dstType, baseShiftedLeft,
541class BitFieldUExtractPattern
544 using SPIRVToLLVMConversion<spirv::BitFieldUExtractOp>::SPIRVToLLVMConversion;
547 matchAndRewrite(spirv::BitFieldUExtractOp op, OpAdaptor adaptor,
548 ConversionPatternRewriter &rewriter)
const override {
549 auto srcType = op.getType();
550 auto dstType = getTypeConverter()->convertType(srcType);
552 return rewriter.notifyMatchFailure(op,
"type conversion failed");
553 Location loc = op.getLoc();
557 *getTypeConverter(), rewriter);
559 *getTypeConverter(), rewriter);
563 Value maskShiftedByCount =
564 LLVM::ShlOp::create(rewriter, loc, dstType, minusOne, count);
565 Value mask = LLVM::XOrOp::create(rewriter, loc, dstType, maskShiftedByCount,
570 LLVM::LShrOp::create(rewriter, loc, dstType, op.getBase(), offset);
571 rewriter.replaceOpWithNewOp<LLVM::AndOp>(op, dstType, shiftedBase, mask);
578 using SPIRVToLLVMConversion<spirv::BranchOp>::SPIRVToLLVMConversion;
581 matchAndRewrite(spirv::BranchOp branchOp, OpAdaptor adaptor,
582 ConversionPatternRewriter &rewriter)
const override {
583 rewriter.replaceOpWithNewOp<LLVM::BrOp>(branchOp, adaptor.getOperands(),
584 branchOp.getTarget());
589class BranchConditionalConversionPattern
592 using SPIRVToLLVMConversion<
593 spirv::BranchConditionalOp>::SPIRVToLLVMConversion;
596 matchAndRewrite(spirv::BranchConditionalOp op, OpAdaptor adaptor,
597 ConversionPatternRewriter &rewriter)
const override {
600 if (
auto weights = op.getBranchWeights()) {
601 SmallVector<int32_t> weightValues;
602 for (
auto weight : weights->getAsRange<IntegerAttr>())
603 weightValues.push_back(weight.getInt());
607 rewriter.replaceOpWithNewOp<LLVM::CondBrOp>(
608 op, op.getCondition(), op.getTrueBlockArguments(),
609 op.getFalseBlockArguments(), branchWeights, op.getTrueBlock(),
618class CompositeExtractPattern
621 using SPIRVToLLVMConversion<spirv::CompositeExtractOp>::SPIRVToLLVMConversion;
624 matchAndRewrite(spirv::CompositeExtractOp op, OpAdaptor adaptor,
625 ConversionPatternRewriter &rewriter)
const override {
626 auto dstType = this->getTypeConverter()->convertType(op.getType());
628 return rewriter.notifyMatchFailure(op,
"type conversion failed");
630 Type containerType = op.getComposite().getType();
631 if (isa<VectorType>(containerType)) {
632 Location loc = op.getLoc();
633 IntegerAttr value = cast<IntegerAttr>(op.getIndices()[0]);
635 rewriter.replaceOpWithNewOp<LLVM::ExtractElementOp>(
636 op, dstType, adaptor.getComposite(), index);
640 rewriter.replaceOpWithNewOp<LLVM::ExtractValueOp>(
641 op, adaptor.getComposite(),
650class CompositeInsertPattern
653 using SPIRVToLLVMConversion<spirv::CompositeInsertOp>::SPIRVToLLVMConversion;
656 matchAndRewrite(spirv::CompositeInsertOp op, OpAdaptor adaptor,
657 ConversionPatternRewriter &rewriter)
const override {
658 auto dstType = this->getTypeConverter()->convertType(op.getType());
660 return rewriter.notifyMatchFailure(op,
"type conversion failed");
662 Type containerType = op.getComposite().getType();
663 if (isa<VectorType>(containerType)) {
664 Location loc = op.getLoc();
665 IntegerAttr value = cast<IntegerAttr>(op.getIndices()[0]);
667 rewriter.replaceOpWithNewOp<LLVM::InsertElementOp>(
668 op, dstType, adaptor.getComposite(), adaptor.getObject(), index);
672 rewriter.replaceOpWithNewOp<LLVM::InsertValueOp>(
673 op, adaptor.getComposite(), adaptor.getObject(),
681template <
typename SPIRVOp,
typename LLVMOp>
684 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
687 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
688 ConversionPatternRewriter &rewriter)
const override {
689 auto dstType = this->getTypeConverter()->convertType(op.getType());
691 return rewriter.notifyMatchFailure(op,
"type conversion failed");
692 typename LLVMOp::Properties properties{};
693 SmallVector<NamedAttribute> discardableAttrs;
694 if (
failed(collectAttrsForConversion<LLVMOp>(op, properties,
697 rewriter.template replaceOpWithNewOp<LLVMOp>(
698 op, dstType, adaptor.getOperands(), properties, discardableAttrs);
708template <
typename SPIRVOp,
typename LLVMOp>
711 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
714 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
715 ConversionPatternRewriter &rewriter)
const override {
716 Type dstType = this->getTypeConverter()->convertType(op.getType());
718 return rewriter.notifyMatchFailure(op,
"type conversion failed");
720 Location loc = op.getLoc();
721 Type operandType = adaptor.getOperand1().getType();
722 Type overflowType = rewriter.getI1Type();
723 if (
auto vecType = dyn_cast<VectorType>(operandType))
724 overflowType = VectorType::get(vecType.getShape(), overflowType);
726 Type intrType = LLVM::LLVMStructType::getLiteral(
727 rewriter.getContext(), {operandType, overflowType});
728 Value intrResult = LLVMOp::create(
729 rewriter, loc, intrType, adaptor.getOperand1(), adaptor.getOperand2());
730 Value lowBits = LLVM::ExtractValueOp::create(rewriter, loc, intrResult, 0);
731 Value overflow = LLVM::ExtractValueOp::create(rewriter, loc, intrResult, 1);
732 overflow = LLVM::ZExtOp::create(rewriter, loc, operandType, overflow);
734 Value
result = LLVM::PoisonOp::create(rewriter, loc, dstType);
735 result = LLVM::InsertValueOp::create(rewriter, loc,
result, lowBits,
736 ArrayRef<int64_t>{0});
737 result = LLVM::InsertValueOp::create(rewriter, loc,
result, overflow,
738 ArrayRef<int64_t>{1});
739 rewriter.replaceOp(op,
result);
747template <
typename SPIRVOp,
typename LLVMExtOp>
750 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
753 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
754 ConversionPatternRewriter &rewriter)
const override {
755 Type dstType = this->getTypeConverter()->convertType(op.getType());
757 return rewriter.notifyMatchFailure(op,
"type conversion failed");
759 Location loc = op.getLoc();
760 Type operandType = adaptor.getOperand1().getType();
762 IntegerType wideElemType = rewriter.getIntegerType(bitwidth * 2);
763 Type wideType = wideElemType;
764 if (
auto vecType = dyn_cast<VectorType>(operandType))
765 wideType = VectorType::get(vecType.getShape(), wideElemType);
768 LLVMExtOp::create(rewriter, loc, wideType, adaptor.getOperand1());
770 LLVMExtOp::create(rewriter, loc, wideType, adaptor.getOperand2());
771 Value
mul = LLVM::MulOp::create(rewriter, loc, wideType,
lhs,
rhs);
772 Value low = LLVM::TruncOp::create(rewriter, loc, operandType,
mul);
775 rewriter.getIntegerAttr(wideElemType, bitwidth));
776 Value high = LLVM::LShrOp::create(rewriter, loc,
mul, shift);
777 high = LLVM::TruncOp::create(rewriter, loc, operandType, high);
779 Value
result = LLVM::PoisonOp::create(rewriter, loc, dstType);
780 result = LLVM::InsertValueOp::create(rewriter, loc,
result, low,
781 ArrayRef<int64_t>{0});
782 result = LLVM::InsertValueOp::create(rewriter, loc,
result, high,
783 ArrayRef<int64_t>{1});
784 rewriter.replaceOp(op,
result);
791class ExecutionModePattern
794 using SPIRVToLLVMConversion<spirv::ExecutionModeOp>::SPIRVToLLVMConversion;
797 matchAndRewrite(spirv::ExecutionModeOp op, OpAdaptor adaptor,
798 ConversionPatternRewriter &rewriter)
const override {
802 ModuleOp module = op->getParentOfType<ModuleOp>();
803 spirv::ExecutionModeAttr executionModeAttr = op.getExecutionModeAttr();
804 std::string moduleName;
805 if (module.getName().has_value())
806 moduleName =
"_" +
module.getName()->str();
809 std::string executionModeInfoName = llvm::formatv(
810 "__spv_{0}_{1}_execution_mode_info_{2}", moduleName, op.getFn().str(),
811 static_cast<uint32_t
>(executionModeAttr.getValue()));
813 MLIRContext *context = rewriter.getContext();
814 OpBuilder::InsertionGuard guard(rewriter);
815 rewriter.setInsertionPointToStart(module.getBody());
822 auto llvmI32Type = IntegerType::get(context, 32);
823 SmallVector<Type, 2> fields;
824 fields.push_back(llvmI32Type);
826 if (!values.empty()) {
827 auto arrayType = LLVM::LLVMArrayType::get(llvmI32Type, values.size());
828 fields.push_back(arrayType);
830 auto structType = LLVM::LLVMStructType::getLiteral(context, fields);
833 auto global = LLVM::GlobalOp::create(
834 rewriter, UnknownLoc::get(context), structType,
true,
835 LLVM::Linkage::External, executionModeInfoName, Attribute(),
837 Location loc = global.getLoc();
838 Region ®ion = global.getInitializerRegion();
839 Block *block = rewriter.createBlock(®ion);
842 rewriter.setInsertionPointToStart(block);
843 Value structValue = LLVM::PoisonOp::create(rewriter, loc, structType);
844 Value executionMode = LLVM::ConstantOp::create(
845 rewriter, loc, llvmI32Type,
846 rewriter.getI32IntegerAttr(
847 static_cast<uint32_t
>(executionModeAttr.getValue())));
848 SmallVector<int64_t> position{0};
849 structValue = LLVM::InsertValueOp::create(rewriter, loc, structValue,
850 executionMode, position);
853 for (
unsigned i = 0, e = values.size(); i < e; ++i) {
854 auto attr = values.getValue()[i];
855 Value entry = LLVM::ConstantOp::create(rewriter, loc, llvmI32Type, attr);
856 structValue = LLVM::InsertValueOp::create(
857 rewriter, loc, structValue, entry, ArrayRef<int64_t>({1, i}));
859 LLVM::ReturnOp::create(rewriter, loc, ArrayRef<Value>({structValue}));
860 rewriter.eraseOp(op);
869class GlobalVariablePattern
872 template <
typename... Args>
873 GlobalVariablePattern(spirv::ClientAPI clientAPI, Args &&...args)
874 : SPIRVToLLVMConversion<spirv::GlobalVariableOp>(
875 std::forward<Args>(args)...),
876 clientAPI(clientAPI) {}
879 matchAndRewrite(spirv::GlobalVariableOp op, OpAdaptor adaptor,
880 ConversionPatternRewriter &rewriter)
const override {
883 if (op.getInitializer())
886 auto srcType = cast<spirv::PointerType>(op.getType());
887 auto dstType = getTypeConverter()->convertType(srcType.getPointeeType());
889 return rewriter.notifyMatchFailure(op,
"type conversion failed");
894 auto storageClass = srcType.getStorageClass();
895 switch (storageClass) {
896 case spirv::StorageClass::Input:
897 case spirv::StorageClass::Private:
898 case spirv::StorageClass::Output:
899 case spirv::StorageClass::StorageBuffer:
900 case spirv::StorageClass::UniformConstant:
909 bool isConstant = (storageClass == spirv::StorageClass::Input) ||
910 (storageClass == spirv::StorageClass::UniformConstant);
916 auto linkage = storageClass == spirv::StorageClass::Private
917 ? LLVM::Linkage::Private
918 : LLVM::Linkage::External;
919 StringAttr locationAttrName = op.getLocationAttrName();
920 IntegerAttr locationAttr = op.getLocationAttr();
921 auto newGlobalOp = rewriter.replaceOpWithNewOp<LLVM::GlobalOp>(
922 op, dstType, isConstant, linkage, op.getSymName(), Attribute(),
927 newGlobalOp->setDiscardableAttr(locationAttrName, locationAttr);
933 spirv::ClientAPI clientAPI;
938template <
typename SPIRVOp,
typename LLVMExtOp,
typename LLVMTruncOp>
941 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
944 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
945 ConversionPatternRewriter &rewriter)
const override {
947 Type fromType = op.getOperand().getType();
948 Type toType = op.getType();
950 auto dstType = this->getTypeConverter()->convertType(toType);
952 return rewriter.notifyMatchFailure(op,
"type conversion failed");
955 rewriter.template replaceOpWithNewOp<LLVMExtOp>(op, dstType,
956 adaptor.getOperands());
960 rewriter.template replaceOpWithNewOp<LLVMTruncOp>(op, dstType,
961 adaptor.getOperands());
968class FunctionCallPattern
971 using SPIRVToLLVMConversion<spirv::FunctionCallOp>::SPIRVToLLVMConversion;
974 matchAndRewrite(spirv::FunctionCallOp callOp, OpAdaptor adaptor,
975 ConversionPatternRewriter &rewriter)
const override {
976 LLVM::CallOp::Properties properties{};
977 SmallVector<NamedAttribute> discardableAttrs;
978 if (
failed(collectAttrsForConversion<LLVM::CallOp>(callOp, properties,
981 properties.operandSegmentSizes = {
982 static_cast<int32_t
>(adaptor.getOperands().size()), 0};
983 properties.op_bundle_sizes = rewriter.getDenseI32ArrayAttr({});
985 if (callOp.getNumResults() == 0) {
986 rewriter.replaceOpWithNewOp<LLVM::CallOp>(callOp,
TypeRange(),
987 adaptor.getOperands(),
988 properties, discardableAttrs);
993 auto dstType = getTypeConverter()->convertType(callOp.getType(0));
995 return rewriter.notifyMatchFailure(callOp,
"type conversion failed");
996 rewriter.replaceOpWithNewOp<LLVM::CallOp>(
997 callOp, dstType, adaptor.getOperands(), properties, discardableAttrs);
1003template <
typename SPIRVOp, LLVM::FCmpPredicate predicate>
1006 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
1009 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
1010 ConversionPatternRewriter &rewriter)
const override {
1012 auto dstType = this->getTypeConverter()->convertType(op.getType());
1014 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1016 rewriter.template replaceOpWithNewOp<LLVM::FCmpOp>(
1017 op, dstType, predicate, op.getOperand1(), op.getOperand2());
1023template <
typename SPIRVOp, LLVM::ICmpPredicate predicate>
1026 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
1029 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
1030 ConversionPatternRewriter &rewriter)
const override {
1032 auto dstType = this->getTypeConverter()->convertType(op.getType());
1034 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1036 rewriter.template replaceOpWithNewOp<LLVM::ICmpOp>(
1037 op, dstType, predicate, op.getOperand1(), op.getOperand2());
1042class InverseSqrtPattern
1045 using SPIRVToLLVMConversion<spirv::GLInverseSqrtOp>::SPIRVToLLVMConversion;
1048 matchAndRewrite(spirv::GLInverseSqrtOp op, OpAdaptor adaptor,
1049 ConversionPatternRewriter &rewriter)
const override {
1050 auto srcType = op.getType();
1051 auto dstType = getTypeConverter()->convertType(srcType);
1053 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1055 Location loc = op.getLoc();
1057 Value sqrt = LLVM::SqrtOp::create(rewriter, loc, dstType, op.getOperand());
1058 rewriter.replaceOpWithNewOp<LLVM::FDivOp>(op, dstType, one, sqrt);
1065class VectorTimesScalarPattern
1068 using SPIRVToLLVMConversion<
1069 spirv::VectorTimesScalarOp>::SPIRVToLLVMConversion;
1072 matchAndRewrite(spirv::VectorTimesScalarOp op, OpAdaptor adaptor,
1073 ConversionPatternRewriter &rewriter)
const override {
1074 Type srcType = op.getType();
1075 Type dstType = getTypeConverter()->convertType(srcType);
1077 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1079 unsigned numElements = op.getVector().getType().getNumElements();
1080 Value broadcasted =
broadcast(op.getLoc(), adaptor.getScalar(), numElements,
1081 *getTypeConverter(), rewriter);
1082 rewriter.replaceOpWithNewOp<LLVM::FMulOp>(op, dstType, adaptor.getVector(),
1091 using SPIRVToLLVMConversion<spirv::SNegateOp>::SPIRVToLLVMConversion;
1094 matchAndRewrite(spirv::SNegateOp op, OpAdaptor adaptor,
1095 ConversionPatternRewriter &rewriter)
const override {
1096 Type srcType = op.getType();
1097 Type dstType = getTypeConverter()->convertType(srcType);
1099 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1101 Location loc = op.getLoc();
1102 IntegerAttr zeroAttr = rewriter.getIntegerAttr(
1106 rewriter.replaceOpWithNewOp<LLVM::SubOp>(op, dstType, zero,
1107 adaptor.getOperand());
1114template <
typename SPIRVOp,
typename LLVMMinOp,
typename LLVMMaxOp>
1117 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
1120 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
1121 ConversionPatternRewriter &rewriter)
const override {
1122 Type dstType = this->getTypeConverter()->convertType(op.getType());
1124 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1126 Location loc = op.getLoc();
1127 Value
max = LLVMMaxOp::create(rewriter, loc, dstType, adaptor.getX(),
1129 rewriter.template replaceOpWithNewOp<LLVMMinOp>(op, dstType,
max,
1140 using SPIRVToLLVMConversion<spirv::FModOp>::SPIRVToLLVMConversion;
1143 matchAndRewrite(spirv::FModOp op, OpAdaptor adaptor,
1144 ConversionPatternRewriter &rewriter)
const override {
1145 Type dstType = getTypeConverter()->convertType(op.getType());
1147 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1149 Location loc = op.getLoc();
1150 Value
lhs = adaptor.getOperand1();
1151 Value
rhs = adaptor.getOperand2();
1152 Value
div = LLVM::FDivOp::create(rewriter, loc, dstType,
lhs,
rhs);
1153 Value floored = LLVM::FFloorOp::create(rewriter, loc, dstType,
div);
1154 Value scaled = LLVM::FMulOp::create(rewriter, loc, dstType,
rhs, floored);
1155 rewriter.replaceOpWithNewOp<LLVM::FSubOp>(op, dstType,
lhs, scaled);
1166 using SPIRVToLLVMConversion<spirv::SModOp>::SPIRVToLLVMConversion;
1169 matchAndRewrite(spirv::SModOp op, OpAdaptor adaptor,
1170 ConversionPatternRewriter &rewriter)
const override {
1171 Type srcType = op.getType();
1172 Type dstType = getTypeConverter()->convertType(srcType);
1174 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1176 Location loc = op.getLoc();
1177 Value
lhs = adaptor.getOperand1();
1178 Value
rhs = adaptor.getOperand2();
1179 Type i1Type = rewriter.getI1Type();
1180 auto vecSrcType = dyn_cast<VectorType>(srcType);
1182 vecSrcType ? VectorType::get(vecSrcType.getShape(), i1Type) : i1Type;
1184 Value
rem = LLVM::SRemOp::create(rewriter, loc, dstType,
lhs,
rhs);
1185 IntegerAttr zeroAttr = rewriter.getIntegerAttr(
1190 Value remNonZero = LLVM::ICmpOp::create(rewriter, loc, cmpType,
1191 LLVM::ICmpPredicate::ne,
rem, zero);
1192 Value remNeg = LLVM::ICmpOp::create(rewriter, loc, cmpType,
1193 LLVM::ICmpPredicate::slt,
rem, zero);
1194 Value rhsNeg = LLVM::ICmpOp::create(rewriter, loc, cmpType,
1195 LLVM::ICmpPredicate::slt,
rhs, zero);
1196 Value signMismatch =
1197 LLVM::XOrOp::create(rewriter, loc, cmpType, remNeg, rhsNeg);
1199 LLVM::AndOp::create(rewriter, loc, cmpType, remNonZero, signMismatch);
1201 Value adjusted = LLVM::AddOp::create(rewriter, loc, dstType,
rem,
rhs);
1202 rewriter.replaceOpWithNewOp<LLVM::SelectOp>(op, dstType, needsAdjust,
1209template <
typename SPIRVOp>
1212 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
1215 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
1216 ConversionPatternRewriter &rewriter)
const override {
1217 if (!op.getMemoryAccess()) {
1219 *this->getTypeConverter(), 0,
1223 auto memoryAccess = *op.getMemoryAccess();
1224 switch (memoryAccess) {
1225 case spirv::MemoryAccess::Aligned:
1226 case spirv::MemoryAccess::None:
1227 case spirv::MemoryAccess::Nontemporal:
1228 case spirv::MemoryAccess::Volatile: {
1229 unsigned alignment =
1230 memoryAccess == spirv::MemoryAccess::Aligned ? *op.getAlignment() : 0;
1231 bool isNonTemporal = memoryAccess == spirv::MemoryAccess::Nontemporal;
1232 bool isVolatile = memoryAccess == spirv::MemoryAccess::Volatile;
1234 *this->getTypeConverter(), alignment,
1235 isVolatile, isNonTemporal);
1245template <
typename SPIRVOp>
1248 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
1251 matchAndRewrite(SPIRVOp notOp,
typename SPIRVOp::Adaptor adaptor,
1252 ConversionPatternRewriter &rewriter)
const override {
1253 auto srcType = notOp.getType();
1254 auto dstType = this->getTypeConverter()->convertType(srcType);
1256 return rewriter.notifyMatchFailure(notOp,
"type conversion failed");
1258 Location loc = notOp.getLoc();
1260 rewriter.template replaceOpWithNewOp<LLVM::XOrOp>(notOp, dstType,
1261 notOp.getOperand(), mask);
1267template <
typename SPIRVOp>
1270 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
1273 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
1274 ConversionPatternRewriter &rewriter)
const override {
1275 rewriter.eraseOp(op);
1282 using SPIRVToLLVMConversion<spirv::ReturnOp>::SPIRVToLLVMConversion;
1285 matchAndRewrite(spirv::ReturnOp returnOp, OpAdaptor adaptor,
1286 ConversionPatternRewriter &rewriter)
const override {
1287 rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(returnOp, ArrayRef<Type>(),
1295 using SPIRVToLLVMConversion<spirv::ReturnValueOp>::SPIRVToLLVMConversion;
1298 matchAndRewrite(spirv::ReturnValueOp returnValueOp, OpAdaptor adaptor,
1299 ConversionPatternRewriter &rewriter)
const override {
1300 rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(returnValueOp, ArrayRef<Type>(),
1301 adaptor.getOperands());
1308 using SPIRVToLLVMConversion<spirv::UnreachableOp>::SPIRVToLLVMConversion;
1311 matchAndRewrite(spirv::UnreachableOp unreachableOp, OpAdaptor adaptor,
1312 ConversionPatternRewriter &rewriter)
const override {
1313 rewriter.replaceOpWithNewOp<LLVM::UnreachableOp>(unreachableOp);
1322 bool convergent =
true) {
1323 auto func = dyn_cast_or_null<LLVM::LLVMFuncOp>(
1329 func = LLVM::LLVMFuncOp::create(
1330 b, symbolTable->
getLoc(), name,
1331 LLVM::LLVMFunctionType::get(resultType, paramTypes));
1332 func.setCConv(LLVM::cconv::CConv::SPIR_FUNC);
1333 func.setConvergent(convergent);
1334 func.setNoUnwind(
true);
1335 func.setWillReturn(
true);
1340 LLVM::LLVMFuncOp
func,
1342 auto call = LLVM::CallOp::create(builder, loc,
func, args);
1343 call.setCConv(
func.getCConv());
1344 call.setConvergentAttr(
func.getConvergentAttr());
1345 call.setNoUnwindAttr(
func.getNoUnwindAttr());
1346 call.setWillReturnAttr(
func.getWillReturnAttr());
1350template <
typename BarrierOpTy>
1353 using OpAdaptor =
typename SPIRVToLLVMConversion<BarrierOpTy>::OpAdaptor;
1355 using SPIRVToLLVMConversion<BarrierOpTy>::SPIRVToLLVMConversion;
1357 static constexpr StringRef getFuncName();
1360 matchAndRewrite(BarrierOpTy controlBarrierOp, OpAdaptor adaptor,
1361 ConversionPatternRewriter &rewriter)
const override {
1362 constexpr StringRef funcName = getFuncName();
1363 Operation *symbolTable =
1364 controlBarrierOp->template getParentWithTrait<OpTrait::SymbolTable>();
1366 Type i32 = rewriter.getI32Type();
1368 Type voidTy = rewriter.getType<LLVM::LLVMVoidType>();
1369 LLVM::LLVMFuncOp func =
1372 Location loc = controlBarrierOp->getLoc();
1373 Value execution = LLVM::ConstantOp::create(
1374 rewriter, loc, i32,
static_cast<int32_t
>(adaptor.getExecutionScope()));
1375 Value memory = LLVM::ConstantOp::create(
1376 rewriter, loc, i32,
static_cast<int32_t
>(adaptor.getMemoryScope()));
1377 Value semantics = LLVM::ConstantOp::create(
1378 rewriter, loc, i32,
static_cast<int32_t
>(adaptor.getMemorySemantics()));
1381 {execution, memory, semantics});
1383 rewriter.replaceOp(controlBarrierOp, call);
1390StringRef getTypeMangling(
Type type,
bool isSigned) {
1392 .Case([](Float16Type) {
return "Dh"; })
1393 .Case([](Float32Type) {
return "f"; })
1394 .Case([](Float64Type) {
return "d"; })
1395 .Case([isSigned](IntegerType intTy) {
1396 switch (intTy.getWidth()) {
1400 return (isSigned) ?
"a" :
"c";
1402 return (isSigned) ?
"s" :
"t";
1404 return (isSigned) ?
"i" :
"j";
1406 return (isSigned) ?
"l" :
"m";
1408 llvm_unreachable(
"Unsupported integer width");
1411 .DefaultUnreachable(
"No mangling defined");
1414template <
typename ReduceOp>
1415constexpr StringLiteral getGroupFuncName();
1418constexpr StringLiteral getGroupFuncName<spirv::GroupIAddOp>() {
1419 return "_Z17__spirv_GroupIAddii";
1422constexpr StringLiteral getGroupFuncName<spirv::GroupFAddOp>() {
1423 return "_Z17__spirv_GroupFAddii";
1426constexpr StringLiteral getGroupFuncName<spirv::GroupSMinOp>() {
1427 return "_Z17__spirv_GroupSMinii";
1430constexpr StringLiteral getGroupFuncName<spirv::GroupUMinOp>() {
1431 return "_Z17__spirv_GroupUMinii";
1434constexpr StringLiteral getGroupFuncName<spirv::GroupFMinOp>() {
1435 return "_Z17__spirv_GroupFMinii";
1438constexpr StringLiteral getGroupFuncName<spirv::GroupSMaxOp>() {
1439 return "_Z17__spirv_GroupSMaxii";
1442constexpr StringLiteral getGroupFuncName<spirv::GroupUMaxOp>() {
1443 return "_Z17__spirv_GroupUMaxii";
1446constexpr StringLiteral getGroupFuncName<spirv::GroupFMaxOp>() {
1447 return "_Z17__spirv_GroupFMaxii";
1450constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformIAddOp>() {
1451 return "_Z27__spirv_GroupNonUniformIAddii";
1454constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformFAddOp>() {
1455 return "_Z27__spirv_GroupNonUniformFAddii";
1458constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformIMulOp>() {
1459 return "_Z27__spirv_GroupNonUniformIMulii";
1462constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformFMulOp>() {
1463 return "_Z27__spirv_GroupNonUniformFMulii";
1466constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformSMinOp>() {
1467 return "_Z27__spirv_GroupNonUniformSMinii";
1470constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformUMinOp>() {
1471 return "_Z27__spirv_GroupNonUniformUMinii";
1474constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformFMinOp>() {
1475 return "_Z27__spirv_GroupNonUniformFMinii";
1478constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformSMaxOp>() {
1479 return "_Z27__spirv_GroupNonUniformSMaxii";
1482constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformUMaxOp>() {
1483 return "_Z27__spirv_GroupNonUniformUMaxii";
1486constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformFMaxOp>() {
1487 return "_Z27__spirv_GroupNonUniformFMaxii";
1490constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformBitwiseAndOp>() {
1491 return "_Z33__spirv_GroupNonUniformBitwiseAndii";
1494constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformBitwiseOrOp>() {
1495 return "_Z32__spirv_GroupNonUniformBitwiseOrii";
1498constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformBitwiseXorOp>() {
1499 return "_Z33__spirv_GroupNonUniformBitwiseXorii";
1502constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformLogicalAndOp>() {
1503 return "_Z33__spirv_GroupNonUniformLogicalAndii";
1506constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformLogicalOrOp>() {
1507 return "_Z32__spirv_GroupNonUniformLogicalOrii";
1510constexpr StringLiteral getGroupFuncName<spirv::GroupNonUniformLogicalXorOp>() {
1511 return "_Z33__spirv_GroupNonUniformLogicalXorii";
1515template <
typename ReduceOp,
bool Signed = false,
bool NonUniform = false>
1518 using SPIRVToLLVMConversion<ReduceOp>::SPIRVToLLVMConversion;
1521 matchAndRewrite(ReduceOp op,
typename ReduceOp::Adaptor adaptor,
1522 ConversionPatternRewriter &rewriter)
const override {
1524 Type retTy = op.getResult().getType();
1528 SmallString<36> funcName = getGroupFuncName<ReduceOp>();
1529 funcName += getTypeMangling(retTy,
false);
1531 Type i32Ty = rewriter.getI32Type();
1532 SmallVector<Type> paramTypes{i32Ty, i32Ty, retTy};
1533 if constexpr (NonUniform) {
1534 if (adaptor.getClusterSize()) {
1536 paramTypes.push_back(i32Ty);
1540 Operation *symbolTable =
1541 op->template getParentWithTrait<OpTrait::SymbolTable>();
1543 LLVM::LLVMFuncOp func =
1546 Location loc = op.getLoc();
1547 Value scope = LLVM::ConstantOp::create(
1548 rewriter, loc, i32Ty,
1549 static_cast<int32_t
>(adaptor.getExecutionScope()));
1550 Value groupOp = LLVM::ConstantOp::create(
1551 rewriter, loc, i32Ty,
1552 static_cast<int32_t
>(adaptor.getGroupOperation()));
1553 SmallVector<Value> operands{scope, groupOp};
1554 operands.append(adaptor.getOperands().begin(), adaptor.getOperands().end());
1557 rewriter.replaceOp(op, call);
1564ControlBarrierPattern<spirv::ControlBarrierOp>::getFuncName() {
1565 return "_Z22__spirv_ControlBarrieriii";
1570ControlBarrierPattern<spirv::INTELControlBarrierArriveOp>::getFuncName() {
1571 return "_Z33__spirv_ControlBarrierArriveINTELiii";
1576ControlBarrierPattern<spirv::INTELControlBarrierWaitOp>::getFuncName() {
1577 return "_Z31__spirv_ControlBarrierWaitINTELiii";
1630 using SPIRVToLLVMConversion<spirv::LoopOp>::SPIRVToLLVMConversion;
1633 matchAndRewrite(spirv::LoopOp loopOp, OpAdaptor adaptor,
1634 ConversionPatternRewriter &rewriter)
const override {
1636 if (loopOp.getLoopControl() != spirv::LoopControl::None)
1640 if (loopOp.getBody().empty()) {
1641 rewriter.eraseOp(loopOp);
1645 Location loc = loopOp.getLoc();
1649 Block *currentBlock = rewriter.getBlock();
1651 Block *endBlock = rewriter.splitBlock(currentBlock, position);
1655 Block *entryBlock = loopOp.getEntryBlock();
1657 auto brOp = dyn_cast<spirv::BranchOp>(entryBlock->
getOperations().front());
1660 Block *headerBlock = loopOp.getHeaderBlock();
1661 rewriter.setInsertionPointToEnd(currentBlock);
1662 LLVM::BrOp::create(rewriter, loc, brOp.getBlockArguments(), headerBlock);
1663 rewriter.eraseBlock(entryBlock);
1666 Block *mergeBlock = loopOp.getMergeBlock();
1669 rewriter.setInsertionPointToEnd(mergeBlock);
1670 LLVM::BrOp::create(rewriter, loc, terminatorOperands, endBlock);
1672 rewriter.inlineRegionBefore(loopOp.getBody(), endBlock);
1683 using SPIRVToLLVMConversion<spirv::SelectionOp>::SPIRVToLLVMConversion;
1686 matchAndRewrite(spirv::SelectionOp op, OpAdaptor adaptor,
1687 ConversionPatternRewriter &rewriter)
const override {
1691 if (op.getSelectionControl() != spirv::SelectionControl::None)
1698 if (op.getBody().getBlocks().size() <= 2) {
1699 rewriter.eraseOp(op);
1703 Location loc = op.getLoc();
1707 auto *currentBlock = rewriter.getInsertionBlock();
1708 rewriter.setInsertionPointAfter(op);
1709 auto position = rewriter.getInsertionPoint();
1710 auto *continueBlock = rewriter.splitBlock(currentBlock, position);
1713 for (
auto ty : op.getResultTypes()) {
1714 Type dstTy = getTypeConverter()->convertType(ty);
1716 return rewriter.notifyMatchFailure(op,
"failed to convert type");
1717 continueBlock->addArgument(dstTy, loc);
1724 auto *headerBlock = op.getHeaderBlock();
1726 auto condBrOp = dyn_cast<spirv::BranchConditionalOp>(
1732 auto *mergeBlock = op.getMergeBlock();
1735 rewriter.setInsertionPointToEnd(mergeBlock);
1736 LLVM::BrOp::create(rewriter, loc, terminatorOperands, continueBlock);
1739 Block *trueBlock = condBrOp.getTrueBlock();
1740 Block *falseBlock = condBrOp.getFalseBlock();
1741 rewriter.setInsertionPointToEnd(currentBlock);
1742 LLVM::CondBrOp::create(rewriter, loc, condBrOp.getCondition(), trueBlock,
1743 condBrOp.getTrueTargetOperands(), falseBlock,
1744 condBrOp.getFalseTargetOperands());
1746 rewriter.eraseBlock(headerBlock);
1747 rewriter.inlineRegionBefore(op.getBody(), continueBlock);
1748 rewriter.replaceOp(op, continueBlock->getArguments());
1757template <
typename SPIRVOp,
typename LLVMOp>
1760 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
1763 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
1764 ConversionPatternRewriter &rewriter)
const override {
1766 auto dstType = this->getTypeConverter()->convertType(op.getType());
1768 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1770 Type op1Type = op.getOperand1().getType();
1771 Type op2Type = op.getOperand2().getType();
1773 if (op1Type == op2Type) {
1774 rewriter.template replaceOpWithNewOp<LLVMOp>(op, dstType,
1775 adaptor.getOperands());
1779 std::optional<uint64_t> dstTypeWidth =
1781 std::optional<uint64_t> op2TypeWidth =
1784 if (!dstTypeWidth || !op2TypeWidth)
1787 Location loc = op.getLoc();
1789 if (op2TypeWidth < dstTypeWidth) {
1792 LLVM::ZExtOp::create(rewriter, loc, dstType, adaptor.getOperand2());
1795 LLVM::SExtOp::create(rewriter, loc, dstType, adaptor.getOperand2());
1797 }
else if (op2TypeWidth == dstTypeWidth) {
1798 extended = adaptor.getOperand2();
1804 LLVMOp::create(rewriter, loc, dstType, adaptor.getOperand1(), extended);
1805 rewriter.replaceOp(op,
result);
1815 using SPIRVToLLVMConversion<spirv::GLSAbsOp>::SPIRVToLLVMConversion;
1818 matchAndRewrite(spirv::GLSAbsOp op, OpAdaptor adaptor,
1819 ConversionPatternRewriter &rewriter)
const override {
1820 Type dstType = getTypeConverter()->convertType(op.getType());
1822 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1824 rewriter.replaceOpWithNewOp<LLVM::AbsOp>(op, dstType, adaptor.getOperand(),
1833 using SPIRVToLLVMConversion<spirv::GLFractOp>::SPIRVToLLVMConversion;
1836 matchAndRewrite(spirv::GLFractOp op, OpAdaptor adaptor,
1837 ConversionPatternRewriter &rewriter)
const override {
1838 Type dstType = getTypeConverter()->convertType(op.getType());
1840 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1842 Location loc = op.getLoc();
1843 Value operand = adaptor.getOperand();
1844 Value floored = LLVM::FFloorOp::create(rewriter, loc, dstType, operand);
1845 rewriter.replaceOpWithNewOp<LLVM::FSubOp>(op, dstType, operand, floored);
1854 using SPIRVToLLVMConversion<spirv::GLFMixOp>::SPIRVToLLVMConversion;
1857 matchAndRewrite(spirv::GLFMixOp op, OpAdaptor adaptor,
1858 ConversionPatternRewriter &rewriter)
const override {
1859 Type dstType = getTypeConverter()->convertType(op.getType());
1861 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1863 Location loc = op.getLoc();
1864 Value x = adaptor.getX();
1865 Value y = adaptor.getY();
1866 Value a = adaptor.getA();
1868 Value oneMinusA = LLVM::FSubOp::create(rewriter, loc, dstType, one, a);
1869 Value
lhs = LLVM::FMulOp::create(rewriter, loc, dstType, x, oneMinusA);
1870 Value
rhs = LLVM::FMulOp::create(rewriter, loc, dstType, y, a);
1871 rewriter.replaceOpWithNewOp<LLVM::FAddOp>(op, dstType,
lhs,
rhs);
1880 using SPIRVToLLVMConversion<spirv::CLMixOp>::SPIRVToLLVMConversion;
1883 matchAndRewrite(spirv::CLMixOp op, OpAdaptor adaptor,
1884 ConversionPatternRewriter &rewriter)
const override {
1885 Type dstType = getTypeConverter()->convertType(op.getType());
1887 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1889 Location loc = op.getLoc();
1890 Value x = adaptor.getX();
1891 Value y = adaptor.getY();
1892 Value a = adaptor.getZ();
1893 Value diff = LLVM::FSubOp::create(rewriter, loc, dstType, y, x);
1894 rewriter.replaceOpWithNewOp<LLVM::FMAOp>(op, dstType, a, diff, x);
1901template <
typename SPIRVOp>
1904 template <
typename... Args>
1905 ScalePattern(
double scale, Args &&...args)
1906 : SPIRVToLLVMConversion<SPIRVOp>(std::forward<Args>(args)...),
1910 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
1911 ConversionPatternRewriter &rewriter)
const override {
1912 Type srcType = op.getType();
1913 Type dstType = this->getTypeConverter()->convertType(srcType);
1915 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1917 Location loc = op.getLoc();
1919 rewriter.replaceOpWithNewOp<LLVM::FMulOp>(op, dstType, adaptor.getOperand(),
1931template <
typename SPIRVOp,
bool isFloat>
1934 using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
1937 matchAndRewrite(SPIRVOp op,
typename SPIRVOp::Adaptor adaptor,
1938 ConversionPatternRewriter &rewriter)
const override {
1939 Type srcType = op.getType();
1940 Type dstType = this->getTypeConverter()->convertType(srcType);
1942 return rewriter.notifyMatchFailure(op,
"type conversion failed");
1944 Location loc = op.getLoc();
1945 Value operand = adaptor.getOperand();
1946 auto vecSrcType = dyn_cast<VectorType>(srcType);
1947 Type i1Type = rewriter.getI1Type();
1949 vecSrcType ? VectorType::get(vecSrcType.getShape(), i1Type) : i1Type;
1951 Value zero, one, minusOne, gt, lt;
1952 if constexpr (isFloat) {
1956 gt = LLVM::FCmpOp::create(rewriter, loc, cmpType,
1957 LLVM::FCmpPredicate::ogt, operand, zero);
1958 lt = LLVM::FCmpOp::create(rewriter, loc, cmpType,
1959 LLVM::FCmpPredicate::olt, operand, zero);
1963 rewriter.getIntegerAttr(intElemType, 0));
1965 rewriter.getIntegerAttr(intElemType, 1));
1967 gt = LLVM::ICmpOp::create(rewriter, loc, cmpType,
1968 LLVM::ICmpPredicate::sgt, operand, zero);
1969 lt = LLVM::ICmpOp::create(rewriter, loc, cmpType,
1970 LLVM::ICmpPredicate::slt, operand, zero);
1974 LLVM::SelectOp::create(rewriter, loc, dstType, lt, minusOne, zero);
1975 rewriter.replaceOpWithNewOp<LLVM::SelectOp>(op, dstType, gt, one,
1983 using SPIRVToLLVMConversion<spirv::VariableOp>::SPIRVToLLVMConversion;
1986 matchAndRewrite(spirv::VariableOp varOp, OpAdaptor adaptor,
1987 ConversionPatternRewriter &rewriter)
const override {
1988 auto srcType = varOp.getType();
1990 auto pointerTo = cast<spirv::PointerType>(srcType).getPointeeType();
1991 auto init = varOp.getInitializer();
1992 if (init && !pointerTo.isIntOrFloat() && !isa<VectorType>(pointerTo))
1995 auto dstType = getTypeConverter()->convertType(srcType);
1997 return rewriter.notifyMatchFailure(varOp,
"type conversion failed");
1999 Location loc = varOp.getLoc();
2002 auto elementType = getTypeConverter()->convertType(pointerTo);
2004 return rewriter.notifyMatchFailure(varOp,
"type conversion failed");
2005 rewriter.replaceOpWithNewOp<LLVM::AllocaOp>(varOp, dstType, elementType,
2009 auto elementType = getTypeConverter()->convertType(pointerTo);
2011 return rewriter.notifyMatchFailure(varOp,
"type conversion failed");
2013 LLVM::AllocaOp::create(rewriter, loc, dstType, elementType, size);
2014 LLVM::StoreOp::create(rewriter, loc, adaptor.getInitializer(), allocated);
2015 rewriter.replaceOp(varOp, allocated);
2024class BitcastConversionPattern
2027 using SPIRVToLLVMConversion<spirv::BitcastOp>::SPIRVToLLVMConversion;
2030 matchAndRewrite(spirv::BitcastOp bitcastOp, OpAdaptor adaptor,
2031 ConversionPatternRewriter &rewriter)
const override {
2032 auto dstType = getTypeConverter()->convertType(bitcastOp.getType());
2034 return rewriter.notifyMatchFailure(bitcastOp,
"type conversion failed");
2037 if (isa<LLVM::LLVMPointerType>(dstType)) {
2038 rewriter.replaceOp(bitcastOp, adaptor.getOperand());
2042 LLVM::BitcastOp::Properties properties{};
2043 SmallVector<NamedAttribute> discardableAttrs;
2044 if (
failed(collectAttrsForConversion<LLVM::BitcastOp>(bitcastOp, properties,
2047 rewriter.replaceOpWithNewOp<LLVM::BitcastOp>(bitcastOp, dstType,
2048 adaptor.getOperands(),
2049 properties, discardableAttrs);
2060 using SPIRVToLLVMConversion<spirv::FuncOp>::SPIRVToLLVMConversion;
2063 matchAndRewrite(spirv::FuncOp funcOp, OpAdaptor adaptor,
2064 ConversionPatternRewriter &rewriter)
const override {
2068 auto funcType = funcOp.getFunctionType();
2069 TypeConverter::SignatureConversion signatureConverter(
2070 funcType.getNumInputs());
2071 auto llvmType =
static_cast<const LLVMTypeConverter *
>(getTypeConverter())
2072 ->convertFunctionSignature(
2074 false, signatureConverter);
2079 Location loc = funcOp.getLoc();
2080 StringRef name = funcOp.getName();
2081 auto newFuncOp = LLVM::LLVMFuncOp::create(rewriter, loc, name, llvmType);
2084 MLIRContext *context = funcOp.getContext();
2085 switch (funcOp.getFunctionControl()) {
2086 case spirv::FunctionControl::Inline:
2087 newFuncOp.setAlwaysInline(
true);
2089 case spirv::FunctionControl::DontInline:
2090 newFuncOp.setNoInline(
true);
2093#define DISPATCH(functionControl, llvmAttr) \
2094 case functionControl: \
2095 newFuncOp->setDiscardableAttr("passthrough", \
2096 ArrayAttr::get(context, {llvmAttr})); \
2099 DISPATCH(spirv::FunctionControl::Pure,
2100 StringAttr::get(context,
"readonly"));
2101 DISPATCH(spirv::FunctionControl::Const,
2102 StringAttr::get(context,
"readnone"));
2112 rewriter.inlineRegionBefore(funcOp.getBody(), newFuncOp.getBody(),
2114 if (
failed(rewriter.convertRegionTypes(
2115 &newFuncOp.getBody(), *getTypeConverter(), &signatureConverter))) {
2118 rewriter.eraseOp(funcOp);
2129 using SPIRVToLLVMConversion<spirv::ModuleOp>::SPIRVToLLVMConversion;
2132 matchAndRewrite(spirv::ModuleOp spvModuleOp, OpAdaptor adaptor,
2133 ConversionPatternRewriter &rewriter)
const override {
2136 ModuleOp::create(rewriter, spvModuleOp.getLoc(), spvModuleOp.getName());
2137 rewriter.inlineRegionBefore(spvModuleOp.getRegion(), newModuleOp.getBody());
2140 rewriter.eraseBlock(&newModuleOp.getBodyRegion().back());
2141 rewriter.eraseOp(spvModuleOp);
2150class VectorShufflePattern
2153 using SPIRVToLLVMConversion<spirv::VectorShuffleOp>::SPIRVToLLVMConversion;
2155 matchAndRewrite(spirv::VectorShuffleOp op, OpAdaptor adaptor,
2156 ConversionPatternRewriter &rewriter)
const override {
2157 Location loc = op.getLoc();
2158 auto components = adaptor.getComponents();
2159 auto vector1 = adaptor.getVector1();
2160 auto vector2 = adaptor.getVector2();
2161 int vector1Size = cast<VectorType>(vector1.getType()).getNumElements();
2162 int vector2Size = cast<VectorType>(vector2.getType()).getNumElements();
2163 if (vector1Size == vector2Size) {
2164 rewriter.replaceOpWithNewOp<LLVM::ShuffleVectorOp>(
2165 op, vector1, vector2,
2170 auto dstType = getTypeConverter()->convertType(op.getType());
2172 return rewriter.notifyMatchFailure(op,
"type conversion failed");
2173 auto scalarType = cast<VectorType>(dstType).getElementType();
2174 auto componentsArray = components.getValue();
2175 auto *context = rewriter.getContext();
2176 auto llvmI32Type = IntegerType::get(context, 32);
2177 Value targetOp = LLVM::PoisonOp::create(rewriter, loc, dstType);
2178 for (
unsigned i = 0; i < componentsArray.size(); i++) {
2179 if (!isa<IntegerAttr>(componentsArray[i]))
2180 return op.emitError(
"unable to support non-constant component");
2182 int indexVal = cast<IntegerAttr>(componentsArray[i]).getInt();
2187 Value baseVector = vector1;
2188 if (indexVal >= vector1Size) {
2189 offsetVal = vector1Size;
2190 baseVector = vector2;
2193 Value dstIndex = LLVM::ConstantOp::create(
2194 rewriter, loc, llvmI32Type,
2195 rewriter.getIntegerAttr(rewriter.getI32Type(), i));
2196 Value index = LLVM::ConstantOp::create(
2197 rewriter, loc, llvmI32Type,
2198 rewriter.getIntegerAttr(rewriter.getI32Type(), indexVal - offsetVal));
2200 auto extractOp = LLVM::ExtractElementOp::create(rewriter, loc, scalarType,
2202 targetOp = LLVM::InsertElementOp::create(rewriter, loc, dstType, targetOp,
2203 extractOp, dstIndex);
2205 rewriter.replaceOp(op, targetOp);
2216 spirv::ClientAPI clientAPI) {
2233 spirv::ClientAPI clientAPI) {
2236 DirectConversionPattern<spirv::IAddOp, LLVM::AddOp>,
2237 DirectConversionPattern<spirv::IMulOp, LLVM::MulOp>,
2238 DirectConversionPattern<spirv::ISubOp, LLVM::SubOp>,
2239 DirectConversionPattern<spirv::FAddOp, LLVM::FAddOp>,
2240 DirectConversionPattern<spirv::FDivOp, LLVM::FDivOp>,
2241 DirectConversionPattern<spirv::FMulOp, LLVM::FMulOp>,
2242 DirectConversionPattern<spirv::FNegateOp, LLVM::FNegOp>,
2243 DirectConversionPattern<spirv::FRemOp, LLVM::FRemOp>,
2244 DirectConversionPattern<spirv::FSubOp, LLVM::FSubOp>,
2245 DirectConversionPattern<spirv::SDivOp, LLVM::SDivOp>,
2246 DirectConversionPattern<spirv::SRemOp, LLVM::SRemOp>,
2247 DirectConversionPattern<spirv::UDivOp, LLVM::UDivOp>,
2248 DirectConversionPattern<spirv::UModOp, LLVM::URemOp>, FModPattern,
2249 SModPattern, VectorTimesScalarPattern, SNegatePattern,
2250 ArithmeticWithOverflowPattern<spirv::IAddCarryOp,
2251 LLVM::UAddWithOverflowOp>,
2252 ArithmeticWithOverflowPattern<spirv::ISubBorrowOp,
2253 LLVM::USubWithOverflowOp>,
2254 MulExtendedPattern<spirv::SMulExtendedOp, LLVM::SExtOp>,
2255 MulExtendedPattern<spirv::UMulExtendedOp, LLVM::ZExtOp>,
2258 BitFieldInsertPattern, BitFieldUExtractPattern, BitFieldSExtractPattern,
2259 DirectConversionPattern<spirv::BitCountOp, LLVM::CtPopOp>,
2260 DirectConversionPattern<spirv::BitReverseOp, LLVM::BitReverseOp>,
2261 DirectConversionPattern<spirv::BitwiseAndOp, LLVM::AndOp>,
2262 DirectConversionPattern<spirv::BitwiseOrOp, LLVM::OrOp>,
2263 DirectConversionPattern<spirv::BitwiseXorOp, LLVM::XOrOp>,
2264 NotPattern<spirv::NotOp>,
2267 BitcastConversionPattern,
2268 DirectConversionPattern<spirv::ConvertFToSOp, LLVM::FPToSIOp>,
2269 DirectConversionPattern<spirv::ConvertFToUOp, LLVM::FPToUIOp>,
2270 DirectConversionPattern<spirv::ConvertSToFOp, LLVM::SIToFPOp>,
2271 DirectConversionPattern<spirv::ConvertUToFOp, LLVM::UIToFPOp>,
2272 IndirectCastPattern<spirv::FConvertOp, LLVM::FPExtOp, LLVM::FPTruncOp>,
2273 IndirectCastPattern<spirv::SConvertOp, LLVM::SExtOp, LLVM::TruncOp>,
2274 IndirectCastPattern<spirv::UConvertOp, LLVM::ZExtOp, LLVM::TruncOp>,
2275 DirectConversionPattern<spirv::ConvertPtrToUOp, LLVM::PtrToIntOp>,
2276 DirectConversionPattern<spirv::ConvertUToPtrOp, LLVM::IntToPtrOp>,
2277 DirectConversionPattern<spirv::PtrCastToGenericOp, LLVM::AddrSpaceCastOp>,
2278 DirectConversionPattern<spirv::GenericCastToPtrOp, LLVM::AddrSpaceCastOp>,
2279 DirectConversionPattern<spirv::GenericCastToPtrExplicitOp,
2280 LLVM::AddrSpaceCastOp>,
2283 IComparePattern<spirv::IEqualOp, LLVM::ICmpPredicate::eq>,
2284 IComparePattern<spirv::INotEqualOp, LLVM::ICmpPredicate::ne>,
2285 FComparePattern<spirv::FOrdEqualOp, LLVM::FCmpPredicate::oeq>,
2286 FComparePattern<spirv::FOrdGreaterThanOp, LLVM::FCmpPredicate::ogt>,
2287 FComparePattern<spirv::FOrdGreaterThanEqualOp, LLVM::FCmpPredicate::oge>,
2288 FComparePattern<spirv::FOrdLessThanEqualOp, LLVM::FCmpPredicate::ole>,
2289 FComparePattern<spirv::FOrdLessThanOp, LLVM::FCmpPredicate::olt>,
2290 FComparePattern<spirv::FOrdNotEqualOp, LLVM::FCmpPredicate::one>,
2291 FComparePattern<spirv::FUnordEqualOp, LLVM::FCmpPredicate::ueq>,
2292 FComparePattern<spirv::FUnordGreaterThanOp, LLVM::FCmpPredicate::ugt>,
2293 FComparePattern<spirv::FUnordGreaterThanEqualOp,
2294 LLVM::FCmpPredicate::uge>,
2295 FComparePattern<spirv::FUnordLessThanEqualOp, LLVM::FCmpPredicate::ule>,
2296 FComparePattern<spirv::FUnordLessThanOp, LLVM::FCmpPredicate::ult>,
2297 FComparePattern<spirv::FUnordNotEqualOp, LLVM::FCmpPredicate::une>,
2298 FComparePattern<spirv::OrderedOp, LLVM::FCmpPredicate::ord>,
2299 FComparePattern<spirv::UnorderedOp, LLVM::FCmpPredicate::uno>,
2300 IComparePattern<spirv::SGreaterThanOp, LLVM::ICmpPredicate::sgt>,
2301 IComparePattern<spirv::SGreaterThanEqualOp, LLVM::ICmpPredicate::sge>,
2302 IComparePattern<spirv::SLessThanEqualOp, LLVM::ICmpPredicate::sle>,
2303 IComparePattern<spirv::SLessThanOp, LLVM::ICmpPredicate::slt>,
2304 IComparePattern<spirv::UGreaterThanOp, LLVM::ICmpPredicate::ugt>,
2305 IComparePattern<spirv::UGreaterThanEqualOp, LLVM::ICmpPredicate::uge>,
2306 IComparePattern<spirv::ULessThanEqualOp, LLVM::ICmpPredicate::ule>,
2307 IComparePattern<spirv::ULessThanOp, LLVM::ICmpPredicate::ult>,
2310 ConstantScalarAndVectorPattern,
2313 BranchConversionPattern, BranchConditionalConversionPattern,
2314 FunctionCallPattern, LoopPattern, SelectionPattern,
2315 ErasePattern<spirv::MergeOp>,
2318 ErasePattern<spirv::EntryPointOp>, ExecutionModePattern,
2321 DirectConversionPattern<spirv::GLCeilOp, LLVM::FCeilOp>,
2322 DirectConversionPattern<spirv::GLCosOp, LLVM::CosOp>,
2323 DirectConversionPattern<spirv::GLExpOp, LLVM::ExpOp>,
2324 DirectConversionPattern<spirv::GLExp2Op, LLVM::Exp2Op>,
2325 DirectConversionPattern<spirv::GLFAbsOp, LLVM::FAbsOp>,
2326 DirectConversionPattern<spirv::GLFloorOp, LLVM::FFloorOp>,
2327 DirectConversionPattern<spirv::GLFmaOp, LLVM::FMAOp>,
2328 ClampPattern<spirv::GLFClampOp, LLVM::MinNumOp, LLVM::MaxNumOp>,
2329 ClampPattern<spirv::GLSClampOp, LLVM::SMinOp, LLVM::SMaxOp>,
2330 ClampPattern<spirv::GLUClampOp, LLVM::UMinOp, LLVM::UMaxOp>,
2331 DirectConversionPattern<spirv::GLFMaxOp, LLVM::MaxNumOp>,
2332 DirectConversionPattern<spirv::GLFMinOp, LLVM::MinNumOp>,
2333 DirectConversionPattern<spirv::GLNMaxOp, LLVM::MaxNumOp>,
2334 DirectConversionPattern<spirv::GLNMinOp, LLVM::MinNumOp>,
2335 DirectConversionPattern<spirv::GLLogOp, LLVM::LogOp>,
2336 DirectConversionPattern<spirv::GLLog2Op, LLVM::Log2Op>,
2337 DirectConversionPattern<spirv::GLPowOp, LLVM::PowOp>,
2338 DirectConversionPattern<spirv::GLRoundOp, LLVM::RoundOp>,
2339 DirectConversionPattern<spirv::GLRoundEvenOp, LLVM::RoundEvenOp>,
2340 DirectConversionPattern<spirv::GLSinOp, LLVM::SinOp>,
2341 DirectConversionPattern<spirv::GLSinhOp, LLVM::SinhOp>,
2342 DirectConversionPattern<spirv::GLCoshOp, LLVM::CoshOp>,
2343 DirectConversionPattern<spirv::GLSMaxOp, LLVM::SMaxOp>,
2344 DirectConversionPattern<spirv::GLSMinOp, LLVM::SMinOp>,
2345 DirectConversionPattern<spirv::GLSqrtOp, LLVM::SqrtOp>,
2346 DirectConversionPattern<spirv::GLUMaxOp, LLVM::UMaxOp>,
2347 DirectConversionPattern<spirv::GLUMinOp, LLVM::UMinOp>,
2348 DirectConversionPattern<spirv::GLTruncOp, LLVM::FTruncOp>,
2349 DirectConversionPattern<spirv::GLAsinOp, LLVM::ASinOp>,
2350 DirectConversionPattern<spirv::GLAcosOp, LLVM::ACosOp>,
2351 DirectConversionPattern<spirv::GLAtanOp, LLVM::ATanOp>,
2352 DirectConversionPattern<spirv::GLTanOp, LLVM::TanOp>,
2353 DirectConversionPattern<spirv::GLTanhOp, LLVM::TanhOp>,
2354 InverseSqrtPattern, SAbsPattern, FractPattern,
2355 SignPattern<spirv::GLFSignOp,
true>,
2356 SignPattern<spirv::GLSSignOp,
false>, GLFMixPattern,
2359 DirectConversionPattern<spirv::CLCeilOp, LLVM::FCeilOp>,
2360 DirectConversionPattern<spirv::CLCosOp, LLVM::CosOp>,
2361 DirectConversionPattern<spirv::CLExpOp, LLVM::ExpOp>,
2362 DirectConversionPattern<spirv::CLExp2Op, LLVM::Exp2Op>,
2363 DirectConversionPattern<spirv::CLExp10Op, LLVM::Exp10Op>,
2364 DirectConversionPattern<spirv::CLFAbsOp, LLVM::FAbsOp>,
2365 DirectConversionPattern<spirv::CLFloorOp, LLVM::FFloorOp>,
2366 DirectConversionPattern<spirv::CLFmaOp, LLVM::FMAOp>,
2367 DirectConversionPattern<spirv::CLFMaxOp, LLVM::MaxNumOp>,
2368 DirectConversionPattern<spirv::CLFMinOp, LLVM::MinNumOp>,
2369 DirectConversionPattern<spirv::CLLogOp, LLVM::LogOp>,
2370 DirectConversionPattern<spirv::CLLog2Op, LLVM::Log2Op>,
2371 DirectConversionPattern<spirv::CLLog10Op, LLVM::Log10Op>,
2372 DirectConversionPattern<spirv::CLPowOp, LLVM::PowOp>,
2373 DirectConversionPattern<spirv::CLRintOp, LLVM::RintOp>,
2374 DirectConversionPattern<spirv::CLRoundOp, LLVM::RoundOp>,
2375 DirectConversionPattern<spirv::CLSinOp, LLVM::SinOp>,
2376 DirectConversionPattern<spirv::CLSinhOp, LLVM::SinhOp>,
2377 DirectConversionPattern<spirv::CLCoshOp, LLVM::CoshOp>,
2378 DirectConversionPattern<spirv::CLTanOp, LLVM::TanOp>,
2379 DirectConversionPattern<spirv::CLTanhOp, LLVM::TanhOp>,
2380 DirectConversionPattern<spirv::CLAsinOp, LLVM::ASinOp>,
2381 DirectConversionPattern<spirv::CLAcosOp, LLVM::ACosOp>,
2382 DirectConversionPattern<spirv::CLAtanOp, LLVM::ATanOp>,
2383 DirectConversionPattern<spirv::CLAtan2Op, LLVM::ATan2Op>,
2384 DirectConversionPattern<spirv::CLSqrtOp, LLVM::SqrtOp>,
2385 DirectConversionPattern<spirv::CLTruncOp, LLVM::FTruncOp>,
2386 DirectConversionPattern<spirv::CLCopysignOp, LLVM::CopySignOp>,
2387 DirectConversionPattern<spirv::CLFmodOp, LLVM::FRemOp>,
2388 DirectConversionPattern<spirv::CLSMaxOp, LLVM::SMaxOp>,
2389 DirectConversionPattern<spirv::CLSMinOp, LLVM::SMinOp>,
2390 DirectConversionPattern<spirv::CLUMaxOp, LLVM::UMaxOp>,
2391 DirectConversionPattern<spirv::CLUMinOp, LLVM::UMinOp>, CLMixPattern,
2394 DirectConversionPattern<spirv::LogicalAndOp, LLVM::AndOp>,
2395 DirectConversionPattern<spirv::LogicalOrOp, LLVM::OrOp>,
2396 IComparePattern<spirv::LogicalEqualOp, LLVM::ICmpPredicate::eq>,
2397 IComparePattern<spirv::LogicalNotEqualOp, LLVM::ICmpPredicate::ne>,
2398 NotPattern<spirv::LogicalNotOp>,
2401 AccessChainPattern, AddressOfPattern, LoadStorePattern<spirv::LoadOp>,
2402 LoadStorePattern<spirv::StoreOp>, VariablePattern,
2405 CompositeExtractPattern, CompositeInsertPattern,
2406 DirectConversionPattern<spirv::SelectOp, LLVM::SelectOp>,
2407 DirectConversionPattern<spirv::UndefOp, LLVM::UndefOp>,
2408 VectorShufflePattern,
2411 ShiftPattern<spirv::ShiftRightArithmeticOp, LLVM::AShrOp>,
2412 ShiftPattern<spirv::ShiftRightLogicalOp, LLVM::LShrOp>,
2413 ShiftPattern<spirv::ShiftLeftLogicalOp, LLVM::ShlOp>,
2416 ReturnPattern, ReturnValuePattern,
2422 ControlBarrierPattern<spirv::ControlBarrierOp>,
2423 ControlBarrierPattern<spirv::INTELControlBarrierArriveOp>,
2424 ControlBarrierPattern<spirv::INTELControlBarrierWaitOp>,
2427 GroupReducePattern<spirv::GroupIAddOp>,
2428 GroupReducePattern<spirv::GroupFAddOp>,
2429 GroupReducePattern<spirv::GroupFMinOp>,
2430 GroupReducePattern<spirv::GroupUMinOp>,
2431 GroupReducePattern<spirv::GroupSMinOp,
true>,
2432 GroupReducePattern<spirv::GroupFMaxOp>,
2433 GroupReducePattern<spirv::GroupUMaxOp>,
2434 GroupReducePattern<spirv::GroupSMaxOp,
true>,
2435 GroupReducePattern<spirv::GroupNonUniformIAddOp,
false,
2437 GroupReducePattern<spirv::GroupNonUniformFAddOp,
false,
2439 GroupReducePattern<spirv::GroupNonUniformIMulOp,
false,
2441 GroupReducePattern<spirv::GroupNonUniformFMulOp,
false,
2443 GroupReducePattern<spirv::GroupNonUniformSMinOp,
true,
2445 GroupReducePattern<spirv::GroupNonUniformUMinOp,
false,
2447 GroupReducePattern<spirv::GroupNonUniformFMinOp,
false,
2449 GroupReducePattern<spirv::GroupNonUniformSMaxOp,
true,
2451 GroupReducePattern<spirv::GroupNonUniformUMaxOp,
false,
2453 GroupReducePattern<spirv::GroupNonUniformFMaxOp,
false,
2455 GroupReducePattern<spirv::GroupNonUniformBitwiseAndOp,
false,
2457 GroupReducePattern<spirv::GroupNonUniformBitwiseOrOp,
false,
2459 GroupReducePattern<spirv::GroupNonUniformBitwiseXorOp,
false,
2461 GroupReducePattern<spirv::GroupNonUniformLogicalAndOp,
false,
2463 GroupReducePattern<spirv::GroupNonUniformLogicalOrOp,
false,
2465 GroupReducePattern<spirv::GroupNonUniformLogicalXorOp,
false,
2469 patterns.
add<GlobalVariablePattern>(clientAPI, patterns.
getContext(),
2472 patterns.
add<ScalePattern<spirv::GLRadiansOp>>(
2473 0.017453292519943295, patterns.
getContext(), typeConverter);
2475 patterns.
add<ScalePattern<spirv::GLDegreesOp>>(
2476 57.29577951308232, patterns.
getContext(), typeConverter);
2481 patterns.
add<FuncConversionPattern>(patterns.
getContext(), typeConverter);
2486 patterns.
add<ModuleConversionPattern>(patterns.
getContext(), typeConverter);
2495 auto spvModules =
module.getOps<spirv::ModuleOp>();
2496 for (
auto spvModule : spvModules) {
2497 spvModule.walk([&](spirv::GlobalVariableOp op) {
2498 IntegerAttr descriptorSet = op.getDescriptorSetAttr();
2499 IntegerAttr binding = op.getBindingAttr();
2502 if (descriptorSet && binding) {
2505 auto moduleAndName =
2506 spvModule.getName().has_value()
2507 ? spvModule.getName()->str() +
"_" + op.getSymName().str()
2508 : op.getSymName().str();
2510 llvm::formatv(
"{0}_descriptor_set{1}_binding{2}", moduleAndName,
2511 std::to_string(descriptorSet.getInt()),
2512 std::to_string(binding.getInt()));
2513 auto nameAttr = StringAttr::get(op->getContext(), name);
2518 op.emitError(
"unable to replace all symbol uses for ") << name;
2520 op.removeDescriptorSetAttr();
2521 op.removeBindingAttr();
static LLVM::CallOp createSPIRVBuiltinCall(Location loc, ConversionPatternRewriter &rewriter, LLVM::LLVMFuncOp func, ValueRange args)
static LLVM::LLVMFuncOp lookupOrCreateSPIRVFn(Operation *symbolTable, StringRef name, ArrayRef< Type > paramTypes, Type resultType, bool isMemNone, bool isConvergent)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
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 Value optionallyTruncateOrExtend(Location loc, Value value, Type llvmType, PatternRewriter &rewriter)
Utility function for bitfield ops:
static Value createFPConstant(Location loc, Type srcType, Type dstType, PatternRewriter &rewriter, double value)
Creates llvm.mlir.constant with a floating-point scalar or vector value.
static Value createI32ConstantOf(Location loc, PatternRewriter &rewriter, unsigned value)
Creates LLVM dialect constant with the given value.
static Type convertPointerType(spirv::PointerType type, const TypeConverter &converter, spirv::ClientAPI clientAPI)
Converts SPIR-V pointer type to LLVM pointer.
static Value processCountOrOffset(Location loc, Value value, Type srcType, Type dstType, const TypeConverter &converter, ConversionPatternRewriter &rewriter)
Utility function for bitfield ops: BitFieldInsert, BitFieldSExtract and BitFieldUExtract.
static unsigned getBitWidth(Type type)
Returns the bit width of integer, float or vector of float or integer values.
static LogicalResult replaceWithLoadOrStore(Operation *op, ValueRange operands, ConversionPatternRewriter &rewriter, const TypeConverter &typeConverter, unsigned alignment, bool isVolatile, bool isNonTemporal)
Utility for spirv.Load and spirv.Store conversion.
static Type convertStructTypePacked(spirv::StructType type, const TypeConverter &converter)
Converts SPIR-V struct with no offset to packed LLVM struct.
static bool isSignedIntegerOrVector(Type type)
Returns true if the given type is a signed integer or vector type.
static bool isUnsignedIntegerOrVector(Type type)
Returns true if the given type is an unsigned integer or vector type.
static std::optional< Type > convertRuntimeArrayType(spirv::RuntimeArrayType type, TypeConverter &converter)
Converts SPIR-V runtime array to LLVM array.
static Value optionallyBroadcast(Location loc, Value value, Type srcType, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Broadcasts the value. If srcType is a scalar, the value remains unchanged.
static Value createConstantAllBitsSet(Location loc, Type srcType, Type dstType, PatternRewriter &rewriter)
Creates llvm.mlir.constant with all bits set for the given type.
static unsigned getLLVMTypeBitWidth(Type type)
Returns the bit width of LLVMType integer or vector.
static std::optional< uint64_t > getIntegerOrVectorElementWidth(Type type)
Returns the width of an integer or of the element type of an integer vector, if applicable.
#define DISPATCH(functionControl, llvmAttr)
static Type convertStructTypeWithOffset(spirv::StructType type, const TypeConverter &converter)
Converts SPIR-V struct with a regular (according to VulkanLayoutUtils) offset to LLVM struct.
static Type convertStructType(spirv::StructType type, const TypeConverter &converter)
Converts SPIR-V struct to LLVM struct.
static Value broadcast(Location loc, Value toBroadcast, unsigned numElements, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter)
Broadcasts the value to vector with numElements number of elements.
static Value createIntegerConstant(Location loc, Type srcType, Type dstType, PatternRewriter &rewriter, IntegerAttr scalarAttr)
Creates llvm.mlir.constant with a scalar or vector integer value, broadcasting scalarAttr across the ...
static std::optional< Type > convertArrayType(spirv::ArrayType type, TypeConverter &converter)
Converts SPIR-V array type to LLVM array.
OpListType::iterator iterator
OpListType & getOperations()
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgListType getArguments()
IntegerAttr getIntegerAttr(Type type, int64_t value)
FloatAttr getFloatAttr(Type type, double value)
MLIRContext * getContext() const
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
Conversion from types to the LLVM IR dialect.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
NamedAttribute represents a combination of a name and an Attribute value.
This class helps build Operations.
Operation is the basic unit of execution within MLIR.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Location getLoc()
The source location the operation was defined or derived from.
operand_range getOperands()
Returns an iterator on the underlying Value's.
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.
static LogicalResult replaceAllSymbolUses(StringAttr oldSymbol, StringAttr newSymbol, Operation *from)
Attempt to replace all uses of the given symbol 'oldSymbol' with the provided symbol 'newSymbol' that...
static Operation * lookupSymbolIn(Operation *op, StringAttr symbol)
Returns the operation registered with the given symbol name with the regions of 'symbolTableOp'.
static void setSymbolName(Operation *symbol, StringAttr name)
Sets the name of the given symbol operation.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isSignedInteger() const
Return true if this is a signed integer type (with the specified width).
bool isUnsignedInteger() const
Return true if this is an unsigned 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.
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.
static spirv::StructType decorateType(spirv::StructType structType)
Returns a new StructType with layout decoration.
static DenseArrayAttrImpl get(MLIRContext *context, ArrayRef< int32_t > content)
Type getElementType() const
unsigned getArrayStride() const
Returns the array stride in bytes.
unsigned getNumElements() const
StorageClass getStorageClass() const
Type getElementType() const
unsigned getArrayStride() const
Returns the array stride in bytes.
void getMemberDecorations(SmallVectorImpl< StructType::MemberDecorationInfo > &memberDecorations) const
TypeRange getElementTypes() const
SmallVector< IntT > convertArrayToIndices(ArrayRef< Attribute > attrs)
Convert an array of integer attributes to a vector of integers that can be used as indices in LLVM op...
bool isCompatibleType(Type type)
Returns true if the given type is compatible with the LLVM dialect.
Include the generated interface declarations.
unsigned storageClassToAddressSpace(spirv::ClientAPI clientAPI, spirv::StorageClass storageClass)
void populateSPIRVToLLVMTypeConversion(LLVMTypeConverter &typeConverter, spirv::ClientAPI clientAPIForAddressSpaceMapping=spirv::ClientAPI::Unknown)
Populates type conversions with additional SPIR-V types.
void populateSPIRVToLLVMFunctionConversionPatterns(const LLVMTypeConverter &typeConverter, RewritePatternSet &patterns)
Populates the given list with patterns for function conversion from SPIR-V to LLVM.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
void populateSPIRVToLLVMConversionPatterns(const LLVMTypeConverter &typeConverter, RewritePatternSet &patterns, spirv::ClientAPI clientAPIForAddressSpaceMapping=spirv::ClientAPI::Unknown)
Populates the given list with patterns that convert from SPIR-V to LLVM.
void encodeBindAttribute(ModuleOp module)
Encodes global variable's descriptor set and binding into its name if they both exist.
void populateSPIRVToLLVMModuleConversionPatterns(const LLVMTypeConverter &typeConverter, RewritePatternSet &patterns)
Populates the given patterns for module conversion from SPIR-V to LLVM.
Structure used by default as a "marker" when no "Properties" are set on an Operation.