Skip to content

Commit

Permalink
Remove iadd_cin and isub_bin, split isub_borrow and iadd_carry (
Browse files Browse the repository at this point in the history
#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
  • Loading branch information
alexcrichton authored Sep 6, 2024
1 parent 75ed0b6 commit ff98760
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 345 deletions.
70 changes: 26 additions & 44 deletions cranelift/codegen/meta/src/shared/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand All @@ -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,
)
Expand Down Expand Up @@ -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,
)
Expand All @@ -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,
)
Expand Down
16 changes: 8 additions & 8 deletions cranelift/filetests/filetests/parser/ternary.clif
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ 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
}

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
}
176 changes: 96 additions & 80 deletions cranelift/filetests/filetests/runtests/iaddcarry.clif
Original file line number Diff line number Diff line change
@@ -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]
48 changes: 0 additions & 48 deletions cranelift/filetests/filetests/runtests/iaddcin.clif

This file was deleted.

Loading

0 comments on commit ff98760

Please sign in to comment.