Author: Brian Gesiak
Date: 2020-12-17T14:11:21-05:00
New Revision: 14f24155a5915a295bd965bb6062bfeab217b9c8
URL:
https://github.com/llvm/llvm-project/commit/14f24155a5915a295bd965bb6062bfeab217b9c8
DIFF:
https://github.com/llvm/llvm-project/commit/14f24155a5915a295bd965bb6062bfeab217b9c8.diff
LOG: [mlir][LLVMIR] Add 'llvm.switch' op
The LLVM IR 'switch' instruction allows control flow to be transferred
to one of any number of branches depending on an integer control value,
or a default value if the control does not match any branch values. This patch
adds `llvm.switch` to the MLIR LLVMIR dialect, as well as translation routines
for lowering it to LLVM IR.
To store a variable number of operands for a variable number of branch
destinations, the new op makes use of the `AttrSizedOperandSegments`
trait. It stores its default branch operands as one segment, and all
remaining case branches' operands as another. It also stores pairs of
begin and end offset values to delineate the sub-range of each case branch's
operands. There's probably a better way to implement this, since the
offset computation complicates several parts of the op definition. This is the
approach I settled on because in doing so I was able to delegate to the default
op builder member functions. However, it may be preferable to instead specify
`skipDefaultBuilders` in the op's ODS, or use a completely separate
approach; feedback is welcome!
Another contentious part of this patch may be the custom printer and
parser functions for the op. Ideally I would have liked the MLIR to be
printed in this way:
```
llvm.switch %0, ^bb1(%1 : !llvm.i32) [
1: ^bb2,
2: ^bb3(%2, %3 : !llvm.i32, !llvm.i32)
]
```
The above would resemble how LLVM IR is formatted for the 'switch'
instruction. But I found it difficult to print and parse something like
this, whether I used the declarative assembly format or custom functions.
I also was not sure a multi-line format would be welcome -- it seems
like most MLIR ops do not use newlines. Again, I'd be happy to hear any
feedback here as well, or on any other aspect of the patch.
Differential Revision: https://reviews.llvm.org/D93005
Added:
Modified:
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
mlir/test/Dialect/LLVMIR/invalid.mlir
mlir/test/Dialect/LLVMIR/roundtrip.mlir
mlir/test/Target/llvmir.mlir
Removed:
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 0088fe38246b..9608e15bb81a 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -635,6 +635,50 @@ def LLVM_UnreachableOp : LLVM_TerminatorOp<"unreachable",
[]> {
let printer = [{ p << getOperationName(); }];
}
+def LLVM_SwitchOp : LLVM_TerminatorOp<"switch",
+[AttrSizedOperandSegments, DeclareOpInterfaceMethods,
+ NoSideEffect]> {
+ let arguments = (ins LLVM_i32:$value,
+ Variadic:$defaultOperands,
+ Variadic:$caseOperands,
+ OptionalAttr:$case_values,
+ OptionalAttr:$case_operand_offsets,
+ OptionalAttr:$branch_weights);
+ let successors = (successor
+AnySuccessor:$defaultDestination,
+VariadicSuccessor:$caseDestinations);
+
+ let verifier = [{ return ::verify(*this); }];
+ let assemblyFormat = [{
+$value `,`
+$defaultDestination (`(` $defaultOperands^ `:` type($defaultOperands) `)`)?
+`[` `\n` custom($case_values, $caseDestinations,
+ $caseOperands, type($caseOperands),
+ $case_operand_offsets) `]`
+attr-dict
+ }];
+
+ let builders = [
+OpBuilderDAG<(ins "Value":$value,
+ "Block *":$defaultDestination,
+ "ValueRange":$defaultOperands,
+ CArg<"ArrayRef", "{}">:$caseValues,
+ CArg<"BlockRange", "{}">:$caseDestinations,
+ CArg<"ArrayRef", "{}">:$caseOperands,
+ CArg<"ArrayRef", "{}">:$branchWeights)>,
+LLVM_TerminatorPassthroughOpBuilder
+ ];
+
+ let extraClassDeclaration = [{
+/// Return the operands for the case destination block at the given index.
+OperandRange getCaseOperands(unsigned index);
+
+/// Return a mutable range of operands for the case destination block at
the
+/// given index.
+MutableOperandRange getCaseOperandsMutable(unsigned index);
+ }];
+}
+
// Auxiliary operations (do not appear in LLVM IR but necessary for the dialect
// to work correctly).
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index d70a327824b7..9b2c88c30a86 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/ml