[Mlir-commits] [mlir] 97f0ab7 - [mlir][emitc] Add 'emitc.switch' op to the dialect (#102331)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Aug 16 09:25:09 PDT 2024
Author: Andrey Timonin
Date: 2024-08-16T18:25:06+02:00
New Revision: 97f0ab71c002e8a14142be3a117b3091ab75c552
URL: https://github.com/llvm/llvm-project/commit/97f0ab71c002e8a14142be3a117b3091ab75c552
DIFF: https://github.com/llvm/llvm-project/commit/97f0ab71c002e8a14142be3a117b3091ab75c552.diff
LOG: [mlir][emitc] Add 'emitc.switch' op to the dialect (#102331)
This PR is continuation of the [previous
one](https://github.com/llvm/llvm-project/pull/101478). As a result, the
`emitc::SwitchOp` op was developed inspired by `scf::IndexSwitchOp`.
Main points of PR:
- Added the `emitc::SwitchOp` op to the EmitC dialect + CppEmitter
- Corresponding tests were added
- Conversion from the SCF dialect to the EmitC dialect for the op
Added:
mlir/test/Conversion/SCFToEmitC/switch.mlir
mlir/test/Target/Cpp/switch.mlir
Modified:
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp
mlir/lib/Dialect/EmitC/IR/EmitC.cpp
mlir/lib/Target/Cpp/TranslateToCpp.cpp
mlir/test/Dialect/EmitC/invalid_ops.mlir
mlir/test/Dialect/EmitC/ops.mlir
mlir/test/Target/Cpp/invalid.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index 16fa58ce47013d..40903b4e288ca6 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -1188,7 +1188,7 @@ def EmitC_AssignOp : EmitC_Op<"assign", []> {
}
def EmitC_YieldOp : EmitC_Op<"yield",
- [Pure, Terminator, ParentOneOf<["ExpressionOp", "IfOp", "ForOp"]>]> {
+ [Pure, Terminator, ParentOneOf<["ExpressionOp", "IfOp", "ForOp", "SwitchOp"]>]> {
let summary = "Block termination operation";
let description = [{
The `emitc.yield` terminates its parent EmitC op's region, optionally yielding
@@ -1302,5 +1302,87 @@ def EmitC_SubscriptOp : EmitC_Op<"subscript", []> {
let assemblyFormat = "$value `[` $indices `]` attr-dict `:` functional-type(operands, results)";
}
+def EmitC_SwitchOp : EmitC_Op<"switch", [RecursiveMemoryEffects,
+ SingleBlockImplicitTerminator<"emitc::YieldOp">,
+ DeclareOpInterfaceMethods<RegionBranchOpInterface,
+ ["getRegionInvocationBounds",
+ "getEntrySuccessorRegions"]>]> {
+ let summary = "Switch operation";
+ let description = [{
+ The `emitc.switch` is a control-flow operation that branches to one of
+ the given regions based on the values of the argument and the cases.
+ The operand to a switch operation is a opaque, integral or pointer
+ wide types.
+
+ The operation always has a "default" region and any number of case regions
+ denoted by integer constants. Control-flow transfers to the case region
+ whose constant value equals the value of the argument. If the argument does
+ not equal any of the case values, control-flow transfer to the "default"
+ region.
+
+ The operation does not return any value. Moreover, case regions must be
+ explicitly terminated using the `emitc.yield` operation. Default region is
+ yielded implicitly.
+
+ Example:
+
+ ```mlir
+ // Example:
+ emitc.switch %0 : i32
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ }
+ ```
+ ```c++
+ // Code emitted for the operations above.
+ switch (v1) {
+ case 2: {
+ int32_t v2 = func_b();
+ break;
+ }
+ case 5: {
+ int32_t v3 = func_a();
+ break;
+ }
+ default: {
+ float v4 = 4.200000000e+01f;
+ func2(v4);
+ break;
+ }
+ ```
+ }];
+
+ let arguments = (ins IntegerIndexOrOpaqueType:$arg, DenseI64ArrayAttr:$cases);
+ let results = (outs);
+ let regions = (region SizedRegion<1>:$defaultRegion,
+ VariadicRegion<SizedRegion<1>>:$caseRegions);
+
+ let assemblyFormat = [{
+ $arg `:` type($arg) attr-dict custom<SwitchCases>($cases, $caseRegions) `\n`
+ `` `default` $defaultRegion
+ }];
+
+ let extraClassDeclaration = [{
+ /// Get the number of cases.
+ unsigned getNumCases();
+
+ /// Get the default region body.
+ Block &getDefaultBlock();
+
+ /// Get the body of a case region.
+ Block &getCaseBlock(unsigned idx);
+ }];
+
+ let hasVerifier = 1;
+}
#endif // MLIR_DIALECT_EMITC_IR_EMITC
diff --git a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp
index 0a892422252554..ede811c6e1bb1e 100644
--- a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp
+++ b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp
@@ -94,6 +94,19 @@ static void lowerYield(SmallVector<Value> &resultVariables,
rewriter.eraseOp(yield);
}
+// Lower the contents of an scf::if/scf::index_switch regions to an
+// emitc::if/emitc::switch region. The contents of the lowering region is
+// moved into the respective lowered region, but the scf::yield is replaced not
+// only with an emitc::yield, but also with a sequence of emitc::assign ops that
+// set the yielded values into the result variables.
+static void lowerRegion(SmallVector<Value> &resultVariables,
+ PatternRewriter &rewriter, Region ®ion,
+ Region &loweredRegion) {
+ rewriter.inlineRegionBefore(region, loweredRegion, loweredRegion.end());
+ Operation *terminator = loweredRegion.back().getTerminator();
+ lowerYield(resultVariables, rewriter, cast<scf::YieldOp>(terminator));
+}
+
LogicalResult ForLowering::matchAndRewrite(ForOp forOp,
PatternRewriter &rewriter) const {
Location loc = forOp.getLoc();
@@ -145,18 +158,6 @@ LogicalResult IfLowering::matchAndRewrite(IfOp ifOp,
SmallVector<Value> resultVariables =
createVariablesForResults(ifOp, rewriter);
- // Utility function to lower the contents of an scf::if region to an emitc::if
- // region. The contents of the scf::if regions is moved into the respective
- // emitc::if regions, but the scf::yield is replaced not only with an
- // emitc::yield, but also with a sequence of emitc::assign ops that set the
- // yielded values into the result variables.
- auto lowerRegion = [&resultVariables, &rewriter](Region ®ion,
- Region &loweredRegion) {
- rewriter.inlineRegionBefore(region, loweredRegion, loweredRegion.end());
- Operation *terminator = loweredRegion.back().getTerminator();
- lowerYield(resultVariables, rewriter, cast<scf::YieldOp>(terminator));
- };
-
Region &thenRegion = ifOp.getThenRegion();
Region &elseRegion = ifOp.getElseRegion();
@@ -166,20 +167,59 @@ LogicalResult IfLowering::matchAndRewrite(IfOp ifOp,
rewriter.create<emitc::IfOp>(loc, ifOp.getCondition(), false, false);
Region &loweredThenRegion = loweredIf.getThenRegion();
- lowerRegion(thenRegion, loweredThenRegion);
+ lowerRegion(resultVariables, rewriter, thenRegion, loweredThenRegion);
if (hasElseBlock) {
Region &loweredElseRegion = loweredIf.getElseRegion();
- lowerRegion(elseRegion, loweredElseRegion);
+ lowerRegion(resultVariables, rewriter, elseRegion, loweredElseRegion);
}
rewriter.replaceOp(ifOp, resultVariables);
return success();
}
+// Lower scf::index_switch to emitc::switch, implementing result values as
+// emitc::variable's updated within the case and default regions.
+struct IndexSwitchOpLowering : public OpRewritePattern<IndexSwitchOp> {
+ using OpRewritePattern<IndexSwitchOp>::OpRewritePattern;
+
+ LogicalResult matchAndRewrite(IndexSwitchOp indexSwitchOp,
+ PatternRewriter &rewriter) const override;
+};
+
+LogicalResult
+IndexSwitchOpLowering::matchAndRewrite(IndexSwitchOp indexSwitchOp,
+ PatternRewriter &rewriter) const {
+ Location loc = indexSwitchOp.getLoc();
+
+ // Create an emitc::variable op for each result. These variables will be
+ // assigned to by emitc::assign ops within the case and default regions.
+ SmallVector<Value> resultVariables =
+ createVariablesForResults(indexSwitchOp, rewriter);
+
+ auto loweredSwitch = rewriter.create<emitc::SwitchOp>(
+ loc, indexSwitchOp.getArg(), indexSwitchOp.getCases(),
+ indexSwitchOp.getNumCases());
+
+ // Lowering all case regions.
+ for (auto pair : llvm::zip(indexSwitchOp.getCaseRegions(),
+ loweredSwitch.getCaseRegions())) {
+ lowerRegion(resultVariables, rewriter, std::get<0>(pair),
+ std::get<1>(pair));
+ }
+
+ // Lowering default region.
+ lowerRegion(resultVariables, rewriter, indexSwitchOp.getDefaultRegion(),
+ loweredSwitch.getDefaultRegion());
+
+ rewriter.replaceOp(indexSwitchOp, resultVariables);
+ return success();
+}
+
void mlir::populateSCFToEmitCConversionPatterns(RewritePatternSet &patterns) {
patterns.add<ForLowering>(patterns.getContext());
patterns.add<IfLowering>(patterns.getContext());
+ patterns.add<IndexSwitchOpLowering>(patterns.getContext());
}
void SCFToEmitCPass::runOnOperation() {
@@ -188,7 +228,7 @@ void SCFToEmitCPass::runOnOperation() {
// Configure conversion to lower out SCF operations.
ConversionTarget target(getContext());
- target.addIllegalOp<scf::ForOp, scf::IfOp>();
+ target.addIllegalOp<scf::ForOp, scf::IfOp, scf::IndexSwitchOp>();
target.markUnknownOpDynamicallyLegal([](Operation *) { return true; });
if (failed(
applyPartialConversion(getOperation(), target, std::move(patterns))))
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 70e3e728e01950..d731a6756ff630 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -1096,6 +1096,138 @@ GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
return success();
}
+//===----------------------------------------------------------------------===//
+// SwitchOp
+//===----------------------------------------------------------------------===//
+
+/// Parse the case regions and values.
+static ParseResult
+parseSwitchCases(OpAsmParser &parser, DenseI64ArrayAttr &cases,
+ SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) {
+ SmallVector<int64_t> caseValues;
+ while (succeeded(parser.parseOptionalKeyword("case"))) {
+ int64_t value;
+ Region ®ion = *caseRegions.emplace_back(std::make_unique<Region>());
+ if (parser.parseInteger(value) ||
+ parser.parseRegion(region, /*arguments=*/{}))
+ return failure();
+ caseValues.push_back(value);
+ }
+ cases = parser.getBuilder().getDenseI64ArrayAttr(caseValues);
+ return success();
+}
+
+/// Print the case regions and values.
+static void printSwitchCases(OpAsmPrinter &p, Operation *op,
+ DenseI64ArrayAttr cases, RegionRange caseRegions) {
+ for (auto [value, region] : llvm::zip(cases.asArrayRef(), caseRegions)) {
+ p.printNewline();
+ p << "case " << value << ' ';
+ p.printRegion(*region, /*printEntryBlockArgs=*/false);
+ }
+}
+
+static LogicalResult verifyRegion(emitc::SwitchOp op, Region ®ion,
+ const Twine &name) {
+ auto yield = dyn_cast<emitc::YieldOp>(region.front().back());
+ if (!yield)
+ return op.emitOpError("expected region to end with emitc.yield, but got ")
+ << region.front().back().getName();
+
+ if (yield.getNumOperands() != 0) {
+ return (op.emitOpError("expected each region to return ")
+ << "0 values, but " << name << " returns "
+ << yield.getNumOperands())
+ .attachNote(yield.getLoc())
+ << "see yield operation here";
+ }
+
+ return success();
+}
+
+LogicalResult emitc::SwitchOp::verify() {
+ if (!isIntegerIndexOrOpaqueType(getArg().getType()))
+ return emitOpError("unsupported type ") << getArg().getType();
+
+ if (getCases().size() != getCaseRegions().size()) {
+ return emitOpError("has ")
+ << getCaseRegions().size() << " case regions but "
+ << getCases().size() << " case values";
+ }
+
+ DenseSet<int64_t> valueSet;
+ for (int64_t value : getCases())
+ if (!valueSet.insert(value).second)
+ return emitOpError("has duplicate case value: ") << value;
+
+ if (failed(verifyRegion(*this, getDefaultRegion(), "default region")))
+ return failure();
+
+ for (auto [idx, caseRegion] : llvm::enumerate(getCaseRegions()))
+ if (failed(verifyRegion(*this, caseRegion, "case region #" + Twine(idx))))
+ return failure();
+
+ return success();
+}
+
+unsigned emitc::SwitchOp::getNumCases() { return getCases().size(); }
+
+Block &emitc::SwitchOp::getDefaultBlock() { return getDefaultRegion().front(); }
+
+Block &emitc::SwitchOp::getCaseBlock(unsigned idx) {
+ assert(idx < getNumCases() && "case index out-of-bounds");
+ return getCaseRegions()[idx].front();
+}
+
+void SwitchOp::getSuccessorRegions(
+ RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &successors) {
+ llvm::copy(getRegions(), std::back_inserter(successors));
+}
+
+void SwitchOp::getEntrySuccessorRegions(
+ ArrayRef<Attribute> operands,
+ SmallVectorImpl<RegionSuccessor> &successors) {
+ FoldAdaptor adaptor(operands, *this);
+
+ // If a constant was not provided, all regions are possible successors.
+ auto arg = dyn_cast_or_null<IntegerAttr>(adaptor.getArg());
+ if (!arg) {
+ llvm::copy(getRegions(), std::back_inserter(successors));
+ return;
+ }
+
+ // Otherwise, try to find a case with a matching value. If not, the
+ // default region is the only successor.
+ for (auto [caseValue, caseRegion] : llvm::zip(getCases(), getCaseRegions())) {
+ if (caseValue == arg.getInt()) {
+ successors.emplace_back(&caseRegion);
+ return;
+ }
+ }
+ successors.emplace_back(&getDefaultRegion());
+}
+
+void SwitchOp::getRegionInvocationBounds(
+ ArrayRef<Attribute> operands, SmallVectorImpl<InvocationBounds> &bounds) {
+ auto operandValue = llvm::dyn_cast_or_null<IntegerAttr>(operands.front());
+ if (!operandValue) {
+ // All regions are invoked at most once.
+ bounds.append(getNumRegions(), InvocationBounds(/*lb=*/0, /*ub=*/1));
+ return;
+ }
+
+ unsigned liveIndex = getNumRegions() - 1;
+ const auto *iteratorToInt = llvm::find(getCases(), operandValue.getInt());
+
+ liveIndex = iteratorToInt != getCases().end()
+ ? std::distance(getCases().begin(), iteratorToInt)
+ : liveIndex;
+
+ for (unsigned regIndex = 0, regNum = getNumRegions(); regIndex < regNum;
+ ++regIndex)
+ bounds.emplace_back(/*lb=*/0, /*ub=*/regIndex == liveIndex);
+}
+
//===----------------------------------------------------------------------===//
// TableGen'd op method definitions
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 1dadb9dd691e70..8e112e6f7dda65 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -449,6 +449,43 @@ static LogicalResult printOperation(CppEmitter &emitter, emitc::SubOp subOp) {
return printBinaryOperation(emitter, operation, "-");
}
+static LogicalResult emitSwitchCase(CppEmitter &emitter,
+ raw_indented_ostream &os, Region ®ion) {
+ for (Region::OpIterator iteratorOp = region.op_begin(), end = region.op_end();
+ std::next(iteratorOp) != end; ++iteratorOp) {
+ if (failed(emitter.emitOperation(*iteratorOp, /*trailingSemicolon=*/true)))
+ return failure();
+ }
+ os << "break;\n";
+ return success();
+}
+
+static LogicalResult printOperation(CppEmitter &emitter,
+ emitc::SwitchOp switchOp) {
+ raw_indented_ostream &os = emitter.ostream();
+
+ os << "\nswitch (" << emitter.getOrCreateName(switchOp.getArg()) << ") {";
+
+ for (auto pair : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions())) {
+ os << "\ncase " << std::get<0>(pair) << ": {\n";
+ os.indent();
+
+ if (failed(emitSwitchCase(emitter, os, std::get<1>(pair))))
+ return failure();
+
+ os.unindent() << "}";
+ }
+
+ os << "\ndefault: {\n";
+ os.indent();
+
+ if (failed(emitSwitchCase(emitter, os, switchOp.getDefaultRegion())))
+ return failure();
+
+ os.unindent() << "}";
+ return success();
+}
+
static LogicalResult printOperation(CppEmitter &emitter, emitc::CmpOp cmpOp) {
Operation *operation = cmpOp.getOperation();
@@ -998,7 +1035,7 @@ static LogicalResult printFunctionBody(CppEmitter &emitter,
// trailing semicolon is handled within the printOperation function.
bool trailingSemicolon =
!isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::ForOp,
- emitc::IfOp, emitc::VerbatimOp>(op);
+ emitc::IfOp, emitc::SwitchOp, emitc::VerbatimOp>(op);
if (failed(emitter.emitOperation(
op, /*trailingSemicolon=*/trailingSemicolon)))
@@ -1509,8 +1546,8 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
emitc::GlobalOp, emitc::IfOp, emitc::IncludeOp,
emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
emitc::MulOp, emitc::RemOp, emitc::ReturnOp, emitc::SubOp,
- emitc::UnaryMinusOp, emitc::UnaryPlusOp, emitc::VariableOp,
- emitc::VerbatimOp>(
+ emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
+ emitc::VariableOp, emitc::VerbatimOp>(
[&](auto op) { return printOperation(*this, op); })
// Func ops.
.Case<func::CallOp, func::FuncOp, func::ReturnOp>(
diff --git a/mlir/test/Conversion/SCFToEmitC/switch.mlir b/mlir/test/Conversion/SCFToEmitC/switch.mlir
new file mode 100644
index 00000000000000..659d9f43963efa
--- /dev/null
+++ b/mlir/test/Conversion/SCFToEmitC/switch.mlir
@@ -0,0 +1,117 @@
+// RUN: mlir-opt -allow-unregistered-dialect -convert-scf-to-emitc %s | FileCheck %s
+
+// CHECK-LABEL: func.func @switch_no_result(
+// CHECK-SAME: %[[VAL_0:.*]]: index) {
+// CHECK: emitc.switch %[[VAL_0]]
+// CHECK: case 2 {
+// CHECK: %[[VAL_1:.*]] = arith.constant 10 : i32
+// CHECK: emitc.yield
+// CHECK: }
+// CHECK: case 5 {
+// CHECK: %[[VAL_2:.*]] = arith.constant 20 : i32
+// CHECK: emitc.yield
+// CHECK: }
+// CHECK: default {
+// CHECK: %[[VAL_3:.*]] = arith.constant 30 : i32
+// CHECK: }
+// CHECK: return
+// CHECK: }
+func.func @switch_no_result(%arg0 : index) {
+ scf.index_switch %arg0
+ case 2 {
+ %1 = arith.constant 10 : i32
+ scf.yield
+ }
+ case 5 {
+ %2 = arith.constant 20 : i32
+ scf.yield
+ }
+ default {
+ %3 = arith.constant 30 : i32
+ }
+ return
+}
+
+// CHECK-LABEL: func.func @switch_one_result(
+// CHECK-SAME: %[[VAL_0:.*]]: index) {
+// CHECK: %[[VAL_1:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32
+// CHECK: emitc.switch %[[VAL_0]]
+// CHECK: case 2 {
+// CHECK: %[[VAL_2:.*]] = arith.constant 10 : i32
+// CHECK: emitc.assign %[[VAL_2]] : i32 to %[[VAL_1]] : i32
+// CHECK: emitc.yield
+// CHECK: }
+// CHECK: case 5 {
+// CHECK: %[[VAL_3:.*]] = arith.constant 20 : i32
+// CHECK: emitc.assign %[[VAL_3]] : i32 to %[[VAL_1]] : i32
+// CHECK: emitc.yield
+// CHECK: }
+// CHECK: default {
+// CHECK: %[[VAL_4:.*]] = arith.constant 30 : i32
+// CHECK: emitc.assign %[[VAL_4]] : i32 to %[[VAL_1]] : i32
+// CHECK: }
+// CHECK: return
+// CHECK: }
+func.func @switch_one_result(%arg0 : index) {
+ %0 = scf.index_switch %arg0 -> i32
+ case 2 {
+ %1 = arith.constant 10 : i32
+ scf.yield %1 : i32
+ }
+ case 5 {
+ %2 = arith.constant 20 : i32
+ scf.yield %2 : i32
+ }
+ default {
+ %3 = arith.constant 30 : i32
+ scf.yield %3 : i32
+ }
+ return
+}
+
+// CHECK-LABEL: func.func @switch_two_results(
+// CHECK-SAME: %[[VAL_0:.*]]: index) {
+// CHECK: %[[VAL_1:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> i32
+// CHECK: %[[VAL_2:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> f32
+// CHECK: emitc.switch %[[VAL_0]]
+// CHECK: case 2 {
+// CHECK: %[[VAL_3:.*]] = arith.constant 10 : i32
+// CHECK: %[[VAL_4:.*]] = arith.constant 1.200000e+00 : f32
+// CHECK: emitc.assign %[[VAL_3]] : i32 to %[[VAL_1]] : i32
+// CHECK: emitc.assign %[[VAL_4]] : f32 to %[[VAL_2]] : f32
+// CHECK: emitc.yield
+// CHECK: }
+// CHECK: case 5 {
+// CHECK: %[[VAL_5:.*]] = arith.constant 20 : i32
+// CHECK: %[[VAL_6:.*]] = arith.constant 2.400000e+00 : f32
+// CHECK: emitc.assign %[[VAL_5]] : i32 to %[[VAL_1]] : i32
+// CHECK: emitc.assign %[[VAL_6]] : f32 to %[[VAL_2]] : f32
+// CHECK: emitc.yield
+// CHECK: }
+// CHECK: default {
+// CHECK: %[[VAL_7:.*]] = arith.constant 30 : i32
+// CHECK: %[[VAL_8:.*]] = arith.constant 3.600000e+00 : f32
+// CHECK: emitc.assign %[[VAL_7]] : i32 to %[[VAL_1]] : i32
+// CHECK: emitc.assign %[[VAL_8]] : f32 to %[[VAL_2]] : f32
+// CHECK: }
+// CHECK: return
+// CHECK: }
+func.func @switch_two_results(%arg0 : index) {
+ %0, %1 = scf.index_switch %arg0 -> i32, f32
+ case 2 {
+ %2 = arith.constant 10 : i32
+ %3 = arith.constant 1.2 : f32
+ scf.yield %2, %3 : i32, f32
+ }
+ case 5 {
+ %4 = arith.constant 20 : i32
+ %5 = arith.constant 2.4 : f32
+ scf.yield %4, %5 : i32, f32
+ }
+ default {
+ %6 = arith.constant 30 : i32
+ %7 = arith.constant 3.6 : f32
+ scf.yield %6, %7 : i32, f32
+ }
+ return
+}
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index 4181b726593e4a..4b5bcf46c1aab9 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -227,7 +227,7 @@ func.func @sub_pointer_pointer(%arg0: !emitc.ptr<f32>, %arg1: !emitc.ptr<f32>) {
// -----
func.func @test_misplaced_yield() {
- // expected-error @+1 {{'emitc.yield' op expects parent op to be one of 'emitc.expression, emitc.if, emitc.for'}}
+ // expected-error @+1 {{'emitc.yield' op expects parent op to be one of 'emitc.expression, emitc.if, emitc.for, emitc.switch'}}
emitc.yield
return
}
@@ -466,3 +466,89 @@ func.func @member_of_ptr(%arg0: i32) {
%0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (i32) -> i32
return
}
+
+// -----
+
+func.func @emitc_switch() {
+ %0 = "emitc.variable"(){value = 1 : i16} : () -> i16
+
+ // expected-error at +1 {{'emitc.switch' op expected region to end with emitc.yield, but got emitc.call_opaque}}
+ emitc.switch %0 : i16
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// -----
+
+func.func @emitc_switch() {
+ %0 = "emitc.variable"(){value = 1 : i32} : () -> i32
+
+ emitc.switch %0 : i32
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ // expected-error at +1 {{custom op 'emitc.switch' expected integer value}}
+ case {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// -----
+
+func.func @emitc_switch() {
+ %0 = "emitc.variable"(){value = 1 : i8} : () -> i8
+
+ emitc.switch %0 : i8
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 3 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ // expected-error at +1 {{custom op 'emitc.switch' expected 'default'}}
+ return
+}
+
+// -----
+
+func.func @emitc_switch() {
+ %0 = "emitc.variable"(){value = 1 : i64} : () -> i64
+
+ // expected-error at +1 {{'emitc.switch' op has duplicate case value: 2}}
+ emitc.switch %0 : i64
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 2 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
diff --git a/mlir/test/Dialect/EmitC/ops.mlir b/mlir/test/Dialect/EmitC/ops.mlir
index 20ac077e4402b4..64f22e8ad6b983 100644
--- a/mlir/test/Dialect/EmitC/ops.mlir
+++ b/mlir/test/Dialect/EmitC/ops.mlir
@@ -261,3 +261,23 @@ func.func @member_access(%arg0: !emitc.opaque<"mystruct">, %arg1: !emitc.opaque<
%2 = "emitc.member_of_ptr" (%arg2) {member = "a"} : (!emitc.ptr<!emitc.opaque<"mystruct">>) -> i32
return
}
+
+func.func @switch() {
+ %0 = "emitc.variable"(){value = 1 : index} : () -> !emitc.ptr
diff _t
+
+ emitc.switch %0 : !emitc.ptr
diff _t
+ case 1 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 2 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ }
+
+ return
+}
diff --git a/mlir/test/Target/Cpp/invalid.mlir b/mlir/test/Target/Cpp/invalid.mlir
index 513371a09cde1d..4e777239fba662 100644
--- a/mlir/test/Target/Cpp/invalid.mlir
+++ b/mlir/test/Target/Cpp/invalid.mlir
@@ -80,6 +80,7 @@ func.func @array_as_result(%arg: !emitc.array<4xi8>) -> (!emitc.array<4xi8>) {
}
// -----
+
func.func @ptr_to_array() {
// expected-error at +1 {{cannot emit pointer to array type '!emitc.ptr<!emitc.array<9xi16>>'}}
%v = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.ptr<!emitc.array<9xi16>>
diff --git a/mlir/test/Target/Cpp/switch.mlir b/mlir/test/Target/Cpp/switch.mlir
new file mode 100644
index 00000000000000..0f2e716a98f16b
--- /dev/null
+++ b/mlir/test/Target/Cpp/switch.mlir
@@ -0,0 +1,856 @@
+// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s -check-prefix=CPP-DEFAULT
+// RUN: mlir-translate -mlir-to-cpp -declare-variables-at-top %s | FileCheck %s -check-prefix=CPP-DECLTOP
+
+// CPP-DEFAULT-LABEL: void emitc_switch_ptr
diff _t() {
+// CPP-DEFAULT: ptr
diff _t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_ptr
diff _t() {
+// CPP-DECLTOP: ptr
diff _t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_ptr
diff _t() {
+ %0 = "emitc.variable"(){value = 1 : index} : () -> !emitc.ptr
diff _t
+
+ emitc.switch %0 : !emitc.ptr
diff _t
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_ssize_t() {
+// CPP-DEFAULT: ssize_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_ssize_t() {
+// CPP-DECLTOP: ssize_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_ssize_t() {
+ %0 = "emitc.variable"(){value = 1 : index} : () -> !emitc.ssize_t
+
+ emitc.switch %0 : !emitc.ssize_t
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_size_t() {
+// CPP-DEFAULT: size_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_size_t() {
+// CPP-DECLTOP: size_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_size_t() {
+ %0 = "emitc.variable"(){value = 1 : index} : () -> !emitc.size_t
+
+ emitc.switch %0 : !emitc.size_t
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_index() {
+// CPP-DEFAULT: size_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_index() {
+// CPP-DECLTOP: size_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_index() {
+ %0 = "emitc.variable"(){value = 1 : index} : () -> index
+
+ emitc.switch %0 : index
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_opaque() {
+// CPP-DEFAULT: size_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_opaque() {
+// CPP-DECLTOP: size_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_opaque() {
+ %0 = "emitc.variable"() {value = #emitc.opaque<"1">}
+ : () -> !emitc.opaque<"size_t">
+
+ emitc.switch %0 : !emitc.opaque<"size_t">
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_i1() {
+// CPP-DEFAULT: bool v1 = true;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_i1() {
+// CPP-DECLTOP: bool v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = true;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_i1() {
+ %0 = "emitc.variable"(){value = 1 : i1} : () -> i1
+
+ emitc.switch %0 : i1
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_i8() {
+// CPP-DEFAULT: int8_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_i8() {
+// CPP-DECLTOP: int8_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_i8() {
+ %0 = "emitc.variable"(){value = 1 : i8} : () -> i8
+
+ emitc.switch %0 : i8
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_ui8() {
+// CPP-DEFAULT: uint8_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_ui8() {
+// CPP-DECLTOP: uint8_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_ui8() {
+ %0 = "emitc.variable"(){value = 1 : ui8} : () -> ui8
+
+ emitc.switch %0 : ui8
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_i16() {
+// CPP-DEFAULT: int16_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_i16() {
+// CPP-DECLTOP: int16_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_i16() {
+ %0 = "emitc.variable"(){value = 1 : i16} : () -> i16
+
+ emitc.switch %0 : i16
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_ui16() {
+// CPP-DEFAULT: uint16_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_ui16() {
+// CPP-DECLTOP: uint16_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_ui16() {
+ %0 = "emitc.variable"(){value = 1 : ui16} : () -> ui16
+
+ emitc.switch %0 : ui16
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_i32() {
+// CPP-DEFAULT: int32_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_i32() {
+// CPP-DECLTOP: int32_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_i32() {
+ %0 = "emitc.variable"(){value = 1 : i32} : () -> i32
+
+ emitc.switch %0 : i32
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_ui32() {
+// CPP-DEFAULT: uint32_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_ui32() {
+// CPP-DECLTOP: uint32_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_ui32() {
+ %0 = "emitc.variable"(){value = 1 : ui32} : () -> ui32
+
+ emitc.switch %0 : ui32
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_i64() {
+// CPP-DEFAULT: int64_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_i64() {
+// CPP-DECLTOP: int64_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_i64() {
+ %0 = "emitc.variable"(){value = 1 : i64} : () -> i64
+
+ emitc.switch %0 : i64
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
+
+// CPP-DEFAULT-LABEL: void emitc_switch_ui64() {
+// CPP-DEFAULT: uint64_t v1 = 1;
+// CPP-DEFAULT: switch (v1) {
+// CPP-DEFAULT: case 2: {
+// CPP-DEFAULT: int32_t v2 = func_b();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: case 5: {
+// CPP-DEFAULT: int32_t v3 = func_a();
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: default: {
+// CPP-DEFAULT: float v4 = 4.200000000e+01f;
+// CPP-DEFAULT: func2(v4);
+// CPP-DEFAULT: break;
+// CPP-DEFAULT: }
+// CPP-DEFAULT: return;
+// CPP-DEFAULT: }
+
+// CPP-DECLTOP-LABEL: void emitc_switch_ui64() {
+// CPP-DECLTOP: uint64_t v1;
+// CPP-DECLTOP: float v2;
+// CPP-DECLTOP: int32_t v3;
+// CPP-DECLTOP: int32_t v4;
+// CPP-DECLTOP: v1 = 1;
+// CPP-DECLTOP: switch (v1) {
+// CPP-DECLTOP: case 2: {
+// CPP-DECLTOP: v3 = func_b();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: case 5: {
+// CPP-DECLTOP: v4 = func_a();
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: default: {
+// CPP-DECLTOP: v2 = 4.200000000e+01f;
+// CPP-DECLTOP: func2(v2);
+// CPP-DECLTOP: break;
+// CPP-DECLTOP: }
+// CPP-DECLTOP: return;
+// CPP-DECLTOP: }
+func.func @emitc_switch_ui64() {
+ %0 = "emitc.variable"(){value = 1 : ui64} : () -> ui64
+
+ emitc.switch %0 : ui64
+ case 2 {
+ %1 = emitc.call_opaque "func_b" () : () -> i32
+ emitc.yield
+ }
+ case 5 {
+ %2 = emitc.call_opaque "func_a" () : () -> i32
+ emitc.yield
+ }
+ default {
+ %3 = "emitc.variable"(){value = 42.0 : f32} : () -> f32
+ emitc.call_opaque "func2" (%3) : (f32) -> ()
+ emitc.yield
+ }
+ return
+}
More information about the Mlir-commits
mailing list