Skip to content

Commit 4288a05

Browse files
committed
Support math_div, math_mod, and math_power imports
1 parent e3a2db9 commit 4288a05

File tree

4 files changed

+169
-0
lines changed

4 files changed

+169
-0
lines changed

integration/stylus/milestone_3.sol

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,36 @@ contract C {
4242
assert(y == 6);
4343
}
4444

45+
function test_div() public pure {
46+
uint256 x = 500;
47+
uint256 y = 100;
48+
uint256 z = x / y;
49+
50+
print("z = {}".format(z));
51+
52+
assert(z == 5);
53+
}
54+
55+
function test_mod() public pure {
56+
uint256 x = 511;
57+
uint256 y = 100;
58+
uint256 z = x % y;
59+
60+
print("z = {}".format(z));
61+
62+
assert(z == 11);
63+
}
64+
65+
function test_power() public pure {
66+
uint256 x = 3;
67+
uint256 y = 5;
68+
uint256 z = x ** y;
69+
70+
print("z = {}".format(z));
71+
72+
assert(z == 243);
73+
}
74+
4575
function getCode() public view returns (bytes) {
4676
return address(this).code;
4777
}

src/emit/expression.rs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,48 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
244244
let left = expression(target, bin, left, vartab, function).into_int_value();
245245
let right = expression(target, bin, right, vartab, function).into_int_value();
246246

247+
// smoelius: If the target is Stylus and `left` and `right` are both `uint256`s, we can
248+
// use the `math_div` import.
249+
if bin.ns.target == Target::Stylus
250+
&& left.get_type().get_bit_width() == 256
251+
&& right.get_type().get_bit_width() == 256
252+
{
253+
let left_unswapped_ptr =
254+
bin.build_alloca(function, bin.value_type(), "left_unswapped_ptr");
255+
let right_unswapped_ptr =
256+
bin.build_alloca(function, bin.value_type(), "right_unswapped_ptr");
257+
let left_swapped_ptr =
258+
bin.build_alloca(function, bin.value_type(), "left_swapped_ptr");
259+
let right_swapped_ptr =
260+
bin.build_alloca(function, bin.value_type(), "right_swapped_ptr");
261+
bin.builder.build_store(left_unswapped_ptr, left).unwrap();
262+
bin.builder.build_store(right_unswapped_ptr, right).unwrap();
263+
byte_swap_value(
264+
bin,
265+
&Type::Uint(256),
266+
left_unswapped_ptr,
267+
left_swapped_ptr,
268+
true,
269+
);
270+
byte_swap_value(
271+
bin,
272+
&Type::Uint(256),
273+
right_unswapped_ptr,
274+
right_swapped_ptr,
275+
true,
276+
);
277+
call!(
278+
"math_div",
279+
&[left_swapped_ptr.into(), right_swapped_ptr.into(),]
280+
);
281+
let quotient_ptr = bin.build_alloca(function, bin.value_type(), "quotient_ptr");
282+
byte_swap_value(bin, &Type::Uint(256), left_swapped_ptr, quotient_ptr, false);
283+
return bin
284+
.builder
285+
.build_load(bin.value_type(), quotient_ptr, "quotient")
286+
.unwrap();
287+
}
288+
247289
let bits = left.get_type().get_bit_width();
248290

249291
if bits > 64 {
@@ -513,6 +555,54 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
513555
let left = expression(target, bin, left, vartab, function).into_int_value();
514556
let right = expression(target, bin, right, vartab, function).into_int_value();
515557

558+
// smoelius: If the target is Stylus and `left` and `right` are both `uint256`s, we can
559+
// use the `math_mod` import.
560+
if bin.ns.target == Target::Stylus
561+
&& left.get_type().get_bit_width() == 256
562+
&& right.get_type().get_bit_width() == 256
563+
{
564+
let left_unswapped_ptr =
565+
bin.build_alloca(function, bin.value_type(), "left_unswapped_ptr");
566+
let right_unswapped_ptr =
567+
bin.build_alloca(function, bin.value_type(), "right_unswapped_ptr");
568+
let left_swapped_ptr =
569+
bin.build_alloca(function, bin.value_type(), "left_swapped_ptr");
570+
let right_swapped_ptr =
571+
bin.build_alloca(function, bin.value_type(), "right_swapped_ptr");
572+
bin.builder.build_store(left_unswapped_ptr, left).unwrap();
573+
bin.builder.build_store(right_unswapped_ptr, right).unwrap();
574+
byte_swap_value(
575+
bin,
576+
&Type::Uint(256),
577+
left_unswapped_ptr,
578+
left_swapped_ptr,
579+
true,
580+
);
581+
byte_swap_value(
582+
bin,
583+
&Type::Uint(256),
584+
right_unswapped_ptr,
585+
right_swapped_ptr,
586+
true,
587+
);
588+
call!(
589+
"math_mod",
590+
&[left_swapped_ptr.into(), right_swapped_ptr.into(),]
591+
);
592+
let remainder_ptr = bin.build_alloca(function, bin.value_type(), "remainder_ptr");
593+
byte_swap_value(
594+
bin,
595+
&Type::Uint(256),
596+
left_swapped_ptr,
597+
remainder_ptr,
598+
false,
599+
);
600+
return bin
601+
.builder
602+
.build_load(bin.value_type(), remainder_ptr, "remainder")
603+
.unwrap();
604+
}
605+
516606
let bits = left.get_type().get_bit_width();
517607

518608
if bits > 64 {
@@ -782,6 +872,48 @@ pub(super) fn expression<'a, T: TargetRuntime<'a> + ?Sized>(
782872
let left = expression(target, bin, l, vartab, function);
783873
let right = expression(target, bin, r, vartab, function);
784874

875+
// smoelius: If the target is Stylus and `left` and `right` are both `uint256`s, we can
876+
// use the `math_pow` import.
877+
if bin.ns.target == Target::Stylus
878+
&& left.into_int_value().get_type().get_bit_width() == 256
879+
&& right.into_int_value().get_type().get_bit_width() == 256
880+
{
881+
let left_unswapped_ptr =
882+
bin.build_alloca(function, bin.value_type(), "left_unswapped_ptr");
883+
let right_unswapped_ptr =
884+
bin.build_alloca(function, bin.value_type(), "right_unswapped_ptr");
885+
let left_swapped_ptr =
886+
bin.build_alloca(function, bin.value_type(), "left_swapped_ptr");
887+
let right_swapped_ptr =
888+
bin.build_alloca(function, bin.value_type(), "right_swapped_ptr");
889+
bin.builder.build_store(left_unswapped_ptr, left).unwrap();
890+
bin.builder.build_store(right_unswapped_ptr, right).unwrap();
891+
byte_swap_value(
892+
bin,
893+
&Type::Uint(256),
894+
left_unswapped_ptr,
895+
left_swapped_ptr,
896+
true,
897+
);
898+
byte_swap_value(
899+
bin,
900+
&Type::Uint(256),
901+
right_unswapped_ptr,
902+
right_swapped_ptr,
903+
true,
904+
);
905+
call!(
906+
"math_pow",
907+
&[left_swapped_ptr.into(), right_swapped_ptr.into(),]
908+
);
909+
let power_ptr = bin.build_alloca(function, bin.value_type(), "power_ptr");
910+
byte_swap_value(bin, &Type::Uint(256), left_swapped_ptr, power_ptr, false);
911+
return bin
912+
.builder
913+
.build_load(bin.value_type(), power_ptr, "power")
914+
.unwrap();
915+
}
916+
785917
let bits = left.into_int_value().get_type().get_bit_width();
786918
let o = bin.build_alloca(function, left.get_type(), "");
787919
let f = power(

tests/stylus.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ fn deploy(path: impl AsRef<Path>, contract: &str) -> Result<(TempDir, String)> {
161161
// smoelius: The default LLVM optimization level can cause public functions to be
162162
// inlined into the dispatch function.
163163
"-O=less",
164+
"--no-constant-folding",
164165
],
165166
)?;
166167

tests/stylus_tests/milestone_3.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ fn milestone_3() {
6161
call(dir, &address, ["test_addmod()"]).unwrap();
6262

6363
call(dir, &address, ["test_mulmod()"]).unwrap();
64+
65+
call(dir, &address, ["test_div()"]).unwrap();
66+
67+
call(dir, &address, ["test_mod()"]).unwrap();
68+
69+
call(dir, &address, ["test_power()"]).unwrap();
6470
}
6571

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

0 commit comments

Comments
 (0)