[Mlir-commits] [mlir] [mlir][cf] Fix switch case value round-tripping (PR #226660)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sat Sep 26 01:41:58 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: Ziliang Zhang (ziliangzl)
<details>
<summary>Changes</summary>
Fixes #<!-- -->225658.
`cf.switch` printed negative case values as unsigned integers, producing text that could not be parsed back. Print case values as signed APInts, parse arbitrary-width values, and diagnose values outside the flag type range.
Tests cover custom and generic round-tripping plus signed, unsigned, and overflow boundaries for i1, i8, i64, and i128.
---
Full diff: https://github.com/llvm/llvm-project/pull/226660.diff
3 Files Affected:
- (modified) mlir/lib/Dialect/ControlFlow/IR/ControlFlowOps.cpp (+10-3)
- (modified) mlir/test/Dialect/ControlFlow/invalid.mlir (+96)
- (modified) mlir/test/Dialect/ControlFlow/ops.mlir (+99-1)
``````````diff
diff --git a/mlir/lib/Dialect/ControlFlow/IR/ControlFlowOps.cpp b/mlir/lib/Dialect/ControlFlow/IR/ControlFlowOps.cpp
index 9016d1929f859..b39fe1e2ca420 100644
--- a/mlir/lib/Dialect/ControlFlow/IR/ControlFlowOps.cpp
+++ b/mlir/lib/Dialect/ControlFlow/IR/ControlFlowOps.cpp
@@ -647,10 +647,17 @@ static ParseResult parseSwitchOpCases(
SmallVector<APInt> values;
unsigned bitWidth = flagType.getIntOrFloatBitWidth();
while (succeeded(parser.parseOptionalComma())) {
- int64_t value = 0;
+ SMLoc valueLoc = parser.getCurrentLocation();
+ APInt value;
if (failed(parser.parseInteger(value)))
return failure();
- values.push_back(APInt(bitWidth, value, /*isSigned=*/true));
+ // Signless integers accept negative values in the signed range and
+ // non-negative values in the unsigned range.
+ if ((value.isNegative() && !value.isSignedIntN(bitWidth)) ||
+ (!value.isNegative() && !value.isIntN(bitWidth)))
+ return parser.emitError(valueLoc)
+ << "case value does not fit in flag type " << flagType;
+ values.push_back(value.sextOrTrunc(bitWidth));
Block *destination;
SmallVector<OpAsmParser::UnresolvedOperand> operands;
@@ -693,7 +700,7 @@ static void printSwitchOpCases(
p << ',';
p.printNewline();
p << " ";
- p << it.value().getLimitedValue();
+ it.value().print(p.getStream(), /*isSigned=*/true);
p << ": ";
p.printSuccessorAndUseList(caseDestinations[it.index()],
caseOperands[it.index()]);
diff --git a/mlir/test/Dialect/ControlFlow/invalid.mlir b/mlir/test/Dialect/ControlFlow/invalid.mlir
index 0a71c62ec31af..1ecd47b2702ff 100644
--- a/mlir/test/Dialect/ControlFlow/invalid.mlir
+++ b/mlir/test/Dialect/ControlFlow/invalid.mlir
@@ -70,6 +70,102 @@ func.func @switch_missing_default(%flag : i32, %caseOperand : i32) {
// -----
+func.func @switch_i1_positive_overflow(%flag : i1) {
+ cf.switch %flag : i1, [
+ default: ^bb1,
+ // expected-error at +1 {{case value does not fit in flag type 'i1'}}
+ 2: ^bb1
+ ]
+^bb1:
+ return
+}
+
+// -----
+
+func.func @switch_i1_negative_overflow(%flag : i1) {
+ cf.switch %flag : i1, [
+ default: ^bb1,
+ // expected-error at +1 {{case value does not fit in flag type 'i1'}}
+ -2: ^bb1
+ ]
+^bb1:
+ return
+}
+
+// -----
+
+func.func @switch_i8_positive_overflow(%flag : i8) {
+ cf.switch %flag : i8, [
+ default: ^bb1,
+ // expected-error at +1 {{case value does not fit in flag type 'i8'}}
+ 256: ^bb1
+ ]
+^bb1:
+ return
+}
+
+// -----
+
+func.func @switch_i8_negative_overflow(%flag : i8) {
+ cf.switch %flag : i8, [
+ default: ^bb1,
+ // expected-error at +1 {{case value does not fit in flag type 'i8'}}
+ -129: ^bb1
+ ]
+^bb1:
+ return
+}
+
+// -----
+
+func.func @switch_i64_positive_overflow(%flag : i64) {
+ cf.switch %flag : i64, [
+ default: ^bb1,
+ // expected-error at +1 {{case value does not fit in flag type 'i64'}}
+ 18446744073709551616: ^bb1
+ ]
+^bb1:
+ return
+}
+
+// -----
+
+func.func @switch_i64_negative_overflow(%flag : i64) {
+ cf.switch %flag : i64, [
+ default: ^bb1,
+ // expected-error at +1 {{case value does not fit in flag type 'i64'}}
+ -9223372036854775809: ^bb1
+ ]
+^bb1:
+ return
+}
+
+// -----
+
+func.func @switch_i128_positive_overflow(%flag : i128) {
+ cf.switch %flag : i128, [
+ default: ^bb1,
+ // expected-error at +1 {{case value does not fit in flag type 'i128'}}
+ 340282366920938463463374607431768211456: ^bb1
+ ]
+^bb1:
+ return
+}
+
+// -----
+
+func.func @switch_i128_negative_overflow(%flag : i128) {
+ cf.switch %flag : i128, [
+ default: ^bb1,
+ // expected-error at +1 {{case value does not fit in flag type 'i128'}}
+ -170141183460469231731687303715884105729: ^bb1
+ ]
+^bb1:
+ return
+}
+
+// -----
+
// CHECK-LABEL: func @wrong_weights_number
func.func @wrong_weights_number(%cond: i1) {
// expected-error at +1 {{expects number of branch weights to match number of successors: 1 vs 2}}
diff --git a/mlir/test/Dialect/ControlFlow/ops.mlir b/mlir/test/Dialect/ControlFlow/ops.mlir
index 03091a95b456e..629ba89fb39b9 100644
--- a/mlir/test/Dialect/ControlFlow/ops.mlir
+++ b/mlir/test/Dialect/ControlFlow/ops.mlir
@@ -8,11 +8,13 @@ func.func @assert(%arg : i1) {
}
// CHECK-LABEL: func @switch(
+// CHECK: -1:
func.func @switch(%flag : i32, %caseOperand : i32) {
cf.switch %flag : i32, [
default: ^bb1(%caseOperand : i32),
42: ^bb2(%caseOperand : i32),
- 43: ^bb3(%caseOperand : i32)
+ 43: ^bb3(%caseOperand : i32),
+ -1: ^bb4(%caseOperand : i32)
]
^bb1(%bb1arg : i32):
@@ -21,6 +23,8 @@ func.func @switch(%flag : i32, %caseOperand : i32) {
return
^bb3(%bb3arg : i32):
return
+ ^bb4(%bb4arg : i32):
+ return
}
// CHECK-LABEL: func @switch_i64(
@@ -39,6 +43,100 @@ func.func @switch_i64(%flag : i64, %caseOperand : i32) {
return
}
+// CHECK-LABEL: func @switch_i1_unsigned_boundary(
+// CHECK: -1:
+func.func @switch_i1_unsigned_boundary(%flag : i1) {
+ cf.switch %flag : i1, [
+ default: ^bb1,
+ 1: ^bb1
+ ]
+
+ ^bb1:
+ return
+}
+
+// CHECK-LABEL: func @switch_i8_signed_boundaries(
+// CHECK: -128:
+// CHECK: 127:
+func.func @switch_i8_signed_boundaries(%flag : i8) {
+ cf.switch %flag : i8, [
+ default: ^bb1,
+ -128: ^bb1,
+ 127: ^bb1
+ ]
+
+ ^bb1:
+ return
+}
+
+// CHECK-LABEL: func @switch_i8_unsigned_boundaries(
+// CHECK: -128:
+// CHECK: -1:
+func.func @switch_i8_unsigned_boundaries(%flag : i8) {
+ cf.switch %flag : i8, [
+ default: ^bb1,
+ 128: ^bb1,
+ 255: ^bb1
+ ]
+
+ ^bb1:
+ return
+}
+
+// CHECK-LABEL: func @switch_i64_signed_boundaries(
+// CHECK: -9223372036854775808:
+// CHECK: 9223372036854775807:
+func.func @switch_i64_signed_boundaries(%flag : i64) {
+ cf.switch %flag : i64, [
+ default: ^bb1,
+ -9223372036854775808: ^bb1,
+ 9223372036854775807: ^bb1
+ ]
+
+ ^bb1:
+ return
+}
+
+// CHECK-LABEL: func @switch_i64_unsigned_boundary(
+// CHECK: -1:
+func.func @switch_i64_unsigned_boundary(%flag : i64) {
+ cf.switch %flag : i64, [
+ default: ^bb1,
+ 18446744073709551615: ^bb1
+ ]
+
+ ^bb1:
+ return
+}
+
+// CHECK-LABEL: func @switch_i128_signed_boundaries(
+// CHECK: -170141183460469231731687303715884105728:
+// CHECK: 170141183460469231731687303715884105727:
+func.func @switch_i128_signed_boundaries(%flag : i128) {
+ cf.switch %flag : i128, [
+ default: ^bb1,
+ -170141183460469231731687303715884105728: ^bb1,
+ 170141183460469231731687303715884105727: ^bb1
+ ]
+
+ ^bb1:
+ return
+}
+
+// CHECK-LABEL: func @switch_i128_unsigned_boundaries(
+// CHECK: -170141183460469231731687303715884105728:
+// CHECK: -1:
+func.func @switch_i128_unsigned_boundaries(%flag : i128) {
+ cf.switch %flag : i128, [
+ default: ^bb1,
+ 170141183460469231731687303715884105728: ^bb1,
+ 340282366920938463463374607431768211455: ^bb1
+ ]
+
+ ^bb1:
+ return
+}
+
// CHECK-LABEL: func @switch_result_number
func.func @switch_result_number(%arg0: i32) {
%0:2 = "test.op_with_two_results"() : () -> (i32, i32)
``````````
</details>
https://github.com/llvm/llvm-project/pull/226660
More information about the Mlir-commits
mailing list