cranelift: Implement scalar FMA on x86 (#4460)
x86 does not have dedicated instructions for scalar FMA, lower to a libcall which seems to be what llvm does.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
//! Naming well-known routines in the runtime library.
|
//! Naming well-known routines in the runtime library.
|
||||||
|
|
||||||
use crate::ir::{types, ExternalName, FuncRef, Function, Opcode, Type};
|
use crate::ir::{types, AbiParam, ExternalName, FuncRef, Function, Opcode, Signature, Type};
|
||||||
|
use crate::isa::CallConv;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
#[cfg(feature = "enable-serde")]
|
#[cfg(feature = "enable-serde")]
|
||||||
@@ -50,6 +51,10 @@ pub enum LibCall {
|
|||||||
NearestF32,
|
NearestF32,
|
||||||
/// nearest.f64
|
/// nearest.f64
|
||||||
NearestF64,
|
NearestF64,
|
||||||
|
/// fma.f32
|
||||||
|
FmaF32,
|
||||||
|
/// fma.f64
|
||||||
|
FmaF64,
|
||||||
/// libc.memcpy
|
/// libc.memcpy
|
||||||
Memcpy,
|
Memcpy,
|
||||||
/// libc.memset
|
/// libc.memset
|
||||||
@@ -91,6 +96,8 @@ impl FromStr for LibCall {
|
|||||||
"TruncF64" => Ok(Self::TruncF64),
|
"TruncF64" => Ok(Self::TruncF64),
|
||||||
"NearestF32" => Ok(Self::NearestF32),
|
"NearestF32" => Ok(Self::NearestF32),
|
||||||
"NearestF64" => Ok(Self::NearestF64),
|
"NearestF64" => Ok(Self::NearestF64),
|
||||||
|
"FmaF32" => Ok(Self::FmaF32),
|
||||||
|
"FmaF64" => Ok(Self::FmaF64),
|
||||||
"Memcpy" => Ok(Self::Memcpy),
|
"Memcpy" => Ok(Self::Memcpy),
|
||||||
"Memset" => Ok(Self::Memset),
|
"Memset" => Ok(Self::Memset),
|
||||||
"Memmove" => Ok(Self::Memmove),
|
"Memmove" => Ok(Self::Memmove),
|
||||||
@@ -124,6 +131,7 @@ impl LibCall {
|
|||||||
Opcode::Floor => Self::FloorF32,
|
Opcode::Floor => Self::FloorF32,
|
||||||
Opcode::Trunc => Self::TruncF32,
|
Opcode::Trunc => Self::TruncF32,
|
||||||
Opcode::Nearest => Self::NearestF32,
|
Opcode::Nearest => Self::NearestF32,
|
||||||
|
Opcode::Fma => Self::FmaF32,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
},
|
},
|
||||||
types::F64 => match opcode {
|
types::F64 => match opcode {
|
||||||
@@ -131,6 +139,7 @@ impl LibCall {
|
|||||||
Opcode::Floor => Self::FloorF64,
|
Opcode::Floor => Self::FloorF64,
|
||||||
Opcode::Trunc => Self::TruncF64,
|
Opcode::Trunc => Self::TruncF64,
|
||||||
Opcode::Nearest => Self::NearestF64,
|
Opcode::Nearest => Self::NearestF64,
|
||||||
|
Opcode::Fma => Self::FmaF64,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
},
|
},
|
||||||
_ => return None,
|
_ => return None,
|
||||||
@@ -157,6 +166,8 @@ impl LibCall {
|
|||||||
TruncF64,
|
TruncF64,
|
||||||
NearestF32,
|
NearestF32,
|
||||||
NearestF64,
|
NearestF64,
|
||||||
|
FmaF32,
|
||||||
|
FmaF64,
|
||||||
Memcpy,
|
Memcpy,
|
||||||
Memset,
|
Memset,
|
||||||
Memmove,
|
Memmove,
|
||||||
@@ -164,6 +175,50 @@ impl LibCall {
|
|||||||
ElfTlsGetAddr,
|
ElfTlsGetAddr,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a [Signature] for the function targeted by this [LibCall].
|
||||||
|
pub fn signature(&self, call_conv: CallConv) -> Signature {
|
||||||
|
use types::*;
|
||||||
|
let mut sig = Signature::new(call_conv);
|
||||||
|
|
||||||
|
match self {
|
||||||
|
LibCall::UdivI64
|
||||||
|
| LibCall::SdivI64
|
||||||
|
| LibCall::UremI64
|
||||||
|
| LibCall::SremI64
|
||||||
|
| LibCall::IshlI64
|
||||||
|
| LibCall::UshrI64
|
||||||
|
| LibCall::SshrI64 => {
|
||||||
|
sig.params.push(AbiParam::new(I64));
|
||||||
|
sig.params.push(AbiParam::new(I64));
|
||||||
|
sig.returns.push(AbiParam::new(I64));
|
||||||
|
}
|
||||||
|
LibCall::CeilF32 | LibCall::FloorF32 | LibCall::TruncF32 | LibCall::NearestF32 => {
|
||||||
|
sig.params.push(AbiParam::new(F32));
|
||||||
|
sig.returns.push(AbiParam::new(F32));
|
||||||
|
}
|
||||||
|
LibCall::TruncF64 | LibCall::FloorF64 | LibCall::CeilF64 | LibCall::NearestF64 => {
|
||||||
|
sig.params.push(AbiParam::new(F64));
|
||||||
|
sig.returns.push(AbiParam::new(F64));
|
||||||
|
}
|
||||||
|
LibCall::FmaF32 | LibCall::FmaF64 => {
|
||||||
|
let ty = if *self == LibCall::FmaF32 { F32 } else { F64 };
|
||||||
|
|
||||||
|
sig.params.push(AbiParam::new(ty));
|
||||||
|
sig.params.push(AbiParam::new(ty));
|
||||||
|
sig.params.push(AbiParam::new(ty));
|
||||||
|
sig.returns.push(AbiParam::new(ty));
|
||||||
|
}
|
||||||
|
LibCall::Probestack
|
||||||
|
| LibCall::Memcpy
|
||||||
|
| LibCall::Memset
|
||||||
|
| LibCall::Memmove
|
||||||
|
| LibCall::Memcmp
|
||||||
|
| LibCall::ElfTlsGetAddr => unimplemented!(),
|
||||||
|
}
|
||||||
|
|
||||||
|
sig
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a function reference for the probestack function in `func`.
|
/// Get a function reference for the probestack function in `func`.
|
||||||
|
|||||||
@@ -1551,7 +1551,7 @@ impl LowerBackend for AArch64Backend {
|
|||||||
type MInst = Inst;
|
type MInst = Inst;
|
||||||
|
|
||||||
fn lower<C: LowerCtx<I = Inst>>(&self, ctx: &mut C, ir_inst: IRInst) -> CodegenResult<()> {
|
fn lower<C: LowerCtx<I = Inst>>(&self, ctx: &mut C, ir_inst: IRInst) -> CodegenResult<()> {
|
||||||
lower_inst::lower_insn_to_regs(ctx, ir_inst, &self.flags, &self.isa_flags)
|
lower_inst::lower_insn_to_regs(ctx, ir_inst, &self.triple, &self.flags, &self.isa_flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_branch_group<C: LowerCtx<I = Inst>>(
|
fn lower_branch_group<C: LowerCtx<I = Inst>>(
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ use regalloc2::PReg;
|
|||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
type BoxCallInfo = Box<CallInfo>;
|
type BoxCallInfo = Box<CallInfo>;
|
||||||
type BoxCallIndInfo = Box<CallIndInfo>;
|
type BoxCallIndInfo = Box<CallIndInfo>;
|
||||||
@@ -40,6 +41,7 @@ type BoxExternalName = Box<ExternalName>;
|
|||||||
/// The main entry point for lowering with ISLE.
|
/// The main entry point for lowering with ISLE.
|
||||||
pub(crate) fn lower<C>(
|
pub(crate) fn lower<C>(
|
||||||
lower_ctx: &mut C,
|
lower_ctx: &mut C,
|
||||||
|
triple: &Triple,
|
||||||
flags: &Flags,
|
flags: &Flags,
|
||||||
isa_flags: &IsaFlags,
|
isa_flags: &IsaFlags,
|
||||||
outputs: &[InsnOutput],
|
outputs: &[InsnOutput],
|
||||||
@@ -48,9 +50,15 @@ pub(crate) fn lower<C>(
|
|||||||
where
|
where
|
||||||
C: LowerCtx<I = MInst>,
|
C: LowerCtx<I = MInst>,
|
||||||
{
|
{
|
||||||
lower_common(lower_ctx, flags, isa_flags, outputs, inst, |cx, insn| {
|
lower_common(
|
||||||
generated_code::constructor_lower(cx, insn)
|
lower_ctx,
|
||||||
})
|
triple,
|
||||||
|
flags,
|
||||||
|
isa_flags,
|
||||||
|
outputs,
|
||||||
|
inst,
|
||||||
|
|cx, insn| generated_code::constructor_lower(cx, insn),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExtendedValue {
|
pub struct ExtendedValue {
|
||||||
|
|||||||
@@ -16,11 +16,13 @@ use crate::{CodegenError, CodegenResult};
|
|||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
/// Actually codegen an instruction's results into registers.
|
/// Actually codegen an instruction's results into registers.
|
||||||
pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
||||||
ctx: &mut C,
|
ctx: &mut C,
|
||||||
insn: IRInst,
|
insn: IRInst,
|
||||||
|
triple: &Triple,
|
||||||
flags: &Flags,
|
flags: &Flags,
|
||||||
isa_flags: &aarch64_settings::Flags,
|
isa_flags: &aarch64_settings::Flags,
|
||||||
) -> CodegenResult<()> {
|
) -> CodegenResult<()> {
|
||||||
@@ -33,7 +35,7 @@ pub(crate) fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(()) = super::lower::isle::lower(ctx, flags, isa_flags, &outputs, insn) {
|
if let Ok(()) = super::lower::isle::lower(ctx, triple, flags, isa_flags, &outputs, insn) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,14 @@ impl LowerBackend for S390xBackend {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(()) =
|
if let Ok(()) = super::lower::isle::lower(
|
||||||
super::lower::isle::lower(ctx, &self.flags, &self.isa_flags, &outputs, ir_inst)
|
ctx,
|
||||||
{
|
&self.triple,
|
||||||
|
&self.flags,
|
||||||
|
&self.isa_flags,
|
||||||
|
&outputs,
|
||||||
|
ir_inst,
|
||||||
|
) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,6 +300,7 @@ impl LowerBackend for S390xBackend {
|
|||||||
// the second branch (if any) by emitting a two-way conditional branch.
|
// the second branch (if any) by emitting a two-way conditional branch.
|
||||||
if let Ok(()) = super::lower::isle::lower_branch(
|
if let Ok(()) = super::lower::isle::lower_branch(
|
||||||
ctx,
|
ctx,
|
||||||
|
&self.triple,
|
||||||
&self.flags,
|
&self.flags,
|
||||||
&self.isa_flags,
|
&self.isa_flags,
|
||||||
branches[0],
|
branches[0],
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ use std::boxed::Box;
|
|||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
type BoxCallInfo = Box<CallInfo>;
|
type BoxCallInfo = Box<CallInfo>;
|
||||||
type BoxCallIndInfo = Box<CallIndInfo>;
|
type BoxCallIndInfo = Box<CallIndInfo>;
|
||||||
@@ -37,6 +38,7 @@ type VecMInstBuilder = Cell<Vec<MInst>>;
|
|||||||
/// The main entry point for lowering with ISLE.
|
/// The main entry point for lowering with ISLE.
|
||||||
pub(crate) fn lower<C>(
|
pub(crate) fn lower<C>(
|
||||||
lower_ctx: &mut C,
|
lower_ctx: &mut C,
|
||||||
|
triple: &Triple,
|
||||||
flags: &Flags,
|
flags: &Flags,
|
||||||
isa_flags: &IsaFlags,
|
isa_flags: &IsaFlags,
|
||||||
outputs: &[InsnOutput],
|
outputs: &[InsnOutput],
|
||||||
@@ -45,14 +47,21 @@ pub(crate) fn lower<C>(
|
|||||||
where
|
where
|
||||||
C: LowerCtx<I = MInst>,
|
C: LowerCtx<I = MInst>,
|
||||||
{
|
{
|
||||||
lower_common(lower_ctx, flags, isa_flags, outputs, inst, |cx, insn| {
|
lower_common(
|
||||||
generated_code::constructor_lower(cx, insn)
|
lower_ctx,
|
||||||
})
|
triple,
|
||||||
|
flags,
|
||||||
|
isa_flags,
|
||||||
|
outputs,
|
||||||
|
inst,
|
||||||
|
|cx, insn| generated_code::constructor_lower(cx, insn),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main entry point for branch lowering with ISLE.
|
/// The main entry point for branch lowering with ISLE.
|
||||||
pub(crate) fn lower_branch<C>(
|
pub(crate) fn lower_branch<C>(
|
||||||
lower_ctx: &mut C,
|
lower_ctx: &mut C,
|
||||||
|
triple: &Triple,
|
||||||
flags: &Flags,
|
flags: &Flags,
|
||||||
isa_flags: &IsaFlags,
|
isa_flags: &IsaFlags,
|
||||||
branch: Inst,
|
branch: Inst,
|
||||||
@@ -61,9 +70,15 @@ pub(crate) fn lower_branch<C>(
|
|||||||
where
|
where
|
||||||
C: LowerCtx<I = MInst>,
|
C: LowerCtx<I = MInst>,
|
||||||
{
|
{
|
||||||
lower_common(lower_ctx, flags, isa_flags, &[], branch, |cx, insn| {
|
lower_common(
|
||||||
generated_code::constructor_lower_branch(cx, insn, &targets.to_vec())
|
lower_ctx,
|
||||||
})
|
triple,
|
||||||
|
flags,
|
||||||
|
isa_flags,
|
||||||
|
&[],
|
||||||
|
branch,
|
||||||
|
|cx, insn| generated_code::constructor_lower_branch(cx, insn, &targets.to_vec()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> generated_code::Context for IsleContext<'_, C, Flags, IsaFlags, 6>
|
impl<C> generated_code::Context for IsleContext<'_, C, Flags, IsaFlags, 6>
|
||||||
|
|||||||
@@ -3354,3 +3354,13 @@
|
|||||||
(decl x64_rsp () Reg)
|
(decl x64_rsp () Reg)
|
||||||
(rule (x64_rsp)
|
(rule (x64_rsp)
|
||||||
(mov_preg (preg_rsp)))
|
(mov_preg (preg_rsp)))
|
||||||
|
|
||||||
|
;;;; Helpers for Emitting LibCalls ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(type LibCall extern
|
||||||
|
(enum
|
||||||
|
FmaF32
|
||||||
|
FmaF64))
|
||||||
|
|
||||||
|
(decl libcall_3 (LibCall Reg Reg Reg) Reg)
|
||||||
|
(extern constructor libcall_3 libcall_3)
|
||||||
|
|||||||
@@ -2491,6 +2491,10 @@
|
|||||||
|
|
||||||
;; Rules for `fma` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;; Rules for `fma` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(rule (lower (has_type $F32 (fma x y z)))
|
||||||
|
(libcall_3 (LibCall.FmaF32) x y z))
|
||||||
|
(rule (lower (has_type $F64 (fma x y z)))
|
||||||
|
(libcall_3 (LibCall.FmaF64) x y z))
|
||||||
(rule (lower (has_type $F32X4 (fma x y z)))
|
(rule (lower (has_type $F32X4 (fma x y z)))
|
||||||
(x64_vfmadd213ps x y z))
|
(x64_vfmadd213ps x y z))
|
||||||
(rule (lower (has_type $F64X2 (fma x y z)))
|
(rule (lower (has_type $F64X2 (fma x y z)))
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ pub(super) mod isle;
|
|||||||
use crate::data_value::DataValue;
|
use crate::data_value::DataValue;
|
||||||
use crate::ir::{
|
use crate::ir::{
|
||||||
condcodes::{CondCode, FloatCC, IntCC},
|
condcodes::{CondCode, FloatCC, IntCC},
|
||||||
types, AbiParam, ExternalName, Inst as IRInst, InstructionData, LibCall, Opcode, Signature,
|
types, ExternalName, Inst as IRInst, InstructionData, LibCall, Opcode, Type,
|
||||||
Type,
|
|
||||||
};
|
};
|
||||||
use crate::isa::x64::abi::*;
|
use crate::isa::x64::abi::*;
|
||||||
use crate::isa::x64::inst::args::*;
|
use crate::isa::x64::inst::args::*;
|
||||||
@@ -573,29 +572,13 @@ fn emit_fcmp<C: LowerCtx<I = Inst>>(
|
|||||||
cond_result
|
cond_result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_libcall_sig<C: LowerCtx<I = Inst>>(
|
|
||||||
ctx: &mut C,
|
|
||||||
insn: IRInst,
|
|
||||||
call_conv: CallConv,
|
|
||||||
) -> Signature {
|
|
||||||
let mut sig = Signature::new(call_conv);
|
|
||||||
for i in 0..ctx.num_inputs(insn) {
|
|
||||||
sig.params.push(AbiParam::new(ctx.input_ty(insn, i)));
|
|
||||||
}
|
|
||||||
for i in 0..ctx.num_outputs(insn) {
|
|
||||||
sig.returns.push(AbiParam::new(ctx.output_ty(insn, i)));
|
|
||||||
}
|
|
||||||
sig
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_vm_call<C: LowerCtx<I = Inst>>(
|
fn emit_vm_call<C: LowerCtx<I = Inst>>(
|
||||||
ctx: &mut C,
|
ctx: &mut C,
|
||||||
flags: &Flags,
|
flags: &Flags,
|
||||||
triple: &Triple,
|
triple: &Triple,
|
||||||
libcall: LibCall,
|
libcall: LibCall,
|
||||||
insn: IRInst,
|
inputs: &[Reg],
|
||||||
inputs: SmallVec<[InsnInput; 4]>,
|
outputs: &[Writable<Reg>],
|
||||||
outputs: SmallVec<[InsnOutput; 2]>,
|
|
||||||
) -> CodegenResult<()> {
|
) -> CodegenResult<()> {
|
||||||
let extname = ExternalName::LibCall(libcall);
|
let extname = ExternalName::LibCall(libcall);
|
||||||
|
|
||||||
@@ -607,7 +590,7 @@ fn emit_vm_call<C: LowerCtx<I = Inst>>(
|
|||||||
|
|
||||||
// TODO avoid recreating signatures for every single Libcall function.
|
// TODO avoid recreating signatures for every single Libcall function.
|
||||||
let call_conv = CallConv::for_libcall(flags, CallConv::triple_default(triple));
|
let call_conv = CallConv::for_libcall(flags, CallConv::triple_default(triple));
|
||||||
let sig = make_libcall_sig(ctx, insn, call_conv);
|
let sig = libcall.signature(call_conv);
|
||||||
let caller_conv = ctx.abi().call_conv();
|
let caller_conv = ctx.abi().call_conv();
|
||||||
|
|
||||||
let mut abi = X64ABICaller::from_func(&sig, &extname, dist, caller_conv, flags)?;
|
let mut abi = X64ABICaller::from_func(&sig, &extname, dist, caller_conv, flags)?;
|
||||||
@@ -617,14 +600,12 @@ fn emit_vm_call<C: LowerCtx<I = Inst>>(
|
|||||||
assert_eq!(inputs.len(), abi.num_args());
|
assert_eq!(inputs.len(), abi.num_args());
|
||||||
|
|
||||||
for (i, input) in inputs.iter().enumerate() {
|
for (i, input) in inputs.iter().enumerate() {
|
||||||
let arg_reg = put_input_in_reg(ctx, *input);
|
abi.emit_copy_regs_to_arg(ctx, i, ValueRegs::one(*input));
|
||||||
abi.emit_copy_regs_to_arg(ctx, i, ValueRegs::one(arg_reg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abi.emit_call(ctx);
|
abi.emit_call(ctx);
|
||||||
for (i, output) in outputs.iter().enumerate() {
|
for (i, output) in outputs.iter().enumerate() {
|
||||||
let retval_reg = get_output_reg(ctx, *output).only_reg().unwrap();
|
abi.emit_copy_retval_to_regs(ctx, i, ValueRegs::one(*output));
|
||||||
abi.emit_copy_retval_to_regs(ctx, i, ValueRegs::one(retval_reg));
|
|
||||||
}
|
}
|
||||||
abi.emit_stack_post_adjust(ctx);
|
abi.emit_stack_post_adjust(ctx);
|
||||||
|
|
||||||
@@ -810,7 +791,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(()) = isle::lower(ctx, flags, isa_flags, &outputs, insn) {
|
if let Ok(()) = isle::lower(ctx, triple, flags, isa_flags, &outputs, insn) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -884,6 +865,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
| Opcode::FvpromoteLow
|
| Opcode::FvpromoteLow
|
||||||
| Opcode::Fdemote
|
| Opcode::Fdemote
|
||||||
| Opcode::Fvdemote
|
| Opcode::Fvdemote
|
||||||
|
| Opcode::Fma
|
||||||
| Opcode::Icmp
|
| Opcode::Icmp
|
||||||
| Opcode::Fcmp
|
| Opcode::Fcmp
|
||||||
| Opcode::Load
|
| Opcode::Load
|
||||||
@@ -1974,7 +1956,11 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
ty, op
|
ty, op
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
emit_vm_call(ctx, flags, triple, libcall, insn, inputs, outputs)?;
|
|
||||||
|
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])?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2726,8 +2712,6 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
|
|||||||
|
|
||||||
Opcode::Cls => unimplemented!("Cls not supported"),
|
Opcode::Cls => unimplemented!("Cls not supported"),
|
||||||
|
|
||||||
Opcode::Fma => implemented_in_isle(ctx),
|
|
||||||
|
|
||||||
Opcode::BorNot | Opcode::BxorNot => {
|
Opcode::BorNot | Opcode::BxorNot => {
|
||||||
unimplemented!("or-not / xor-not opcodes not implemented");
|
unimplemented!("or-not / xor-not opcodes not implemented");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ use generated_code::{Context, MInst};
|
|||||||
|
|
||||||
// Types that the generated ISLE code uses via `use super::*`.
|
// Types that the generated ISLE code uses via `use super::*`.
|
||||||
use super::{is_int_or_ref_ty, is_mergeable_load, lower_to_amode};
|
use super::{is_int_or_ref_ty, is_mergeable_load, lower_to_amode};
|
||||||
|
use crate::ir::LibCall;
|
||||||
|
use crate::isa::x64::lower::emit_vm_call;
|
||||||
use crate::{
|
use crate::{
|
||||||
ir::{
|
ir::{
|
||||||
condcodes::{FloatCC, IntCC},
|
condcodes::{FloatCC, IntCC},
|
||||||
@@ -35,6 +37,7 @@ use regalloc2::PReg;
|
|||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
type BoxCallInfo = Box<CallInfo>;
|
type BoxCallInfo = Box<CallInfo>;
|
||||||
type BoxVecMachLabel = Box<SmallVec<[MachLabel; 4]>>;
|
type BoxVecMachLabel = Box<SmallVec<[MachLabel; 4]>>;
|
||||||
@@ -48,6 +51,7 @@ pub struct SinkableLoad {
|
|||||||
/// The main entry point for lowering with ISLE.
|
/// The main entry point for lowering with ISLE.
|
||||||
pub(crate) fn lower<C>(
|
pub(crate) fn lower<C>(
|
||||||
lower_ctx: &mut C,
|
lower_ctx: &mut C,
|
||||||
|
triple: &Triple,
|
||||||
flags: &Flags,
|
flags: &Flags,
|
||||||
isa_flags: &IsaFlags,
|
isa_flags: &IsaFlags,
|
||||||
outputs: &[InsnOutput],
|
outputs: &[InsnOutput],
|
||||||
@@ -56,9 +60,15 @@ pub(crate) fn lower<C>(
|
|||||||
where
|
where
|
||||||
C: LowerCtx<I = MInst>,
|
C: LowerCtx<I = MInst>,
|
||||||
{
|
{
|
||||||
lower_common(lower_ctx, flags, isa_flags, outputs, inst, |cx, insn| {
|
lower_common(
|
||||||
generated_code::constructor_lower(cx, insn)
|
lower_ctx,
|
||||||
})
|
triple,
|
||||||
|
flags,
|
||||||
|
isa_flags,
|
||||||
|
outputs,
|
||||||
|
inst,
|
||||||
|
|cx, insn| generated_code::constructor_lower(cx, insn),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> Context for IsleContext<'_, C, Flags, IsaFlags, 6>
|
impl<C> Context for IsleContext<'_, C, Flags, IsaFlags, 6>
|
||||||
@@ -647,6 +657,24 @@ where
|
|||||||
fn preg_rsp(&mut self) -> PReg {
|
fn preg_rsp(&mut self) -> PReg {
|
||||||
regs::rsp().to_real_reg().unwrap().into()
|
regs::rsp().to_real_reg().unwrap().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn libcall_3(&mut self, libcall: &LibCall, a: Reg, b: Reg, c: 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, b, c],
|
||||||
|
&[output_reg],
|
||||||
|
)
|
||||||
|
.expect("Failed to emit LibCall");
|
||||||
|
|
||||||
|
output_reg.to_reg()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> IsleContext<'_, C, Flags, IsaFlags, 6>
|
impl<C> IsleContext<'_, C, Flags, IsaFlags, 6>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use alloc::boxed::Box;
|
|||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use target_lexicon::Triple;
|
||||||
|
|
||||||
pub use super::MachLabel;
|
pub use super::MachLabel;
|
||||||
pub use crate::ir::{
|
pub use crate::ir::{
|
||||||
@@ -899,6 +900,7 @@ where
|
|||||||
[(C::I, bool); N]: smallvec::Array,
|
[(C::I, bool); N]: smallvec::Array,
|
||||||
{
|
{
|
||||||
pub lower_ctx: &'a mut C,
|
pub lower_ctx: &'a mut C,
|
||||||
|
pub triple: &'a Triple,
|
||||||
pub flags: &'a F,
|
pub flags: &'a F,
|
||||||
pub isa_flags: &'a I,
|
pub isa_flags: &'a I,
|
||||||
}
|
}
|
||||||
@@ -910,6 +912,7 @@ where
|
|||||||
/// lowering.
|
/// lowering.
|
||||||
pub(crate) fn lower_common<C, F, I, IF, const N: usize>(
|
pub(crate) fn lower_common<C, F, I, IF, const N: usize>(
|
||||||
lower_ctx: &mut C,
|
lower_ctx: &mut C,
|
||||||
|
triple: &Triple,
|
||||||
flags: &F,
|
flags: &F,
|
||||||
isa_flags: &I,
|
isa_flags: &I,
|
||||||
outputs: &[InsnOutput],
|
outputs: &[InsnOutput],
|
||||||
@@ -925,6 +928,7 @@ where
|
|||||||
// internal heap allocations.
|
// internal heap allocations.
|
||||||
let mut isle_ctx = IsleContext {
|
let mut isle_ctx = IsleContext {
|
||||||
lower_ctx,
|
lower_ctx,
|
||||||
|
triple,
|
||||||
flags,
|
flags,
|
||||||
isa_flags,
|
isa_flags,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -169,9 +169,8 @@ const OPCODE_SIGNATURES: &'static [(
|
|||||||
(Opcode::Fcopysign, &[F32, F32], &[F32], insert_opcode),
|
(Opcode::Fcopysign, &[F32, F32], &[F32], insert_opcode),
|
||||||
(Opcode::Fcopysign, &[F64, F64], &[F64], insert_opcode),
|
(Opcode::Fcopysign, &[F64, F64], &[F64], insert_opcode),
|
||||||
// Fma
|
// Fma
|
||||||
// TODO: Missing on X86, see https://github.com/bytecodealliance/wasmtime/pull/4460
|
(Opcode::Fma, &[F32, F32, F32], &[F32], insert_opcode),
|
||||||
// (Opcode::Fma, &[F32, F32, F32], &[F32], insert_opcode),
|
(Opcode::Fma, &[F64, F64, F64], &[F64], insert_opcode),
|
||||||
// (Opcode::Fma, &[F64, F64, F64], &[F64], insert_opcode),
|
|
||||||
// Fabs
|
// Fabs
|
||||||
(Opcode::Fabs, &[F32], &[F32], insert_opcode),
|
(Opcode::Fabs, &[F32], &[F32], insert_opcode),
|
||||||
(Opcode::Fabs, &[F64], &[F64], insert_opcode),
|
(Opcode::Fabs, &[F64], &[F64], insert_opcode),
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ pub fn default_libcall_names() -> Box<dyn Fn(ir::LibCall) -> String + Send + Syn
|
|||||||
ir::LibCall::TruncF64 => "trunc".to_owned(),
|
ir::LibCall::TruncF64 => "trunc".to_owned(),
|
||||||
ir::LibCall::NearestF32 => "nearbyintf".to_owned(),
|
ir::LibCall::NearestF32 => "nearbyintf".to_owned(),
|
||||||
ir::LibCall::NearestF64 => "nearbyint".to_owned(),
|
ir::LibCall::NearestF64 => "nearbyint".to_owned(),
|
||||||
|
ir::LibCall::FmaF32 => "fmaf".to_owned(),
|
||||||
|
ir::LibCall::FmaF64 => "fma".to_owned(),
|
||||||
ir::LibCall::Memcpy => "memcpy".to_owned(),
|
ir::LibCall::Memcpy => "memcpy".to_owned(),
|
||||||
ir::LibCall::Memset => "memset".to_owned(),
|
ir::LibCall::Memset => "memset".to_owned(),
|
||||||
ir::LibCall::Memmove => "memmove".to_owned(),
|
ir::LibCall::Memmove => "memmove".to_owned(),
|
||||||
|
|||||||
Reference in New Issue
Block a user