From f95d2574e403ce23b607264515c4a36713c61c4f Mon Sep 17 00:00:00 2001 From: dheaton-arm Date: Mon, 16 Aug 2021 11:39:46 +0100 Subject: [PATCH 1/3] Implement `IaddCin`, `IaddCout`, and `IaddCarry` for Cranelift interpreter Implemented the following Opcodes for the Cranelift interpreter: - `IaddCin` to add two scalar integers with an input carry flag. - `IaddCout` to add two scalar integers and report overflow with the carry flag. - `IaddCarry` to add two scalar integers with an input carry flag, reporting overflow with the output carry flag. Copyright (c) 2021, Arm Limited --- .../filetests/interpreter/iaddcarry.clif | 73 ++++++++++++++++ .../filetests/interpreter/iaddcin.clif | 48 ++++++++++ .../filetests/interpreter/iaddcout.clif | 87 +++++++++++++++++++ cranelift/interpreter/src/step.rs | 24 ++++- 4 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 cranelift/filetests/filetests/interpreter/iaddcarry.clif create mode 100644 cranelift/filetests/filetests/interpreter/iaddcin.clif create mode 100644 cranelift/filetests/filetests/interpreter/iaddcout.clif diff --git a/cranelift/filetests/filetests/interpreter/iaddcarry.clif b/cranelift/filetests/filetests/interpreter/iaddcarry.clif new file mode 100644 index 000000000000..9719cabca9e9 --- /dev/null +++ b/cranelift/filetests/filetests/interpreter/iaddcarry.clif @@ -0,0 +1,73 @@ +test interpret + +function %iaddcarry_i8_v(i8, i8, b1) -> i8 { +block0(v0: i8, v1: i8, v2: b1): + v3, v4 = iadd_carry v0, v1, v2 + return v3 +} +; run: %iaddcarry_i8_v(0, 1, true) == 2 +; run: %iaddcarry_i8_v(0, 1, false) == 1 +; run: %iaddcarry_i8_v(100, 27, true) == -128 +; run: %iaddcarry_i8_v(100, 27, false) == 127 +; run: %iaddcarry_i8_v(127, 127, true) == -1 +; run: %iaddcarry_i8_v(127, 127, false) == -2 + +function %iaddcarry_i8_c(i8, i8, b1) -> b1 { +block0(v0: i8, v1: i8, v2: b1): + v3, v4 = iadd_carry v0, v1, v2 + return v4 +} +; run: %iaddcarry_i8_c(0, 1, true) == false +; run: %iaddcarry_i8_c(0, 1, false) == false +; run: %iaddcarry_i8_c(100, 27, true) == true +; run: %iaddcarry_i8_c(100, 27, false) == false +; run: %iaddcarry_i8_c(127, 127, true) == true +; run: %iaddcarry_i8_c(127, 127, false) == true + +function %iaddcarry_i16_v(i16, i16, b1) -> i16 { +block0(v0: i16, v1: i16, v2: b1): + v3, v4 = iadd_carry v0, v1, v2 + return v3 +} +; run: %iaddcarry_i16_v(0, 1, true) == 2 +; run: %iaddcarry_i16_v(0, 1, false) == 1 +; run: %iaddcarry_i16_v(100, 27, true) == 128 +; run: %iaddcarry_i16_v(100, 27, false) == 127 +; run: %iaddcarry_i16_v(32000, 767, true) == -32768 +; run: %iaddcarry_i16_v(32000, 767, false) == 32767 + +function %iaddcarry_i16_c(i16, i16, b1) -> b1 { +block0(v0: i16, v1: i16, v2: b1): + v3, v4 = iadd_carry v0, v1, v2 + return v4 +} +; run: %iaddcarry_i16_c(0, 1, true) == false +; run: %iaddcarry_i16_c(0, 1, false) == false +; run: %iaddcarry_i16_c(100, 27, true) == false +; run: %iaddcarry_i16_c(100, 27, false) == false +; run: %iaddcarry_i16_c(32000, 767, true) == true +; run: %iaddcarry_i16_c(32000, 767, false) == false + +function %iaddcarry_i32_v(i32, i32, b1) -> i32 { +block0(v0: i32, v1: i32, v2: b1): + v3, v4 = iadd_carry v0, v1, v2 + return v3 +} +; run: %iaddcarry_i32_v(0, 1, true) == 2 +; run: %iaddcarry_i32_v(0, 1, false) == 1 +; run: %iaddcarry_i32_v(100, 27, true) == 128 +; run: %iaddcarry_i32_v(100, 27, false) == 127 +; run: %iaddcarry_i32_v(2000000000, 147483647, true) == -2147483648 +; run: %iaddcarry_i32_v(2000000000, 147483647, false) == 2147483647 + +function %iaddcarry_i32_c(i32, i32, b1) -> b1 { +block0(v0: i32, v1: i32, v2: b1): + v3, v4 = iadd_carry v0, v1, v2 + return v4 +} +; run: %iaddcarry_i32_c(0, 1, true) == false +; run: %iaddcarry_i32_c(0, 1, false) == false +; run: %iaddcarry_i32_c(100, 27, true) == false +; run: %iaddcarry_i32_c(100, 27, false) == false +; run: %iaddcarry_i32_c(2000000000, 147483647, true) == true +; run: %iaddcarry_i32_c(2000000000, 147483647, false) == false \ No newline at end of file diff --git a/cranelift/filetests/filetests/interpreter/iaddcin.clif b/cranelift/filetests/filetests/interpreter/iaddcin.clif new file mode 100644 index 000000000000..8f36ee0d7001 --- /dev/null +++ b/cranelift/filetests/filetests/interpreter/iaddcin.clif @@ -0,0 +1,48 @@ +test interpret + +function %iaddcin_i8(i8, i8, b1) -> i8 { +block0(v0: i8, v1: i8, v2: b1): + v3 = iadd_cin v0, v1, v2 + return v3 +} +; run: %iaddcin_i8(0, 1, true) == 2 +; run: %iaddcin_i8(0, 1, false) == 1 +; run: %iaddcin_i8(100, 27, true) == -128 +; run: %iaddcin_i8(100, 27, false) == 127 + +function %iaddcin_i16(i16, i16, b1) -> i16 { +block0(v0: i16, v1: i16, v2: b1): + v3 = iadd_cin v0, v1, v2 + return v3 +} +; run: %iaddcin_i16(0, 1, true) == 2 +; run: %iaddcin_i16(0, 1, false) == 1 +; run: %iaddcin_i16(100, 27, true) == 128 +; run: %iaddcin_i16(100, 27, false) == 127 +; run: %iaddcin_i16(32000, 767, true) == -32768 +; run: %iaddcin_i16(32000, 767, false) == 32767 + +function %iaddcin_i32(i32, i32, b1) -> i32 { +block0(v0: i32, v1: i32, v2: b1): + v3 = iadd_cin v0, v1, v2 + return v3 +} +; run: %iaddcin_i32(0, 1, true) == 2 +; run: %iaddcin_i32(0, 1, false) == 1 +; run: %iaddcin_i32(100, 27, true) == 128 +; run: %iaddcin_i32(100, 27, false) == 127 +; run: %iaddcin_i32(2000000000, 147483647, true) == -2147483648 +; run: %iaddcin_i32(2000000000, 147483647, false) == 2147483647 + + +function %iaddcin_i64(i64, i64, b1) -> i64 { +block0(v0: i64, v1: i64, v2: b1): + v3 = iadd_cin v0, v1, v2 + return v3 +} +; run: %iaddcin_i64(0, 1, true) == 2 +; run: %iaddcin_i64(0, 1, false) == 1 +; run: %iaddcin_i64(100, 27, true) == 128 +; run: %iaddcin_i64(100, 27, false) == 127 +; run: %iaddcin_i64(2000000000, 147483647, true) == 2147483648 +; run: %iaddcin_i64(2000000000, 147483647, false) == 2147483647 diff --git a/cranelift/filetests/filetests/interpreter/iaddcout.clif b/cranelift/filetests/filetests/interpreter/iaddcout.clif new file mode 100644 index 000000000000..6f497b61e51d --- /dev/null +++ b/cranelift/filetests/filetests/interpreter/iaddcout.clif @@ -0,0 +1,87 @@ +test interpret + +function %iaddcout_i8_v(i8, i8) -> i8 { +block0(v0: i8, v1: i8): + v2, v3 = iadd_cout v0, v1 + return v2 +} +; run: %iaddcout_i8_v(0, 1) == 1 +; run: %iaddcout_i8_v(100, 27) == 127 +; run: %iaddcout_i8_v(100, -20) == 80 +; run: %iaddcout_i8_v(100, 28) == -128 + +function %iaddcout_i8_c(i8, i8) -> b1 { +block0(v0: i8, v1: i8): + v2, v3 = iadd_cout v0, v1 + return v3 +} +; run: %iaddcout_i8_c(0, 1) == false +; run: %iaddcout_i8_c(100, 27) == false +; run: %iaddcout_i8_c(100, -20) == false +; run: %iaddcout_i8_c(100, 28) == true + +function %iaddcout_i16_v(i16, i16) -> i16 { +block0(v0: i16, v1: i16): + v2, v3 = iadd_cout v0, v1 + return v2 +} +; run: %iaddcout_i16_v(0, 1) == 1 +; run: %iaddcout_i16_v(100, 27) == 127 +; run: %iaddcout_i16_v(100, 28) == 128 +; run: %iaddcout_i16_v(32000, 767) == 32767 +; run: %iaddcout_i16_v(32000, 768) == -32768 + +function %iaddcout_i16_c(i16, i16) -> b1 { +block0(v0: i16, v1: i16): + v2, v3 = iadd_cout v0, v1 + return v3 +} +; run: %iaddcout_i16_c(0, 1) == false +; run: %iaddcout_i16_c(100, 27) == false +; run: %iaddcout_i16_c(100, 28) == false +; run: %iaddcout_i16_c(32000, 767) == false +; run: %iaddcout_i16_c(32000, 768) == true + +function %iaddcout_i32_v(i32, i32) -> i32 { +block0(v0: i32, v1: i32): + v2, v3 = iadd_cout v0, v1 + return v2 +} +; run: %iaddcout_i32_v(0, 1) == 1 +; run: %iaddcout_i32_v(100, 27) == 127 +; run: %iaddcout_i32_v(100, 28) == 128 +; run: %iaddcout_i32_v(2000000000, 147483647) == 2147483647 +; run: %iaddcout_i32_v(2000000000, 147483648) == -2147483648 + +function %iaddcout_i32_c(i32, i32) -> b1 { +block0(v0: i32, v1: i32): + v2, v3 = iadd_cout v0, v1 + return v3 +} +; run: %iaddcout_i32_c(0, 1) == false +; run: %iaddcout_i32_c(100, 27) == false +; run: %iaddcout_i32_c(100, 28) == false +; run: %iaddcout_i32_c(2000000000, 147483647) == false +; run: %iaddcout_i32_c(2000000000, 147483648) == true + +function %iaddcout_i64_v(i64, i64) -> i64 { +block0(v0: i64, v1: i64): + v2, v3 = iadd_cout v0, v1 + return v2 +} +; run: %iaddcout_i64_v(0, 1) == 1 +; run: %iaddcout_i64_v(100, 27) == 127 +; run: %iaddcout_i64_v(100, 28) == 128 +; run: %iaddcout_i64_v(2000000000, 147483647) == 2147483647 +; run: %iaddcout_i64_v(2000000000, 147483648) == 2147483648 + +function %iaddcout_i64_c(i64, i64) -> b1 { +block0(v0: i64, v1: i64): + v2, v3 = iadd_cout v0, v1 + return v3 +} +; run: %iaddcout_i64_c(0, 1) == false +; run: %iaddcout_i64_c(100, 27) == false +; run: %iaddcout_i64_c(100, 28) == false +; run: %iaddcout_i64_c(2000000000, 147483647) == false +; run: %iaddcout_i64_c(2000000000, 147483648) == false diff --git a/cranelift/interpreter/src/step.rs b/cranelift/interpreter/src/step.rs index c9c03729809b..2b1f1e533b46 100644 --- a/cranelift/interpreter/src/step.rs +++ b/cranelift/interpreter/src/step.rs @@ -454,11 +454,29 @@ where Opcode::UremImm => binary_unsigned_can_trap(Value::rem, arg(0)?, imm())?, Opcode::SremImm => binary_can_trap(Value::rem, arg(0)?, imm_as_ctrl_ty()?)?, Opcode::IrsubImm => binary(Value::sub, imm_as_ctrl_ty()?, arg(0)?)?, - Opcode::IaddCin => unimplemented!("IaddCin"), + Opcode::IaddCin => choose( + Value::into_bool(arg(2)?)?, + Value::add(Value::add(arg(0)?, arg(1)?)?, Value::int(1, ctrl_ty)?)?, + Value::add(arg(0)?, arg(1)?)?, + ), Opcode::IaddIfcin => unimplemented!("IaddIfcin"), - Opcode::IaddCout => unimplemented!("IaddCout"), + Opcode::IaddCout => { + let sum = Value::add(arg(0)?, arg(1)?)?; + let mut carry = false; + if Value::lt(&sum, &arg(0)?)? && Value::lt(&sum, &arg(1)?)? { + carry = true; + } + assign_multiple(&[sum, Value::bool(carry, types::B1)?]) + } Opcode::IaddIfcout => unimplemented!("IaddIfcout"), - Opcode::IaddCarry => unimplemented!("IaddCarry"), + Opcode::IaddCarry => { + let mut sum = Value::add(arg(0)?, arg(1)?)?; + if Value::into_bool(arg(2)?)? { + sum = Value::add(sum, Value::int(1, ctrl_ty)?)? + } + let carry = Value::lt(&sum, &arg(0)?)? && Value::lt(&sum, &arg(1)?)?; + assign_multiple(&[sum, Value::bool(carry, types::B1)?]) + } Opcode::IaddIfcarry => unimplemented!("IaddIfcarry"), Opcode::IsubBin => unimplemented!("IsubBin"), Opcode::IsubIfbin => unimplemented!("IsubIfbin"), From e99cc57a73ab543930ee981ff36f10f49b4c1105 Mon Sep 17 00:00:00 2001 From: dheaton-arm Date: Wed, 25 Aug 2021 14:49:26 +0100 Subject: [PATCH 2/3] Simplify carry check + add i64 `IaddCarry` tests Copyright (c) 2021, Arm Limited --- .../filetests/interpreter/iaddcarry.clif | 26 ++++++++++++++++++- cranelift/interpreter/src/step.rs | 5 +--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/cranelift/filetests/filetests/interpreter/iaddcarry.clif b/cranelift/filetests/filetests/interpreter/iaddcarry.clif index 9719cabca9e9..51389ed60c6f 100644 --- a/cranelift/filetests/filetests/interpreter/iaddcarry.clif +++ b/cranelift/filetests/filetests/interpreter/iaddcarry.clif @@ -70,4 +70,28 @@ block0(v0: i32, v1: i32, v2: b1): ; run: %iaddcarry_i32_c(100, 27, true) == false ; run: %iaddcarry_i32_c(100, 27, false) == false ; run: %iaddcarry_i32_c(2000000000, 147483647, true) == true -; run: %iaddcarry_i32_c(2000000000, 147483647, false) == false \ No newline at end of file +; run: %iaddcarry_i32_c(2000000000, 147483647, false) == false + +function %iaddcarry_i64_v(i64, i64, b1) -> i64 { +block0(v0: i64, v1: i64, v2: b1): + v3, v4 = iadd_carry v0, v1, v2 + return v3 +} +; run: %iaddcarry_i64_v(0, 1, true) == 2 +; run: %iaddcarry_i64_v(0, 1, false) == 1 +; run: %iaddcarry_i64_v(100, 27, true) == 128 +; run: %iaddcarry_i64_v(100, 27, false) == 127 +; run: %iaddcarry_i64_v(9000000000000000000, 223372036854775807, true) == -9223372036854775808 +; run: %iaddcarry_i64_v(9000000000000000000, 223372036854775807, false) == 9223372036854775807 + +function %iaddcarry_i64_c(i64, i64, b1) -> b1 { +block0(v0: i64, v1: i64, v2: b1): + v3, v4 = iadd_carry v0, v1, v2 + return v4 +} +; run: %iaddcarry_i64_c(0, 1, true) == false +; run: %iaddcarry_i64_c(0, 1, false) == false +; run: %iaddcarry_i64_c(100, 27, true) == false +; run: %iaddcarry_i64_c(100, 27, false) == false +; run: %iaddcarry_i64_c(9000000000000000000, 223372036854775807, true) == true +; run: %iaddcarry_i64_c(9000000000000000000, 223372036854775807, false) == false diff --git a/cranelift/interpreter/src/step.rs b/cranelift/interpreter/src/step.rs index 2b1f1e533b46..b199ef4d4866 100644 --- a/cranelift/interpreter/src/step.rs +++ b/cranelift/interpreter/src/step.rs @@ -462,10 +462,7 @@ where Opcode::IaddIfcin => unimplemented!("IaddIfcin"), Opcode::IaddCout => { let sum = Value::add(arg(0)?, arg(1)?)?; - let mut carry = false; - if Value::lt(&sum, &arg(0)?)? && Value::lt(&sum, &arg(1)?)? { - carry = true; - } + let carry = Value::lt(&sum, &arg(0)?)? && Value::lt(&sum, &arg(1)?)?; assign_multiple(&[sum, Value::bool(carry, types::B1)?]) } Opcode::IaddIfcout => unimplemented!("IaddIfcout"), From 565d5c9bcb1aadfa958fef234ba60118f3838084 Mon Sep 17 00:00:00 2001 From: dheaton-arm Date: Tue, 31 Aug 2021 10:45:09 +0100 Subject: [PATCH 3/3] Move tests to `runtests` Copyright (c) 2021, Arm Limited --- .../filetests/filetests/{interpreter => runtests}/iaddcarry.clif | 0 .../filetests/filetests/{interpreter => runtests}/iaddcin.clif | 0 .../filetests/filetests/{interpreter => runtests}/iaddcout.clif | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename cranelift/filetests/filetests/{interpreter => runtests}/iaddcarry.clif (100%) rename cranelift/filetests/filetests/{interpreter => runtests}/iaddcin.clif (100%) rename cranelift/filetests/filetests/{interpreter => runtests}/iaddcout.clif (100%) diff --git a/cranelift/filetests/filetests/interpreter/iaddcarry.clif b/cranelift/filetests/filetests/runtests/iaddcarry.clif similarity index 100% rename from cranelift/filetests/filetests/interpreter/iaddcarry.clif rename to cranelift/filetests/filetests/runtests/iaddcarry.clif diff --git a/cranelift/filetests/filetests/interpreter/iaddcin.clif b/cranelift/filetests/filetests/runtests/iaddcin.clif similarity index 100% rename from cranelift/filetests/filetests/interpreter/iaddcin.clif rename to cranelift/filetests/filetests/runtests/iaddcin.clif diff --git a/cranelift/filetests/filetests/interpreter/iaddcout.clif b/cranelift/filetests/filetests/runtests/iaddcout.clif similarity index 100% rename from cranelift/filetests/filetests/interpreter/iaddcout.clif rename to cranelift/filetests/filetests/runtests/iaddcout.clif