mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 13:59:08 +00:00
Merge pull request #3658 from rtfeldman/wasm-fix-shiftRightBy
wasm: Fix shiftRightBy for U8 and U16
This commit is contained in:
commit
94ccfc30a3
2 changed files with 52 additions and 22 deletions
|
@ -1610,13 +1610,46 @@ impl<'a> LowLevelCall<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NumShiftRightBy => {
|
NumShiftRightBy => {
|
||||||
backend.storage.load_symbols(
|
let bits = self.arguments[0];
|
||||||
&mut backend.code_builder,
|
let num = self.arguments[1];
|
||||||
&[self.arguments[1], self.arguments[0]],
|
|
||||||
);
|
|
||||||
match CodeGenNumType::from(self.ret_layout) {
|
match CodeGenNumType::from(self.ret_layout) {
|
||||||
I32 => backend.code_builder.i32_shr_s(),
|
I32 => {
|
||||||
I64 => backend.code_builder.i64_shr_s(),
|
// In most languages this operation is for signed numbers, but Roc defines it on all integers.
|
||||||
|
// So the argument is implicitly converted to signed before the shift operator.
|
||||||
|
// We need to make that conversion explicit for i8 and i16, which use Wasm's i32 type.
|
||||||
|
let bit_width = 8 * self.ret_layout.stack_size(TARGET_INFO) as i32;
|
||||||
|
if bit_width < 32 && !symbol_is_signed_int(backend, num) {
|
||||||
|
// Sign-extend the number by shifting left and right again
|
||||||
|
backend
|
||||||
|
.storage
|
||||||
|
.load_symbols(&mut backend.code_builder, &[num]);
|
||||||
|
backend.code_builder.i32_const(32 - bit_width);
|
||||||
|
backend.code_builder.i32_shl();
|
||||||
|
backend.code_builder.i32_const(32 - bit_width);
|
||||||
|
backend.code_builder.i32_shr_s();
|
||||||
|
backend
|
||||||
|
.storage
|
||||||
|
.load_symbols(&mut backend.code_builder, &[bits]);
|
||||||
|
|
||||||
|
// Do the actual bitshift operation
|
||||||
|
backend.code_builder.i32_shr_s();
|
||||||
|
|
||||||
|
// Restore to unsigned
|
||||||
|
backend.code_builder.i32_const((1 << bit_width) - 1);
|
||||||
|
backend.code_builder.i32_and();
|
||||||
|
} else {
|
||||||
|
backend
|
||||||
|
.storage
|
||||||
|
.load_symbols(&mut backend.code_builder, &[num, bits]);
|
||||||
|
backend.code_builder.i32_shr_s();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
I64 => {
|
||||||
|
backend
|
||||||
|
.storage
|
||||||
|
.load_symbols(&mut backend.code_builder, &[num, bits]);
|
||||||
|
backend.code_builder.i64_shr_s();
|
||||||
|
}
|
||||||
I128 => todo!("{:?} for I128", self.lowlevel),
|
I128 => todo!("{:?} for I128", self.lowlevel),
|
||||||
_ => panic_ret_type(),
|
_ => panic_ret_type(),
|
||||||
}
|
}
|
||||||
|
@ -1624,7 +1657,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
NumShiftRightZfBy => {
|
NumShiftRightZfBy => {
|
||||||
match CodeGenNumType::from(self.ret_layout) {
|
match CodeGenNumType::from(self.ret_layout) {
|
||||||
I32 => {
|
I32 => {
|
||||||
// This is normally an unsigned operation, but Roc defines it on all integer types.
|
// In most languages this operation is for unsigned numbers, but Roc defines it on all integers.
|
||||||
// So the argument is implicitly converted to unsigned before the shift operator.
|
// So the argument is implicitly converted to unsigned before the shift operator.
|
||||||
// We need to make that conversion explicit for i8 and i16, which use Wasm's i32 type.
|
// We need to make that conversion explicit for i8 and i16, which use Wasm's i32 type.
|
||||||
let bit_width = 8 * self.ret_layout.stack_size(TARGET_INFO);
|
let bit_width = 8 * self.ret_layout.stack_size(TARGET_INFO);
|
||||||
|
|
|
@ -2004,25 +2004,22 @@ fn shift_left_by() {
|
||||||
fn shift_right_by() {
|
fn shift_right_by() {
|
||||||
// Sign Extended Right Shift
|
// Sign Extended Right Shift
|
||||||
|
|
||||||
let is_wasm = cfg!(feature = "gen-wasm");
|
|
||||||
let is_llvm_release_mode = cfg!(feature = "gen-llvm") && !cfg!(debug_assertions);
|
let is_llvm_release_mode = cfg!(feature = "gen-llvm") && !cfg!(debug_assertions);
|
||||||
|
|
||||||
// FIXME (Brian) Something funny happening with 8-bit binary literals in tests
|
// FIXME (Brian) Something funny happening with 8-bit binary literals in tests
|
||||||
if !is_wasm {
|
assert_evals_to!(
|
||||||
assert_evals_to!(
|
"Num.shiftRightBy 2 (Num.toI8 0b1100_0000u8)",
|
||||||
"Num.shiftRightBy 2 (Num.toI8 0b1100_0000u8)",
|
0b1111_0000u8 as i8,
|
||||||
0b1111_0000u8 as i8,
|
i8
|
||||||
i8
|
);
|
||||||
);
|
assert_evals_to!("Num.shiftRightBy 2 0b0100_0000i8", 0b0001_0000i8, i8);
|
||||||
assert_evals_to!("Num.shiftRightBy 2 0b0100_0000i8", 0b0001_0000i8, i8);
|
assert_evals_to!("Num.shiftRightBy 1 0b1110_0000u8", 0b1111_0000u8, u8);
|
||||||
assert_evals_to!("Num.shiftRightBy 1 0b1110_0000u8", 0b1111_0000u8, u8);
|
assert_evals_to!("Num.shiftRightBy 2 0b1100_0000u8", 0b1111_0000u8, u8);
|
||||||
assert_evals_to!("Num.shiftRightBy 2 0b1100_0000u8", 0b1111_0000u8, u8);
|
assert_evals_to!("Num.shiftRightBy 12 0b0100_0000u8", 0b0000_0000u8, u8);
|
||||||
assert_evals_to!("Num.shiftRightBy 12 0b0100_0000u8", 0b0000_0000u8, u8);
|
|
||||||
|
|
||||||
// LLVM in release mode returns 0 instead of -1 for some reason
|
// LLVM in release mode returns 0 instead of -1 for some reason
|
||||||
if !is_llvm_release_mode {
|
if !is_llvm_release_mode {
|
||||||
assert_evals_to!("Num.shiftRightBy 12 0b1000_0000u8", 0b1111_1111u8, u8);
|
assert_evals_to!("Num.shiftRightBy 12 0b1000_0000u8", 0b1111_1111u8, u8);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert_evals_to!("Num.shiftRightBy 0 12", 12, i64);
|
assert_evals_to!("Num.shiftRightBy 0 12", 12, i64);
|
||||||
assert_evals_to!("Num.shiftRightBy 1 12", 6, i64);
|
assert_evals_to!("Num.shiftRightBy 1 12", 6, i64);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue