diff --git a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs index 48e8f790885..eaf834c5d81 100644 --- a/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs +++ b/sway-core/src/asm_generation/fuel/fuel_asm_builder.rs @@ -588,6 +588,24 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { val2_reg, VirtualImmediate06::wide_op(WideOperations::Sub, true), ), + BinaryOpKind::And => VirtualOp::WQOP( + result_reg, + val1_reg, + val2_reg, + VirtualImmediate06::wide_op(WideOperations::And, true), + ), + BinaryOpKind::Or => VirtualOp::WQOP( + result_reg, + val1_reg, + val2_reg, + VirtualImmediate06::wide_op(WideOperations::Or, true), + ), + BinaryOpKind::Xor => VirtualOp::WQOP( + result_reg, + val1_reg, + val2_reg, + VirtualImmediate06::wide_op(WideOperations::Xor, true), + ), BinaryOpKind::Lsh => VirtualOp::WQOP( result_reg, val1_reg, @@ -670,7 +688,18 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> { val2_reg, VirtualImmediate06::wide_cmp(WideCmp::Equality, true), ), - _ => todo!(), + Predicate::LessThan => VirtualOp::WQCM( + res_reg.clone(), + val1_reg, + val2_reg, + VirtualImmediate06::wide_cmp(WideCmp::LessThan, true), + ), + Predicate::GreaterThan => VirtualOp::WQCM( + res_reg.clone(), + val1_reg, + val2_reg, + VirtualImmediate06::wide_cmp(WideCmp::GreaterThan, true), + ), }; self.cur_bytecode.push(Op { diff --git a/sway-core/src/asm_lang/virtual_immediate.rs b/sway-core/src/asm_lang/virtual_immediate.rs index 0c21c22ae61..0bead6b4892 100644 --- a/sway-core/src/asm_lang/virtual_immediate.rs +++ b/sway-core/src/asm_lang/virtual_immediate.rs @@ -11,6 +11,9 @@ pub enum WideOperations { Add = 0, Sub = 1, Not = 2, + Or = 3, + Xor = 4, + And = 5, Lsh = 6, Rsh = 7, } @@ -18,6 +21,8 @@ pub enum WideOperations { #[repr(u8)] pub enum WideCmp { Equality = 0, + LessThan = 2, + GreaterThan = 3, } /// 6-bit immediate value type diff --git a/sway-ir/src/optimize/misc_demotion.rs b/sway-ir/src/optimize/misc_demotion.rs index 354c6319007..67496f815a9 100644 --- a/sway-ir/src/optimize/misc_demotion.rs +++ b/sway-ir/src/optimize/misc_demotion.rs @@ -354,7 +354,9 @@ fn wide_binary_op_demotion(context: &mut Context, function: Function) -> Result< (Some(256), Some(256)) => { use BinaryOpKind::*; match op { - Add | Sub | Mul | Div | Mod => Some((block, instr_val)), + Add | Sub | Mul | Div | Mod | And | Or | Xor => { + Some((block, instr_val)) + } _ => todo!(), } } @@ -585,8 +587,7 @@ fn wide_cmp_demotion(context: &mut Context, function: Function) -> Result { use Predicate::*; match op { - Equal => Some((block, instr_val)), - _ => todo!(), + Equal | LessThan | GreaterThan => Some((block, instr_val)), } } _ => None, diff --git a/sway-ir/tests/serialize/wide_ops.ir b/sway-ir/tests/serialize/wide_ops.ir index 4097ed92843..e185d586b2a 100644 --- a/sway-ir/tests/serialize/wide_ops.ir +++ b/sway-ir/tests/serialize/wide_ops.ir @@ -29,6 +29,24 @@ script { wide not v0 to v0 // check: wide not v0 to v0 + wide and v0, v0 to v0 +// check: wide and v0, v0 to v0 + + wide or v0, v0 to v0 +// check: wide or v0, v0 to v0 + + wide xor v0, v0 to v0 +// check: wide xor v0, v0 to v0 + + v2 = wide cmp eq v0 v0 +// check: v2 = wide cmp eq v0 v0 + + v3 = wide cmp lt v0 v0 +// check: v3 = wide cmp lt v0 v0 + + v4 = wide cmp gt v0 v0 +// check: v4 = wide cmp gt v0 v0 + v5 = const unit () ret () v5 } diff --git a/sway-lib-core/src/ops.sw b/sway-lib-core/src/ops.sw index d624e2e2d05..c32e1f3b8a9 100644 --- a/sway-lib-core/src/ops.sw +++ b/sway-lib-core/src/ops.sw @@ -432,6 +432,34 @@ impl Not for u256 { } } + +impl Not for u64 { + fn not(self) -> Self { + __not(self) + } +} + +impl Not for u32 { + fn not(self) -> Self { + let v = __not(self); + __and(v, u32::max()) + } +} + +impl Not for u16 { + fn not(self) -> Self { + let v = __not(self); + __and(v, u16::max()) + } +} + +impl Not for u8 { + fn not(self) -> Self { + let v = __not(self); + __and(v, u8::max()) + } +} + /// Trait to evaluate if two types are equal. pub trait Eq { /// Evaluates if two values of the same type are equal. @@ -625,6 +653,15 @@ pub trait Ord { fn lt(self, other: Self) -> bool; } +impl Ord for u256 { + fn gt(self, other: Self) -> bool { + __gt(self, other) + } + fn lt(self, other: Self) -> bool { + __lt(self, other) + } +} + impl Ord for u64 { fn gt(self, other: Self) -> bool { __gt(self, other) @@ -735,6 +772,12 @@ pub trait BitwiseAnd { fn binary_and(self, other: Self) -> Self; } +impl BitwiseAnd for u256 { + fn binary_and(self, other: Self) -> Self { + __and(self, other) + } +} + impl BitwiseAnd for u64 { fn binary_and(self, other: Self) -> Self { __and(self, other) @@ -797,6 +840,12 @@ pub trait BitwiseOr { fn binary_or(self, other: Self) -> Self; } +impl BitwiseOr for u256 { + fn binary_or(self, other: Self) -> Self { + __or(self, other) + } +} + impl BitwiseOr for u64 { fn binary_or(self, other: Self) -> Self { __or(self, other) @@ -859,6 +908,12 @@ pub trait BitwiseXor { fn binary_xor(self, other: Self) -> Self; } +impl BitwiseXor for u256 { + fn binary_xor(self, other: Self) -> Self { + __xor(self, other) + } +} + impl BitwiseXor for u64 { fn binary_xor(self, other: Self) -> Self { __xor(self, other) @@ -883,33 +938,6 @@ impl BitwiseXor for u8 { } } -impl Not for u64 { - fn not(self) -> Self { - __not(self) - } -} - -impl Not for u32 { - fn not(self) -> Self { - let v = __not(self); - __and(v, u32::max()) - } -} - -impl Not for u16 { - fn not(self) -> Self { - let v = __not(self); - __and(v, u16::max()) - } -} - -impl Not for u8 { - fn not(self) -> Self { - let v = __not(self); - __and(v, u8::max()) - } -} - impl BitwiseAnd for b256 { fn binary_and(val: self, other: Self) -> Self { let (value_word_1, value_word_2, value_word_3, value_word_4) = decompose(val); @@ -1045,6 +1073,7 @@ trait OrdEq: Ord + Eq { } } +impl OrdEq for u256 {} impl OrdEq for u64 {} impl OrdEq for u32 {} impl OrdEq for u16 {} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/src/main.sw index 34a0c7a0108..532f11755b1 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/src/main.sw @@ -19,11 +19,27 @@ fn locals() -> u256 { result } -// returns 2 -fn not_operator() -> u256 { +// returns 11 +fn bitwise_operators() -> u256 { + let a = 18446744073709551615u64; + let b = 3u64; + let c = 2u64; + let d = 4u64; + let e = 15u64; + + let r = !(a - b) & c | d ^ e; + assert(r == 11); + let a = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFu256; - let b = 0x0000000000000000000000000000000000000000000000000000000000000002u256; - !(a - b) + let b = 0x0000000000000000000000000000000000000000000000000000000000000003u256; + let c = 0x0000000000000000000000000000000000000000000000000000000000000002u256; + let d = 0x0000000000000000000000000000000000000000000000000000000000000004u256; + let e = 0x000000000000000000000000000000000000000000000000000000000000000Fu256; + let r = !(a - b) & c | d ^ e; + + assert(r == 0x000000000000000000000000000000000000000000000000000000000000000Bu256); + + r } // returns 8 @@ -66,6 +82,40 @@ fn shift_operators() -> u256 { (a << 4) >> 2 } + +// returns 0 +fn comparison_operators() -> u256 { + let a = 0x0000000000000000000000000000000000000000000000000000000000000001u256; + let b = 0x0000000000000000000000000000000000000000000000000000000000000002u256; + let c = 0x0000000000000000000000000000000000000000000000000000000000000003u256; + let d = 0x0000000000000000000000000000000000000000000000000000000000000003u256; + + assert(c == c); + assert(c <= c); + assert(c >= c); + + assert(c == d); + assert(d == c); + assert(c <= d); + assert(c >= d); + assert(d <= c); + assert(d >= c); + + assert(a < b); + assert(b < c); + assert(a < c); + + assert(a <= b); + assert(b <= c); + assert(a <= c); + + assert(b > a); + assert(c > b); + assert(c > a); + + return 0x0000000000000000000000000000000000000000000000000000000000000000u256; +} + fn main() -> u256 { - constants() + locals() + not_operator() + shift_operators() + constants() + locals() + bitwise_operators() + shift_operators() + comparison_operators() } \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/test.toml index d3b2918a072..e0beb8b65ab 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/u256/test.toml @@ -1,3 +1,3 @@ category = "run" -expected_result = { action = "return_data", value = "000000000000000000000000000000000000000000000000000000000000000E" } +expected_result = { action = "return_data", value = "0000000000000000000000000000000000000000000000000000000000000017" } validate_abi = true