cranelift: add i64.{ishl,ushr,ashr} libcalls.
These libcalls are useful for 32-bit platforms.
On x86_32 in particular, commit 4ec16fa0 added support for legalizing
64-bit shifts through SIMD operations. However, that legalization
requires SIMD to be enabled and SSE 4.1 to be supported, which is not
acceptable as a hard requirement.
This commit is contained in:
@@ -32,6 +32,12 @@ pub enum LibCall {
|
|||||||
UremI64,
|
UremI64,
|
||||||
/// srem.i64
|
/// srem.i64
|
||||||
SremI64,
|
SremI64,
|
||||||
|
/// ishl.i64
|
||||||
|
IshlI64,
|
||||||
|
/// ushr.i64
|
||||||
|
UshrI64,
|
||||||
|
/// sshr.i64
|
||||||
|
SshrI64,
|
||||||
/// ceil.f32
|
/// ceil.f32
|
||||||
CeilF32,
|
CeilF32,
|
||||||
/// ceil.f64
|
/// ceil.f64
|
||||||
@@ -75,6 +81,9 @@ impl FromStr for LibCall {
|
|||||||
"SdivI64" => Ok(Self::SdivI64),
|
"SdivI64" => Ok(Self::SdivI64),
|
||||||
"UremI64" => Ok(Self::UremI64),
|
"UremI64" => Ok(Self::UremI64),
|
||||||
"SremI64" => Ok(Self::SremI64),
|
"SremI64" => Ok(Self::SremI64),
|
||||||
|
"IshlI64" => Ok(Self::IshlI64),
|
||||||
|
"UshrI64" => Ok(Self::UshrI64),
|
||||||
|
"SshrI64" => Ok(Self::SshrI64),
|
||||||
"CeilF32" => Ok(Self::CeilF32),
|
"CeilF32" => Ok(Self::CeilF32),
|
||||||
"CeilF64" => Ok(Self::CeilF64),
|
"CeilF64" => Ok(Self::CeilF64),
|
||||||
"FloorF32" => Ok(Self::FloorF32),
|
"FloorF32" => Ok(Self::FloorF32),
|
||||||
@@ -105,6 +114,9 @@ impl LibCall {
|
|||||||
Opcode::Sdiv => Self::SdivI64,
|
Opcode::Sdiv => Self::SdivI64,
|
||||||
Opcode::Urem => Self::UremI64,
|
Opcode::Urem => Self::UremI64,
|
||||||
Opcode::Srem => Self::SremI64,
|
Opcode::Srem => Self::SremI64,
|
||||||
|
Opcode::Ishl => Self::IshlI64,
|
||||||
|
Opcode::Ushr => Self::UshrI64,
|
||||||
|
Opcode::Sshr => Self::SshrI64,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
},
|
},
|
||||||
types::F32 => match opcode {
|
types::F32 => match opcode {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use crate::isa::encoding::base_size;
|
|||||||
use crate::isa::encoding::{Encoding, RecipeSizing};
|
use crate::isa::encoding::{Encoding, RecipeSizing};
|
||||||
use crate::isa::RegUnit;
|
use crate::isa::RegUnit;
|
||||||
use crate::isa::{self, TargetIsa};
|
use crate::isa::{self, TargetIsa};
|
||||||
|
use crate::legalizer::expand_as_libcall;
|
||||||
use crate::predicates;
|
use crate::predicates;
|
||||||
use crate::regalloc::RegDiversions;
|
use crate::regalloc::RegDiversions;
|
||||||
|
|
||||||
@@ -1428,10 +1429,20 @@ fn convert_ushr(
|
|||||||
pos.func.dfg.replace(inst).x86_psrl(arg0, shift_index);
|
pos.func.dfg.replace(inst).x86_psrl(arg0, shift_index);
|
||||||
} else if arg0_type == I64 {
|
} else if arg0_type == I64 {
|
||||||
// 64 bit shifts need to be legalized on x86_32.
|
// 64 bit shifts need to be legalized on x86_32.
|
||||||
let value = expand_dword_to_xmm(&mut pos, arg0, arg0_type);
|
let x86_isa = isa
|
||||||
let amount = expand_dword_to_xmm(&mut pos, arg1, arg1_type);
|
.as_any()
|
||||||
let shifted = pos.ins().x86_psrl(value, amount);
|
.downcast_ref::<isa::x86::Isa>()
|
||||||
contract_dword_from_xmm(&mut pos, inst, shifted, arg0_type);
|
.expect("the target ISA must be x86 at this point");
|
||||||
|
if x86_isa.isa_flags.has_sse41() {
|
||||||
|
// if we have pinstrq/pextrq (SSE 4.1), legalize to that
|
||||||
|
let value = expand_dword_to_xmm(&mut pos, arg0, arg0_type);
|
||||||
|
let amount = expand_dword_to_xmm(&mut pos, arg1, arg1_type);
|
||||||
|
let shifted = pos.ins().x86_psrl(value, amount);
|
||||||
|
contract_dword_from_xmm(&mut pos, inst, shifted, arg0_type);
|
||||||
|
} else {
|
||||||
|
// otherwise legalize to libcall
|
||||||
|
expand_as_libcall(inst, func, isa);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Everything else should be already legal.
|
// Everything else should be already legal.
|
||||||
unreachable!()
|
unreachable!()
|
||||||
@@ -1502,10 +1513,20 @@ fn convert_ishl(
|
|||||||
pos.func.dfg.replace(inst).x86_psll(arg0, shift_index);
|
pos.func.dfg.replace(inst).x86_psll(arg0, shift_index);
|
||||||
} else if arg0_type == I64 {
|
} else if arg0_type == I64 {
|
||||||
// 64 bit shifts need to be legalized on x86_32.
|
// 64 bit shifts need to be legalized on x86_32.
|
||||||
let value = expand_dword_to_xmm(&mut pos, arg0, arg0_type);
|
let x86_isa = isa
|
||||||
let amount = expand_dword_to_xmm(&mut pos, arg1, arg1_type);
|
.as_any()
|
||||||
let shifted = pos.ins().x86_psll(value, amount);
|
.downcast_ref::<isa::x86::Isa>()
|
||||||
contract_dword_from_xmm(&mut pos, inst, shifted, arg0_type);
|
.expect("the target ISA must be x86 at this point");
|
||||||
|
if x86_isa.isa_flags.has_sse41() {
|
||||||
|
// if we have pinstrq/pextrq (SSE 4.1), legalize to that
|
||||||
|
let value = expand_dword_to_xmm(&mut pos, arg0, arg0_type);
|
||||||
|
let amount = expand_dword_to_xmm(&mut pos, arg1, arg1_type);
|
||||||
|
let shifted = pos.ins().x86_psll(value, amount);
|
||||||
|
contract_dword_from_xmm(&mut pos, inst, shifted, arg0_type);
|
||||||
|
} else {
|
||||||
|
// otherwise legalize to libcall
|
||||||
|
expand_as_libcall(inst, func, isa);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Everything else should be already legal.
|
// Everything else should be already legal.
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ mod table;
|
|||||||
use self::call::expand_call;
|
use self::call::expand_call;
|
||||||
use self::globalvalue::expand_global_value;
|
use self::globalvalue::expand_global_value;
|
||||||
use self::heap::expand_heap_addr;
|
use self::heap::expand_heap_addr;
|
||||||
use self::libcall::expand_as_libcall;
|
pub(crate) use self::libcall::expand_as_libcall;
|
||||||
use self::table::expand_table_addr;
|
use self::table::expand_table_addr;
|
||||||
|
|
||||||
enum LegalizeInstResult {
|
enum LegalizeInstResult {
|
||||||
|
|||||||
@@ -29,3 +29,39 @@ block0(v0: i64, v1: i64):
|
|||||||
v2 = urem v0, v1
|
v2 = urem v0, v1
|
||||||
return v2
|
return v2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function %i64_i32_shl(i64, i32) -> i64 {
|
||||||
|
block0(v0: i64, v1: i32):
|
||||||
|
v2 = ishl v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
function %i64_i32_shr_u(i64, i32) -> i64 {
|
||||||
|
block0(v0: i64, v1: i32):
|
||||||
|
v2 = ushr v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
function %i64_i32_shr_s(i64, i32) -> i64 {
|
||||||
|
block0(v0: i64, v1: i32):
|
||||||
|
v2 = sshr v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
function %i64_i64_shl(i64, i64) -> i64 {
|
||||||
|
block0(v0: i64, v1: i64):
|
||||||
|
v2 = ishl v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
function %i64_i64_shr_u(i64, i64) -> i64 {
|
||||||
|
block0(v0: i64, v1: i64):
|
||||||
|
v2 = ushr v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
function %i64_i64_shr_s(i64, i64) -> i64 {
|
||||||
|
block0(v0: i64, v1: i64):
|
||||||
|
v2 = sshr v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|||||||
@@ -183,6 +183,9 @@ pub fn default_libcall_names() -> Box<dyn Fn(ir::LibCall) -> String> {
|
|||||||
ir::LibCall::SdivI64 => "__divdi3".to_owned(),
|
ir::LibCall::SdivI64 => "__divdi3".to_owned(),
|
||||||
ir::LibCall::UremI64 => "__umoddi3".to_owned(),
|
ir::LibCall::UremI64 => "__umoddi3".to_owned(),
|
||||||
ir::LibCall::SremI64 => "__moddi3".to_owned(),
|
ir::LibCall::SremI64 => "__moddi3".to_owned(),
|
||||||
|
ir::LibCall::IshlI64 => "__ashldi3".to_owned(),
|
||||||
|
ir::LibCall::UshrI64 => "__lshrdi3".to_owned(),
|
||||||
|
ir::LibCall::SshrI64 => "__ashrdi3".to_owned(),
|
||||||
ir::LibCall::CeilF32 => "ceilf".to_owned(),
|
ir::LibCall::CeilF32 => "ceilf".to_owned(),
|
||||||
ir::LibCall::CeilF64 => "ceil".to_owned(),
|
ir::LibCall::CeilF64 => "ceil".to_owned(),
|
||||||
ir::LibCall::FloorF32 => "floorf".to_owned(),
|
ir::LibCall::FloorF32 => "floorf".to_owned(),
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ fn apply_reloc(
|
|||||||
SdivI64 => wasmtime_i64_sdiv as usize,
|
SdivI64 => wasmtime_i64_sdiv as usize,
|
||||||
UremI64 => wasmtime_i64_urem as usize,
|
UremI64 => wasmtime_i64_urem as usize,
|
||||||
SremI64 => wasmtime_i64_srem as usize,
|
SremI64 => wasmtime_i64_srem as usize,
|
||||||
|
IshlI64 => wasmtime_i64_ishl as usize,
|
||||||
|
UshrI64 => wasmtime_i64_ushr as usize,
|
||||||
|
SshrI64 => wasmtime_i64_sshr as usize,
|
||||||
CeilF32 => wasmtime_f32_ceil as usize,
|
CeilF32 => wasmtime_f32_ceil as usize,
|
||||||
FloorF32 => wasmtime_f32_floor as usize,
|
FloorF32 => wasmtime_f32_floor as usize,
|
||||||
TruncF32 => wasmtime_f32_trunc as usize,
|
TruncF32 => wasmtime_f32_trunc as usize,
|
||||||
|
|||||||
@@ -98,6 +98,21 @@ pub extern "C" fn wasmtime_i64_srem(x: i64, y: i64) -> i64 {
|
|||||||
x % y
|
x % y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implementation of i64.ishl
|
||||||
|
pub extern "C" fn wasmtime_i64_ishl(x: i64, y: i64) -> i64 {
|
||||||
|
x << y
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of i64.ushr
|
||||||
|
pub extern "C" fn wasmtime_i64_ushr(x: u64, y: i64) -> u64 {
|
||||||
|
x >> y
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementation of i64.sshr
|
||||||
|
pub extern "C" fn wasmtime_i64_sshr(x: i64, y: i64) -> i64 {
|
||||||
|
x >> y
|
||||||
|
}
|
||||||
|
|
||||||
/// Implementation of f64.ceil
|
/// Implementation of f64.ceil
|
||||||
pub extern "C" fn wasmtime_f64_ceil(x: f64) -> f64 {
|
pub extern "C" fn wasmtime_f64_ceil(x: f64) -> f64 {
|
||||||
x.ceil()
|
x.ceil()
|
||||||
|
|||||||
Reference in New Issue
Block a user