x64: Lower fcopysign, ceil, floor, nearest, and trunc in ISLE (#4730)
https://github.com/bytecodealliance/wasmtime/pull/4730
This commit is contained in:
@@ -1120,6 +1120,15 @@
|
|||||||
(decl encode_fcmp_imm (FcmpImm) u8)
|
(decl encode_fcmp_imm (FcmpImm) u8)
|
||||||
(extern constructor encode_fcmp_imm encode_fcmp_imm)
|
(extern constructor encode_fcmp_imm encode_fcmp_imm)
|
||||||
|
|
||||||
|
(type RoundImm extern
|
||||||
|
(enum RoundNearest
|
||||||
|
RoundDown
|
||||||
|
RoundUp
|
||||||
|
RoundZero))
|
||||||
|
|
||||||
|
(decl encode_round_imm (RoundImm) u8)
|
||||||
|
(extern constructor encode_round_imm encode_round_imm)
|
||||||
|
|
||||||
;;;; Newtypes for Different Register Classes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Newtypes for Different Register Classes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(type Gpr (primitive Gpr))
|
(type Gpr (primitive Gpr))
|
||||||
@@ -1394,6 +1403,9 @@
|
|||||||
(decl use_fma () Type)
|
(decl use_fma () Type)
|
||||||
(extern extractor use_fma use_fma)
|
(extern extractor use_fma use_fma)
|
||||||
|
|
||||||
|
(decl use_sse41 () Type)
|
||||||
|
(extern extractor use_sse41 use_sse41)
|
||||||
|
|
||||||
;;;; Helpers for Merging and Sinking Immediates/Loads ;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;; Helpers for Merging and Sinking Immediates/Loads ;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
;; Extract a constant `Imm8Reg.Imm8` from a value operand.
|
;; Extract a constant `Imm8Reg.Imm8` from a value operand.
|
||||||
@@ -2575,6 +2587,42 @@
|
|||||||
lane
|
lane
|
||||||
size))
|
size))
|
||||||
|
|
||||||
|
;; Helper for creating `roundss` instructions.
|
||||||
|
(decl x64_roundss (Xmm RoundImm) Xmm)
|
||||||
|
(rule (x64_roundss src1 round)
|
||||||
|
(xmm_rm_r_imm (SseOpcode.Roundss)
|
||||||
|
src1
|
||||||
|
src1
|
||||||
|
(encode_round_imm round)
|
||||||
|
(OperandSize.Size32)))
|
||||||
|
|
||||||
|
;; Helper for creating `roundsd` instructions.
|
||||||
|
(decl x64_roundsd (Xmm RoundImm) Xmm)
|
||||||
|
(rule (x64_roundsd src1 round)
|
||||||
|
(xmm_rm_r_imm (SseOpcode.Roundsd)
|
||||||
|
src1
|
||||||
|
src1
|
||||||
|
(encode_round_imm round)
|
||||||
|
(OperandSize.Size32)))
|
||||||
|
|
||||||
|
;; Helper for creating `roundps` instructions.
|
||||||
|
(decl x64_roundps (Xmm RoundImm) Xmm)
|
||||||
|
(rule (x64_roundps src1 round)
|
||||||
|
(xmm_rm_r_imm (SseOpcode.Roundps)
|
||||||
|
src1
|
||||||
|
src1
|
||||||
|
(encode_round_imm round)
|
||||||
|
(OperandSize.Size32)))
|
||||||
|
|
||||||
|
;; Helper for creating `roundpd` instructions.
|
||||||
|
(decl x64_roundpd (Xmm RoundImm) Xmm)
|
||||||
|
(rule (x64_roundpd src1 round)
|
||||||
|
(xmm_rm_r_imm (SseOpcode.Roundpd)
|
||||||
|
src1
|
||||||
|
src1
|
||||||
|
(encode_round_imm round)
|
||||||
|
(OperandSize.Size32)))
|
||||||
|
|
||||||
;; Helper for creating `pmaddwd` instructions.
|
;; Helper for creating `pmaddwd` instructions.
|
||||||
(decl x64_pmaddwd (Xmm XmmMem) Xmm)
|
(decl x64_pmaddwd (Xmm XmmMem) Xmm)
|
||||||
(rule (x64_pmaddwd src1 src2)
|
(rule (x64_pmaddwd src1 src2)
|
||||||
@@ -3659,7 +3707,18 @@
|
|||||||
(type LibCall extern
|
(type LibCall extern
|
||||||
(enum
|
(enum
|
||||||
FmaF32
|
FmaF32
|
||||||
FmaF64))
|
FmaF64
|
||||||
|
CeilF32
|
||||||
|
CeilF64
|
||||||
|
FloorF32
|
||||||
|
FloorF64
|
||||||
|
NearestF32
|
||||||
|
NearestF64
|
||||||
|
TruncF32
|
||||||
|
TruncF64))
|
||||||
|
|
||||||
|
(decl libcall_1 (LibCall Reg) Reg)
|
||||||
|
(extern constructor libcall_1 libcall_1)
|
||||||
|
|
||||||
(decl libcall_3 (LibCall Reg Reg Reg) Reg)
|
(decl libcall_3 (LibCall Reg Reg Reg) Reg)
|
||||||
(extern constructor libcall_3 libcall_3)
|
(extern constructor libcall_3 libcall_3)
|
||||||
|
|||||||
@@ -1770,7 +1770,8 @@ impl From<FloatCC> for FcmpImm {
|
|||||||
/// However the rounding immediate which this field helps make up, also includes
|
/// However the rounding immediate which this field helps make up, also includes
|
||||||
/// bits 3 and 4 which define the rounding select and precision mask respectively.
|
/// bits 3 and 4 which define the rounding select and precision mask respectively.
|
||||||
/// These two bits are not defined here and are implictly set to zero when encoded.
|
/// These two bits are not defined here and are implictly set to zero when encoded.
|
||||||
pub(crate) enum RoundImm {
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum RoundImm {
|
||||||
RoundNearest = 0x00,
|
RoundNearest = 0x00,
|
||||||
RoundDown = 0x01,
|
RoundDown = 0x01,
|
||||||
RoundUp = 0x02,
|
RoundUp = 0x02,
|
||||||
|
|||||||
@@ -3332,3 +3332,97 @@
|
|||||||
|
|
||||||
(rule (lower (has_type $F64 (bitcast src @ (value_type $I64))))
|
(rule (lower (has_type $F64 (bitcast src @ (value_type $I64))))
|
||||||
(bitcast_gpr_to_xmm $I64 src))
|
(bitcast_gpr_to_xmm $I64 src))
|
||||||
|
|
||||||
|
;; Rules for `fcopysign` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(rule (lower (has_type $F32 (fcopysign a @ (value_type $F32) b)))
|
||||||
|
(let ((sign_bit Xmm (imm $F32 0x80000000)))
|
||||||
|
(x64_orps
|
||||||
|
(x64_andnps sign_bit a)
|
||||||
|
(x64_andps sign_bit b))))
|
||||||
|
|
||||||
|
(rule (lower (has_type $F64 (fcopysign a @ (value_type $F64) b)))
|
||||||
|
(let ((sign_bit Xmm (imm $F64 0x8000000000000000)))
|
||||||
|
(x64_orpd
|
||||||
|
(x64_andnpd sign_bit a)
|
||||||
|
(x64_andpd sign_bit b))))
|
||||||
|
|
||||||
|
;; Rules for `ceil` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (ceil a @ (value_type $F32))))
|
||||||
|
(x64_roundss a (RoundImm.RoundUp)))
|
||||||
|
|
||||||
|
(rule (lower (ceil a @ (value_type $F32)))
|
||||||
|
(libcall_1 (LibCall.CeilF32) a))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (ceil a @ (value_type $F64))))
|
||||||
|
(x64_roundsd a (RoundImm.RoundUp)))
|
||||||
|
|
||||||
|
(rule (lower (ceil a @ (value_type $F64)))
|
||||||
|
(libcall_1 (LibCall.CeilF64) a))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (ceil a @ (value_type $F32X4))))
|
||||||
|
(x64_roundps a (RoundImm.RoundUp)))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (ceil a @ (value_type $F64X2))))
|
||||||
|
(x64_roundpd a (RoundImm.RoundUp)))
|
||||||
|
|
||||||
|
;; Rules for `floor` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (floor a @ (value_type $F32))))
|
||||||
|
(x64_roundss a (RoundImm.RoundDown)))
|
||||||
|
|
||||||
|
(rule (lower (floor a @ (value_type $F32)))
|
||||||
|
(libcall_1 (LibCall.FloorF32) a))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (floor a @ (value_type $F64))))
|
||||||
|
(x64_roundsd a (RoundImm.RoundDown)))
|
||||||
|
|
||||||
|
(rule (lower (floor a @ (value_type $F64)))
|
||||||
|
(libcall_1 (LibCall.FloorF64) a))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (floor a @ (value_type $F32X4))))
|
||||||
|
(x64_roundps a (RoundImm.RoundDown)))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (floor a @ (value_type $F64X2))))
|
||||||
|
(x64_roundpd a (RoundImm.RoundDown)))
|
||||||
|
|
||||||
|
;; Rules for `nearest` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (nearest a @ (value_type $F32))))
|
||||||
|
(x64_roundss a (RoundImm.RoundNearest)))
|
||||||
|
|
||||||
|
(rule (lower (nearest a @ (value_type $F32)))
|
||||||
|
(libcall_1 (LibCall.NearestF32) a))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (nearest a @ (value_type $F64))))
|
||||||
|
(x64_roundsd a (RoundImm.RoundNearest)))
|
||||||
|
|
||||||
|
(rule (lower (nearest a @ (value_type $F64)))
|
||||||
|
(libcall_1 (LibCall.NearestF64) a))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (nearest a @ (value_type $F32X4))))
|
||||||
|
(x64_roundps a (RoundImm.RoundNearest)))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (nearest a @ (value_type $F64X2))))
|
||||||
|
(x64_roundpd a (RoundImm.RoundNearest)))
|
||||||
|
|
||||||
|
;; Rules for `trunc` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (trunc a @ (value_type $F32))))
|
||||||
|
(x64_roundss a (RoundImm.RoundZero)))
|
||||||
|
|
||||||
|
(rule (lower (trunc a @ (value_type $F32)))
|
||||||
|
(libcall_1 (LibCall.TruncF32) a))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (trunc a @ (value_type $F64))))
|
||||||
|
(x64_roundsd a (RoundImm.RoundZero)))
|
||||||
|
|
||||||
|
(rule (lower (trunc a @ (value_type $F64)))
|
||||||
|
(libcall_1 (LibCall.TruncF64) a))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (trunc a @ (value_type $F32X4))))
|
||||||
|
(x64_roundps a (RoundImm.RoundZero)))
|
||||||
|
|
||||||
|
(rule (lower (has_type (use_sse41) (trunc a @ (value_type $F64X2))))
|
||||||
|
(x64_roundpd a (RoundImm.RoundZero)))
|
||||||
|
|||||||
@@ -569,118 +569,15 @@ fn lower_insn_to_regs(
|
|||||||
| Opcode::Unarrow
|
| Opcode::Unarrow
|
||||||
| Opcode::Bitcast
|
| Opcode::Bitcast
|
||||||
| Opcode::Fabs
|
| Opcode::Fabs
|
||||||
| Opcode::Fneg => {
|
| Opcode::Fneg
|
||||||
|
| Opcode::Fcopysign
|
||||||
|
| Opcode::Ceil
|
||||||
|
| Opcode::Floor
|
||||||
|
| Opcode::Nearest
|
||||||
|
| Opcode::Trunc => {
|
||||||
implemented_in_isle(ctx);
|
implemented_in_isle(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode::Fcopysign => {
|
|
||||||
let dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
|
||||||
let lhs = put_input_in_reg(ctx, inputs[0]);
|
|
||||||
let rhs = put_input_in_reg(ctx, inputs[1]);
|
|
||||||
|
|
||||||
let ty = ty.unwrap();
|
|
||||||
|
|
||||||
// We're going to generate the following sequence:
|
|
||||||
//
|
|
||||||
// movabs $INT_MIN, tmp_gpr1
|
|
||||||
// mov{d,q} tmp_gpr1, tmp_xmm1
|
|
||||||
// movap{s,d} tmp_xmm1, dst
|
|
||||||
// andnp{s,d} src_1, dst
|
|
||||||
// movap{s,d} src_2, tmp_xmm2
|
|
||||||
// andp{s,d} tmp_xmm1, tmp_xmm2
|
|
||||||
// orp{s,d} tmp_xmm2, dst
|
|
||||||
|
|
||||||
let tmp_xmm1 = ctx.alloc_tmp(types::F32).only_reg().unwrap();
|
|
||||||
let tmp_xmm2 = ctx.alloc_tmp(types::F32).only_reg().unwrap();
|
|
||||||
|
|
||||||
let (sign_bit_cst, mov_op, and_not_op, and_op, or_op) = match ty {
|
|
||||||
types::F32 => (
|
|
||||||
0x8000_0000,
|
|
||||||
SseOpcode::Movaps,
|
|
||||||
SseOpcode::Andnps,
|
|
||||||
SseOpcode::Andps,
|
|
||||||
SseOpcode::Orps,
|
|
||||||
),
|
|
||||||
types::F64 => (
|
|
||||||
0x8000_0000_0000_0000,
|
|
||||||
SseOpcode::Movapd,
|
|
||||||
SseOpcode::Andnpd,
|
|
||||||
SseOpcode::Andpd,
|
|
||||||
SseOpcode::Orpd,
|
|
||||||
),
|
|
||||||
_ => {
|
|
||||||
panic!("unexpected type {:?} for copysign", ty);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for inst in Inst::gen_constant(ValueRegs::one(tmp_xmm1), sign_bit_cst, ty, |ty| {
|
|
||||||
ctx.alloc_tmp(ty).only_reg().unwrap()
|
|
||||||
}) {
|
|
||||||
ctx.emit(inst);
|
|
||||||
}
|
|
||||||
ctx.emit(Inst::xmm_mov(mov_op, RegMem::reg(tmp_xmm1.to_reg()), dst));
|
|
||||||
ctx.emit(Inst::xmm_rm_r(and_not_op, RegMem::reg(lhs), dst));
|
|
||||||
ctx.emit(Inst::xmm_mov(mov_op, RegMem::reg(rhs), tmp_xmm2));
|
|
||||||
ctx.emit(Inst::xmm_rm_r(
|
|
||||||
and_op,
|
|
||||||
RegMem::reg(tmp_xmm1.to_reg()),
|
|
||||||
tmp_xmm2,
|
|
||||||
));
|
|
||||||
ctx.emit(Inst::xmm_rm_r(or_op, RegMem::reg(tmp_xmm2.to_reg()), dst));
|
|
||||||
}
|
|
||||||
|
|
||||||
Opcode::Ceil | Opcode::Floor | Opcode::Nearest | Opcode::Trunc => {
|
|
||||||
let ty = ty.unwrap();
|
|
||||||
if isa_flags.use_sse41() {
|
|
||||||
let mode = match op {
|
|
||||||
Opcode::Ceil => RoundImm::RoundUp,
|
|
||||||
Opcode::Floor => RoundImm::RoundDown,
|
|
||||||
Opcode::Nearest => RoundImm::RoundNearest,
|
|
||||||
Opcode::Trunc => RoundImm::RoundZero,
|
|
||||||
_ => panic!("unexpected opcode {:?} in Ceil/Floor/Nearest/Trunc", op),
|
|
||||||
};
|
|
||||||
let op = match ty {
|
|
||||||
types::F32 => SseOpcode::Roundss,
|
|
||||||
types::F64 => SseOpcode::Roundsd,
|
|
||||||
types::F32X4 => SseOpcode::Roundps,
|
|
||||||
types::F64X2 => SseOpcode::Roundpd,
|
|
||||||
_ => panic!("unexpected type {:?} in Ceil/Floor/Nearest/Trunc", ty),
|
|
||||||
};
|
|
||||||
let src = input_to_reg_mem(ctx, inputs[0]);
|
|
||||||
let dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
|
||||||
ctx.emit(Inst::xmm_rm_r_imm(
|
|
||||||
op,
|
|
||||||
src,
|
|
||||||
dst,
|
|
||||||
mode.encode(),
|
|
||||||
OperandSize::Size32,
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
// Lower to VM calls when there's no access to SSE4.1.
|
|
||||||
// Note, for vector types on platforms that don't support sse41
|
|
||||||
// the execution will panic here.
|
|
||||||
let libcall = match (op, ty) {
|
|
||||||
(Opcode::Ceil, types::F32) => LibCall::CeilF32,
|
|
||||||
(Opcode::Ceil, types::F64) => LibCall::CeilF64,
|
|
||||||
(Opcode::Floor, types::F32) => LibCall::FloorF32,
|
|
||||||
(Opcode::Floor, types::F64) => LibCall::FloorF64,
|
|
||||||
(Opcode::Nearest, types::F32) => LibCall::NearestF32,
|
|
||||||
(Opcode::Nearest, types::F64) => LibCall::NearestF64,
|
|
||||||
(Opcode::Trunc, types::F32) => LibCall::TruncF32,
|
|
||||||
(Opcode::Trunc, types::F64) => LibCall::TruncF64,
|
|
||||||
_ => panic!(
|
|
||||||
"unexpected type/opcode {:?}/{:?} in Ceil/Floor/Nearest/Trunc",
|
|
||||||
ty, op
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
let input = put_input_in_reg(ctx, inputs[0]);
|
|
||||||
let dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
|
|
||||||
|
|
||||||
emit_vm_call(ctx, flags, triple, libcall, &[input], &[dst])?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Opcode::DynamicStackAddr => unimplemented!("DynamicStackAddr"),
|
Opcode::DynamicStackAddr => unimplemented!("DynamicStackAddr"),
|
||||||
|
|
||||||
Opcode::StackAddr => {
|
Opcode::StackAddr => {
|
||||||
|
|||||||
@@ -176,6 +176,11 @@ impl Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> {
|
|||||||
imm.encode()
|
imm.encode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn encode_round_imm(&mut self, imm: &RoundImm) -> u8 {
|
||||||
|
imm.encode()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn avx512vl_enabled(&mut self, _: Type) -> Option<()> {
|
fn avx512vl_enabled(&mut self, _: Type) -> Option<()> {
|
||||||
if self.isa_flags.use_avx512vl_simd() {
|
if self.isa_flags.use_avx512vl_simd() {
|
||||||
@@ -248,6 +253,15 @@ impl Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn use_sse41(&mut self, _: Type) -> Option<()> {
|
||||||
|
if self.isa_flags.use_sse41() {
|
||||||
|
Some(())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn imm8_from_value(&mut self, val: Value) -> Option<Imm8Reg> {
|
fn imm8_from_value(&mut self, val: Value) -> Option<Imm8Reg> {
|
||||||
let inst = self.lower_ctx.dfg().value_def(val).inst()?;
|
let inst = self.lower_ctx.dfg().value_def(val).inst()?;
|
||||||
@@ -715,6 +729,24 @@ impl Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> {
|
|||||||
regs::rsp().to_real_reg().unwrap().into()
|
regs::rsp().to_real_reg().unwrap().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn libcall_1(&mut self, libcall: &LibCall, a: Reg) -> Reg {
|
||||||
|
let call_conv = self.lower_ctx.abi().call_conv();
|
||||||
|
let ret_ty = libcall.signature(call_conv).returns[0].value_type;
|
||||||
|
let output_reg = self.lower_ctx.alloc_tmp(ret_ty).only_reg().unwrap();
|
||||||
|
|
||||||
|
emit_vm_call(
|
||||||
|
self.lower_ctx,
|
||||||
|
self.flags,
|
||||||
|
self.triple,
|
||||||
|
libcall.clone(),
|
||||||
|
&[a],
|
||||||
|
&[output_reg],
|
||||||
|
)
|
||||||
|
.expect("Failed to emit LibCall");
|
||||||
|
|
||||||
|
output_reg.to_reg()
|
||||||
|
}
|
||||||
|
|
||||||
fn libcall_3(&mut self, libcall: &LibCall, a: Reg, b: Reg, c: Reg) -> Reg {
|
fn libcall_3(&mut self, libcall: &LibCall, a: Reg, b: Reg, c: Reg) -> Reg {
|
||||||
let call_conv = self.lower_ctx.abi().call_conv();
|
let call_conv = self.lower_ctx.abi().call_conv();
|
||||||
let ret_ty = libcall.signature(call_conv).returns[0].value_type;
|
let ret_ty = libcall.signature(call_conv).returns[0].value_type;
|
||||||
|
|||||||
33
cranelift/filetests/filetests/isa/x64/ceil-libcall.clif
Normal file
33
cranelift/filetests/filetests/isa/x64/ceil-libcall.clif
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
test compile precise-output
|
||||||
|
target x86_64 has_sse41=false
|
||||||
|
|
||||||
|
function %f1(f32) -> f32 {
|
||||||
|
block0(v0: f32):
|
||||||
|
v1 = ceil v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; load_ext_name %CeilF32+0, %r8
|
||||||
|
; call *%r8
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f2(f64) -> f64 {
|
||||||
|
block0(v0: f64):
|
||||||
|
v1 = ceil v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; load_ext_name %CeilF64+0, %r8
|
||||||
|
; call *%r8
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
59
cranelift/filetests/filetests/isa/x64/ceil.clif
Normal file
59
cranelift/filetests/filetests/isa/x64/ceil.clif
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
test compile precise-output
|
||||||
|
target x86_64 has_sse41=true
|
||||||
|
|
||||||
|
function %f1(f32) -> f32 {
|
||||||
|
block0(v0: f32):
|
||||||
|
v1 = ceil v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundss $2, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f2(f64) -> f64 {
|
||||||
|
block0(v0: f64):
|
||||||
|
v1 = ceil v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundsd $2, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f4(f32x4) -> f32x4 {
|
||||||
|
block0(v0: f32x4):
|
||||||
|
v1 = ceil v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundps $2, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f4(f64x2) -> f64x2 {
|
||||||
|
block0(v0: f64x2):
|
||||||
|
v1 = ceil v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundpd $2, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
43
cranelift/filetests/filetests/isa/x64/fcopysign.clif
Normal file
43
cranelift/filetests/filetests/isa/x64/fcopysign.clif
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
test compile precise-output
|
||||||
|
target x86_64
|
||||||
|
|
||||||
|
function %f1(f32, f32) -> f32 {
|
||||||
|
block0(v0: f32, v1: f32):
|
||||||
|
v2 = fcopysign v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; movl $-2147483648, %r8d
|
||||||
|
; movd %r8d, %xmm9
|
||||||
|
; movdqa %xmm0, %xmm14
|
||||||
|
; movdqa %xmm9, %xmm0
|
||||||
|
; andnps %xmm0, %xmm14, %xmm0
|
||||||
|
; andps %xmm9, %xmm1, %xmm9
|
||||||
|
; orps %xmm0, %xmm9, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f1(f64, f64) -> f64 {
|
||||||
|
block0(v0: f64, v1: f64):
|
||||||
|
v2 = fcopysign v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; movabsq $-9223372036854775808, %r8
|
||||||
|
; movq %r8, %xmm9
|
||||||
|
; movdqa %xmm0, %xmm14
|
||||||
|
; movdqa %xmm9, %xmm0
|
||||||
|
; andnpd %xmm0, %xmm14, %xmm0
|
||||||
|
; andpd %xmm9, %xmm1, %xmm9
|
||||||
|
; orpd %xmm0, %xmm9, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
33
cranelift/filetests/filetests/isa/x64/floor-libcall.clif
Normal file
33
cranelift/filetests/filetests/isa/x64/floor-libcall.clif
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
test compile precise-output
|
||||||
|
target x86_64 has_sse41=false
|
||||||
|
|
||||||
|
function %f1(f32) -> f32 {
|
||||||
|
block0(v0: f32):
|
||||||
|
v1 = floor v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; load_ext_name %FloorF32+0, %r8
|
||||||
|
; call *%r8
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f2(f64) -> f64 {
|
||||||
|
block0(v0: f64):
|
||||||
|
v1 = floor v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; load_ext_name %FloorF64+0, %r8
|
||||||
|
; call *%r8
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
59
cranelift/filetests/filetests/isa/x64/floor.clif
Normal file
59
cranelift/filetests/filetests/isa/x64/floor.clif
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
test compile precise-output
|
||||||
|
target x86_64 has_sse41=true
|
||||||
|
|
||||||
|
function %f1(f32) -> f32 {
|
||||||
|
block0(v0: f32):
|
||||||
|
v1 = floor v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundss $1, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f2(f64) -> f64 {
|
||||||
|
block0(v0: f64):
|
||||||
|
v1 = floor v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundsd $1, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f4(f32x4) -> f32x4 {
|
||||||
|
block0(v0: f32x4):
|
||||||
|
v1 = floor v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundps $1, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f4(f64x2) -> f64x2 {
|
||||||
|
block0(v0: f64x2):
|
||||||
|
v1 = floor v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundpd $1, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
33
cranelift/filetests/filetests/isa/x64/nearest-libcall.clif
Normal file
33
cranelift/filetests/filetests/isa/x64/nearest-libcall.clif
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
test compile precise-output
|
||||||
|
target x86_64 has_sse41=false
|
||||||
|
|
||||||
|
function %f1(f32) -> f32 {
|
||||||
|
block0(v0: f32):
|
||||||
|
v1 = nearest v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; load_ext_name %NearestF32+0, %r8
|
||||||
|
; call *%r8
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f2(f64) -> f64 {
|
||||||
|
block0(v0: f64):
|
||||||
|
v1 = nearest v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; load_ext_name %NearestF64+0, %r8
|
||||||
|
; call *%r8
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
59
cranelift/filetests/filetests/isa/x64/nearest.clif
Normal file
59
cranelift/filetests/filetests/isa/x64/nearest.clif
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
test compile precise-output
|
||||||
|
target x86_64 has_sse41=true
|
||||||
|
|
||||||
|
function %f1(f32) -> f32 {
|
||||||
|
block0(v0: f32):
|
||||||
|
v1 = nearest v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundss $0, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f2(f64) -> f64 {
|
||||||
|
block0(v0: f64):
|
||||||
|
v1 = nearest v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundsd $0, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f4(f32x4) -> f32x4 {
|
||||||
|
block0(v0: f32x4):
|
||||||
|
v1 = nearest v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundps $0, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f4(f64x2) -> f64x2 {
|
||||||
|
block0(v0: f64x2):
|
||||||
|
v1 = nearest v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundpd $0, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
33
cranelift/filetests/filetests/isa/x64/trunc-libcall.clif
Normal file
33
cranelift/filetests/filetests/isa/x64/trunc-libcall.clif
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
test compile precise-output
|
||||||
|
target x86_64 has_sse41=false
|
||||||
|
|
||||||
|
function %f1(f32) -> f32 {
|
||||||
|
block0(v0: f32):
|
||||||
|
v1 = trunc v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; load_ext_name %TruncF32+0, %r8
|
||||||
|
; call *%r8
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f2(f64) -> f64 {
|
||||||
|
block0(v0: f64):
|
||||||
|
v1 = trunc v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; load_ext_name %TruncF64+0, %r8
|
||||||
|
; call *%r8
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
59
cranelift/filetests/filetests/isa/x64/trunc.clif
Normal file
59
cranelift/filetests/filetests/isa/x64/trunc.clif
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
test compile precise-output
|
||||||
|
target x86_64 has_sse41=true
|
||||||
|
|
||||||
|
function %f1(f32) -> f32 {
|
||||||
|
block0(v0: f32):
|
||||||
|
v1 = trunc v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundss $3, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f2(f64) -> f64 {
|
||||||
|
block0(v0: f64):
|
||||||
|
v1 = trunc v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundsd $3, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f4(f32x4) -> f32x4 {
|
||||||
|
block0(v0: f32x4):
|
||||||
|
v1 = trunc v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundps $3, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
|
function %f4(f64x2) -> f64x2 {
|
||||||
|
block0(v0: f64x2):
|
||||||
|
v1 = trunc v0
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
|
||||||
|
; pushq %rbp
|
||||||
|
; movq %rsp, %rbp
|
||||||
|
; block0:
|
||||||
|
; roundpd $3, %xmm0, %xmm0
|
||||||
|
; movq %rbp, %rsp
|
||||||
|
; popq %rbp
|
||||||
|
; ret
|
||||||
|
|
||||||
Reference in New Issue
Block a user