mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Merge pull request #4683 from roc-lang/gen-wasm-shr-128
gen_wasm: Implement u128 right shift by delegating to compiler_rt
This commit is contained in:
commit
ac45fa2bba
4 changed files with 70 additions and 46 deletions
|
@ -993,33 +993,11 @@ wymix = \a, b ->
|
|||
|
||||
wymum : U64, U64 -> { lower : U64, upper : U64 }
|
||||
wymum = \a, b ->
|
||||
# uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo;
|
||||
# uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t<rl;
|
||||
# lo=t+(rm1<<32); c+=lo<t; hi=rh+(rm0>>32)+(rm1>>32)+c;
|
||||
ha = Num.shiftRightZfBy a 32
|
||||
hb = Num.shiftRightZfBy b 32
|
||||
la = Num.bitwiseAnd a 0x0000_0000_FFFF_FFFF
|
||||
lb = Num.bitwiseAnd b 0x0000_0000_FFFF_FFFF
|
||||
rh = ha * hb
|
||||
rm0 = ha * lb
|
||||
rm1 = hb * la
|
||||
rl = la * lb
|
||||
t = Num.addWrap rl (Num.shiftLeftBy rm0 32)
|
||||
c = if t < rl then 1 else 0
|
||||
lower = Num.addWrap t (Num.shiftLeftBy rm1 32)
|
||||
c2 = c + (if lower < t then 1 else 0)
|
||||
upper =
|
||||
rh
|
||||
|> Num.addWrap (Num.shiftRightZfBy rm0 32)
|
||||
|> Num.addWrap (Num.shiftRightZfBy rm1 32)
|
||||
|> Num.addWrap c2
|
||||
r = Num.toU128 a * Num.toU128 b
|
||||
lower = Num.toU64 r
|
||||
upper = Num.shiftRightZfBy r 64 |> Num.toU64
|
||||
|
||||
# TODO: switch back to this once wasm supports bit shifting a U128.
|
||||
# The above code is manually doing the 128bit multiplication.
|
||||
# r = Num.toU128 a * Num.toU128 b
|
||||
# lower = Num.toU64 r
|
||||
# upper = Num.shiftRightZfBy r 64 |> Num.toU64
|
||||
# This is the more robust form.
|
||||
# This is the more robust form, which we may look into later
|
||||
# { lower: Num.bitwiseXor a lower, upper: Num.bitwiseXor b upper }
|
||||
{ lower, upper }
|
||||
|
||||
|
|
|
@ -1708,12 +1708,11 @@ impl<'a> LowLevelCall<'a> {
|
|||
backend.code_builder.i64_extend_u_i32();
|
||||
backend.code_builder.i64_shr_u();
|
||||
}
|
||||
I128 => todo!("{:?} for I128", self.lowlevel),
|
||||
I128 => self.load_args_and_call_zig(backend, "__lshrti3"), // from compiler_rt
|
||||
_ => panic_ret_type(),
|
||||
}
|
||||
}
|
||||
NumIntCast => {
|
||||
self.load_args(backend);
|
||||
let arg_layout = backend.storage.symbol_layouts[&self.arguments[0]];
|
||||
let arg_type = CodeGenNumType::from(arg_layout);
|
||||
let arg_width = match backend.layout_interner.get(arg_layout) {
|
||||
|
@ -1729,19 +1728,56 @@ impl<'a> LowLevelCall<'a> {
|
|||
};
|
||||
|
||||
match (ret_type, arg_type) {
|
||||
(I32, I32) => self.wrap_small_int(backend, ret_width),
|
||||
(I32, I32) => {
|
||||
self.load_args(backend);
|
||||
self.wrap_small_int(backend, ret_width);
|
||||
}
|
||||
(I32, I64) => {
|
||||
self.load_args(backend);
|
||||
backend.code_builder.i32_wrap_i64();
|
||||
self.wrap_small_int(backend, ret_width);
|
||||
}
|
||||
(I32, I128) => {
|
||||
self.load_args(backend);
|
||||
backend.code_builder.i32_load(Align::Bytes4, 0);
|
||||
}
|
||||
(I64, I32) => {
|
||||
self.load_args(backend);
|
||||
if arg_width.is_signed() {
|
||||
backend.code_builder.i64_extend_s_i32()
|
||||
} else {
|
||||
backend.code_builder.i64_extend_u_i32()
|
||||
}
|
||||
}
|
||||
(I64, I64) => {}
|
||||
(I64, I64) => {
|
||||
self.load_args(backend);
|
||||
}
|
||||
(I64, I128) => {
|
||||
let (frame_ptr, offset) = match backend.storage.get(&self.arguments[0]) {
|
||||
StoredValue::StackMemory { location, .. } => {
|
||||
location.local_and_offset(backend.storage.stack_frame_pointer)
|
||||
}
|
||||
_ => internal_error!("I128 should be in stack memory"),
|
||||
};
|
||||
backend.code_builder.get_local(frame_ptr);
|
||||
backend.code_builder.i64_load(Align::Bytes8, offset);
|
||||
}
|
||||
(I128, I64) => {
|
||||
// Symbols are loaded as if for a call, so the i128 "return address" and i64 value are on the value stack
|
||||
self.load_args(backend);
|
||||
backend.code_builder.i64_store(Align::Bytes8, 0);
|
||||
|
||||
// Zero the most significant 64 bits
|
||||
let (frame_ptr, offset) = match &self.ret_storage {
|
||||
StoredValue::StackMemory { location, .. } => {
|
||||
location.local_and_offset(backend.storage.stack_frame_pointer)
|
||||
}
|
||||
_ => internal_error!("I128 should be in stack memory"),
|
||||
};
|
||||
backend.code_builder.get_local(frame_ptr);
|
||||
backend.code_builder.i64_const(0);
|
||||
backend.code_builder.i64_store(Align::Bytes8, offset + 8);
|
||||
}
|
||||
|
||||
_ => todo!("{:?}: {:?} -> {:?}", self.lowlevel, arg_type, ret_type),
|
||||
}
|
||||
|
|
|
@ -2156,6 +2156,16 @@ fn shift_right_zf_by() {
|
|||
assert_evals_to!("Num.shiftRightZfBy 0b0000_0010u8 1", 0b0000_0001u8, u8);
|
||||
assert_evals_to!("Num.shiftRightZfBy 0b0000_1100u8 2", 0b0000_0011u8, u8);
|
||||
assert_evals_to!("Num.shiftRightZfBy 0b1000_0000u8 12", 0b0000_0000u8, u8);
|
||||
assert_evals_to!(
|
||||
"Num.shiftRightZfBy 0xffff_0000_0000_0000_0000_0000_0000_ffffu128 4",
|
||||
0x0fff_f000_0000_0000_0000_0000_0000_0fffu128,
|
||||
u128
|
||||
);
|
||||
assert_evals_to!(
|
||||
"Num.shiftRightZfBy 0xaaaa_0000_0000_bbbb_ffff_ffff_ffff_ffffu128 68",
|
||||
0x0000_0000_0000_0000_0aaa_a000_0000_0bbbu128,
|
||||
u128
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
procedure Dict.1 (Dict.518):
|
||||
let Dict.521 : List {[], []} = Array [];
|
||||
let Dict.528 : U64 = 0i64;
|
||||
let Dict.529 : U64 = 8i64;
|
||||
let Dict.522 : List U64 = CallByName List.11 Dict.528 Dict.529;
|
||||
let Dict.525 : I8 = CallByName Dict.34;
|
||||
let Dict.526 : U64 = 8i64;
|
||||
let Dict.523 : List I8 = CallByName List.11 Dict.525 Dict.526;
|
||||
let Dict.524 : U64 = 0i64;
|
||||
let Dict.520 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.521, Dict.522, Dict.523, Dict.524};
|
||||
ret Dict.520;
|
||||
procedure Dict.1 (Dict.508):
|
||||
let Dict.511 : List {[], []} = Array [];
|
||||
let Dict.518 : U64 = 0i64;
|
||||
let Dict.519 : U64 = 8i64;
|
||||
let Dict.512 : List U64 = CallByName List.11 Dict.518 Dict.519;
|
||||
let Dict.515 : I8 = CallByName Dict.34;
|
||||
let Dict.516 : U64 = 8i64;
|
||||
let Dict.513 : List I8 = CallByName List.11 Dict.515 Dict.516;
|
||||
let Dict.514 : U64 = 0i64;
|
||||
let Dict.510 : {List {[], []}, List U64, List I8, U64} = Struct {Dict.511, Dict.512, Dict.513, Dict.514};
|
||||
ret Dict.510;
|
||||
|
||||
procedure Dict.34 ():
|
||||
let Dict.527 : I8 = -128i64;
|
||||
ret Dict.527;
|
||||
let Dict.517 : I8 = -128i64;
|
||||
ret Dict.517;
|
||||
|
||||
procedure Dict.4 (Dict.507):
|
||||
let Dict.85 : U64 = StructAtIndex 3 Dict.507;
|
||||
dec Dict.507;
|
||||
procedure Dict.4 (Dict.497):
|
||||
let Dict.85 : U64 = StructAtIndex 3 Dict.497;
|
||||
dec Dict.497;
|
||||
ret Dict.85;
|
||||
|
||||
procedure List.11 (List.114, List.115):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue