Skip to content

Commit e3a2db9

Browse files
committed
Support imports math_add_mod and math_mul_mod
1 parent c68f427 commit e3a2db9

File tree

3 files changed

+127
-25
lines changed

3 files changed

+127
-25
lines changed

integration/stylus/milestone_3.sol

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,28 @@ contract C {
2020
return (balance, codehash, manual_codehash, gasprice);
2121
}
2222

23+
function test_addmod() public pure {
24+
uint256 x = addmod(500, 100, 3);
25+
uint256 y = addmod(500, 100, 7);
26+
27+
print("x = {}".format(x));
28+
print("y = {}".format(y));
29+
30+
assert(x == 0);
31+
assert(y == 5);
32+
}
33+
34+
function test_mulmod() public pure {
35+
uint256 x = mulmod(500, 100, 3);
36+
uint256 y = mulmod(500, 100, 7);
37+
38+
print("x = {}".format(x));
39+
print("y = {}".format(y));
40+
41+
assert(x == 2);
42+
assert(y == 6);
43+
}
44+
2345
function getCode() public view returns (bytes) {
2446
return address(this).code;
2547
}

src/emit/expression.rs

Lines changed: 101 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,12 +1757,45 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
17571757
args,
17581758
..
17591759
} => {
1760-
let arith_ty = bin.context.custom_width_int_type(512);
1761-
let res_ty = bin.context.custom_width_int_type(256);
1762-
17631760
let x = expression(target, bin, &args[0], vartab, function).into_int_value();
17641761
let y = expression(target, bin, &args[1], vartab, function).into_int_value();
17651762
let k = expression(target, bin, &args[2], vartab, function).into_int_value();
1763+
1764+
if bin.ns.target == Target::Stylus {
1765+
let x_unswapped_ptr =
1766+
bin.build_alloca(function, bin.value_type(), "x_unswapped_ptr");
1767+
let y_unswapped_ptr =
1768+
bin.build_alloca(function, bin.value_type(), "y_unswapped_ptr");
1769+
let k_unswapped_ptr =
1770+
bin.build_alloca(function, bin.value_type(), "k_unswapped_ptr");
1771+
let x_swapped_ptr = bin.build_alloca(function, bin.value_type(), "x_swapped_ptr");
1772+
let y_swapped_ptr = bin.build_alloca(function, bin.value_type(), "y_swapped_ptr");
1773+
let k_swapped_ptr = bin.build_alloca(function, bin.value_type(), "k_swapped_ptr");
1774+
bin.builder.build_store(x_unswapped_ptr, x).unwrap();
1775+
bin.builder.build_store(y_unswapped_ptr, y).unwrap();
1776+
bin.builder.build_store(k_unswapped_ptr, k).unwrap();
1777+
byte_swap_value(bin, &Type::Uint(256), x_unswapped_ptr, x_swapped_ptr, true);
1778+
byte_swap_value(bin, &Type::Uint(256), y_unswapped_ptr, y_swapped_ptr, true);
1779+
byte_swap_value(bin, &Type::Uint(256), k_unswapped_ptr, k_swapped_ptr, true);
1780+
call!(
1781+
"math_add_mod",
1782+
&[
1783+
x_swapped_ptr.into(),
1784+
y_swapped_ptr.into(),
1785+
k_swapped_ptr.into()
1786+
]
1787+
);
1788+
let sum_ptr = bin.build_alloca(function, bin.value_type(), "sum_ptr");
1789+
byte_swap_value(bin, &Type::Uint(256), x_swapped_ptr, sum_ptr, false);
1790+
return bin
1791+
.builder
1792+
.build_load(bin.value_type(), sum_ptr, "sum")
1793+
.unwrap();
1794+
}
1795+
1796+
let arith_ty = bin.context.custom_width_int_type(512);
1797+
let res_ty = bin.context.custom_width_int_type(256);
1798+
17661799
let dividend = bin
17671800
.builder
17681801
.build_int_add(
@@ -1855,11 +1888,45 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
18551888
args,
18561889
..
18571890
} => {
1891+
let x = expression(target, bin, &args[0], vartab, function).into_int_value();
1892+
let y = expression(target, bin, &args[1], vartab, function).into_int_value();
1893+
let k = expression(target, bin, &args[2], vartab, function).into_int_value();
1894+
1895+
if bin.ns.target == Target::Stylus {
1896+
let x_unswapped_ptr =
1897+
bin.build_alloca(function, bin.value_type(), "x_unswapped_ptr");
1898+
let y_unswapped_ptr =
1899+
bin.build_alloca(function, bin.value_type(), "y_unswapped_ptr");
1900+
let k_unswapped_ptr =
1901+
bin.build_alloca(function, bin.value_type(), "k_unswapped_ptr");
1902+
let x_swapped_ptr = bin.build_alloca(function, bin.value_type(), "x_swapped_ptr");
1903+
let y_swapped_ptr = bin.build_alloca(function, bin.value_type(), "y_swapped_ptr");
1904+
let k_swapped_ptr = bin.build_alloca(function, bin.value_type(), "k_swapped_ptr");
1905+
bin.builder.build_store(x_unswapped_ptr, x).unwrap();
1906+
bin.builder.build_store(y_unswapped_ptr, y).unwrap();
1907+
bin.builder.build_store(k_unswapped_ptr, k).unwrap();
1908+
byte_swap_value(bin, &Type::Uint(256), x_unswapped_ptr, x_swapped_ptr, true);
1909+
byte_swap_value(bin, &Type::Uint(256), y_unswapped_ptr, y_swapped_ptr, true);
1910+
byte_swap_value(bin, &Type::Uint(256), k_unswapped_ptr, k_swapped_ptr, true);
1911+
call!(
1912+
"math_mul_mod",
1913+
&[
1914+
x_swapped_ptr.into(),
1915+
y_swapped_ptr.into(),
1916+
k_swapped_ptr.into()
1917+
]
1918+
);
1919+
let product_ptr = bin.build_alloca(function, bin.value_type(), "product_ptr");
1920+
byte_swap_value(bin, &Type::Uint(256), x_swapped_ptr, product_ptr, false);
1921+
return bin
1922+
.builder
1923+
.build_load(bin.value_type(), product_ptr, "product")
1924+
.unwrap();
1925+
}
1926+
18581927
let arith_ty = bin.context.custom_width_int_type(512);
18591928
let res_ty = bin.context.custom_width_int_type(256);
18601929

1861-
let x = expression(target, bin, &args[0], vartab, function).into_int_value();
1862-
let y = expression(target, bin, &args[1], vartab, function).into_int_value();
18631930
let x_m = bin.build_alloca(function, arith_ty, "x_m");
18641931
let y_m = bin.build_alloca(function, arith_ty, "x_y");
18651932
let x_times_y_m = bin.build_alloca(function, arith_ty, "x_times_y_m");
@@ -1893,7 +1960,6 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
18931960
"",
18941961
)
18951962
.unwrap();
1896-
let k = expression(target, bin, &args[2], vartab, function).into_int_value();
18971963
let dividend = bin
18981964
.builder
18991965
.build_load(arith_ty, x_times_y_m, "x_t_y")
@@ -2138,7 +2204,7 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
21382204

21392205
Expression::ByteSwap { expr, le_to_be } => {
21402206
let ty = expr.ty();
2141-
bytes_swap(target, bin, &ty, expr, *le_to_be, vartab, function)
2207+
byte_swap_expression(target, bin, &ty, expr, *le_to_be, vartab, function)
21422208
}
21432209

21442210
Expression::RationalNumberLiteral { .. }
@@ -2696,7 +2762,7 @@ fn basic_value_to_slice<'a>(
26962762

26972763
// smoelius: I think this type-walking must be done during the emit phase and not during the codegen
26982764
// phase. For example, the bounds on a dynamic array cannot be known. Hence, a loop must be emitted.
2699-
fn bytes_swap<'a, T: TargetRuntime<'a> + ?Sized>(
2765+
fn byte_swap_expression<'a, T: TargetRuntime<'a> + ?Sized>(
27002766
target: &T,
27012767
bin: &Binary<'a>,
27022768
ty: &Type,
@@ -2723,31 +2789,41 @@ fn bytes_swap<'a, T: TargetRuntime<'a> + ?Sized>(
27232789
"dest",
27242790
);
27252791

2726-
let name = if le_to_be { "__leNtobeN" } else { "__beNtoleN" };
2727-
2728-
bin.builder
2729-
.build_call(
2730-
bin.module.get_function(name).unwrap(),
2731-
&[
2732-
src.into(),
2733-
dest.into(),
2734-
bin.context
2735-
.i32_type()
2736-
.const_int((ty.get_type_size() / 8) as u64, false)
2737-
.into(),
2738-
],
2739-
name,
2740-
)
2741-
.unwrap();
2792+
byte_swap_value(bin, ty, src, dest, le_to_be);
27422793

27432794
bin.builder
27442795
.build_load(llvm_ty, dest, "swapped bytes")
27452796
.unwrap()
27462797
}
27472798
Type::UserType(no) => {
27482799
let ty = &bin.ns.user_types[*no].ty;
2749-
bytes_swap(target, bin, ty, expr, le_to_be, vartab, function)
2800+
byte_swap_expression(target, bin, ty, expr, le_to_be, vartab, function)
27502801
}
27512802
_ => unimplemented!("{ty:?}"),
27522803
}
27532804
}
2805+
2806+
fn byte_swap_value(
2807+
bin: &Binary<'_>,
2808+
ty: &Type,
2809+
from: PointerValue<'_>,
2810+
to: PointerValue<'_>,
2811+
le_to_be: bool,
2812+
) {
2813+
let name = if le_to_be { "__leNtobeN" } else { "__beNtoleN" };
2814+
2815+
bin.builder
2816+
.build_call(
2817+
bin.module.get_function(name).unwrap(),
2818+
&[
2819+
from.into(),
2820+
to.into(),
2821+
bin.context
2822+
.i32_type()
2823+
.const_int((ty.get_type_size() / 8) as u64, false)
2824+
.into(),
2825+
],
2826+
name,
2827+
)
2828+
.unwrap();
2829+
}

tests/stylus_tests/milestone_3.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ fn milestone_3() {
5757
.position(|c| c.is_ascii_whitespace())
5858
.unwrap_or_else(|| gasprice.len());
5959
assert_eq!(100000000, u64::from_str_radix(&gasprice[..i], 10).unwrap());
60+
61+
call(dir, &address, ["test_addmod()"]).unwrap();
62+
63+
call(dir, &address, ["test_mulmod()"]).unwrap();
6064
}
6165

6266
fn label(stdout: &str) -> String {

0 commit comments

Comments
 (0)