32template <
typename SourceOp, spirv::BuiltIn builtin>
33class LaunchConfigConversion :
public OpConversionPattern<SourceOp> {
35 using OpConversionPattern<SourceOp>::OpConversionPattern;
38 matchAndRewrite(SourceOp op,
typename SourceOp::Adaptor adaptor,
39 ConversionPatternRewriter &rewriter)
const override;
44template <
typename SourceOp, spirv::BuiltIn builtin>
45class SingleDimLaunchConfigConversion :
public OpConversionPattern<SourceOp> {
47 using OpConversionPattern<SourceOp>::OpConversionPattern;
50 matchAndRewrite(SourceOp op,
typename SourceOp::Adaptor adaptor,
51 ConversionPatternRewriter &rewriter)
const override;
58class WorkGroupSizeConversion :
public OpConversionPattern<gpu::BlockDimOp> {
62 : OpConversionPattern(typeConverter, context, 10) {}
65 matchAndRewrite(gpu::BlockDimOp op, OpAdaptor adaptor,
66 ConversionPatternRewriter &rewriter)
const override;
70class GPUFuncOpConversion final :
public OpConversionPattern<gpu::GPUFuncOp> {
75 matchAndRewrite(gpu::GPUFuncOp funcOp, OpAdaptor adaptor,
76 ConversionPatternRewriter &rewriter)
const override;
83class GPUModuleConversion final :
public OpConversionPattern<gpu::GPUModuleOp> {
88 matchAndRewrite(gpu::GPUModuleOp moduleOp, OpAdaptor adaptor,
89 ConversionPatternRewriter &rewriter)
const override;
94class GPUReturnOpConversion final :
public OpConversionPattern<gpu::ReturnOp> {
99 matchAndRewrite(gpu::ReturnOp returnOp, OpAdaptor adaptor,
100 ConversionPatternRewriter &rewriter)
const override;
105class GPUBarrierConversion final :
public OpConversionPattern<gpu::BarrierOp> {
110 matchAndRewrite(gpu::BarrierOp barrierOp, OpAdaptor adaptor,
111 ConversionPatternRewriter &rewriter)
const override;
116class GPUInitializeNamedBarrierConversion final
117 :
public OpConversionPattern<gpu::InitializeNamedBarrierOp> {
122 matchAndRewrite(gpu::InitializeNamedBarrierOp op, OpAdaptor adaptor,
123 ConversionPatternRewriter &rewriter)
const override;
127class GPUShuffleConversion final :
public OpConversionPattern<gpu::ShuffleOp> {
132 matchAndRewrite(gpu::ShuffleOp shuffleOp, OpAdaptor adaptor,
133 ConversionPatternRewriter &rewriter)
const override;
137class GPURotateConversion final :
public OpConversionPattern<gpu::RotateOp> {
142 matchAndRewrite(gpu::RotateOp rotateOp, OpAdaptor adaptor,
143 ConversionPatternRewriter &rewriter)
const override;
148class GPUSubgroupBroadcastConversion final
149 :
public OpConversionPattern<gpu::SubgroupBroadcastOp> {
154 matchAndRewrite(gpu::SubgroupBroadcastOp op, OpAdaptor adaptor,
155 ConversionPatternRewriter &rewriter)
const override;
158class GPUBallotConversion final :
public OpConversionPattern<gpu::BallotOp> {
163 matchAndRewrite(gpu::BallotOp ballotOp, OpAdaptor adaptor,
164 ConversionPatternRewriter &rewriter)
const override;
167class GPUPrintfConversion final :
public OpConversionPattern<gpu::PrintfOp> {
172 matchAndRewrite(gpu::PrintfOp gpuPrintfOp, OpAdaptor adaptor,
173 ConversionPatternRewriter &rewriter)
const override;
182template <
typename SourceOp, spirv::BuiltIn builtin>
183LogicalResult LaunchConfigConversion<SourceOp, builtin>::matchAndRewrite(
184 SourceOp op,
typename SourceOp::Adaptor adaptor,
185 ConversionPatternRewriter &rewriter)
const {
186 auto *typeConverter = this->
template getTypeConverter<SPIRVTypeConverter>();
187 Type indexType = typeConverter->getIndexType();
201 typeConverter->getTargetEnv().allows(spirv::Capability::Shader);
202 Type builtinType = forShader ? rewriter.getIntegerType(32) : indexType;
206 Value dim = spirv::CompositeExtractOp::create(
207 rewriter, op.getLoc(), builtinType,
vector,
208 rewriter.getI32ArrayAttr({static_cast<int32_t>(op.getDimension())}));
209 if (forShader && builtinType != indexType)
210 dim = spirv::UConvertOp::create(rewriter, op.getLoc(), indexType, dim);
211 rewriter.replaceOp(op, dim);
215template <
typename SourceOp, spirv::BuiltIn builtin>
217SingleDimLaunchConfigConversion<SourceOp, builtin>::matchAndRewrite(
218 SourceOp op,
typename SourceOp::Adaptor adaptor,
219 ConversionPatternRewriter &rewriter)
const {
220 auto *typeConverter = this->
template getTypeConverter<SPIRVTypeConverter>();
221 Type indexType = typeConverter->getIndexType();
222 Type i32Type = rewriter.getIntegerType(32);
234 if (i32Type != indexType)
235 builtinValue = spirv::UConvertOp::create(rewriter, op.getLoc(), indexType,
237 rewriter.replaceOp(op, builtinValue);
241LogicalResult WorkGroupSizeConversion::matchAndRewrite(
242 gpu::BlockDimOp op, OpAdaptor adaptor,
243 ConversionPatternRewriter &rewriter)
const {
245 if (!workGroupSizeAttr)
249 workGroupSizeAttr.
asArrayRef()[
static_cast<int32_t
>(op.getDimension())];
251 getTypeConverter()->convertType(op.getResult().getType());
254 rewriter.replaceOpWithNewOp<spirv::ConstantOp>(
255 op, convertedType, IntegerAttr::get(convertedType, val));
266 ConversionPatternRewriter &rewriter,
267 spirv::EntryPointABIAttr entryPointInfo,
269 auto fnType = funcOp.getFunctionType();
270 if (fnType.getNumResults()) {
271 funcOp.emitError(
"SPIR-V lowering only supports entry functions"
272 "with no return values right now");
275 if (!argABIInfo.empty() && fnType.getNumInputs() != argABIInfo.size()) {
277 "lowering as entry functions requires ABI info for all arguments "
284 TypeConverter::SignatureConversion signatureConverter(fnType.getNumInputs());
286 for (
const auto &argType :
287 enumerate(funcOp.getFunctionType().getInputs())) {
288 auto convertedType = typeConverter.convertType(argType.value());
291 signatureConverter.addInputs(argType.index(), convertedType);
294 auto newFuncOp = spirv::FuncOp::create(
295 rewriter, funcOp.getLoc(), funcOp.getName(),
296 rewriter.getFunctionType(signatureConverter.getConvertedTypes(), {}));
297 for (
const auto &namedAttr : funcOp->getAttrs()) {
298 if (namedAttr.getName() == funcOp.getFunctionTypeAttrName() ||
301 newFuncOp->setAttr(namedAttr.getName(), namedAttr.getValue());
304 rewriter.inlineRegionBefore(funcOp.getBody(), newFuncOp.getBody(),
306 if (failed(rewriter.convertRegionTypes(&newFuncOp.getBody(), typeConverter,
307 &signatureConverter)))
309 rewriter.eraseOp(funcOp);
313 for (
auto argIndex : llvm::seq<unsigned>(0, argABIInfo.size())) {
314 newFuncOp.setArgAttr(argIndex, argABIAttrName, argABIInfo[argIndex]);
330 for (
auto argIndex : llvm::seq<unsigned>(0, funcOp.getNumArguments())) {
336 std::optional<spirv::StorageClass> sc;
337 if (funcOp.getArgument(argIndex).getType().isIntOrIndexOrFloat())
338 sc = spirv::StorageClass::StorageBuffer;
345LogicalResult GPUFuncOpConversion::matchAndRewrite(
346 gpu::GPUFuncOp funcOp, OpAdaptor adaptor,
347 ConversionPatternRewriter &rewriter)
const {
348 if (!gpu::GPUDialect::isKernel(funcOp))
351 auto *typeConverter = getTypeConverter<SPIRVTypeConverter>();
352 SmallVector<spirv::InterfaceVarABIAttr, 4> argABI;
356 for (
auto argIndex : llvm::seq<unsigned>(0, funcOp.getNumArguments())) {
358 auto abiAttr = funcOp.getArgAttrOfType<spirv::InterfaceVarABIAttr>(
362 "match failure: missing 'spirv.interface_var_abi' attribute at "
367 argABI.push_back(abiAttr);
372 if (!entryPointAttr) {
374 "match failure: missing 'spirv.entry_point_abi' attribute");
378 funcOp, *getTypeConverter(), rewriter, entryPointAttr, argABI);
381 newFuncOp->removeAttr(
382 rewriter.getStringAttr(gpu::GPUDialect::getKernelFuncAttrName()));
390LogicalResult GPUModuleConversion::matchAndRewrite(
391 gpu::GPUModuleOp moduleOp, OpAdaptor adaptor,
392 ConversionPatternRewriter &rewriter)
const {
393 auto *typeConverter = getTypeConverter<SPIRVTypeConverter>();
394 const spirv::TargetEnv &targetEnv = typeConverter->getTargetEnv();
396 targetEnv, typeConverter->getOptions().use64bitIndex);
399 return moduleOp.emitRemark(
400 "cannot deduce memory model from 'spirv.target_env'");
403 std::string spvModuleName = (
kSPIRVModule + moduleOp.getName()).str();
404 auto spvModule = spirv::ModuleOp::create(
405 rewriter, moduleOp.getLoc(), addressingModel, *memoryModel, std::nullopt,
406 StringRef(spvModuleName));
409 Region &spvModuleRegion = spvModule.getRegion();
410 rewriter.inlineRegionBefore(moduleOp.getBodyRegion(), spvModuleRegion,
411 spvModuleRegion.
begin());
413 rewriter.eraseBlock(&spvModuleRegion.
back());
419 if (
auto attr = moduleOp->getAttrOfType<spirv::TargetEnvAttr>(
422 if (
ArrayAttr targets = moduleOp.getTargetsAttr()) {
423 for (Attribute targetAttr : targets)
424 if (
auto spirvTargetEnvAttr =
425 dyn_cast<spirv::TargetEnvAttr>(targetAttr)) {
431 rewriter.eraseOp(moduleOp);
439LogicalResult GPUReturnOpConversion::matchAndRewrite(
440 gpu::ReturnOp returnOp, OpAdaptor adaptor,
441 ConversionPatternRewriter &rewriter)
const {
442 if (!adaptor.getOperands().empty())
445 rewriter.replaceOpWithNewOp<spirv::ReturnOp>(returnOp);
454static FailureOr<spirv::Scope>
457 case gpu::BarrierScope::Subgroup:
458 return spirv::Scope::Subgroup;
459 case gpu::BarrierScope::Workgroup:
460 return spirv::Scope::Workgroup;
461 case gpu::BarrierScope::Cluster:
467LogicalResult GPUBarrierConversion::matchAndRewrite(
468 gpu::BarrierOp barrierOp, OpAdaptor adaptor,
469 ConversionPatternRewriter &rewriter)
const {
475 return rewriter.notifyMatchFailure(
476 barrierOp,
"cluster scope is not supported in SPIR-V");
478 auto scopeAttr = spirv::ScopeAttr::get(context, *spirvScope);
479 auto memoryScopeAttr =
480 spirv::ScopeAttr::get(context, spirv::Scope::Workgroup);
483 auto memorySemantics = spirv::MemorySemanticsAttr::get(
484 context, spirv::MemorySemantics::WorkgroupMemory |
485 spirv::MemorySemantics::AcquireRelease);
487 if (adaptor.getNamedBarrier()) {
488 spirv::MemoryNamedBarrierOp::create(rewriter, barrierOp.getLoc(),
489 adaptor.getNamedBarrier(),
490 memoryScopeAttr, memorySemantics);
491 rewriter.eraseOp(barrierOp);
493 rewriter.replaceOpWithNewOp<spirv::ControlBarrierOp>(
494 barrierOp, scopeAttr, memoryScopeAttr, memorySemantics);
499LogicalResult GPUInitializeNamedBarrierConversion::matchAndRewrite(
500 gpu::InitializeNamedBarrierOp op, OpAdaptor adaptor,
501 ConversionPatternRewriter &rewriter)
const {
503 rewriter.replaceOpWithNewOp<spirv::NamedBarrierInitializeOp>(
504 op, nbType, adaptor.getMemberCount());
512LogicalResult GPUShuffleConversion::matchAndRewrite(
513 gpu::ShuffleOp shuffleOp, OpAdaptor adaptor,
514 ConversionPatternRewriter &rewriter)
const {
518 auto targetEnv = getTypeConverter<SPIRVTypeConverter>()->getTargetEnv();
519 unsigned subgroupSize =
521 IntegerAttr widthAttr;
523 widthAttr.getValue().getZExtValue() != subgroupSize)
524 return rewriter.notifyMatchFailure(
525 shuffleOp,
"shuffle width and target subgroup size mismatch");
527 assert(!adaptor.getOffset().getType().isSignedInteger() &&
528 "shuffle offset must be a signless/unsigned integer");
530 Location loc = shuffleOp.getLoc();
531 auto scope = rewriter.getAttr<spirv::ScopeAttr>(spirv::Scope::Subgroup);
535 switch (shuffleOp.getMode()) {
536 case gpu::ShuffleMode::XOR: {
537 result = spirv::GroupNonUniformShuffleXorOp::create(
538 rewriter, loc, scope, adaptor.getValue(), adaptor.getOffset());
539 validVal = spirv::ConstantOp::getOne(rewriter.getI1Type(),
540 shuffleOp.getLoc(), rewriter);
543 case gpu::ShuffleMode::IDX: {
544 result = spirv::GroupNonUniformShuffleOp::create(
545 rewriter, loc, scope, adaptor.getValue(), adaptor.getOffset());
546 validVal = spirv::ConstantOp::getOne(rewriter.getI1Type(),
547 shuffleOp.getLoc(), rewriter);
550 case gpu::ShuffleMode::DOWN: {
551 result = spirv::GroupNonUniformShuffleDownOp::create(
552 rewriter, loc, scope, adaptor.getValue(), adaptor.getOffset());
554 Value laneId = gpu::LaneIdOp::create(rewriter, loc, widthAttr);
556 arith::AddIOp::create(rewriter, loc, laneId, adaptor.getOffset());
557 validVal = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::ult,
558 resultLaneId, adaptor.getWidth());
561 case gpu::ShuffleMode::UP: {
562 result = spirv::GroupNonUniformShuffleUpOp::create(
563 rewriter, loc, scope, adaptor.getValue(), adaptor.getOffset());
565 Value laneId = gpu::LaneIdOp::create(rewriter, loc, widthAttr);
567 arith::SubIOp::create(rewriter, loc, laneId, adaptor.getOffset());
568 auto i32Type = rewriter.getIntegerType(32);
569 validVal = arith::CmpIOp::create(
570 rewriter, loc, arith::CmpIPredicate::sge, resultLaneId,
571 arith::ConstantOp::create(rewriter, loc, i32Type,
572 rewriter.getIntegerAttr(i32Type, 0)));
577 rewriter.replaceOp(shuffleOp, {
result, validVal});
585LogicalResult GPURotateConversion::matchAndRewrite(
586 gpu::RotateOp rotateOp, OpAdaptor adaptor,
587 ConversionPatternRewriter &rewriter)
const {
588 const spirv::TargetEnv &targetEnv =
589 getTypeConverter<SPIRVTypeConverter>()->getTargetEnv();
590 unsigned subgroupSize =
592 unsigned width = rotateOp.getWidth();
593 if (width > subgroupSize)
594 return rewriter.notifyMatchFailure(
595 rotateOp,
"rotate width is larger than target subgroup size");
597 Location loc = rotateOp.getLoc();
598 auto scope = rewriter.getAttr<spirv::ScopeAttr>(spirv::Scope::Subgroup);
600 arith::ConstantOp::create(rewriter, loc, adaptor.getOffsetAttr());
602 arith::ConstantOp::create(rewriter, loc, adaptor.getWidthAttr());
603 Value rotateResult = spirv::GroupNonUniformRotateKHROp::create(
604 rewriter, loc, scope, adaptor.getValue(), offsetVal, widthVal);
606 if (width == subgroupSize) {
607 validVal = spirv::ConstantOp::getOne(rewriter.getI1Type(), loc, rewriter);
609 IntegerAttr widthAttr = adaptor.getWidthAttr();
610 Value laneId = gpu::LaneIdOp::create(rewriter, loc, widthAttr);
611 validVal = arith::CmpIOp::create(rewriter, loc, arith::CmpIPredicate::ult,
615 rewriter.replaceOp(rotateOp, {rotateResult, validVal});
623LogicalResult GPUSubgroupBroadcastConversion::matchAndRewrite(
624 gpu::SubgroupBroadcastOp op, OpAdaptor adaptor,
625 ConversionPatternRewriter &rewriter)
const {
626 Location loc = op.getLoc();
627 auto scope = rewriter.getAttr<spirv::ScopeAttr>(spirv::Scope::Subgroup);
630 switch (op.getBroadcastType()) {
631 case gpu::BroadcastType::specific_lane:
632 result = spirv::GroupNonUniformBroadcastOp::create(
633 rewriter, loc, scope, adaptor.getSrc(), adaptor.getLane());
635 case gpu::BroadcastType::first_active_lane:
636 result = spirv::GroupNonUniformBroadcastFirstOp::create(
637 rewriter, loc, scope, adaptor.getSrc());
641 rewriter.replaceOp(op,
result);
645LogicalResult GPUBallotConversion::matchAndRewrite(
646 gpu::BallotOp ballotOp, OpAdaptor adaptor,
647 ConversionPatternRewriter &rewriter)
const {
648 Location loc = ballotOp.getLoc();
649 auto scope = rewriter.getAttr<spirv::ScopeAttr>(spirv::Scope::Subgroup);
650 auto int32Type = rewriter.getI32Type();
651 auto vec4i32Type = VectorType::get({4}, int32Type);
654 Value ballot = spirv::GroupNonUniformBallotOp::create(
655 rewriter, loc, vec4i32Type, scope, adaptor.getPredicate());
657 auto intType = cast<IntegerType>(ballotOp.getType());
658 unsigned width = intType.getWidth();
662 spirv::CompositeExtractOp::create(rewriter, loc, ballot, {0});
663 rewriter.replaceOp(ballotOp,
result);
664 }
else if (width == 64) {
666 Value low = spirv::CompositeExtractOp::create(rewriter, loc, ballot, {0});
667 Value high = spirv::CompositeExtractOp::create(rewriter, loc, ballot, {1});
669 auto int64Type = rewriter.getI64Type();
670 Value lowExt = spirv::UConvertOp::create(rewriter, loc, int64Type, low);
671 Value highExt = spirv::UConvertOp::create(rewriter, loc, int64Type, high);
673 Value shift32 = spirv::ConstantOp::create(
674 rewriter, loc, int64Type, rewriter.getIntegerAttr(int64Type, 32));
676 spirv::ShiftLeftLogicalOp::create(rewriter, loc, highExt, shift32);
679 spirv::BitwiseOrOp::create(rewriter, loc, lowExt, highShifted);
680 rewriter.replaceOp(ballotOp,
result);
682 return rewriter.notifyMatchFailure(
683 ballotOp,
"only i32 and i64 result types are supported for SPIR-V");
693template <
typename UniformOp,
typename NonUniformOp>
695 Value arg,
bool isGroup,
bool isUniform,
696 std::optional<uint32_t> clusterSize) {
698 auto scope = mlir::spirv::ScopeAttr::get(builder.
getContext(),
699 isGroup ? spirv::Scope::Workgroup
700 : spirv::Scope::Subgroup);
701 auto groupOp = spirv::GroupOperationAttr::get(
703 ? spirv::GroupOperation::ClusteredReduce
704 : spirv::GroupOperation::Reduce);
706 return UniformOp::create(builder, loc, type, scope, groupOp, arg)
710 Value clusterSizeValue;
711 if (clusterSize.has_value())
712 clusterSizeValue = spirv::ConstantOp::create(
716 return NonUniformOp::create(builder, loc, type, scope, groupOp, arg,
721static std::optional<Value>
723 gpu::AllReduceOperation opType,
bool isGroup,
724 bool isUniform, std::optional<uint32_t> clusterSize) {
725 enum class ElemType { Float, Boolean, Integer };
727 std::optional<uint32_t>);
729 gpu::AllReduceOperation kind;
735 ElemType elementType;
736 if (isa<FloatType>(type)) {
737 elementType = ElemType::Float;
738 }
else if (
auto intTy = dyn_cast<IntegerType>(type)) {
739 elementType = (intTy.getIntOrFloatBitWidth() == 1) ? ElemType::Boolean
750 using ReduceType = gpu::AllReduceOperation;
751 const OpHandler handlers[] = {
752 {ReduceType::ADD, ElemType::Integer,
754 spirv::GroupNonUniformIAddOp>},
755 {ReduceType::ADD, ElemType::Float,
757 spirv::GroupNonUniformFAddOp>},
758 {ReduceType::MUL, ElemType::Integer,
760 spirv::GroupNonUniformIMulOp>},
761 {ReduceType::MUL, ElemType::Float,
763 spirv::GroupNonUniformFMulOp>},
764 {ReduceType::MINUI, ElemType::Integer,
766 spirv::GroupNonUniformUMinOp>},
767 {ReduceType::MINSI, ElemType::Integer,
769 spirv::GroupNonUniformSMinOp>},
770 {ReduceType::MINNUMF, ElemType::Float,
772 spirv::GroupNonUniformFMinOp>},
773 {ReduceType::MAXUI, ElemType::Integer,
775 spirv::GroupNonUniformUMaxOp>},
776 {ReduceType::MAXSI, ElemType::Integer,
778 spirv::GroupNonUniformSMaxOp>},
779 {ReduceType::MAXNUMF, ElemType::Float,
781 spirv::GroupNonUniformFMaxOp>},
782 {ReduceType::MINIMUMF, ElemType::Float,
784 spirv::GroupNonUniformFMinOp>},
785 {ReduceType::MAXIMUMF, ElemType::Float,
787 spirv::GroupNonUniformFMaxOp>}};
789 for (
const OpHandler &handler : handlers)
790 if (handler.kind == opType && elementType == handler.elemType)
791 return handler.func(builder, loc, arg, isGroup, isUniform, clusterSize);
798 :
public OpConversionPattern<gpu::AllReduceOp> {
804 ConversionPatternRewriter &rewriter)
const override {
805 auto opType = op.getOp();
814 true, op.getUniform(), std::nullopt);
818 rewriter.replaceOp(op, *
result);
825 :
public OpConversionPattern<gpu::SubgroupReduceOp> {
831 ConversionPatternRewriter &rewriter)
const override {
832 if (op.getClusterStride() > 1) {
833 return rewriter.notifyMatchFailure(
834 op,
"lowering for cluster stride > 1 is not implemented");
837 if (!isa<spirv::ScalarType>(adaptor.getValue().getType()))
838 return rewriter.notifyMatchFailure(op,
"reduction type is not a scalar");
841 rewriter, op.getLoc(), adaptor.getValue(), adaptor.getOp(),
842 false, adaptor.getUniform(), op.getClusterSize());
846 rewriter.replaceOp(op, *
result);
855static std::string
makeVarName(spirv::ModuleOp moduleOp, llvm::Twine prefix) {
861 name = (prefix + llvm::Twine(number++)).str();
862 }
while (moduleOp.lookupSymbol(name));
869LogicalResult GPUPrintfConversion::matchAndRewrite(
870 gpu::PrintfOp gpuPrintfOp, OpAdaptor adaptor,
871 ConversionPatternRewriter &rewriter)
const {
873 Location loc = gpuPrintfOp.getLoc();
875 auto moduleOp = gpuPrintfOp->getParentOfType<spirv::ModuleOp>();
882 std::string globalVarName =
makeVarName(moduleOp, llvm::Twine(
"printfMsg"));
883 spirv::GlobalVariableOp globalVar;
885 IntegerType i8Type = rewriter.getI8Type();
886 IntegerType i32Type = rewriter.getI32Type();
893 auto createSpecConstant = [&](
unsigned value) {
894 auto attr = rewriter.getI8IntegerAttr(value);
895 std::string specCstName =
896 makeVarName(moduleOp, llvm::Twine(globalVarName) +
"_sc");
898 return spirv::SpecConstantOp::create(
899 rewriter, loc, rewriter.getStringAttr(specCstName), attr);
905 ConversionPatternRewriter::InsertionGuard guard(rewriter);
908 rewriter.setInsertionPointToStart(
915 llvm::SmallString<20> formatString(adaptor.getFormat());
916 formatString.push_back(
'\0');
917 SmallVector<Attribute, 4> constituents;
918 for (
char c : formatString) {
919 spirv::SpecConstantOp cSpecConstantOp = createSpecConstant(c);
920 constituents.push_back(SymbolRefAttr::get(cSpecConstantOp));
924 size_t contentSize = constituents.size();
926 spirv::SpecConstantCompositeOp specCstComposite;
929 std::string specCstCompositeName =
930 (llvm::Twine(globalVarName) +
"_scc").str();
932 specCstComposite = spirv::SpecConstantCompositeOp::create(
933 rewriter, loc, TypeAttr::get(globalType),
934 rewriter.getStringAttr(specCstCompositeName),
935 rewriter.getArrayAttr(constituents));
938 globalType, spirv::StorageClass::UniformConstant);
943 globalVar = spirv::GlobalVariableOp::create(
944 rewriter, loc, ptrType, globalVarName,
947 globalVar->setAttr(
"Constant", rewriter.getUnitAttr());
951 Value globalPtr = spirv::AddressOfOp::create(rewriter, loc, globalVar);
952 Value fmtStr = spirv::BitcastOp::create(
958 auto printfArgs = llvm::to_vector_of<Value, 4>(adaptor.getArgs());
960 spirv::CLPrintfOp::create(rewriter, loc, i32Type, fmtStr, printfArgs);
965 rewriter.eraseOp(gpuPrintfOp);
977 GPUBarrierConversion, GPUInitializeNamedBarrierConversion,
978 GPUBallotConversion, GPUFuncOpConversion, GPUModuleConversion,
979 GPUReturnOpConversion, GPUShuffleConversion, GPURotateConversion,
980 GPUSubgroupBroadcastConversion,
981 LaunchConfigConversion<gpu::BlockIdOp, spirv::BuiltIn::WorkgroupId>,
982 LaunchConfigConversion<gpu::GridDimOp, spirv::BuiltIn::NumWorkgroups>,
983 LaunchConfigConversion<gpu::BlockDimOp, spirv::BuiltIn::WorkgroupSize>,
984 LaunchConfigConversion<gpu::ThreadIdOp,
985 spirv::BuiltIn::LocalInvocationId>,
986 LaunchConfigConversion<gpu::GlobalIdOp,
987 spirv::BuiltIn::GlobalInvocationId>,
988 SingleDimLaunchConfigConversion<gpu::SubgroupIdOp,
989 spirv::BuiltIn::SubgroupId>,
990 SingleDimLaunchConfigConversion<gpu::NumSubgroupsOp,
991 spirv::BuiltIn::NumSubgroups>,
992 SingleDimLaunchConfigConversion<gpu::SubgroupSizeOp,
993 spirv::BuiltIn::SubgroupSize>,
994 SingleDimLaunchConfigConversion<
995 gpu::LaneIdOp, spirv::BuiltIn::SubgroupLocalInvocationId>,
static std::optional< Value > createGroupReduceOp(OpBuilder &builder, Location loc, Value arg, gpu::AllReduceOperation opType, bool isGroup, bool isUniform, std::optional< uint32_t > clusterSize)
static FailureOr< spirv::Scope > mapGPUBarrierScopeToSPIRV(gpu::BarrierScope gpuScope)
Map gpu::BarrierScope to spirv::Scope.
static LogicalResult getDefaultABIAttrs(const spirv::TargetEnv &targetEnv, gpu::GPUFuncOp funcOp, SmallVectorImpl< spirv::InterfaceVarABIAttr > &argABI)
Populates argABI with spirv.interface_var_abi attributes for lowering gpu.func to spirv....
static constexpr const char kSPIRVModule[]
static Value createGroupReduceOpImpl(OpBuilder &builder, Location loc, Value arg, bool isGroup, bool isUniform, std::optional< uint32_t > clusterSize)
static spirv::FuncOp lowerAsEntryFunction(gpu::GPUFuncOp funcOp, const TypeConverter &typeConverter, ConversionPatternRewriter &rewriter, spirv::EntryPointABIAttr entryPointInfo, ArrayRef< spirv::InterfaceVarABIAttr > argABIInfo)
static std::string makeVarName(spirv::ModuleOp moduleOp, llvm::Twine prefix)
Pattern to convert a gpu.all_reduce op into a SPIR-V group op.
LogicalResult matchAndRewrite(gpu::AllReduceOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
Pattern to convert a gpu.subgroup_reduce op into a SPIR-V group op.
LogicalResult matchAndRewrite(gpu::SubgroupReduceOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
IntegerAttr getIntegerAttr(Type type, int64_t value)
MLIRContext * getContext() const
static FlatSymbolRefAttr get(StringAttr value)
Construct a symbol reference for the given value name.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
This class helps build Operations.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
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.
Type conversion from builtin types to SPIR-V types for shader interface.
static StringRef getSymbolAttrName()
Return the name of the attribute used for symbol names.
static Operation * getNearestSymbolTable(Operation *from)
Returns the nearest symbol table from a given operation from.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
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.
ArrayRef< T > asArrayRef() const
static ArrayType get(Type elementType, unsigned elementCount)
An attribute that specifies the information regarding the interface variable: descriptor set,...
static NamedBarrierType get(MLIRContext *context)
static PointerType get(Type pointeeType, StorageClass storageClass)
ResourceLimitsAttr getResourceLimits() const
Returns the target resource limits.
A wrapper class around a spirv::TargetEnvAttr to provide query methods for allowed version/capabiliti...
TargetEnvAttr getAttr() const
StringRef getInterfaceVarABIAttrName()
Returns the attribute name for specifying argument ABI information.
bool needsInterfaceVarABIAttrs(TargetEnvAttr targetAttr)
Returns whether the given SPIR-V target (described by TargetEnvAttr) needs ABI attributes for interfa...
InterfaceVarABIAttr getInterfaceVarABIAttr(unsigned descriptorSet, unsigned binding, std::optional< StorageClass > storageClass, MLIRContext *context)
Gets the InterfaceVarABIAttr given its fields.
Value getBuiltinVariableValue(Operation *op, BuiltIn builtin, Type integerType, OpBuilder &builder, StringRef prefix="__builtin__", StringRef suffix="__")
Returns the value for the given builtin variable.
EntryPointABIAttr lookupEntryPointABI(Operation *op)
Queries the entry point ABI on the nearest function-like op containing the given op.
StringRef getTargetEnvAttrName()
Returns the attribute name for specifying SPIR-V target environment.
DenseI32ArrayAttr lookupLocalWorkGroupSize(Operation *op)
Queries the local workgroup size from entry point ABI on the nearest function-like op containing the ...
AddressingModel getAddressingModel(TargetEnvAttr targetAttr, bool use64bitAddress)
Returns addressing model selected based on target environment.
FailureOr< MemoryModel > getMemoryModel(TargetEnvAttr targetAttr)
Returns memory model selected based on target environment.
StringRef getEntryPointABIAttrName()
Returns the attribute name for specifying entry point information.
Include the generated interface declarations.
bool matchPattern(Value value, const Pattern &pattern)
Entry point for matching a pattern over a Value.
void populateGPUNamedBarrierToSPIRVTypeConversion(SPIRVTypeConverter &typeConverter)
Adds gpu::NamedBarrierType to spirv::NamedBarrierType conversion.
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr
void populateGPUToSPIRVPatterns(const SPIRVTypeConverter &typeConverter, RewritePatternSet &patterns)
Appends to a pattern list additional patterns for translating GPU Ops to SPIR-V ops.
detail::constant_op_matcher m_Constant()
Matches a constant foldable operation.