mirror of
https://github.com/intel/llvm.git
synced 2026-02-02 10:08:59 +08:00
[MLIR][SPIRV] Rename spv.selection to spv.mlir.selection.
To unify the naming scheme across all ops in the SPIR-V dialect, we are moving from spv.camelCase to spv.CamelCase everywhere. For ops that don't have a SPIR-V spec counterpart, we use spv.mlir.snake_case. Reviewed By: antiagainst Differential Revision: https://reviews.llvm.org/D98014
This commit is contained in:
committed by
KareemErgawy
parent
34d1a5c7b1
commit
3fb384d50e
@@ -525,14 +525,14 @@ control flow construct. With this approach, it's easier to discover all blocks
|
||||
belonging to a structured control flow construct. It is also more idiomatic to
|
||||
MLIR system.
|
||||
|
||||
We introduce a `spv.selection` and `spv.mlir.loop` op for structured selections and
|
||||
We introduce a `spv.mlir.selection` and `spv.mlir.loop` op for structured selections and
|
||||
loops, respectively. The merge targets are the next ops following them. Inside
|
||||
their regions, a special terminator, `spv.mlir.merge` is introduced for branching to
|
||||
the merge target.
|
||||
|
||||
### Selection
|
||||
|
||||
`spv.selection` defines a selection construct. It contains one region. The
|
||||
`spv.mlir.selection` defines a selection construct. It contains one region. The
|
||||
region should contain at least two blocks: one selection header block and one
|
||||
merge block.
|
||||
|
||||
@@ -586,7 +586,7 @@ func @selection(%cond: i1) -> () {
|
||||
%two = spv.Constant 2: i32
|
||||
%x = spv.Variable init(%zero) : !spv.ptr<i32, Function>
|
||||
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^else
|
||||
|
||||
^then:
|
||||
@@ -731,7 +731,7 @@ It will be represented as:
|
||||
func @foo() -> () {
|
||||
%var = spv.Variable : !spv.ptr<i32, Function>
|
||||
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
%true = spv.Constant true
|
||||
spv.BranchConditional %true, ^true, ^false
|
||||
|
||||
@@ -969,7 +969,7 @@ the representational differences between SPIR-V dialect and binary format:
|
||||
* Attributes on ops, if not part of the op's binary encoding, are emitted as
|
||||
`OpDecorate*` instructions in the SPIR-V binary module section for
|
||||
decorations.
|
||||
* `spv.selection`s and `spv.mlir.loop`s are emitted as basic blocks with `Op*Merge`
|
||||
* `spv.mlir.selection`s and `spv.mlir.loop`s are emitted as basic blocks with `Op*Merge`
|
||||
instructions in the header block as required by the binary format.
|
||||
* Block arguments are materialized as `OpPhi` instructions at the beginning of
|
||||
the corresponding blocks.
|
||||
@@ -991,7 +991,7 @@ Similarly, a few transformations are performed during deserialization:
|
||||
`spv.mlir.referenceof` op to turn the symbol of the corresponding
|
||||
`spv.SpecConstant` into an SSA value.
|
||||
* `OpPhi` instructions are converted to block arguments.
|
||||
* Structured control flow are placed inside `spv.selection` and `spv.mlir.loop`.
|
||||
* Structured control flow are placed inside `spv.mlir.selection` and `spv.mlir.loop`.
|
||||
|
||||
## Conversions
|
||||
|
||||
|
||||
@@ -663,9 +663,9 @@ the conditional branch.
|
||||
spv.FunctionCall @bar(%0) : (i32) -> () => llvm.call @bar(%0) : (f32) -> ()
|
||||
```
|
||||
|
||||
### `spv.selection` and `spv.mlir.loop`
|
||||
### `spv.mlir.selection` and `spv.mlir.loop`
|
||||
|
||||
Control flow within `spv.selection` and `spv.mlir.loop` is lowered directly to LLVM
|
||||
Control flow within `spv.mlir.selection` and `spv.mlir.loop` is lowered directly to LLVM
|
||||
via branch ops. The conversion can only be applied to selection or loop with all
|
||||
blocks being reachable. Moreover, selection and loop control attributes (such as
|
||||
`Flatten` or `Unroll`) are not supported at the moment.
|
||||
@@ -673,7 +673,7 @@ blocks being reachable. Moreover, selection and loop control attributes (such as
|
||||
```mlir
|
||||
// Conversion of selection
|
||||
%cond = spv.Constant true %cond = llvm.mlir.constant(true) : i1
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^true, ^false llvm.cond_br %cond, ^true, ^false
|
||||
|
||||
^true: ^true:
|
||||
|
||||
@@ -317,9 +317,9 @@ def SPV_MergeOp : SPV_Op<"mlir.merge", [NoSideEffect, Terminator]> {
|
||||
let summary = "A special terminator for merging a structured selection/loop.";
|
||||
|
||||
let description = [{
|
||||
We use `spv.selection`/`spv.mlir.loop` for modelling structured selection/loop.
|
||||
We use `spv.mlir.selection`/`spv.mlir.loop` for modelling structured selection/loop.
|
||||
This op is a terminator used inside their regions to mean jumping to the
|
||||
merge point, which is the next op following the `spv.selection` or
|
||||
merge point, which is the next op following the `spv.mlir.selection` or
|
||||
`spv.mlir.loop` op. This op does not have a corresponding instruction in the
|
||||
SPIR-V binary format; it's solely for structural purpose.
|
||||
}];
|
||||
@@ -415,7 +415,7 @@ def SPV_ReturnValueOp : SPV_Op<"ReturnValue", [InFunctionScope, NoSideEffect,
|
||||
let assemblyFormat = "$value attr-dict `:` type($value)";
|
||||
}
|
||||
|
||||
def SPV_SelectionOp : SPV_Op<"selection", [InFunctionScope]> {
|
||||
def SPV_SelectionOp : SPV_Op<"mlir.selection", [InFunctionScope]> {
|
||||
let summary = "Define a structured selection.";
|
||||
|
||||
let description = [{
|
||||
@@ -429,10 +429,10 @@ def SPV_SelectionOp : SPV_Op<"selection", [InFunctionScope]> {
|
||||
Instead of having a `spv.SelectionMerge` op to directly model selection
|
||||
merge instruction for indicating the merge target, we use regions to delimit
|
||||
the boundary of the selection: the merge target is the next op following the
|
||||
`spv.selection` op. This way it's easier to discover all blocks belonging to
|
||||
`spv.mlir.selection` op. This way it's easier to discover all blocks belonging to
|
||||
the selection and it plays nicer with the MLIR system.
|
||||
|
||||
The `spv.selection` region should contain at least two blocks: one selection
|
||||
The `spv.mlir.selection` region should contain at least two blocks: one selection
|
||||
header block, and one selection merge. The selection header block should be
|
||||
the first block. The selection merge block should be the last block.
|
||||
The merge block should only contain a `spv.mlir.merge` op.
|
||||
@@ -456,9 +456,9 @@ def SPV_SelectionOp : SPV_Op<"selection", [InFunctionScope]> {
|
||||
/// Adds a selection merge block containing one spv.mlir.merge op.
|
||||
void addMergeBlock();
|
||||
|
||||
/// Creates a spv.selection op for `if (<condition>) then { <thenBody> }`
|
||||
/// Creates a spv.mlir.selection op for `if (<condition>) then { <thenBody> }`
|
||||
/// with `builder`. `builder`'s insertion point will remain at after the
|
||||
/// newly inserted spv.selection op afterwards.
|
||||
/// newly inserted spv.mlir.selection op afterwards.
|
||||
static SelectionOp createIfThen(
|
||||
Location loc, Value condition,
|
||||
function_ref<void(OpBuilder &builder)> thenBody,
|
||||
|
||||
@@ -27,8 +27,8 @@ using namespace mlir;
|
||||
namespace mlir {
|
||||
struct ScfToSPIRVContextImpl {
|
||||
// Map between the spirv region control flow operation (spv.mlir.loop or
|
||||
// spv.selection) to the VariableOp created to store the region results. The
|
||||
// order of the VariableOp matches the order of the results.
|
||||
// spv.mlir.selection) to the VariableOp created to store the region results.
|
||||
// The order of the VariableOp matches the order of the results.
|
||||
DenseMap<Operation *, SmallVector<spirv::VariableOp, 8>> outputVars;
|
||||
};
|
||||
} // namespace mlir
|
||||
@@ -111,8 +111,9 @@ public:
|
||||
|
||||
/// Helper function to replaces SCF op outputs with SPIR-V variable loads.
|
||||
/// We create VariableOp to handle the results value of the control flow region.
|
||||
/// spv.mlir.loop/spv.selection currently don't yield value. Right after the
|
||||
/// loop we load the value from the allocation and use it as the SCF op result.
|
||||
/// spv.mlir.loop/spv.mlir.selection currently don't yield value. Right after
|
||||
/// the loop we load the value from the allocation and use it as the SCF op
|
||||
/// result.
|
||||
template <typename ScfOp, typename OpTy>
|
||||
static void replaceSCFOutputValue(ScfOp scfOp, OpTy newOp,
|
||||
ConversionPatternRewriter &rewriter,
|
||||
@@ -237,7 +238,8 @@ IfOpConversion::matchAndRewrite(scf::IfOp ifOp, ArrayRef<Value> operands,
|
||||
scf::IfOpAdaptor ifOperands(operands);
|
||||
auto loc = ifOp.getLoc();
|
||||
|
||||
// Create `spv.selection` operation, selection header block and merge block.
|
||||
// Create `spv.mlir.selection` operation, selection header block and merge
|
||||
// block.
|
||||
auto selectionControl = rewriter.getI32IntegerAttr(
|
||||
static_cast<uint32_t>(spirv::SelectionControl::None));
|
||||
auto selectionOp = rewriter.create<spirv::SelectionOp>(loc, selectionControl);
|
||||
|
||||
@@ -1073,8 +1073,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// Converts `spv.selection` with `spv.BranchConditional` in its header block.
|
||||
/// All blocks within selection should be reachable for conversion to succeed.
|
||||
/// Converts `spv.mlir.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;
|
||||
@@ -1088,9 +1089,9 @@ public:
|
||||
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
|
||||
// `spv.mlir.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);
|
||||
@@ -1099,8 +1100,8 @@ public:
|
||||
|
||||
Location loc = op.getLoc();
|
||||
|
||||
// Split the current block after `spv.selection`. The remaining ops will be
|
||||
// used in `continueBlock`.
|
||||
// Split the current block after `spv.mlir.selection`. The remaining ops
|
||||
// will be used in `continueBlock`.
|
||||
auto *currentBlock = rewriter.getInsertionBlock();
|
||||
rewriter.setInsertionPointAfter(op);
|
||||
auto position = rewriter.getInsertionPoint();
|
||||
|
||||
@@ -257,12 +257,12 @@ OpFoldResult spirv::LogicalOrOp::fold(ArrayRef<Attribute> operands) {
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// spv.selection
|
||||
// spv.mlir.selection
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
// Blocks from the given `spv.selection` operation must satisfy the following
|
||||
// layout:
|
||||
// Blocks from the given `spv.mlir.selection` operation must satisfy the
|
||||
// following layout:
|
||||
//
|
||||
// +-----------------------------------------------+
|
||||
// | header block |
|
||||
@@ -294,7 +294,7 @@ struct ConvertSelectionOpToSelect
|
||||
PatternRewriter &rewriter) const override {
|
||||
auto *op = selectionOp.getOperation();
|
||||
auto &body = op->getRegion(0);
|
||||
// Verifier allows an empty region for `spv.selection`.
|
||||
// Verifier allows an empty region for `spv.mlir.selection`.
|
||||
if (body.empty()) {
|
||||
return failure();
|
||||
}
|
||||
@@ -332,7 +332,7 @@ struct ConvertSelectionOpToSelect
|
||||
rewriter.create<spirv::StoreOp>(selectOp.getLoc(), ptrValue,
|
||||
selectOp.getResult(), storeOpAttributes);
|
||||
|
||||
// `spv.selection` is not needed anymore.
|
||||
// `spv.mlir.selection` is not needed anymore.
|
||||
rewriter.eraseOp(op);
|
||||
return success();
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ struct SPIRVInlinerInterface : public DialectInlinerInterface {
|
||||
/// 'dest' that is attached to an operation registered to the current dialect.
|
||||
bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned,
|
||||
BlockAndValueMapping &) const final {
|
||||
// Return true here when inlining into spv.func, spv.selection, and
|
||||
// Return true here when inlining into spv.func, spv.mlir.selection, and
|
||||
// spv.mlir.loop operations.
|
||||
auto *op = dest->getParentOp();
|
||||
return isa<spirv::FuncOp, spirv::SelectionOp, spirv::LoopOp>(op);
|
||||
|
||||
@@ -2463,12 +2463,12 @@ static LogicalResult verify(spirv::MergeOp mergeOp) {
|
||||
auto *parentOp = mergeOp->getParentOp();
|
||||
if (!parentOp || !isa<spirv::SelectionOp, spirv::LoopOp>(parentOp))
|
||||
return mergeOp.emitOpError(
|
||||
"expected parent op to be 'spv.selection' or 'spv.mlir.loop'");
|
||||
"expected parent op to be 'spv.mlir.selection' or 'spv.mlir.loop'");
|
||||
|
||||
Block &parentLastBlock = mergeOp->getParentRegion()->back();
|
||||
if (mergeOp.getOperation() != parentLastBlock.getTerminator())
|
||||
return mergeOp.emitOpError("can only be used in the last block of "
|
||||
"'spv.selection' or 'spv.mlir.loop'");
|
||||
"'spv.mlir.selection' or 'spv.mlir.loop'");
|
||||
return success();
|
||||
}
|
||||
|
||||
@@ -2696,7 +2696,7 @@ static LogicalResult verify(spirv::SelectOp op) {
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// spv.selection
|
||||
// spv.mlir.selection
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static ParseResult parseSelectionOp(OpAsmParser &parser,
|
||||
|
||||
@@ -470,7 +470,7 @@ spirv::Deserializer::processFunctionEnd(ArrayRef<uint32_t> operands) {
|
||||
}
|
||||
|
||||
// Wire up block arguments from OpPhi instructions.
|
||||
// Put all structured control flow in spv.selection/spv.mlir.loop ops.
|
||||
// Put all structured control flow in spv.mlir.selection/spv.mlir.loop ops.
|
||||
if (failed(wireUpBlockArgument()) || failed(structurizeControlFlow())) {
|
||||
return failure();
|
||||
}
|
||||
@@ -1413,9 +1413,9 @@ Block *spirv::Deserializer::getOrCreateBlock(uint32_t id) {
|
||||
return block;
|
||||
}
|
||||
|
||||
// We don't know where this block will be placed finally (in a spv.selection
|
||||
// or spv.mlir.loop or function). Create it into the function for now and sort
|
||||
// out the proper place later.
|
||||
// We don't know where this block will be placed finally (in a
|
||||
// spv.mlir.selection or spv.mlir.loop or function). Create it into the
|
||||
// function for now and sort out the proper place later.
|
||||
auto *block = curFunction->addBlock();
|
||||
LLVM_DEBUG(llvm::dbgs() << "[block] created block for id = " << id << " @ "
|
||||
<< block << "\n");
|
||||
@@ -1584,7 +1584,7 @@ LogicalResult spirv::Deserializer::processPhi(ArrayRef<uint32_t> operands) {
|
||||
|
||||
namespace {
|
||||
/// A class for putting all blocks in a structured selection/loop in a
|
||||
/// spv.selection/spv.mlir.loop op.
|
||||
/// spv.mlir.selection/spv.mlir.loop op.
|
||||
class ControlFlowStructurizer {
|
||||
public:
|
||||
/// Structurizes the loop at the given `headerBlock`.
|
||||
@@ -1610,7 +1610,7 @@ private:
|
||||
: location(loc), control(control), blockMergeInfo(mergeInfo),
|
||||
headerBlock(header), mergeBlock(merge), continueBlock(cont) {}
|
||||
|
||||
/// Creates a new spv.selection op at the beginning of the `mergeBlock`.
|
||||
/// Creates a new spv.mlir.selection op at the beginning of the `mergeBlock`.
|
||||
spirv::SelectionOp createSelectionOp(uint32_t selectionControl);
|
||||
|
||||
/// Creates a new spv.mlir.loop op at the beginning of the `mergeBlock`.
|
||||
@@ -1628,7 +1628,7 @@ private:
|
||||
|
||||
Block *headerBlock;
|
||||
Block *mergeBlock;
|
||||
Block *continueBlock; // nullptr for spv.selection
|
||||
Block *continueBlock; // nullptr for spv.mlir.selection
|
||||
|
||||
llvm::SetVector<Block *> constructBlocks;
|
||||
};
|
||||
|
||||
@@ -45,11 +45,11 @@ namespace spirv {
|
||||
/// A struct for containing a header block's merge and continue targets.
|
||||
///
|
||||
/// This struct is used to track original structured control flow info from
|
||||
/// SPIR-V blob. This info will be used to create spv.selection/spv.mlir.loop
|
||||
/// later.
|
||||
/// SPIR-V blob. This info will be used to create
|
||||
/// spv.mlir.selection/spv.mlir.loop later.
|
||||
struct BlockMergeInfo {
|
||||
Block *mergeBlock;
|
||||
Block *continueBlock; // nullptr for spv.selection
|
||||
Block *continueBlock; // nullptr for spv.mlir.selection
|
||||
Location loc;
|
||||
uint32_t control;
|
||||
|
||||
@@ -346,9 +346,9 @@ private:
|
||||
|
||||
// In SPIR-V, structured control flow is explicitly declared using merge
|
||||
// instructions (OpSelectionMerge and OpLoopMerge). In the SPIR-V dialect,
|
||||
// we use spv.selection and spv.mlir.loop to group structured control flow.
|
||||
// The deserializer need to turn structured control flow marked with merge
|
||||
// instructions into using spv.selection/spv.mlir.loop ops.
|
||||
// we use spv.mlir.selection and spv.mlir.loop to group structured control
|
||||
// flow. The deserializer need to turn structured control flow marked with
|
||||
// merge instructions into using spv.mlir.selection/spv.mlir.loop ops.
|
||||
//
|
||||
// Because structured control flow can nest and the basic block order have
|
||||
// flexibility, we cannot isolate a structured selection/loop without
|
||||
@@ -360,12 +360,14 @@ private:
|
||||
// target blocks.
|
||||
// 2. For each selection/loop header block, recursively get all basic blocks
|
||||
// reachable (except the merge block) and put them in a newly created
|
||||
// spv.selection/spv.mlir.loop's region. Structured control flow guarantees
|
||||
// that we enter and exit in structured ways and the construct is nestable.
|
||||
// 3. Put the new spv.selection/spv.mlir.loop op at the beginning of the old
|
||||
// merge
|
||||
// spv.mlir.selection/spv.mlir.loop's region. Structured control flow
|
||||
// guarantees that we enter and exit in structured ways and the construct
|
||||
// is nestable.
|
||||
// 3. Put the new spv.mlir.selection/spv.mlir.loop op at the beginning of the
|
||||
// old merge
|
||||
// block and redirect all branches to the old header block to the old
|
||||
// merge block (which contains the spv.selection/spv.mlir.loop op now).
|
||||
// merge block (which contains the spv.mlir.selection/spv.mlir.loop op
|
||||
// now).
|
||||
|
||||
/// For OpPhi instructions, we use block arguments to represent them. OpPhi
|
||||
/// encodes a list of (value, predecessor) pairs. At the time of handling the
|
||||
@@ -411,7 +413,7 @@ private:
|
||||
LogicalResult wireUpBlockArgument();
|
||||
|
||||
/// Extracts blocks belonging to a structured selection/loop into a
|
||||
/// spv.selection/spv.mlir.loop op. This method iterates until all blocks
|
||||
/// spv.mlir.selection/spv.mlir.loop op. This method iterates until all blocks
|
||||
/// declared as selection/loop headers are handled.
|
||||
LogicalResult structurizeControlFlow();
|
||||
|
||||
|
||||
@@ -400,9 +400,9 @@ LogicalResult Serializer::processSelectionOp(spirv::SelectionOp selectionOp) {
|
||||
// For structured selection, we cannot have blocks in the selection construct
|
||||
// branching to the selection header block. Entering the selection (and
|
||||
// reaching the selection header) must be from the block containing the
|
||||
// spv.selection op. If there are ops ahead of the spv.selection op in the
|
||||
// block, we can "merge" them into the selection header. So here we don't need
|
||||
// to emit a separate block; just continue with the existing block.
|
||||
// spv.mlir.selection op. If there are ops ahead of the spv.mlir.selection op
|
||||
// in the block, we can "merge" them into the selection header. So here we
|
||||
// don't need to emit a separate block; just continue with the existing block.
|
||||
if (failed(processBlock(headerBlock, /*omitLabel=*/true, emitSelectionMerge)))
|
||||
return failure();
|
||||
|
||||
|
||||
@@ -966,9 +966,9 @@ LogicalResult Serializer::emitPhiForBlockArguments(Block *block) {
|
||||
// structure. It does not directly map to the incoming parent block for the
|
||||
// OpPhi instructions at SPIR-V binary level. This is because structured
|
||||
// control flow ops are serialized to multiple SPIR-V blocks. If there is a
|
||||
// spv.selection/spv.mlir.loop op in the MLIR predecessor block, the branch
|
||||
// op jumping to the OpPhi's block then resides in the previous structured
|
||||
// control flow op's merge block.
|
||||
// spv.mlir.selection/spv.mlir.loop op in the MLIR predecessor block, the
|
||||
// branch op jumping to the OpPhi's block then resides in the previous
|
||||
// structured control flow op's merge block.
|
||||
predecessor = getPhiIncomingBlock(predecessor);
|
||||
if (auto branchOp = dyn_cast<spirv::BranchOp>(terminator)) {
|
||||
predecessors.emplace_back(predecessor, branchOp.operand_begin());
|
||||
|
||||
@@ -34,7 +34,7 @@ module attributes {
|
||||
// CHECK: %[[OUTPTR:.+]] = spv.AccessChain %[[OUTPUT]][%[[ZERO]], %[[ZERO]]]
|
||||
// CHECK: %[[ELECT:.+]] = spv.GroupNonUniformElect Subgroup : i1
|
||||
|
||||
// CHECK: spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
// CHECK: spv.BranchConditional %[[ELECT]], ^bb1, ^bb2
|
||||
// CHECK: ^bb1:
|
||||
// CHECK: spv.AtomicIAdd "Device" "AcquireRelease" %[[OUTPTR]], %[[ADD]]
|
||||
|
||||
@@ -10,7 +10,7 @@ func @kernel_simple_selection(%arg2 : memref<10xf32>, %arg3 : i1) {
|
||||
%value = constant 0.0 : f32
|
||||
%i = constant 0 : index
|
||||
|
||||
// CHECK: spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
// CHECK-NEXT: spv.BranchConditional {{%.*}}, [[TRUE:\^.*]], [[MERGE:\^.*]]
|
||||
// CHECK-NEXT: [[TRUE]]:
|
||||
// CHECK: spv.Branch [[MERGE]]
|
||||
@@ -30,10 +30,10 @@ func @kernel_nested_selection(%arg3 : memref<10xf32>, %arg4 : memref<10xf32>, %a
|
||||
%i = constant 0 : index
|
||||
%j = constant 9 : index
|
||||
|
||||
// CHECK: spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
// CHECK-NEXT: spv.BranchConditional {{%.*}}, [[TRUE_TOP:\^.*]], [[FALSE_TOP:\^.*]]
|
||||
// CHECK-NEXT: [[TRUE_TOP]]:
|
||||
// CHECK-NEXT: spv.selection {
|
||||
// CHECK-NEXT: spv.mlir.selection {
|
||||
// CHECK-NEXT: spv.BranchConditional {{%.*}}, [[TRUE_NESTED_TRUE_PATH:\^.*]], [[FALSE_NESTED_TRUE_PATH:\^.*]]
|
||||
// CHECK-NEXT: [[TRUE_NESTED_TRUE_PATH]]:
|
||||
// CHECK: spv.Branch [[MERGE_NESTED_TRUE_PATH:\^.*]]
|
||||
@@ -44,7 +44,7 @@ func @kernel_nested_selection(%arg3 : memref<10xf32>, %arg4 : memref<10xf32>, %a
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: spv.Branch [[MERGE_TOP:\^.*]]
|
||||
// CHECK-NEXT: [[FALSE_TOP]]:
|
||||
// CHECK-NEXT: spv.selection {
|
||||
// CHECK-NEXT: spv.mlir.selection {
|
||||
// CHECK-NEXT: spv.BranchConditional {{%.*}}, [[TRUE_NESTED_FALSE_PATH:\^.*]], [[FALSE_NESTED_FALSE_PATH:\^.*]]
|
||||
// CHECK-NEXT: [[TRUE_NESTED_FALSE_PATH]]:
|
||||
// CHECK: spv.Branch [[MERGE_NESTED_FALSE_PATH:\^.*]]
|
||||
@@ -83,7 +83,7 @@ func @kernel_nested_selection(%arg3 : memref<10xf32>, %arg4 : memref<10xf32>, %a
|
||||
func @simple_if_yield(%arg2 : memref<10xf32>, %arg3 : i1) {
|
||||
// CHECK: %[[VAR1:.*]] = spv.Variable : !spv.ptr<f32, Function>
|
||||
// CHECK: %[[VAR2:.*]] = spv.Variable : !spv.ptr<f32, Function>
|
||||
// CHECK: spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
// CHECK-NEXT: spv.BranchConditional {{%.*}}, [[TRUE:\^.*]], [[FALSE:\^.*]]
|
||||
// CHECK-NEXT: [[TRUE]]:
|
||||
// CHECK: %[[RET1TRUE:.*]] = spv.Constant 0.000000e+00 : f32
|
||||
@@ -127,7 +127,7 @@ func @simple_if_yield(%arg2 : memref<10xf32>, %arg3 : i1) {
|
||||
func @simple_if_yield_type_change(%arg2 : memref<10xf32>, %arg3 : memref<10xf32>, %arg4 : i1) {
|
||||
// CHECK-LABEL: @simple_if_yield_type_change
|
||||
// CHECK: %[[VAR:.*]] = spv.Variable : !spv.ptr<!spv.ptr<!spv.struct<(!spv.array<10 x f32, stride=4> [0])>, StorageBuffer>, Function>
|
||||
// CHECK: spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
// CHECK-NEXT: spv.BranchConditional {{%.*}}, [[TRUE:\^.*]], [[FALSE:\^.*]]
|
||||
// CHECK-NEXT: [[TRUE]]:
|
||||
// CHECK: spv.Store "Function" %[[VAR]], {{%.*}} : !spv.ptr<!spv.struct<(!spv.array<10 x f32, stride=4> [0])>, StorageBuffer>
|
||||
|
||||
@@ -121,13 +121,13 @@ spv.module Logical GLSL450 {
|
||||
// -----
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// spv.selection
|
||||
// spv.mlir.selection
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
spv.module Logical GLSL450 {
|
||||
spv.func @selection_empty() -> () "None" {
|
||||
// CHECK: llvm.return
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
}
|
||||
spv.Return
|
||||
}
|
||||
@@ -135,7 +135,7 @@ spv.module Logical GLSL450 {
|
||||
spv.func @selection_with_merge_block_only() -> () "None" {
|
||||
%cond = spv.Constant true
|
||||
// CHECK: llvm.return
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^merge, ^merge
|
||||
^merge:
|
||||
spv.mlir.merge
|
||||
@@ -147,7 +147,7 @@ spv.module Logical GLSL450 {
|
||||
// CHECK: %[[COND:.*]] = llvm.mlir.constant(true) : i1
|
||||
%cond = spv.Constant true
|
||||
// CHECK: llvm.cond_br %[[COND]], ^bb1, ^bb2
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^true, ^merge
|
||||
// CHECK: ^bb1:
|
||||
^true:
|
||||
@@ -167,7 +167,7 @@ spv.module Logical GLSL450 {
|
||||
// CHECK: %[[COND:.*]] = llvm.mlir.constant(true) : i1
|
||||
%cond = spv.Constant true
|
||||
// CHECK: llvm.cond_br %[[COND]], ^bb1, ^bb2
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^true, ^false
|
||||
// CHECK: ^bb1:
|
||||
^true:
|
||||
@@ -191,7 +191,7 @@ spv.module Logical GLSL450 {
|
||||
// CHECK: %[[ZERO:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
%0 = spv.Constant 0 : i32
|
||||
// CHECK: llvm.cond_br %{{.*}}, ^bb1(%[[ZERO]] : i32), ^bb2
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %arg0, ^true(%0 : i32), ^merge
|
||||
// CHECK: ^bb1(%[[ARG:.*]]: i32):
|
||||
^true(%arg1: i32):
|
||||
|
||||
@@ -431,7 +431,7 @@ func @only_entry_and_continue_branch_to_header() -> () {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
func @merge() -> () {
|
||||
// expected-error @+1 {{expected parent op to be 'spv.selection' or 'spv.mlir.loop'}}
|
||||
// expected-error @+1 {{expected parent op to be 'spv.mlir.selection' or 'spv.mlir.loop'}}
|
||||
spv.mlir.merge
|
||||
}
|
||||
|
||||
@@ -442,12 +442,12 @@ func @only_allowed_in_last_block(%cond : i1) -> () {
|
||||
%one = spv.Constant 1: i32
|
||||
%var = spv.Variable init(%zero) : !spv.ptr<i32, Function>
|
||||
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^merge
|
||||
|
||||
^then:
|
||||
spv.Store "Function" %var, %one : i32
|
||||
// expected-error @+1 {{can only be used in the last block of 'spv.selection' or 'spv.mlir.loop'}}
|
||||
// expected-error @+1 {{can only be used in the last block of 'spv.mlir.selection' or 'spv.mlir.loop'}}
|
||||
spv.mlir.merge
|
||||
|
||||
^merge:
|
||||
@@ -466,7 +466,7 @@ func @only_allowed_in_last_block() -> () {
|
||||
^header:
|
||||
spv.BranchConditional %true, ^body, ^merge
|
||||
^body:
|
||||
// expected-error @+1 {{can only be used in the last block of 'spv.selection' or 'spv.mlir.loop'}}
|
||||
// expected-error @+1 {{can only be used in the last block of 'spv.mlir.selection' or 'spv.mlir.loop'}}
|
||||
spv.mlir.merge
|
||||
^continue:
|
||||
spv.Branch ^header
|
||||
@@ -484,7 +484,7 @@ func @only_allowed_in_last_block() -> () {
|
||||
|
||||
// CHECK-LABEL: func @in_selection
|
||||
func @in_selection(%cond : i1) -> () {
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^merge
|
||||
^then:
|
||||
// CHECK: spv.Return
|
||||
@@ -539,7 +539,7 @@ spv.module Logical GLSL450 {
|
||||
|
||||
spv.module Logical GLSL450 {
|
||||
spv.func @in_nested_region(%cond: i1) -> (i32) "None" {
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^merge
|
||||
^then:
|
||||
// expected-error @+1 {{cannot be used in functions returning value}}
|
||||
@@ -567,7 +567,7 @@ func @ret_val() -> (i32) {
|
||||
|
||||
// CHECK-LABEL: func @in_selection
|
||||
func @in_selection(%cond : i1) -> (i32) {
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^merge
|
||||
^then:
|
||||
%zero = spv.Constant 0 : i32
|
||||
@@ -637,7 +637,7 @@ spv.module Logical GLSL450 {
|
||||
|
||||
spv.module Logical GLSL450 {
|
||||
spv.func @in_nested_region(%cond: i1) -> () "None" {
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^merge
|
||||
^then:
|
||||
%cst = spv.Constant 0: i32
|
||||
@@ -654,7 +654,7 @@ spv.module Logical GLSL450 {
|
||||
// -----
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// spv.selection
|
||||
// spv.mlir.selection
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
func @selection(%cond: i1) -> () {
|
||||
@@ -662,8 +662,8 @@ func @selection(%cond: i1) -> () {
|
||||
%one = spv.Constant 1: i32
|
||||
%var = spv.Variable init(%zero) : !spv.ptr<i32, Function>
|
||||
|
||||
// CHECK: spv.selection {
|
||||
spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
spv.mlir.selection {
|
||||
// CHECK-NEXT: spv.BranchConditional %{{.*}}, ^bb1, ^bb2
|
||||
spv.BranchConditional %cond, ^then, ^merge
|
||||
|
||||
@@ -690,8 +690,8 @@ func @selection(%cond: i1) -> () {
|
||||
%two = spv.Constant 2: i32
|
||||
%var = spv.Variable init(%zero) : !spv.ptr<i32, Function>
|
||||
|
||||
// CHECK: spv.selection {
|
||||
spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
spv.mlir.selection {
|
||||
// CHECK-NEXT: spv.BranchConditional %{{.*}}, ^bb1, ^bb2
|
||||
spv.BranchConditional %cond, ^then, ^else
|
||||
|
||||
@@ -720,8 +720,8 @@ func @selection(%cond: i1) -> () {
|
||||
|
||||
// CHECK-LABEL: @empty_region
|
||||
func @empty_region() -> () {
|
||||
// CHECK: spv.selection
|
||||
spv.selection {
|
||||
// CHECK: spv.mlir.selection
|
||||
spv.mlir.selection {
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -730,8 +730,8 @@ func @empty_region() -> () {
|
||||
|
||||
// CHECK-LABEL: @selection_with_control
|
||||
func @selection_with_control() -> () {
|
||||
// CHECK: spv.selection control(Flatten)
|
||||
spv.selection control(Flatten) {
|
||||
// CHECK: spv.mlir.selection control(Flatten)
|
||||
spv.mlir.selection control(Flatten) {
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -740,7 +740,7 @@ func @selection_with_control() -> () {
|
||||
|
||||
func @wrong_merge_block() -> () {
|
||||
// expected-error @+1 {{last block must be the merge block with only one 'spv.mlir.merge' op}}
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.Return
|
||||
}
|
||||
return
|
||||
@@ -750,7 +750,7 @@ func @wrong_merge_block() -> () {
|
||||
|
||||
func @missing_entry_block() -> () {
|
||||
// expected-error @+1 {{must have a selection header block}}
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.mlir.merge
|
||||
}
|
||||
return
|
||||
|
||||
@@ -480,7 +480,7 @@ func @convert_logical_or_true_false_vector(%arg: vector<3xi1>) -> (vector<3xi1>,
|
||||
// -----
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// spv.selection
|
||||
// spv.mlir.selection
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
func @canonicalize_selection_op_scalar_type(%cond: i1) -> () {
|
||||
@@ -495,7 +495,7 @@ func @canonicalize_selection_op_scalar_type(%cond: i1) -> () {
|
||||
// CHECK: %[[SRC_VALUE:.*]] = spv.Select {{%.*}}, %[[TRUE_VALUE]], %[[FALSE_VALUE]] : i1, i32
|
||||
// CHECK-NEXT: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE]] ["Aligned", 4] : i32
|
||||
// CHECK-NEXT: spv.Return
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^else
|
||||
|
||||
^else:
|
||||
@@ -526,7 +526,7 @@ func @canonicalize_selection_op_vector_type(%cond: i1) -> () {
|
||||
// CHECK: %[[SRC_VALUE:.*]] = spv.Select {{%.*}}, %[[TRUE_VALUE]], %[[FALSE_VALUE]] : i1, vector<3xi32>
|
||||
// CHECK-NEXT: spv.Store "Function" %[[DST_VAR]], %[[SRC_VALUE]] ["Aligned", 8] : vector<3xi32>
|
||||
// CHECK-NEXT: spv.Return
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^else
|
||||
|
||||
^then:
|
||||
@@ -557,8 +557,8 @@ func @cannot_canonicalize_selection_op_0(%cond: i1) -> () {
|
||||
// CHECK: %[[DST_VAR_1:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
|
||||
%4 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
|
||||
|
||||
// CHECK: spv.selection {
|
||||
spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
spv.mlir.selection {
|
||||
// CHECK: spv.BranchConditional
|
||||
// CHECK-SAME: ^bb1(%[[DST_VAR_0]], %[[SRC_VALUE_0]]
|
||||
// CHECK-SAME: ^bb1(%[[DST_VAR_1]], %[[SRC_VALUE_1]]
|
||||
@@ -594,8 +594,8 @@ func @cannot_canonicalize_selection_op_1(%cond: i1) -> () {
|
||||
// CHECK: %[[DST_VAR_1:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
|
||||
%4 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
|
||||
|
||||
// CHECK: spv.selection {
|
||||
spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^else
|
||||
|
||||
^then:
|
||||
@@ -628,8 +628,8 @@ func @cannot_canonicalize_selection_op_2(%cond: i1) -> () {
|
||||
// CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
|
||||
%3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
|
||||
|
||||
// CHECK: spv.selection {
|
||||
spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^else
|
||||
|
||||
^then:
|
||||
@@ -660,8 +660,8 @@ func @cannot_canonicalize_selection_op_3(%cond: i1) -> () {
|
||||
// CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
|
||||
%3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
|
||||
|
||||
// CHECK: spv.selection {
|
||||
spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^else
|
||||
|
||||
^then:
|
||||
@@ -692,8 +692,8 @@ func @cannot_canonicalize_selection_op_4(%cond: i1) -> () {
|
||||
// CHECK: %[[DST_VAR:.*]] = spv.Variable init({{%.*}}) : !spv.ptr<vector<3xi32>, Function>
|
||||
%3 = spv.Variable init(%0) : !spv.ptr<vector<3xi32>, Function>
|
||||
|
||||
// CHECK: spv.selection {
|
||||
spv.selection {
|
||||
// CHECK: spv.mlir.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^else
|
||||
|
||||
^then:
|
||||
|
||||
@@ -69,7 +69,7 @@ spv.module Logical GLSL450 {
|
||||
|
||||
spv.module Logical GLSL450 {
|
||||
spv.func @callee(%cond : i1) -> () "None" {
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^merge
|
||||
^then:
|
||||
spv.Return
|
||||
@@ -92,7 +92,7 @@ spv.module Logical GLSL450 {
|
||||
|
||||
spv.module Logical GLSL450 {
|
||||
spv.func @callee(%cond : i1) -> () "None" {
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %cond, ^then, ^merge
|
||||
^then:
|
||||
spv.Branch ^merge
|
||||
@@ -106,7 +106,7 @@ spv.module Logical GLSL450 {
|
||||
spv.func @calling_selection_no_ret_func() "None" {
|
||||
// CHECK-NEXT: %[[TRUE:.*]] = spv.Constant true
|
||||
%0 = spv.Constant true
|
||||
// CHECK-NEXT: spv.selection
|
||||
// CHECK-NEXT: spv.mlir.selection
|
||||
// CHECK-NEXT: spv.BranchConditional %[[TRUE]], ^bb1, ^bb2
|
||||
// CHECK-NEXT: ^bb1:
|
||||
// CHECK-NEXT: spv.Branch ^bb2
|
||||
@@ -199,8 +199,8 @@ spv.module Logical GLSL450 {
|
||||
%4 = spv.AccessChain %2[%1] : !spv.ptr<!spv.struct<(i32 [0])>, StorageBuffer>, i32
|
||||
%5 = spv.Load "StorageBuffer" %4 : i32
|
||||
%6 = spv.SGreaterThan %5, %1 : i32
|
||||
// CHECK: spv.selection
|
||||
spv.selection {
|
||||
// CHECK: spv.mlir.selection
|
||||
spv.mlir.selection {
|
||||
spv.BranchConditional %6, ^bb1, ^bb2
|
||||
^bb1: // pred: ^bb0
|
||||
// CHECK: [[STOREPTR:%.*]] = spv.AccessChain [[ADDRESS_ARG1]]
|
||||
|
||||
@@ -125,7 +125,7 @@ spv.module Logical GLSL450 requires #spv.vce<v1.0, [Shader], []> {
|
||||
%one = spv.Constant 1: i32
|
||||
%two = spv.Constant 2: i32
|
||||
%var = spv.Variable init(%zero) : !spv.ptr<i32, Function>
|
||||
spv.selection {
|
||||
spv.mlir.selection {
|
||||
// CHECK: loc({{".*debug.mlir"}}:128:5)
|
||||
spv.BranchConditional %cond [5, 10], ^then, ^else
|
||||
^then:
|
||||
|
||||
@@ -113,8 +113,8 @@ spv.module Logical GLSL450 requires #spv.vce<v1.0, [Shader], []> {
|
||||
spv.func @foo() -> () "None" {
|
||||
%var = spv.Variable : !spv.ptr<i32, Function>
|
||||
|
||||
// CHECK: spv.selection
|
||||
spv.selection {
|
||||
// CHECK: spv.mlir.selection
|
||||
spv.mlir.selection {
|
||||
%true = spv.Constant true
|
||||
// CHECK: spv.BranchConditional %{{.*}}, ^bb1, ^bb2
|
||||
spv.BranchConditional %true, ^true, ^false
|
||||
|
||||
@@ -11,10 +11,10 @@ spv.module Logical GLSL450 requires #spv.vce<v1.0, [Shader], []> {
|
||||
%two = spv.Constant 2: i32
|
||||
%var = spv.Variable init(%zero) : !spv.ptr<i32, Function>
|
||||
|
||||
// CHECK-NEXT: spv.selection control(Flatten)
|
||||
// CHECK-NEXT: spv.mlir.selection control(Flatten)
|
||||
// CHECK-NEXT: spv.Constant 0
|
||||
// CHECK-NEXT: spv.Variable
|
||||
spv.selection control(Flatten) {
|
||||
spv.mlir.selection control(Flatten) {
|
||||
// CHECK-NEXT: spv.BranchConditional %{{.*}} [5, 10], ^bb1, ^bb2
|
||||
spv.BranchConditional %cond [5, 10], ^then, ^else
|
||||
|
||||
@@ -60,8 +60,8 @@ spv.module Logical GLSL450 requires #spv.vce<v1.0, [Shader], []> {
|
||||
spv.func @selection(%cond: i1) -> (i32) "None" {
|
||||
// CHECK: spv.Branch ^bb1
|
||||
// CHECK-NEXT: ^bb1:
|
||||
// CHECK-NEXT: spv.selection
|
||||
spv.selection {
|
||||
// CHECK-NEXT: spv.mlir.selection
|
||||
spv.mlir.selection {
|
||||
// CHECK-NEXT: spv.BranchConditional %[[ARG]], ^bb1, ^bb2
|
||||
spv.BranchConditional %cond, ^then, ^merge
|
||||
|
||||
|
||||
Reference in New Issue
Block a user