From ff987608b7f2dee7940037d2cfb11da0e00a3f1b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 6 Sep 2024 14:29:46 -0500 Subject: [PATCH] Remove `iadd_cin` and `isub_bin`, split `isub_borrow` and `iadd_carry` (#9199) * Remove `iadd_cin` and `isub_bin`, split `isub_borrow` and `iadd_carry` This commit refactors the opcodes the Cranelift supports for add-with-carry and subtract-with-borrow. None of these opcodes are currently in use by the wasm frontend nor supported by any backend. In that sense it's unlikely they have many users and the hope is that refactoring won't cause much impact. The `iadd_cin` and `isub_bin` opcodes are the equivalent of `*_borrow` and `*_carry` except that they don't return the carry flag, they only return the result of the operation. While theoretically useful I've elected to remove them here in favor of only the borrow-returning operations. They can be added back in in the future though if necessary. I've split the preexisting operations `isub_borrow` and `iadd_carry` additionally into signed/unsigned portions: * `isub_borrow` => `usub_borrow` and `ssub_borrow` * `iadd_carry` => `uadd_carry` and `sadd_carry` This reflects how the condition needs to differ on the carry flag computation for signed/unsigned inputs. I've additionally fixed the interpreter's implementation of `IsubBorrow` when switching to the signed/unsigned opcodes. Finally the documentation for these instructions now explicitly say that the incoming carry/borrow is zero-or-nonzero even though it's typed as `i8`. Additionally the tests have been refactored to make use of multi-return which may not have existed when they were first written. * Rename instructions * Fix more renames * Update instruction descriptions --- .../codegen/meta/src/shared/instructions.rs | 70 +++---- .../filetests/filetests/parser/ternary.clif | 16 +- .../filetests/runtests/iaddcarry.clif | 176 ++++++++++-------- .../filetests/filetests/runtests/iaddcin.clif | 48 ----- .../filetests/filetests/runtests/isubbin.clif | 49 ----- .../filetests/runtests/isubborrow.clif | 171 +++++++++-------- cranelift/fuzzgen/src/function_generator.rs | 8 +- cranelift/interpreter/src/step.rs | 70 +++---- 8 files changed, 263 insertions(+), 345 deletions(-) delete mode 100644 cranelift/filetests/filetests/runtests/iaddcin.clif delete mode 100644 cranelift/filetests/filetests/runtests/isubbin.clif diff --git a/cranelift/codegen/meta/src/shared/instructions.rs b/cranelift/codegen/meta/src/shared/instructions.rs index 4348a7b7168c..d094a2850c05 100644 --- a/cranelift/codegen/meta/src/shared/instructions.rs +++ b/cranelift/codegen/meta/src/shared/instructions.rs @@ -2008,18 +2008,12 @@ pub(crate) fn define( ig.push( Inst::new( - "iadd_cin", + "sadd_overflow_cin", r#" - Add integers with carry in. + Add signed integers with carry in and overflow out. - Same as `iadd` with an additional carry input. Computes: - - ```text - a = x + y + c_{in} \pmod 2^B - ``` - - Polymorphic over all scalar integer types, but does not support vector - types. + Same as `sadd_overflow` with an additional carry input. The `c_in` type + is interpreted as 1 if it's nonzero or 0 if it's zero. "#, &formats.ternary, ) @@ -2028,24 +2022,20 @@ pub(crate) fn define( Operand::new("y", iB), Operand::new("c_in", i8).with_doc("Input carry flag"), ]) - .operands_out(vec![Operand::new("a", iB)]), + .operands_out(vec![ + Operand::new("a", iB), + Operand::new("c_out", i8).with_doc("Output carry flag"), + ]), ); ig.push( Inst::new( - "iadd_carry", + "uadd_overflow_cin", r#" - Add integers with carry in and out. - - Same as `iadd` with an additional carry input and output. - - ```text - a &= x + y + c_{in} \pmod 2^B \\ - c_{out} &= x + y + c_{in} >= 2^B - ``` + Add unsigned integers with carry in and overflow out. - Polymorphic over all scalar integer types, but does not support vector - types. + Same as `uadd_overflow` with an additional carry input. The `c_in` type + is interpreted as 1 if it's nonzero or 0 if it's zero. "#, &formats.ternary, ) @@ -2207,18 +2197,13 @@ pub(crate) fn define( ig.push( Inst::new( - "isub_bin", + "ssub_overflow_bin", r#" - Subtract integers with borrow in. + Subtract signed integers with borrow in and overflow out. - Same as `isub` with an additional borrow flag input. Computes: - - ```text - a = x - (y + b_{in}) \pmod 2^B - ``` - - Polymorphic over all scalar integer types, but does not support vector - types. + Same as `ssub_overflow` with an additional borrow input. The `b_in` type + is interpreted as 1 if it's nonzero or 0 if it's zero. The computation + performed here is `x - (y + (b_in != 0))`. "#, &formats.ternary, ) @@ -2227,24 +2212,21 @@ pub(crate) fn define( Operand::new("y", iB), Operand::new("b_in", i8).with_doc("Input borrow flag"), ]) - .operands_out(vec![Operand::new("a", iB)]), + .operands_out(vec![ + Operand::new("a", iB), + Operand::new("b_out", i8).with_doc("Output borrow flag"), + ]), ); ig.push( Inst::new( - "isub_borrow", + "usub_overflow_bin", r#" - Subtract integers with borrow in and out. - - Same as `isub` with an additional borrow flag input and output. - - ```text - a &= x - (y + b_{in}) \pmod 2^B \\ - b_{out} &= x < y + b_{in} - ``` + Subtract unsigned integers with borrow in and overflow out. - Polymorphic over all scalar integer types, but does not support vector - types. + Same as `usub_overflow` with an additional borrow input. The `b_in` type + is interpreted as 1 if it's nonzero or 0 if it's zero. The computation + performed here is `x - (y + (b_in != 0))`. "#, &formats.ternary, ) diff --git a/cranelift/filetests/filetests/parser/ternary.clif b/cranelift/filetests/filetests/parser/ternary.clif index b521aecc8cc9..2406fb293951 100644 --- a/cranelift/filetests/filetests/parser/ternary.clif +++ b/cranelift/filetests/filetests/parser/ternary.clif @@ -12,10 +12,10 @@ function %add_i96(i32, i32, i32, i32, i32, i32) -> i32, i32, i32 { block1(v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32): v10, v11 = uadd_overflow v1, v4 ;check: v10, v11 = uadd_overflow v1, v4 - v20, v21 = iadd_carry v2, v5, v11 - ; check: v20, v21 = iadd_carry v2, v5, v11 - v30 = iadd_cin v3, v6, v21 - ; check: v30 = iadd_cin v3, v6, v21 + v20, v21 = sadd_overflow_cin v2, v5, v11 + ; check: v20, v21 = sadd_overflow_cin v2, v5, v11 + v30, v31 = uadd_overflow_cin v3, v6, v21 + ; check: v30, v31 = uadd_overflow_cin v3, v6, v21 return v10, v20, v30 } @@ -23,9 +23,9 @@ function %sub_i96(i32, i32, i32, i32, i32, i32) -> i32, i32, i32 { block1(v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32): v10, v11 = usub_overflow v1, v4 ;check: v10, v11 = usub_overflow v1, v4 - v20, v21 = isub_borrow v2, v5, v11 - ; check: v20, v21 = isub_borrow v2, v5, v11 - v30 = isub_bin v3, v6, v21 - ; check: v30 = isub_bin v3, v6, v21 + v20, v21 = ssub_overflow_bin v2, v5, v11 + ; check: v20, v21 = ssub_overflow_bin v2, v5, v11 + v30, v31 = usub_overflow_bin v3, v6, v21 + ; check: v30, v31 = usub_overflow_bin v3, v6, v21 return v10, v20, v30 } diff --git a/cranelift/filetests/filetests/runtests/iaddcarry.clif b/cranelift/filetests/filetests/runtests/iaddcarry.clif index 04fd38f124ba..512d13db8689 100644 --- a/cranelift/filetests/filetests/runtests/iaddcarry.clif +++ b/cranelift/filetests/filetests/runtests/iaddcarry.clif @@ -1,99 +1,115 @@ test interpret -function %iaddcarry_i8_v(i8, i8, i8) -> i8 { +function %sadd_overflow_cin_i8(i8, i8, i8) -> i8, i8 { block0(v0: i8, v1: i8, v2: i8): - v3, v4 = iadd_carry v0, v1, v2 - return v3 + v3, v4 = sadd_overflow_cin v0, v1, v2 + return v3, v4 } -; run: %iaddcarry_i8_v(0, 1, 1) == 2 -; run: %iaddcarry_i8_v(0, 1, 0) == 1 -; run: %iaddcarry_i8_v(100, 27, 1) == -128 -; run: %iaddcarry_i8_v(100, 27, 0) == 127 -; run: %iaddcarry_i8_v(127, 127, 1) == -1 -; run: %iaddcarry_i8_v(127, 127, 0) == -2 -; run: %iaddcarry_i8_v(-128, -128, 0) == 0 +; run: %sadd_overflow_cin_i8(0, 1, 1) == [2, 0] +; run: %sadd_overflow_cin_i8(0, 1, 10) == [2, 0] +; run: %sadd_overflow_cin_i8(0, 1, 0) == [1, 0] +; run: %sadd_overflow_cin_i8(100, 27, 1) == [-128, 1] +; run: %sadd_overflow_cin_i8(100, 27, 0) == [127, 0] +; run: %sadd_overflow_cin_i8(127, 127, 1) == [-1, 1] +; run: %sadd_overflow_cin_i8(127, 127, 0) == [-2, 1] +; run: %sadd_overflow_cin_i8(-128, -128, 0) == [0, 1] -function %iaddcarry_i8_c(i8, i8, i8) -> i8 { -block0(v0: i8, v1: i8, v2: i8): - v3, v4 = iadd_carry v0, v1, v2 - return v4 +function %sadd_overflow_cin_i16(i16, i16, i8) -> i16, i8 { +block0(v0: i16, v1: i16, v2: i8): + v3, v4 = sadd_overflow_cin v0, v1, v2 + return v3, v4 } -; run: %iaddcarry_i8_c(0, 1, 1) == 0 -; run: %iaddcarry_i8_c(0, 1, 0) == 0 -; run: %iaddcarry_i8_c(100, 27, 1) == 1 -; run: %iaddcarry_i8_c(100, 27, 0) == 0 -; run: %iaddcarry_i8_c(127, 127, 1) == 1 -; run: %iaddcarry_i8_c(127, 127, 0) == 1 -; run: %iaddcarry_i8_c(-128, -128, 0) == 1 +; run: %sadd_overflow_cin_i16(0, 1, 1) == [2, 0] +; run: %sadd_overflow_cin_i16(0, 1, 10) == [2, 0] +; run: %sadd_overflow_cin_i16(0, 1, 0) == [1, 0] +; run: %sadd_overflow_cin_i16(100, 27, 1) == [128, 0] +; run: %sadd_overflow_cin_i16(100, 27, 0) == [127, 0] +; run: %sadd_overflow_cin_i16(32000, 767, 1) == [-32768, 1] +; run: %sadd_overflow_cin_i16(32000, 767, 0) == [32767, 0] -function %iaddcarry_i16_v(i16, i16, i8) -> i16 { -block0(v0: i16, v1: i16, v2: i8): - v3, v4 = iadd_carry v0, v1, v2 - return v3 +function %sadd_overflow_cin_i32(i32, i32, i8) -> i32, i8 { +block0(v0: i32, v1: i32, v2: i8): + v3, v4 = sadd_overflow_cin v0, v1, v2 + return v3, v4 } -; run: %iaddcarry_i16_v(0, 1, 1) == 2 -; run: %iaddcarry_i16_v(0, 1, 0) == 1 -; run: %iaddcarry_i16_v(100, 27, 1) == 128 -; run: %iaddcarry_i16_v(100, 27, 0) == 127 -; run: %iaddcarry_i16_v(32000, 767, 1) == -32768 -; run: %iaddcarry_i16_v(32000, 767, 0) == 32767 +; run: %sadd_overflow_cin_i32(0, 1, 1) == [2, 0] +; run: %sadd_overflow_cin_i32(0, 1, 10) == [2, 0] +; run: %sadd_overflow_cin_i32(0, 1, 0) == [1, 0] +; run: %sadd_overflow_cin_i32(100, 27, 1) == [128, 0] +; run: %sadd_overflow_cin_i32(100, 27, 0) == [127, 0] +; run: %sadd_overflow_cin_i32(2000000000, 147483647, 1) == [-2147483648, 1] +; run: %sadd_overflow_cin_i32(2000000000, 147483647, 0) == [2147483647, 0] -function %iaddcarry_i16_c(i16, i16, i8) -> i8 { -block0(v0: i16, v1: i16, v2: i8): - v3, v4 = iadd_carry v0, v1, v2 - return v4 +function %sadd_overflow_cin_i64(i64, i64, i8) -> i64, i8 { +block0(v0: i64, v1: i64, v2: i8): + v3, v4 = sadd_overflow_cin v0, v1, v2 + return v3, v4 } -; run: %iaddcarry_i16_c(0, 1, 1) == 0 -; run: %iaddcarry_i16_c(0, 1, 0) == 0 -; run: %iaddcarry_i16_c(100, 27, 1) == 0 -; run: %iaddcarry_i16_c(100, 27, 0) == 0 -; run: %iaddcarry_i16_c(32000, 767, 1) == 1 -; run: %iaddcarry_i16_c(32000, 767, 0) == 0 +; run: %sadd_overflow_cin_i64(0, 1, 1) == [2, 0] +; run: %sadd_overflow_cin_i64(0, 1, 10) == [2, 0] +; run: %sadd_overflow_cin_i64(0, 1, 0) == [1, 0] +; run: %sadd_overflow_cin_i64(100, 27, 1) == [128, 0] +; run: %sadd_overflow_cin_i64(100, 27, 0) == [127, 0] +; run: %sadd_overflow_cin_i64(9000000000000000000, 223372036854775807, 1) == [-9223372036854775808, 1] +; run: %sadd_overflow_cin_i64(9000000000000000000, 223372036854775807, 0) == [9223372036854775807, 0] -function %iaddcarry_i32_v(i32, i32, i8) -> i32 { -block0(v0: i32, v1: i32, v2: i8): - v3, v4 = iadd_carry v0, v1, v2 - return v3 +function %uadd_overflow_cin_i8(i8, i8, i8) -> i8, i8 { +block0(v0: i8, v1: i8, v2: i8): + v3, v4 = uadd_overflow_cin v0, v1, v2 + return v3, v4 } -; run: %iaddcarry_i32_v(0, 1, 1) == 2 -; run: %iaddcarry_i32_v(0, 1, 0) == 1 -; run: %iaddcarry_i32_v(100, 27, 1) == 128 -; run: %iaddcarry_i32_v(100, 27, 0) == 127 -; run: %iaddcarry_i32_v(2000000000, 147483647, 1) == -2147483648 -; run: %iaddcarry_i32_v(2000000000, 147483647, 0) == 2147483647 +; run: %uadd_overflow_cin_i8(0, 1, 1) == [2, 0] +; run: %uadd_overflow_cin_i8(0, 1, 10) == [2, 0] +; run: %uadd_overflow_cin_i8(0, 1, 0) == [1, 0] +; run: %uadd_overflow_cin_i8(100, 27, 1) == [-128, 0] +; run: %uadd_overflow_cin_i8(100, 27, 0) == [127, 0] +; run: %uadd_overflow_cin_i8(127, 127, 1) == [-1, 0] +; run: %uadd_overflow_cin_i8(127, 127, 0) == [-2, 0] +; run: %uadd_overflow_cin_i8(-128, -128, 0) == [0, 1] +; run: %uadd_overflow_cin_i8(-1, -1, 0) == [-2, 1] +; run: %uadd_overflow_cin_i8(-1, -1, 1) == [-1, 1] -function %iaddcarry_i32_c(i32, i32, i8) -> i8 { -block0(v0: i32, v1: i32, v2: i8): - v3, v4 = iadd_carry v0, v1, v2 - return v4 +function %uadd_overflow_cin_i16(i16, i16, i8) -> i16, i8 { +block0(v0: i16, v1: i16, v2: i8): + v3, v4 = uadd_overflow_cin v0, v1, v2 + return v3, v4 } -; run: %iaddcarry_i32_c(0, 1, 1) == 0 -; run: %iaddcarry_i32_c(0, 1, 0) == 0 -; run: %iaddcarry_i32_c(100, 27, 1) == 0 -; run: %iaddcarry_i32_c(100, 27, 0) == 0 -; run: %iaddcarry_i32_c(2000000000, 147483647, 1) == 1 -; run: %iaddcarry_i32_c(2000000000, 147483647, 0) == 0 +; run: %uadd_overflow_cin_i16(0, 1, 1) == [2, 0] +; run: %uadd_overflow_cin_i16(0, 1, 10) == [2, 0] +; run: %uadd_overflow_cin_i16(0, 1, 0) == [1, 0] +; run: %uadd_overflow_cin_i16(100, 27, 1) == [128, 0] +; run: %uadd_overflow_cin_i16(100, 27, 0) == [127, 0] +; run: %uadd_overflow_cin_i16(32000, 767, 1) == [-32768, 0] +; run: %uadd_overflow_cin_i16(32000, 767, 0) == [32767, 0] +; run: %uadd_overflow_cin_i16(-1, -1, 0) == [-2, 1] +; run: %uadd_overflow_cin_i16(-1, -1, 1) == [-1, 1] -function %iaddcarry_i64_v(i64, i64, i8) -> i64 { -block0(v0: i64, v1: i64, v2: i8): - v3, v4 = iadd_carry v0, v1, v2 - return v3 +function %uadd_overflow_cin_i32(i32, i32, i8) -> i32, i8 { +block0(v0: i32, v1: i32, v2: i8): + v3, v4 = uadd_overflow_cin v0, v1, v2 + return v3, v4 } -; run: %iaddcarry_i64_v(0, 1, 1) == 2 -; run: %iaddcarry_i64_v(0, 1, 0) == 1 -; run: %iaddcarry_i64_v(100, 27, 1) == 128 -; run: %iaddcarry_i64_v(100, 27, 0) == 127 -; run: %iaddcarry_i64_v(9000000000000000000, 223372036854775807, 1) == -9223372036854775808 -; run: %iaddcarry_i64_v(9000000000000000000, 223372036854775807, 0) == 9223372036854775807 +; run: %uadd_overflow_cin_i32(0, 1, 1) == [2, 0] +; run: %uadd_overflow_cin_i32(0, 1, 10) == [2, 0] +; run: %uadd_overflow_cin_i32(0, 1, 0) == [1, 0] +; run: %uadd_overflow_cin_i32(100, 27, 1) == [128, 0] +; run: %uadd_overflow_cin_i32(100, 27, 0) == [127, 0] +; run: %uadd_overflow_cin_i32(2000000000, 147483647, 1) == [-2147483648, 0] +; run: %uadd_overflow_cin_i32(2000000000, 147483647, 0) == [2147483647, 0] +; run: %uadd_overflow_cin_i32(-1, -1, 0) == [-2, 1] +; run: %uadd_overflow_cin_i32(-1, -1, 1) == [-1, 1] -function %iaddcarry_i64_c(i64, i64, i8) -> i8 { +function %uadd_overflow_cin_i64(i64, i64, i8) -> i64, i8 { block0(v0: i64, v1: i64, v2: i8): - v3, v4 = iadd_carry v0, v1, v2 - return v4 + v3, v4 = uadd_overflow_cin v0, v1, v2 + return v3, v4 } -; run: %iaddcarry_i64_c(0, 1, 1) == 0 -; run: %iaddcarry_i64_c(0, 1, 0) == 0 -; run: %iaddcarry_i64_c(100, 27, 1) == 0 -; run: %iaddcarry_i64_c(100, 27, 0) == 0 -; run: %iaddcarry_i64_c(9000000000000000000, 223372036854775807, 1) == 1 -; run: %iaddcarry_i64_c(9000000000000000000, 223372036854775807, 0) == 0 +; run: %uadd_overflow_cin_i64(0, 1, 1) == [2, 0] +; run: %uadd_overflow_cin_i64(0, 1, 10) == [2, 0] +; run: %uadd_overflow_cin_i64(0, 1, 0) == [1, 0] +; run: %uadd_overflow_cin_i64(100, 27, 1) == [128, 0] +; run: %uadd_overflow_cin_i64(100, 27, 0) == [127, 0] +; run: %uadd_overflow_cin_i64(9000000000000000000, 223372036854775807, 1) == [-9223372036854775808, 0] +; run: %uadd_overflow_cin_i64(9000000000000000000, 223372036854775807, 0) == [9223372036854775807, 0] +; run: %uadd_overflow_cin_i64(-1, -1, 0) == [-2, 1] +; run: %uadd_overflow_cin_i64(-1, -1, 1) == [-1, 1] diff --git a/cranelift/filetests/filetests/runtests/iaddcin.clif b/cranelift/filetests/filetests/runtests/iaddcin.clif deleted file mode 100644 index 5b185af2a88f..000000000000 --- a/cranelift/filetests/filetests/runtests/iaddcin.clif +++ /dev/null @@ -1,48 +0,0 @@ -test interpret - -function %iaddcin_i8(i8, i8, i8) -> i8 { -block0(v0: i8, v1: i8, v2: i8): - v3 = iadd_cin v0, v1, v2 - return v3 -} -; run: %iaddcin_i8(0, 1, 1) == 2 -; run: %iaddcin_i8(0, 1, 0) == 1 -; run: %iaddcin_i8(100, 27, 1) == -128 -; run: %iaddcin_i8(100, 27, 0) == 127 - -function %iaddcin_i16(i16, i16, i8) -> i16 { -block0(v0: i16, v1: i16, v2: i8): - v3 = iadd_cin v0, v1, v2 - return v3 -} -; run: %iaddcin_i16(0, 1, 1) == 2 -; run: %iaddcin_i16(0, 1, 0) == 1 -; run: %iaddcin_i16(100, 27, 1) == 128 -; run: %iaddcin_i16(100, 27, 0) == 127 -; run: %iaddcin_i16(32000, 767, 1) == -32768 -; run: %iaddcin_i16(32000, 767, 0) == 32767 - -function %iaddcin_i32(i32, i32, i8) -> i32 { -block0(v0: i32, v1: i32, v2: i8): - v3 = iadd_cin v0, v1, v2 - return v3 -} -; run: %iaddcin_i32(0, 1, 1) == 2 -; run: %iaddcin_i32(0, 1, 0) == 1 -; run: %iaddcin_i32(100, 27, 1) == 128 -; run: %iaddcin_i32(100, 27, 0) == 127 -; run: %iaddcin_i32(2000000000, 147483647, 1) == -2147483648 -; run: %iaddcin_i32(2000000000, 147483647, 0) == 2147483647 - - -function %iaddcin_i64(i64, i64, i8) -> i64 { -block0(v0: i64, v1: i64, v2: i8): - v3 = iadd_cin v0, v1, v2 - return v3 -} -; run: %iaddcin_i64(0, 1, 1) == 2 -; run: %iaddcin_i64(0, 1, 0) == 1 -; run: %iaddcin_i64(100, 27, 1) == 128 -; run: %iaddcin_i64(100, 27, 0) == 127 -; run: %iaddcin_i64(2000000000, 147483647, 1) == 2147483648 -; run: %iaddcin_i64(2000000000, 147483647, 0) == 2147483647 diff --git a/cranelift/filetests/filetests/runtests/isubbin.clif b/cranelift/filetests/filetests/runtests/isubbin.clif deleted file mode 100644 index 53ebcf116a92..000000000000 --- a/cranelift/filetests/filetests/runtests/isubbin.clif +++ /dev/null @@ -1,49 +0,0 @@ -test interpret - -function %isubbin_i8(i8, i8, i8) -> i8 { -block0(v0: i8, v1: i8, v2: i8): - v3 = isub_bin v0, v1, v2 - return v3 -} -; run: %isubbin_i8(0, 1, 1) == -2 -; run: %isubbin_i8(0, 1, 0) == -1 -; run: %isubbin_i8(100, 20, 1) == 79 -; run: %isubbin_i8(100, 20, 0) == 80 -; run: %isubbin_i8(-128, 1, 1) == 126 -; run: %isubbin_i8(-128, 1, 0) == 127 - -function %isubbin_i16(i16, i16, i8) -> i16 { -block0(v0: i16, v1: i16, v2: i8): - v3 = isub_bin v0, v1, v2 - return v3 -} -; run: %isubbin_i16(0, 1, 1) == -2 -; run: %isubbin_i16(0, 1, 0) == -1 -; run: %isubbin_i16(100, 20, 1) == 79 -; run: %isubbin_i16(100, 20, 0) == 80 -; run: %isubbin_i16(-32768, 1, 1) == 32766 -; run: %isubbin_i16(-32768, 1, 0) == 32767 - -function %isubbin_i32(i32, i32, i8) -> i32 { -block0(v0: i32, v1: i32, v2: i8): - v3 = isub_bin v0, v1, v2 - return v3 -} -; run: %isubbin_i32(0, 1, 1) == -2 -; run: %isubbin_i32(0, 1, 0) == -1 -; run: %isubbin_i32(100, 20, 1) == 79 -; run: %isubbin_i32(100, 20, 0) == 80 -; run: %isubbin_i32(-2147483648, 1, 1) == 2147483646 -; run: %isubbin_i32(-2147483648, 1, 0) == 2147483647 - -function %isubbin_i64(i64, i64, i8) -> i64 { -block0(v0: i64, v1: i64, v2: i8): - v3 = isub_bin v0, v1, v2 - return v3 -} -; run: %isubbin_i64(0, 1, 1) == -2 -; run: %isubbin_i64(0, 1, 0) == -1 -; run: %isubbin_i64(100, 20, 1) == 79 -; run: %isubbin_i64(100, 20, 0) == 80 -; run: %isubbin_i64(-2147483648, 1, 1) == -2147483650 -; run: %isubbin_i64(-2147483648, 1, 0) == -2147483649 diff --git a/cranelift/filetests/filetests/runtests/isubborrow.clif b/cranelift/filetests/filetests/runtests/isubborrow.clif index 90dd04c53bcc..4dcbf4190cae 100644 --- a/cranelift/filetests/filetests/runtests/isubborrow.clif +++ b/cranelift/filetests/filetests/runtests/isubborrow.clif @@ -1,98 +1,111 @@ test interpret -function %isubborrow_i8_v(i8, i8, i8) -> i8 { +function %ssub_overflow_bin_i8(i8, i8, i8) -> i8, i8 { block0(v0: i8, v1: i8, v2: i8): - v3, v4 = isub_borrow v0, v1, v2 - return v3 + v3, v4 = ssub_overflow_bin v0, v1, v2 + return v3, v4 } -; run: %isubborrow_i8_v(0, 1, 1) == -2 -; run: %isubborrow_i8_v(0, 1, 0) == -1 -; run: %isubborrow_i8_v(100, 20, 1) == 79 -; run: %isubborrow_i8_v(100, 20, 0) == 80 -; run: %isubborrow_i8_v(127, 127, 1) == -1 -; run: %isubborrow_i8_v(127, 127, 0) == 0 +; run: %ssub_overflow_bin_i8(0, 1, 1) == [-2, 0] +; run: %ssub_overflow_bin_i8(0, 1, 10) == [-2, 0] +; run: %ssub_overflow_bin_i8(0, 1, 0) == [-1, 0] +; run: %ssub_overflow_bin_i8(100, 20, 1) == [79, 0] +; run: %ssub_overflow_bin_i8(100, 20, 0) == [80, 0] +; run: %ssub_overflow_bin_i8(127, 127, 1) == [-1, 0] +; run: %ssub_overflow_bin_i8(127, 127, 0) == [0, 0] +; run: %ssub_overflow_bin_i8(-120, 8, 0) == [-128, 0] +; run: %ssub_overflow_bin_i8(-120, 8, 1) == [127, 1] +; run: %ssub_overflow_bin_i8(-120, 8, 10) == [127, 1] -function %isubborrow_i8_c(i8, i8, i8) -> i8 { -block0(v0: i8, v1: i8, v2: i8): - v3, v4 = isub_borrow v0, v1, v2 - return v4 -} -; run: %isubborrow_i8_c(0, 1, 1) == 1 -; run: %isubborrow_i8_c(0, 1, 0) == 1 -; run: %isubborrow_i8_c(100, 20, 1) == 0 -; run: %isubborrow_i8_c(100, 20, 0) == 0 -; run: %isubborrow_i8_c(127, 127, 1) == 0 -; run: %isubborrow_i8_c(127, 127, 0) == 0 - -function %isubborrow_i16_v(i16, i16, i8) -> i16 { +function %ssub_overflow_bin_i16(i16, i16, i8) -> i16, i8 { block0(v0: i16, v1: i16, v2: i8): - v3, v4 = isub_borrow v0, v1, v2 - return v3 + v3, v4 = ssub_overflow_bin v0, v1, v2 + return v3, v4 } -; run: %isubborrow_i16_v(0, 1, 1) == -2 -; run: %isubborrow_i16_v(0, 1, 0) == -1 -; run: %isubborrow_i16_v(100, 20, 1) == 79 -; run: %isubborrow_i16_v(100, 20, 0) == 80 -; run: %isubborrow_i16_v(-32000, 768, 1) == 32767 -; run: %isubborrow_i16_v(-32000, 768, 0) == -32768 +; run: %ssub_overflow_bin_i16(0, 1, 1) == [-2, 0] +; run: %ssub_overflow_bin_i16(0, 1, 10) == [-2, 0] +; run: %ssub_overflow_bin_i16(0, 1, 0) == [-1, 0] +; run: %ssub_overflow_bin_i16(100, 20, 1) == [79, 0] +; run: %ssub_overflow_bin_i16(100, 20, 0) == [80, 0] +; run: %ssub_overflow_bin_i16(-32000, 768, 1) == [32767, 1] +; run: %ssub_overflow_bin_i16(-32000, 768, 0) == [-32768, 0] -function %isubborrow_i16_c(i16, i16, i8) -> i8 { -block0(v0: i16, v1: i16, v2: i8): - v3, v4 = isub_borrow v0, v1, v2 - return v4 +function %ssub_overflow_bin_i32(i32, i32, i8) -> i32, i8 { +block0(v0: i32, v1: i32, v2: i8): + v3, v4 = ssub_overflow_bin v0, v1, v2 + return v3, v4 } -; run: %isubborrow_i16_c(0, 1, 1) == 1 -; run: %isubborrow_i16_c(0, 1, 0) == 1 -; run: %isubborrow_i16_c(100, 20, 1) == 0 -; run: %isubborrow_i16_c(100, 20, 0) == 0 -; run: %isubborrow_i16_c(-32000, 768, 1) == 1 -; run: %isubborrow_i16_c(-32000, 768, 0) == 1 +; run: %ssub_overflow_bin_i32(0, 1, 1) == [-2, 0] +; run: %ssub_overflow_bin_i32(0, 1, 10) == [-2, 0] +; run: %ssub_overflow_bin_i32(0, 1, 0) == [-1, 0] +; run: %ssub_overflow_bin_i32(100, 20, 1) == [79, 0] +; run: %ssub_overflow_bin_i32(100, 20, 0) == [80, 0] +; run: %ssub_overflow_bin_i32(-2147483640, 8, 1) == [2147483647, 1] +; run: %ssub_overflow_bin_i32(-2147483640, 8, 0) == [-2147483648, 0] -function %isubborrow_i32_v(i32, i32, i8) -> i32 { -block0(v0: i32, v1: i32, v2: i8): - v3, v4 = isub_borrow v0, v1, v2 - return v3 +function %ssub_overflow_bin_i64(i64, i64, i8) -> i64, i8 { +block0(v0: i64, v1: i64, v2: i8): + v3, v4 = ssub_overflow_bin v0, v1, v2 + return v3, v4 } -; run: %isubborrow_i32_v(0, 1, 1) == -2 -; run: %isubborrow_i32_v(0, 1, 0) == -1 -; run: %isubborrow_i32_v(100, 20, 1) == 79 -; run: %isubborrow_i32_v(100, 20, 0) == 80 -; run: %isubborrow_i32_v(-2147483640, 8, 1) == 2147483647 -; run: %isubborrow_i32_v(-2147483640, 8, 0) == -2147483648 +; run: %ssub_overflow_bin_i64(0, 1, 1) == [-2, 0] +; run: %ssub_overflow_bin_i64(0, 1, 10) == [-2, 0] +; run: %ssub_overflow_bin_i64(0, 1, 0) == [-1, 0] +; run: %ssub_overflow_bin_i64(100, 20, 1) == [79, 0] +; run: %ssub_overflow_bin_i64(100, 20, 0) == [80, 0] +; run: %ssub_overflow_bin_i64(-9223372036854775800, 8, 1) == [9223372036854775807, 1] +; run: %ssub_overflow_bin_i64(-9223372036854775800, 8, 0) == [-9223372036854775808, 0] -function %isubborrow_i32_c(i32, i32, i8) -> i8 { -block0(v0: i32, v1: i32, v2: i8): - v3, v4 = isub_borrow v0, v1, v2 - return v4 +function %usub_overflow_bin_i8(i8, i8, i8) -> i8, i8 { +block0(v0: i8, v1: i8, v2: i8): + v3, v4 = usub_overflow_bin v0, v1, v2 + return v3, v4 } -; run: %isubborrow_i32_c(0, 1, 1) == 1 -; run: %isubborrow_i32_c(0, 1, 0) == 1 -; run: %isubborrow_i32_c(100, 20, 1) == 0 -; run: %isubborrow_i32_c(100, 20, 0) == 0 -; run: %isubborrow_i32_c(-2147483640, 8, 1) == 1 -; run: %isubborrow_i32_c(-2147483640, 8, 0) == 1 +; run: %usub_overflow_bin_i8(0, 1, 1) == [-2, 1] +; run: %usub_overflow_bin_i8(0, 1, 10) == [-2, 1] +; run: %usub_overflow_bin_i8(0, 1, 0) == [-1, 1] +; run: %usub_overflow_bin_i8(100, 20, 1) == [79, 0] +; run: %usub_overflow_bin_i8(100, 20, 0) == [80, 0] +; run: %usub_overflow_bin_i8(127, 127, 1) == [-1, 1] +; run: %usub_overflow_bin_i8(127, 127, 0) == [0, 0] +; run: %usub_overflow_bin_i8(-120, 8, 0) == [-128, 0] +; run: %usub_overflow_bin_i8(-120, 8, 1) == [127, 0] +; run: %usub_overflow_bin_i8(-120, 8, 10) == [127, 0] +function %usub_overflow_bin_i16(i16, i16, i8) -> i16, i8 { +block0(v0: i16, v1: i16, v2: i8): + v3, v4 = usub_overflow_bin v0, v1, v2 + return v3, v4 +} +; run: %usub_overflow_bin_i16(0, 1, 1) == [-2, 1] +; run: %usub_overflow_bin_i16(0, 1, 10) == [-2, 1] +; run: %usub_overflow_bin_i16(0, 1, 0) == [-1, 1] +; run: %usub_overflow_bin_i16(100, 20, 1) == [79, 0] +; run: %usub_overflow_bin_i16(100, 20, 0) == [80, 0] +; run: %usub_overflow_bin_i16(-32000, 768, 1) == [32767, 0] +; run: %usub_overflow_bin_i16(-32000, 768, 0) == [-32768, 0] -function %isubborrow_i64_v(i64, i64, i8) -> i64 { -block0(v0: i64, v1: i64, v2: i8): - v3, v4 = isub_borrow v0, v1, v2 - return v3 +function %usub_overflow_bin_i32(i32, i32, i8) -> i32, i8 { +block0(v0: i32, v1: i32, v2: i8): + v3, v4 = usub_overflow_bin v0, v1, v2 + return v3, v4 } -; run: %isubborrow_i64_v(0, 1, 1) == -2 -; run: %isubborrow_i64_v(0, 1, 0) == -1 -; run: %isubborrow_i64_v(100, 20, 1) == 79 -; run: %isubborrow_i64_v(100, 20, 0) == 80 -; run: %isubborrow_i64_v(-9223372036854775800, 8, 1) == 9223372036854775807 -; run: %isubborrow_i64_v(-9223372036854775800, 8, 0) == -9223372036854775808 +; run: %usub_overflow_bin_i32(0, 1, 1) == [-2, 1] +; run: %usub_overflow_bin_i32(0, 1, 10) == [-2, 1] +; run: %usub_overflow_bin_i32(0, 1, 0) == [-1, 1] +; run: %usub_overflow_bin_i32(100, 20, 1) == [79, 0] +; run: %usub_overflow_bin_i32(100, 20, 0) == [80, 0] +; run: %usub_overflow_bin_i32(-2147483640, 8, 1) == [2147483647, 0] +; run: %usub_overflow_bin_i32(-2147483640, 8, 0) == [-2147483648, 0] -function %isubborrow_i64_c(i64, i64, i8) -> i8 { +function %usub_overflow_bin_i64(i64, i64, i8) -> i64, i8 { block0(v0: i64, v1: i64, v2: i8): - v3, v4 = isub_borrow v0, v1, v2 - return v4 + v3, v4 = usub_overflow_bin v0, v1, v2 + return v3, v4 } -; run: %isubborrow_i64_c(0, 1, 1) == 1 -; run: %isubborrow_i64_c(0, 1, 0) == 1 -; run: %isubborrow_i64_c(100, 20, 1) == 0 -; run: %isubborrow_i64_c(100, 20, 0) == 0 -; run: %isubborrow_i64_c(-9223372036854775800, 8, 1) == 1 -; run: %isubborrow_i64_c(-9223372036854775800, 8, 0) == 1 +; run: %usub_overflow_bin_i64(0, 1, 1) == [-2, 1] +; run: %usub_overflow_bin_i64(0, 1, 10) == [-2, 1] +; run: %usub_overflow_bin_i64(0, 1, 0) == [-1, 1] +; run: %usub_overflow_bin_i64(100, 20, 1) == [79, 0] +; run: %usub_overflow_bin_i64(100, 20, 0) == [80, 0] +; run: %usub_overflow_bin_i64(-9223372036854775800, 8, 1) == [9223372036854775807, 0] +; run: %usub_overflow_bin_i64(-9223372036854775800, 8, 0) == [-9223372036854775808, 0] diff --git a/cranelift/fuzzgen/src/function_generator.rs b/cranelift/fuzzgen/src/function_generator.rs index b7b1049ae3cc..fca6812cc103 100644 --- a/cranelift/fuzzgen/src/function_generator.rs +++ b/cranelift/fuzzgen/src/function_generator.rs @@ -921,11 +921,11 @@ static OPCODE_SIGNATURES: Lazy> = Lazy::new(|| { (Opcode::UremImm), (Opcode::SremImm), (Opcode::IrsubImm), - (Opcode::IaddCin), - (Opcode::IaddCarry), + (Opcode::UaddOverflowCin), + (Opcode::SaddOverflowCin), (Opcode::UaddOverflowTrap), - (Opcode::IsubBin), - (Opcode::IsubBorrow), + (Opcode::UsubOverflowBin), + (Opcode::SsubOverflowBin), (Opcode::BandImm), (Opcode::BorImm), (Opcode::BxorImm), diff --git a/cranelift/interpreter/src/step.rs b/cranelift/interpreter/src/step.rs index ed5e6177293a..f0afb83a1e5e 100644 --- a/cranelift/interpreter/src/step.rs +++ b/cranelift/interpreter/src/step.rs @@ -718,24 +718,24 @@ where let (sum, carry) = arg(0).smul_overflow(arg(1))?; assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?]) } - Opcode::IaddCin => choose( - DataValueExt::into_bool(arg(2))?, - DataValueExt::add( - DataValueExt::add(arg(0), arg(1))?, - DataValueExt::int(1, ctrl_ty)?, - )?, - DataValueExt::add(arg(0), arg(1))?, - ), - Opcode::IaddCarry => { - let mut sum = DataValueExt::add(arg(0), arg(1))?; - let mut carry = arg(0).sadd_checked(arg(1))?.is_none(); + Opcode::SaddOverflowCin => { + let (mut sum, mut carry) = arg(0).sadd_overflow(arg(1))?; if DataValueExt::into_bool(arg(2))? { - carry |= sum - .clone() - .sadd_checked(DataValueExt::int(1, ctrl_ty)?)? - .is_none(); - sum = DataValueExt::add(sum, DataValueExt::int(1, ctrl_ty)?)?; + let (sum2, carry2) = sum.sadd_overflow(DataValueExt::int(1, ctrl_ty)?)?; + carry |= carry2; + sum = sum2; + } + + assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?]) + } + Opcode::UaddOverflowCin => { + let (mut sum, mut carry) = arg(0).uadd_overflow(arg(1))?; + + if DataValueExt::into_bool(arg(2))? { + let (sum2, carry2) = sum.uadd_overflow(DataValueExt::int(1, ctrl_ty)?)?; + carry |= carry2; + sum = sum2; } assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?]) @@ -749,23 +749,27 @@ where assign(sum) } } - Opcode::IsubBin => choose( - DataValueExt::into_bool(arg(2))?, - DataValueExt::sub( - arg(0), - DataValueExt::add(arg(1), DataValueExt::int(1, ctrl_ty)?)?, - )?, - DataValueExt::sub(arg(0), arg(1))?, - ), - Opcode::IsubBorrow => { - let rhs = if DataValueExt::into_bool(arg(2))? { - DataValueExt::add(arg(1), DataValueExt::int(1, ctrl_ty)?)? - } else { - arg(1) - }; - let borrow = arg(0) < rhs; - let sum = DataValueExt::sub(arg(0), rhs)?; - assign_multiple(&[sum, DataValueExt::bool(borrow, false, types::I8)?]) + Opcode::SsubOverflowBin => { + let (mut sub, mut carry) = arg(0).ssub_overflow(arg(1))?; + + if DataValueExt::into_bool(arg(2))? { + let (sub2, carry2) = sub.ssub_overflow(DataValueExt::int(1, ctrl_ty)?)?; + carry |= carry2; + sub = sub2; + } + + assign_multiple(&[sub, DataValueExt::bool(carry, false, types::I8)?]) + } + Opcode::UsubOverflowBin => { + let (mut sub, mut carry) = arg(0).usub_overflow(arg(1))?; + + if DataValueExt::into_bool(arg(2))? { + let (sub2, carry2) = sub.usub_overflow(DataValueExt::int(1, ctrl_ty)?)?; + carry |= carry2; + sub = sub2; + } + + assign_multiple(&[sub, DataValueExt::bool(carry, false, types::I8)?]) } Opcode::Band => binary(DataValueExt::and, arg(0), arg(1))?, Opcode::Bor => binary(DataValueExt::or, arg(0), arg(1))?,