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.
|
||||
|
||||
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::str::FromStr;
|
||||
#[cfg(feature = "enable-serde")]
|
||||
@@ -50,6 +51,10 @@ pub enum LibCall {
|
||||
NearestF32,
|
||||
/// nearest.f64
|
||||
NearestF64,
|
||||
/// fma.f32
|
||||
FmaF32,
|
||||
/// fma.f64
|
||||
FmaF64,
|
||||
/// libc.memcpy
|
||||
Memcpy,
|
||||
/// libc.memset
|
||||
@@ -91,6 +96,8 @@ impl FromStr for LibCall {
|
||||
"TruncF64" => Ok(Self::TruncF64),
|
||||
"NearestF32" => Ok(Self::NearestF32),
|
||||
"NearestF64" => Ok(Self::NearestF64),
|
||||
"FmaF32" => Ok(Self::FmaF32),
|
||||
"FmaF64" => Ok(Self::FmaF64),
|
||||
"Memcpy" => Ok(Self::Memcpy),
|
||||
"Memset" => Ok(Self::Memset),
|
||||
"Memmove" => Ok(Self::Memmove),
|
||||
@@ -124,6 +131,7 @@ impl LibCall {
|
||||
Opcode::Floor => Self::FloorF32,
|
||||
Opcode::Trunc => Self::TruncF32,
|
||||
Opcode::Nearest => Self::NearestF32,
|
||||
Opcode::Fma => Self::FmaF32,
|
||||
_ => return None,
|
||||
},
|
||||
types::F64 => match opcode {
|
||||
@@ -131,6 +139,7 @@ impl LibCall {
|
||||
Opcode::Floor => Self::FloorF64,
|
||||
Opcode::Trunc => Self::TruncF64,
|
||||
Opcode::Nearest => Self::NearestF64,
|
||||
Opcode::Fma => Self::FmaF64,
|
||||
_ => return None,
|
||||
},
|
||||
_ => return None,
|
||||
@@ -157,6 +166,8 @@ impl LibCall {
|
||||
TruncF64,
|
||||
NearestF32,
|
||||
NearestF64,
|
||||
FmaF32,
|
||||
FmaF64,
|
||||
Memcpy,
|
||||
Memset,
|
||||
Memmove,
|
||||
@@ -164,6 +175,50 @@ impl LibCall {
|
||||
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`.
|
||||
|
||||
Reference in New Issue
Block a user