25#include "llvm/Support/FormatVariadic.h"
29#define GEN_PASS_DEF_SPIRVLOWERABIATTRIBUTESPASS
30#include "mlir/Dialect/SPIRV/Transforms/Passes.h.inc"
37static spirv::GlobalVariableOp
41 auto spirvModule = funcOp->getParentOfType<spirv::ModuleOp>();
48 funcOp.getName().str() +
"_arg_" + std::to_string(argIndex);
53 auto varType = funcOp.getFunctionType().getInput(argIndex);
54 if (cast<spirv::SPIRVType>(varType).isScalarOrVector()) {
61 auto varPtrType = cast<spirv::PointerType>(varType);
62 Type pointeeType = varPtrType.getPointeeType();
67 if (isa<spirv::SampledImageType>(pointeeType))
68 return spirv::GlobalVariableOp::create(builder, funcOp.getLoc(), varType,
72 auto varPointeeType = cast<spirv::StructType>(pointeeType);
84 return spirv::GlobalVariableOp::create(builder, funcOp.getLoc(), varType,
90static spirv::GlobalVariableOp
92 unsigned index,
bool isArg,
94 auto spirvModule = graphOp->getParentOfType<spirv::ModuleOp>();
100 std::string varName = llvm::formatv(
"{}_{}_{}", graphOp.getName(),
101 isArg ?
"arg" :
"res",
index);
103 Type varType = isArg ? graphOp.getFunctionType().getInput(
index)
104 : graphOp.getFunctionType().getResult(
index);
108 abiInfo.
getStorageClass().value_or(spirv::StorageClass::UniformConstant));
110 return spirv::GlobalVariableOp::create(builder, graphOp.getLoc(), pointerType,
120 auto module = funcOp->getParentOfType<spirv::ModuleOp>();
132 funcOp.walk([&](spirv::AddressOfOp addressOfOp) {
134 module.lookupSymbol<spirv::GlobalVariableOp>(addressOfOp.getVariable());
140 const spirv::StorageClass storageClass =
141 cast<spirv::PointerType>(var.getType()).getStorageClass();
142 if ((targetEnvAttr && targetEnv.
getVersion() >= spirv::Version::V_1_4) ||
144 {spirv::StorageClass::Input, spirv::StorageClass::Output},
146 interfaceVarSet.insert(var.getOperation());
149 for (
auto &var : interfaceVarSet) {
150 interfaceVars.push_back(SymbolRefAttr::get(
151 funcOp.getContext(), cast<spirv::GlobalVariableOp>(var).getSymName()));
160 auto entryPointAttr =
161 funcOp->getDiscardableAttrOfType<spirv::EntryPointABIAttr>(
163 if (!entryPointAttr) {
171 auto spirvModule = funcOp->getParentOfType<spirv::ModuleOp>();
181 FailureOr<spirv::ExecutionModel> executionModel =
183 if (failed(executionModel))
184 return funcOp.emitRemark(
"lower entry point failure: could not select "
185 "execution model based on 'spirv.target_env'");
187 spirv::EntryPointOp::create(builder, funcOp.getLoc(), *executionModel, funcOp,
192 std::optional<ArrayRef<spirv::Capability>> caps =
193 spirv::getCapabilities(spirv::ExecutionMode::LocalSize);
195 spirv::ExecutionModeOp::create(builder, funcOp.getLoc(), funcOp,
196 spirv::ExecutionMode::LocalSize,
197 workgroupSizeAttr.asArrayRef());
199 entryPointAttr = spirv::EntryPointABIAttr::get(
201 entryPointAttr.getSubgroupSize(), entryPointAttr.getTargetWidth());
204 if (std::optional<int> subgroupSize = entryPointAttr.getSubgroupSize()) {
205 std::optional<ArrayRef<spirv::Capability>> caps =
206 spirv::getCapabilities(spirv::ExecutionMode::SubgroupSize);
207 if (!caps || targetEnv.
allows(*caps)) {
208 spirv::ExecutionModeOp::create(builder, funcOp.getLoc(), funcOp,
209 spirv::ExecutionMode::SubgroupSize,
212 entryPointAttr = spirv::EntryPointABIAttr::get(
213 entryPointAttr.getContext(), entryPointAttr.getWorkgroupSize(),
214 std::nullopt, entryPointAttr.getTargetWidth());
217 if (std::optional<int> targetWidth = entryPointAttr.getTargetWidth()) {
218 std::optional<ArrayRef<spirv::Capability>> caps =
219 spirv::getCapabilities(spirv::ExecutionMode::SignedZeroInfNanPreserve);
220 if (!caps || targetEnv.
allows(*caps)) {
221 spirv::ExecutionModeOp::create(
222 builder, funcOp.getLoc(), funcOp,
223 spirv::ExecutionMode::SignedZeroInfNanPreserve, *targetWidth);
225 entryPointAttr = spirv::EntryPointABIAttr::get(
226 entryPointAttr.getContext(), entryPointAttr.getWorkgroupSize(),
227 entryPointAttr.getSubgroupSize(), std::nullopt);
230 if (entryPointAttr.getWorkgroupSize() || entryPointAttr.getSubgroupSize() ||
231 entryPointAttr.getTargetWidth())
232 funcOp->setDiscardableAttr(entryPointAttrName, entryPointAttr);
234 funcOp->removeDiscardableAttr(entryPointAttrName);
246class ProcessInterfaceVarABI final :
public OpConversionPattern<spirv::FuncOp> {
251 matchAndRewrite(spirv::FuncOp funcOp, OpAdaptor adaptor,
252 ConversionPatternRewriter &rewriter)
const override;
260class ProcessGraphInterfaceVarABI final
261 :
public OpConversionPattern<spirv::GraphARMOp> {
263 using OpConversionPattern::OpConversionPattern;
266 matchAndRewrite(spirv::GraphARMOp graphOp, OpAdaptor adaptor,
267 ConversionPatternRewriter &rewriter)
const override;
271class LowerABIAttributesPass final
273 LowerABIAttributesPass> {
274 void runOnOperation()
override;
278LogicalResult ProcessInterfaceVarABI::matchAndRewrite(
279 spirv::FuncOp funcOp, OpAdaptor adaptor,
280 ConversionPatternRewriter &rewriter)
const {
281 if (!funcOp->getDiscardableAttrOfType<spirv::EntryPointABIAttr>(
286 TypeConverter::SignatureConversion signatureConverter(
287 funcOp.getFunctionType().getNumInputs());
289 auto &typeConverter = *getTypeConverter<SPIRVTypeConverter>();
290 auto indexType = typeConverter.getIndexType();
294 OpBuilder::InsertionGuard funcInsertionGuard(rewriter);
295 rewriter.setInsertionPointToStart(&funcOp.front());
297 for (
const auto &argType :
298 llvm::enumerate(funcOp.getFunctionType().getInputs())) {
299 auto abiInfo = funcOp.getArgAttrOfType<spirv::InterfaceVarABIAttr>(
300 argType.index(), attrName);
309 rewriter, funcOp, argType.index(), abiInfo);
315 spirv::AddressOfOp::create(rewriter, funcOp.getLoc(), var);
322 if (cast<spirv::SPIRVType>(argType.value()).isScalarOrVector()) {
324 spirv::ConstantOp::getZero(indexType, funcOp.getLoc(), rewriter);
325 auto loadPtr = spirv::AccessChainOp::create(
326 rewriter, funcOp.getLoc(),
replacement, zero.getConstant());
327 replacement = spirv::LoadOp::create(rewriter, funcOp.getLoc(), loadPtr);
329 signatureConverter.remapInput(argType.index(),
replacement);
331 if (
failed(rewriter.convertRegionTypes(&funcOp.getBody(), *getTypeConverter(),
332 &signatureConverter)))
336 rewriter.modifyOpInPlace(funcOp, [&] {
338 rewriter.getFunctionType(signatureConverter.getConvertedTypes(), {}));
343LogicalResult ProcessGraphInterfaceVarABI::matchAndRewrite(
344 spirv::GraphARMOp graphOp, OpAdaptor adaptor,
345 ConversionPatternRewriter &rewriter)
const {
347 if (!graphOp.getEntryPoint().value_or(
false))
350 TypeConverter::SignatureConversion signatureConverter(
351 graphOp.getFunctionType().getNumInputs());
354 SmallVector<Attribute, 4> interfaceVars;
357 unsigned numInputs = graphOp.getFunctionType().getNumInputs();
358 unsigned numResults = graphOp.getFunctionType().getNumResults();
359 for (
unsigned index = 0; index < numInputs; ++index) {
361 graphOp.getArgAttrOfType<spirv::InterfaceVarABIAttr>(index, attrName);
365 rewriter, graphOp, index,
true, abiInfo);
368 interfaceVars.push_back(
369 SymbolRefAttr::get(rewriter.getContext(), var.getSymName()));
372 for (
unsigned index = 0; index < numResults; ++index) {
373 auto abiInfo = graphOp.getResultAttrOfType<spirv::InterfaceVarABIAttr>(
378 rewriter, graphOp, index,
false, abiInfo);
381 interfaceVars.push_back(
382 SymbolRefAttr::get(rewriter.getContext(), var.getSymName()));
386 rewriter.modifyOpInPlace(graphOp, [&] {
387 for (
unsigned index = 0; index < numInputs; ++index) {
388 graphOp.removeArgAttr(index, attrName);
390 for (
unsigned index = 0; index < numResults; ++index) {
391 graphOp.removeResultAttr(index, rewriter.getStringAttr(attrName));
395 spirv::GraphEntryPointARMOp::create(rewriter, graphOp.getLoc(), graphOp,
400void LowerABIAttributesPass::runOnOperation() {
403 spirv::ModuleOp module = getOperation();
407 if (!targetEnvAttr) {
408 module->emitOpError("missing SPIR-V target env attribute");
409 return signalPassFailure();
411 spirv::TargetEnv targetEnv(targetEnvAttr);
413 SPIRVTypeConverter typeConverter(targetEnv);
416 typeConverter.addSourceMaterialization([](OpBuilder &builder,
417 spirv::PointerType type,
419 if (inputs.size() != 1 || !isa<spirv::PointerType>(inputs[0].getType()))
421 return spirv::BitcastOp::create(builder, loc, type, inputs[0]).getResult();
424 RewritePatternSet patterns(context);
425 patterns.add<ProcessInterfaceVarABI, ProcessGraphInterfaceVarABI>(
426 typeConverter, context);
428 ConversionTarget
target(*context);
430 target.addDynamicallyLegalOp<spirv::FuncOp>([&](spirv::FuncOp op) {
432 for (
unsigned i = 0, e = op.getNumArguments(); i < e; ++i)
433 if (op.getArgAttr(i, attrName))
437 target.addDynamicallyLegalOp<spirv::GraphARMOp>([&](spirv::GraphARMOp op) {
439 for (
unsigned i = 0, e = op.getNumArguments(); i < e; ++i)
440 if (op.getArgAttr(i, attrName))
442 for (
unsigned i = 0, e = op.getNumResults(); i < e; ++i)
443 if (op.getResultAttr(i, attrName))
449 target.markUnknownOpDynamicallyLegal([](Operation *op) {
451 spirv::SPIRVDialect::getDialectNamespace();
453 if (
failed(applyPartialConversion(module,
target, std::move(patterns))))
454 return signalPassFailure();
458 OpBuilder builder(context);
459 SmallVector<spirv::FuncOp, 1> entryPointFns;
461 module.walk([&](spirv::FuncOp funcOp) {
462 if (funcOp->getDiscardableAttrOfType<spirv::EntryPointABIAttr>(
463 entryPointAttrName)) {
464 entryPointFns.push_back(funcOp);
467 for (
auto fn : entryPointFns) {
469 return signalPassFailure();
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static spirv::GlobalVariableOp createGlobalVarForEntryPointArgument(OpBuilder &builder, spirv::FuncOp funcOp, unsigned argIndex, spirv::InterfaceVarABIAttr abiInfo)
Creates a global variable for an argument based on the ABI info.
static spirv::GlobalVariableOp createGlobalVarForGraphEntryPoint(OpBuilder &builder, spirv::GraphARMOp graphOp, unsigned index, bool isArg, spirv::InterfaceVarABIAttr abiInfo)
Creates a global variable for an argument or result based on the ABI info.
static LogicalResult lowerEntryPointABIAttr(spirv::FuncOp funcOp, OpBuilder &builder)
Lowers the entry point attribute.
static LogicalResult getInterfaceVariables(mlir::FunctionOpInterface funcOp, SmallVectorImpl< Attribute > &interfaceVars)
Gets the global variables that need to be specified as interface variable with an spirv....
StringRef getNamespace() const
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
static spirv::StructType decorateType(spirv::StructType structType)
Returns a new StructType with layout decoration.
An attribute that specifies the information regarding the interface variable: descriptor set,...
uint32_t getBinding()
Returns binding.
uint32_t getDescriptorSet()
Returns descriptor set.
std::optional< StorageClass > getStorageClass()
Returns spirv::StorageClass.
static PointerType get(Type pointeeType, StorageClass storageClass)
static StructType get(ArrayRef< Type > memberTypes, ArrayRef< OffsetInfo > offsetInfo={}, ArrayRef< MemberDecorationInfo > memberDecorations={}, ArrayRef< StructDecorationInfo > structDecorations={})
Construct a literal StructType with at least one member.
An attribute that specifies the target version, allowed extensions and capabilities,...
A wrapper class around a spirv::TargetEnvAttr to provide query methods for allowed version/capabiliti...
Version getVersion() const
bool allows(Capability) const
Returns true if the given capability is allowed.
StringRef getInterfaceVarABIAttrName()
Returns the attribute name for specifying argument ABI information.
TargetEnvAttr lookupTargetEnv(Operation *op)
Queries the target environment recursively from enclosing symbol table ops containing the given op.
FailureOr< ExecutionModel > getExecutionModel(TargetEnvAttr targetAttr)
Returns execution model selected based on target environment.
StringRef getEntryPointABIAttrName()
Returns the attribute name for specifying entry point information.
Include the generated interface declarations.
llvm::SetVector< T, Vector, Set, N > SetVector
detail::DenseArrayAttrImpl< int32_t > DenseI32ArrayAttr