[Mlir-commits] [mlir] 61dd481 - [MLIR][LLVMDialect] SelectionOp conversion pattern
George Mitenkov
llvmlistbot at llvm.org
Tue Jul 21 07:12:34 PDT 2020
Author: George Mitenkov
Date: 2020-07-21T17:11:46+03:00
New Revision: 61dd481f11051450522bcd2cfcb7222a90d3464e
URL: https://github.com/llvm/llvm-project/commit/61dd481f11051450522bcd2cfcb7222a90d3464e
DIFF: https://github.com/llvm/llvm-project/commit/61dd481f11051450522bcd2cfcb7222a90d3464e.diff
LOG: [MLIR][LLVMDialect] SelectionOp conversion pattern
This patch introduces conversion pattern for `spv.selection` op.
The conversion can only be applied to selection with all blocks being
reachable. Moreover, selection with control attributes "Flatten" and
"DontFlatten" is not supported.
Since the `PatternRewriter` hook for block merging has not been implemented
for `ConversionPatternRewriter`, merge and continue blocks are kept
separately.
Reviewed By: antiagainst, ftynse
Differential Revision: https://reviews.llvm.org/D83860
Added:
Modified:
mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp
mlir/test/Conversion/SPIRVToLLVM/control-flow-ops-to-llvm.mlir
Removed:
################################################################################
diff --git a/mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp b/mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp
index 29e7fcaac520..15aaa7947a49 100644
--- a/mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp
+++ b/mlir/lib/Conversion/SPIRVToLLVM/ConvertSPIRVToLLVM.cpp
@@ -613,6 +613,84 @@ class ReturnValuePattern : public SPIRVToLLVMConversion<spirv::ReturnValueOp> {
}
};
+class MergePattern : public SPIRVToLLVMConversion<spirv::MergeOp> {
+public:
+ using SPIRVToLLVMConversion<spirv::MergeOp>::SPIRVToLLVMConversion;
+
+ LogicalResult
+ matchAndRewrite(spirv::MergeOp op, ArrayRef<Value> operands,
+ ConversionPatternRewriter &rewriter) const override {
+ rewriter.eraseOp(op);
+ return success();
+ }
+};
+
+/// Converts `spv.selection` with `spv.BranchConditional` in its header block.
+/// All blocks within selection should be reachable for conversion to succeed.
+class SelectionPattern : public SPIRVToLLVMConversion<spirv::SelectionOp> {
+public:
+ using SPIRVToLLVMConversion<spirv::SelectionOp>::SPIRVToLLVMConversion;
+
+ LogicalResult
+ matchAndRewrite(spirv::SelectionOp op, ArrayRef<Value> operands,
+ ConversionPatternRewriter &rewriter) const override {
+ // There is no support for `Flatten` or `DontFlatten` selection control at
+ // the moment. This are just compiler hints and can be performed during the
+ // optimization passes.
+ if (op.selection_control() != spirv::SelectionControl::None)
+ return failure();
+
+ // `spv.selection` should have at least two blocks: one selection header
+ // block and one merge block. If no blocks are present, or control flow
+ // branches straight to merge block (two blocks are present), the op is
+ // redundant and it is erased.
+ if (op.body().getBlocks().size() <= 2) {
+ rewriter.eraseOp(op);
+ return success();
+ }
+
+ Location loc = op.getLoc();
+
+ // Split the current block after `spv.selection`. The remaing ops will be
+ // used in `continueBlock`.
+ auto *currentBlock = rewriter.getInsertionBlock();
+ rewriter.setInsertionPointAfter(op);
+ auto position = rewriter.getInsertionPoint();
+ auto *continueBlock = rewriter.splitBlock(currentBlock, position);
+
+ // Extract conditional branch information from the header block. By SPIR-V
+ // dialect spec, it should contain `spv.BranchConditional` or `spv.Switch`
+ // op. Note that `spv.Switch op` is not supported at the moment in the
+ // SPIR-V dialect. Remove this block when finished.
+ auto *headerBlock = op.getHeaderBlock();
+ assert(headerBlock->getOperations().size() == 1);
+ auto condBrOp = dyn_cast<spirv::BranchConditionalOp>(
+ headerBlock->getOperations().front());
+ if (!condBrOp)
+ return failure();
+ rewriter.eraseBlock(headerBlock);
+
+ // Branch from merge block to continue block.
+ auto *mergeBlock = op.getMergeBlock();
+ Operation *terminator = mergeBlock->getTerminator();
+ ValueRange terminatorOperands = terminator->getOperands();
+ rewriter.setInsertionPointToEnd(mergeBlock);
+ rewriter.create<LLVM::BrOp>(loc, terminatorOperands, continueBlock);
+
+ // Link current block to `true` and `false` blocks within the selection.
+ Block *trueBlock = condBrOp.getTrueBlock();
+ Block *falseBlock = condBrOp.getFalseBlock();
+ rewriter.setInsertionPointToEnd(currentBlock);
+ rewriter.create<LLVM::CondBrOp>(loc, condBrOp.condition(), trueBlock,
+ condBrOp.trueTargetOperands(), falseBlock,
+ condBrOp.falseTargetOperands());
+
+ rewriter.inlineRegionBefore(op.body(), continueBlock);
+ rewriter.replaceOp(op, continueBlock->getArguments());
+ return success();
+ }
+};
+
/// Converts SPIR-V shift ops to LLVM shift ops. Since LLVM dialect
/// puts a restriction on `Shift` and `Base` to have the same bit width,
/// `Shift` is zero or sign extended to match this specification. Cases when
@@ -843,6 +921,7 @@ void mlir::populateSPIRVToLLVMConversionPatterns(
// Control Flow ops
BranchConversionPattern, BranchConditionalConversionPattern,
+ SelectionPattern, MergePattern,
// Function Call op
FunctionCallPattern,
diff --git a/mlir/test/Conversion/SPIRVToLLVM/control-flow-ops-to-llvm.mlir b/mlir/test/Conversion/SPIRVToLLVM/control-flow-ops-to-llvm.mlir
index a8472c2f69fa..0a2f6d681769 100644
--- a/mlir/test/Conversion/SPIRVToLLVM/control-flow-ops-to-llvm.mlir
+++ b/mlir/test/Conversion/SPIRVToLLVM/control-flow-ops-to-llvm.mlir
@@ -80,3 +80,93 @@ spv.module Logical GLSL450 {
spv.Return
}
}
+
+// -----
+
+//===----------------------------------------------------------------------===//
+// spv.selection
+//===----------------------------------------------------------------------===//
+
+spv.module Logical GLSL450 {
+ spv.func @selection_empty() -> () "None" {
+ // CHECK: llvm.return
+ spv.selection {
+ }
+ spv.Return
+ }
+
+ spv.func @selection_with_merge_block_only() -> () "None" {
+ %cond = spv.constant true
+ // CHECK: llvm.return
+ spv.selection {
+ spv.BranchConditional %cond, ^merge, ^merge
+ ^merge:
+ spv._merge
+ }
+ spv.Return
+ }
+
+ spv.func @selection_with_true_block_only() -> () "None" {
+ // CHECK: %[[COND:.*]] = llvm.mlir.constant(true) : !llvm.i1
+ %cond = spv.constant true
+ // CHECK: llvm.cond_br %[[COND]], ^bb1, ^bb2
+ spv.selection {
+ spv.BranchConditional %cond, ^true, ^merge
+ // CHECK: ^bb1:
+ ^true:
+ // CHECK: llvm.br ^bb2
+ spv.Branch ^merge
+ // CHECK: ^bb2:
+ ^merge:
+ // CHECK: llvm.br ^bb3
+ spv._merge
+ }
+ // CHECK: ^bb3:
+ // CHECK-NEXT: llvm.return
+ spv.Return
+ }
+
+ spv.func @selection_with_both_true_and_false_block() -> () "None" {
+ // CHECK: %[[COND:.*]] = llvm.mlir.constant(true) : !llvm.i1
+ %cond = spv.constant true
+ // CHECK: llvm.cond_br %[[COND]], ^bb1, ^bb2
+ spv.selection {
+ spv.BranchConditional %cond, ^true, ^false
+ // CHECK: ^bb1:
+ ^true:
+ // CHECK: llvm.br ^bb3
+ spv.Branch ^merge
+ // CHECK: ^bb2:
+ ^false:
+ // CHECK: llvm.br ^bb3
+ spv.Branch ^merge
+ // CHECK: ^bb3:
+ ^merge:
+ // CHECK: llvm.br ^bb4
+ spv._merge
+ }
+ // CHECK: ^bb4:
+ // CHECK-NEXT: llvm.return
+ spv.Return
+ }
+
+ spv.func @selection_with_early_return(%arg0: i1) -> i32 "None" {
+ // CHECK: %[[ZERO:.*]] = llvm.mlir.constant(0 : i32) : !llvm.i32
+ %0 = spv.constant 0 : i32
+ // CHECK: llvm.cond_br %{{.*}}, ^bb1(%[[ZERO]] : !llvm.i32), ^bb2
+ spv.selection {
+ spv.BranchConditional %arg0, ^true(%0 : i32), ^merge
+ // CHECK: ^bb1(%[[ARG:.*]]: !llvm.i32):
+ ^true(%arg1: i32):
+ // CHECK: llvm.return %[[ARG]] : !llvm.i32
+ spv.ReturnValue %arg1 : i32
+ // CHECK: ^bb2:
+ ^merge:
+ // CHECK: llvm.br ^bb3
+ spv._merge
+ }
+ // CHECK: ^bb3:
+ %one = spv.constant 1 : i32
+ spv.ReturnValue %one : i32
+ }
+}
More information about the Mlir-commits
mailing list