19#include "llvm/Support/FormatVariadic.h"
43 impl = std::make_unique<::ScfToSPIRVContextImpl>();
59template <
typename ScfOp,
typename OpTy>
60void replaceSCFOutputValue(ScfOp scfOp, OpTy newOp,
61 ConversionPatternRewriter &rewriter,
66 auto &allocas = scfToSPIRVContext->
outputVars[newOp];
71 for (
Type convertedType : returnTypes) {
74 rewriter.setInsertionPoint(newOp);
75 auto alloc = spirv::VariableOp::create(rewriter, loc, pointerType,
76 spirv::StorageClass::Function,
78 allocas.push_back(alloc);
79 rewriter.setInsertionPointAfter(newOp);
80 Value loadResult = spirv::LoadOp::create(rewriter, loc, alloc);
81 resultValue.push_back(loadResult);
83 rewriter.replaceOp(scfOp, resultValue);
95template <
typename OpTy>
96class SCFToSPIRVPattern :
public OpConversionPattern<OpTy> {
98 SCFToSPIRVPattern(MLIRContext *context,
const SPIRVTypeConverter &converter,
99 ScfToSPIRVContextImpl *scfToSPIRVContext)
100 : OpConversionPattern<OpTy>::OpConversionPattern(converter, context),
101 scfToSPIRVContext(scfToSPIRVContext), typeConverter(converter) {}
104 ScfToSPIRVContextImpl *scfToSPIRVContext;
119 const SPIRVTypeConverter &typeConverter;
127struct ForOpConversion final : SCFToSPIRVPattern<scf::ForOp> {
128 using SCFToSPIRVPattern::SCFToSPIRVPattern;
131 matchAndRewrite(scf::ForOp forOp, OpAdaptor adaptor,
132 ConversionPatternRewriter &rewriter)
const override {
138 auto loc = forOp.getLoc();
139 auto loopControl = spirv::LoopControl::None;
140 if (
auto attr = forOp->getAttrOfType<spirv::LoopControlAttr>(
142 loopControl = attr.getValue();
143 auto loopOp = spirv::LoopOp::create(rewriter, loc, loopControl);
144 loopOp.addEntryAndMergeBlock(rewriter);
146 OpBuilder::InsertionGuard guard(rewriter);
148 Block *header = rewriter.createBlock(&loopOp.getBody(),
149 getBlockIt(loopOp.getBody(), 1));
150 rewriter.setInsertionPointAfter(loopOp);
153 Value adapLowerBound = adaptor.getLowerBound();
154 BlockArgument newIndVar =
156 for (Value arg : adaptor.getInitArgs())
158 Block *body = forOp.getBody();
163 TypeConverter::SignatureConversion signatureConverter(
165 signatureConverter.remapInput(0, newIndVar);
167 signatureConverter.remapInput(i, header->
getArgument(i));
168 body = rewriter.applySignatureConversion(&forOp.getRegion().front(),
173 rewriter.inlineRegionBefore(forOp->getRegion(0), loopOp.getBody(),
174 getBlockIt(loopOp.getBody(), 2));
176 SmallVector<Value, 8> args(1, adaptor.getLowerBound());
177 args.append(adaptor.getInitArgs().begin(), adaptor.getInitArgs().end());
179 rewriter.setInsertionPointToEnd(&(loopOp.getBody().front()));
180 spirv::BranchOp::create(rewriter, loc, header, args);
183 rewriter.setInsertionPointToEnd(header);
184 auto *mergeBlock = loopOp.getMergeBlock();
186 if (forOp.getUnsignedCmp()) {
187 cmpOp = spirv::ULessThanOp::create(rewriter, loc, rewriter.getI1Type(),
188 newIndVar, adaptor.getUpperBound());
190 cmpOp = spirv::SLessThanOp::create(rewriter, loc, rewriter.getI1Type(),
191 newIndVar, adaptor.getUpperBound());
194 spirv::BranchConditionalOp::create(rewriter, loc, cmpOp, body,
195 ArrayRef<Value>(), mergeBlock,
200 Block *continueBlock = loopOp.getContinueBlock();
201 rewriter.setInsertionPointToEnd(continueBlock);
204 Value updatedIndVar = spirv::IAddOp::create(
205 rewriter, loc, newIndVar.
getType(), newIndVar, adaptor.getStep());
206 spirv::BranchOp::create(rewriter, loc, header, updatedIndVar);
212 SmallVector<Type, 8> initTypes;
213 for (
auto arg : adaptor.getInitArgs())
214 initTypes.push_back(arg.getType());
215 replaceSCFOutputValue(forOp, loopOp, rewriter, scfToSPIRVContext,
227struct IfOpConversion : SCFToSPIRVPattern<scf::IfOp> {
228 using SCFToSPIRVPattern::SCFToSPIRVPattern;
231 matchAndRewrite(scf::IfOp ifOp, OpAdaptor adaptor,
232 ConversionPatternRewriter &rewriter)
const override {
236 auto loc = ifOp.getLoc();
239 SmallVector<Type, 8> returnTypes;
240 for (
auto result : ifOp.getResults()) {
241 auto convertedType = typeConverter.convertType(
result.getType());
243 return rewriter.notifyMatchFailure(
245 llvm::formatv(
"failed to convert type '{0}'",
result.getType()));
247 returnTypes.push_back(convertedType);
252 auto selectionControl = spirv::SelectionControl::None;
253 if (
auto attr = ifOp->getAttrOfType<spirv::SelectionControlAttr>(
255 selectionControl = attr.getValue();
257 spirv::SelectionOp::create(rewriter, loc, selectionControl);
258 auto *mergeBlock = rewriter.createBlock(&selectionOp.getBody(),
259 selectionOp.getBody().end());
260 spirv::MergeOp::create(rewriter, loc);
262 OpBuilder::InsertionGuard guard(rewriter);
263 auto *selectionHeaderBlock =
264 rewriter.createBlock(&selectionOp.getBody().front());
267 auto &thenRegion = ifOp.getThenRegion();
268 auto *thenBlock = &thenRegion.front();
269 rewriter.setInsertionPointToEnd(&thenRegion.back());
270 spirv::BranchOp::create(rewriter, loc, mergeBlock);
271 rewriter.inlineRegionBefore(thenRegion, mergeBlock);
273 auto *elseBlock = mergeBlock;
276 if (!ifOp.getElseRegion().empty()) {
277 auto &elseRegion = ifOp.getElseRegion();
278 elseBlock = &elseRegion.front();
279 rewriter.setInsertionPointToEnd(&elseRegion.back());
280 spirv::BranchOp::create(rewriter, loc, mergeBlock);
281 rewriter.inlineRegionBefore(elseRegion, mergeBlock);
285 rewriter.setInsertionPointToEnd(selectionHeaderBlock);
286 spirv::BranchConditionalOp::create(rewriter, loc, adaptor.getCondition(),
287 thenBlock, ArrayRef<Value>(), elseBlock,
290 replaceSCFOutputValue(ifOp, selectionOp, rewriter, scfToSPIRVContext,
302struct IndexSwitchOpConversion final : SCFToSPIRVPattern<scf::IndexSwitchOp> {
303 using SCFToSPIRVPattern::SCFToSPIRVPattern;
306 matchAndRewrite(scf::IndexSwitchOp switchOp, OpAdaptor adaptor,
307 ConversionPatternRewriter &rewriter)
const override {
308 Location loc = switchOp.getLoc();
311 SmallVector<Type, 8> returnTypes;
312 for (Value
result : switchOp.getResults()) {
313 Type convertedType = typeConverter.convertType(
result.getType());
315 return rewriter.notifyMatchFailure(
317 llvm::formatv(
"failed to convert type '{0}'",
result.getType()));
318 returnTypes.push_back(convertedType);
323 Value selector = adaptor.getArg();
324 auto selectorType = dyn_cast<IntegerType>(selector.
getType());
326 return rewriter.notifyMatchFailure(loc,
327 "selector type is not an integer");
328 unsigned selectorWidth = selectorType.getWidth();
331 auto selectionControl = spirv::SelectionControl::None;
332 if (
auto attr = switchOp->getAttrOfType<spirv::SelectionControlAttr>(
334 selectionControl = attr.getValue();
336 spirv::SelectionOp::create(rewriter, loc, selectionControl);
337 auto *mergeBlock = rewriter.createBlock(&selectionOp.getBody(),
338 selectionOp.getBody().end());
339 spirv::MergeOp::create(rewriter, loc);
341 OpBuilder::InsertionGuard guard(rewriter);
342 auto *headerBlock = rewriter.createBlock(&selectionOp.getBody().front());
345 SmallVector<APInt> caseLiterals;
346 SmallVector<Block *> caseBlocks;
347 ArrayRef<int64_t> cases = switchOp.getCases();
348 for (
auto [caseValue, caseRegion] :
349 llvm::zip_equal(cases, switchOp.getCaseRegions())) {
350 Block *caseBlock = &caseRegion.front();
351 rewriter.setInsertionPointToEnd(&caseRegion.back());
352 spirv::BranchOp::create(rewriter, loc, mergeBlock);
353 rewriter.inlineRegionBefore(caseRegion, mergeBlock);
354 caseLiterals.push_back(
355 APInt(selectorWidth, caseValue,
true));
356 caseBlocks.push_back(caseBlock);
360 Region &defaultRegion = switchOp.getDefaultRegion();
362 rewriter.setInsertionPointToEnd(&defaultRegion.
back());
363 spirv::BranchOp::create(rewriter, loc, mergeBlock);
364 rewriter.inlineRegionBefore(defaultRegion, mergeBlock);
369 SmallVector<ValueRange> caseOperands(caseBlocks.size(),
ValueRange());
370 rewriter.setInsertionPointToEnd(headerBlock);
371 spirv::SwitchOp::create(rewriter, loc, selector, defaultBlock,
ValueRange(),
372 caseLiterals, caseBlocks, caseOperands);
374 replaceSCFOutputValue(switchOp, selectionOp, rewriter, scfToSPIRVContext,
384struct TerminatorOpConversion final : SCFToSPIRVPattern<scf::YieldOp> {
386 using SCFToSPIRVPattern::SCFToSPIRVPattern;
389 matchAndRewrite(scf::YieldOp terminatorOp, OpAdaptor adaptor,
390 ConversionPatternRewriter &rewriter)
const override {
393 Operation *parent = terminatorOp->getParentOp();
397 scf::SCFDialect::getDialectNamespace() &&
398 !isa<scf::IfOp, scf::ForOp, scf::WhileOp, scf::IndexSwitchOp>(parent))
399 return rewriter.notifyMatchFailure(
401 llvm::formatv(
"conversion not supported for parent op: '{0}'",
406 if (!operands.empty()) {
407 auto &allocas = scfToSPIRVContext->
outputVars[parent];
408 if (allocas.size() != operands.size())
411 auto loc = terminatorOp.getLoc();
412 for (
unsigned i = 0, e = operands.size(); i < e; i++)
413 spirv::StoreOp::create(rewriter, loc, allocas[i], operands[i]);
414 if (isa<spirv::LoopOp>(parent)) {
417 auto br = cast<spirv::BranchOp>(
418 rewriter.getInsertionBlock()->getTerminator());
419 SmallVector<Value, 8> args(br.getBlockArguments());
420 args.append(operands.begin(), operands.end());
421 rewriter.setInsertionPoint(br);
422 spirv::BranchOp::create(rewriter, terminatorOp.getLoc(), br.getTarget(),
424 rewriter.eraseOp(br);
427 rewriter.eraseOp(terminatorOp);
436struct WhileOpConversion final : SCFToSPIRVPattern<scf::WhileOp> {
437 using SCFToSPIRVPattern::SCFToSPIRVPattern;
440 matchAndRewrite(scf::WhileOp whileOp, OpAdaptor adaptor,
441 ConversionPatternRewriter &rewriter)
const override {
442 auto loc = whileOp.getLoc();
443 auto loopControl = spirv::LoopControl::None;
444 if (
auto attr = whileOp->getAttrOfType<spirv::LoopControlAttr>(
446 loopControl = attr.getValue();
447 auto loopOp = spirv::LoopOp::create(rewriter, loc, loopControl);
448 loopOp.addEntryAndMergeBlock(rewriter);
450 Region &beforeRegion = whileOp.getBefore();
451 Region &afterRegion = whileOp.getAfter();
453 if (
failed(rewriter.convertRegionTypes(&beforeRegion, typeConverter)) ||
454 failed(rewriter.convertRegionTypes(&afterRegion, typeConverter)))
455 return rewriter.notifyMatchFailure(whileOp,
456 "Failed to convert region types");
458 OpBuilder::InsertionGuard guard(rewriter);
460 Block &entryBlock = *loopOp.getEntryBlock();
463 Block &mergeBlock = *loopOp.getMergeBlock();
465 auto cond = cast<scf::ConditionOp>(beforeBlock.
getTerminator());
466 SmallVector<Value> condArgs;
467 if (
failed(rewriter.getRemappedValues(cond.getArgs(), condArgs)))
470 Value conditionVal = rewriter.getRemappedValue(cond.getCondition());
475 SmallVector<Value> yieldArgs;
476 if (
failed(rewriter.getRemappedValues(yield.getResults(), yieldArgs)))
480 rewriter.inlineRegionBefore(beforeRegion, loopOp.getBody(),
481 getBlockIt(loopOp.getBody(), 1));
484 rewriter.inlineRegionBefore(afterRegion, loopOp.getBody(),
485 getBlockIt(loopOp.getBody(), 2));
488 rewriter.setInsertionPointToEnd(&entryBlock);
489 spirv::BranchOp::create(rewriter, loc, &beforeBlock, adaptor.getInits());
491 auto condLoc = cond.getLoc();
493 SmallVector<Value> resultValues(condArgs.size());
502 for (
const auto &it : llvm::enumerate(condArgs)) {
503 auto res = it.value();
509 rewriter.setInsertionPoint(loopOp);
510 auto alloc = spirv::VariableOp::create(rewriter, condLoc, pointerType,
511 spirv::StorageClass::Function,
515 rewriter.setInsertionPointAfter(loopOp);
516 auto loadResult = spirv::LoadOp::create(rewriter, condLoc, alloc);
517 resultValues[i] = loadResult;
520 rewriter.setInsertionPointToEnd(&beforeBlock);
521 spirv::StoreOp::create(rewriter, condLoc, alloc, res);
524 rewriter.setInsertionPointToEnd(&beforeBlock);
525 rewriter.replaceOpWithNewOp<spirv::BranchConditionalOp>(
526 cond, conditionVal, &afterBlock, condArgs, &mergeBlock,
ValueRange());
529 rewriter.setInsertionPointToEnd(&afterBlock);
530 rewriter.replaceOpWithNewOp<spirv::BranchOp>(yield, &beforeBlock,
533 rewriter.replaceOp(whileOp, resultValues);
546 patterns.
add<ForOpConversion, IfOpConversion, IndexSwitchOpConversion,
547 TerminatorOpConversion, WhileOpConversion>(
BlockArgument getArgument(unsigned i)
unsigned getNumArguments()
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
StringRef getNamespace() const
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Dialect * getDialect()
Return the dialect this operation is associated with, or nullptr if the associated dialect is not loa...
OperationName getName()
The name of an operation is the key identifier for it.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
BlockListType::iterator iterator
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.
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.
Location getLoc() const
Return the location of this value.
static PointerType get(Type pointeeType, StorageClass storageClass)
StringRef getLoopControlAttrName()
Returns the attribute name for specifying loop control.
StringRef getSelectionControlAttrName()
Returns the attribute name for specifying selection control.
Include the generated interface declarations.
void populateSCFToSPIRVPatterns(const SPIRVTypeConverter &typeConverter, ScfToSPIRVContext &scfToSPIRVContext, RewritePatternSet &patterns)
Collects a set of patterns to lower from scf.for, scf.if, and loop.terminator to CFG operations withi...
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
DenseMap< Operation *, SmallVector< spirv::VariableOp, 8 > > outputVars
ScfToSPIRVContext()
We use ScfToSPIRVContext to store information about the lowering of the scf region that need to be us...
ScfToSPIRVContextImpl * getImpl()