Skip to content

Commit

Permalink
u256 bitwise and comparison operators (#4947)
Browse files Browse the repository at this point in the history
## Description

This PR is part of #4794. It
implements the missing operators: bitwise and comparison.


## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.

---------

Co-authored-by: Anton Trunov <[email protected]>
  • Loading branch information
xunilrj and anton-trunov authored Aug 30, 2023
1 parent 9b986af commit e1d0ea0
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 37 deletions.
31 changes: 30 additions & 1 deletion sway-core/src/asm_generation/fuel/fuel_asm_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions sway-core/src/asm_lang/virtual_immediate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@ pub enum WideOperations {
Add = 0,
Sub = 1,
Not = 2,
Or = 3,
Xor = 4,
And = 5,
Lsh = 6,
Rsh = 7,
}

#[repr(u8)]
pub enum WideCmp {
Equality = 0,
LessThan = 2,
GreaterThan = 3,
}

/// 6-bit immediate value type
Expand Down
7 changes: 4 additions & 3 deletions sway-ir/src/optimize/misc_demotion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(),
}
}
Expand Down Expand Up @@ -585,8 +587,7 @@ fn wide_cmp_demotion(context: &mut Context, function: Function) -> Result<bool,
(Some(256), Some(256)) => {
use Predicate::*;
match op {
Equal => Some((block, instr_val)),
_ => todo!(),
Equal | LessThan | GreaterThan => Some((block, instr_val)),
}
}
_ => None,
Expand Down
18 changes: 18 additions & 0 deletions sway-ir/tests/serialize/wide_ops.ir
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
83 changes: 56 additions & 27 deletions sway-lib-core/src/ops.sw
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -1045,6 +1073,7 @@ trait OrdEq: Ord + Eq {
}
}

impl OrdEq for u256 {}
impl OrdEq for u64 {}
impl OrdEq for u32 {}
impl OrdEq for u16 {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
category = "run"
expected_result = { action = "return_data", value = "000000000000000000000000000000000000000000000000000000000000000E" }
expected_result = { action = "return_data", value = "0000000000000000000000000000000000000000000000000000000000000017" }
validate_abi = true

0 comments on commit e1d0ea0

Please sign in to comment.