Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions cuda-oxide/crates/dialect-mir/src/rust_intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,24 @@ pub const CALLEE_HYPOT_F32: &str = placeholder!("hypotf32");
/// Placeholder call used for `f64::hypot` / `std::sys::cmath::hypot` (binary).
pub const CALLEE_HYPOT_F64: &str = placeholder!("hypotf64");

/// Placeholder call used for `libm::tgammaf`.
pub const CALLEE_TGAMMA_F32: &str = placeholder!("tgammaf32");
/// Placeholder call used for `libm::tgamma`.
pub const CALLEE_TGAMMA_F64: &str = placeholder!("tgammaf64");
/// Placeholder call used for `libm::ilogbf`.
pub const CALLEE_ILOGB_F32: &str = placeholder!("ilogbf32");
/// Placeholder call used for `libm::ilogb`.
pub const CALLEE_ILOGB_F64: &str = placeholder!("ilogbf64");
/// Placeholder call used for `libm::ldexpf`.
pub const CALLEE_LDEXP_F32: &str = placeholder!("ldexpf32");
/// Placeholder call used for `libm::ldexp`.
pub const CALLEE_LDEXP_F64: &str = placeholder!("ldexpf64");

/// Placeholder call used for `libm::frexpf`, returning `(f32, i32)`.
pub const CALLEE_FREXP_F32: &str = placeholder!("frexpf32");
/// Placeholder call used for `libm::frexp`, returning `(f64, i32)`.
pub const CALLEE_FREXP_F64: &str = placeholder!("frexpf64");

/// Placeholder call used for `core::intrinsics::fadd_fast` (generic over float type).
///
/// Lowered to `llvm.fadd` with explicit `fast` fast-math flags. The `f*_fast` intrinsics
Expand Down Expand Up @@ -350,6 +368,14 @@ pub fn is_libdevice_backed_placeholder(callee: &str) -> bool {
| CALLEE_LOG1P_F64
| CALLEE_HYPOT_F32
| CALLEE_HYPOT_F64
| CALLEE_TGAMMA_F32
| CALLEE_TGAMMA_F64
| CALLEE_ILOGB_F32
| CALLEE_ILOGB_F64
| CALLEE_LDEXP_F32
| CALLEE_LDEXP_F64
| CALLEE_FREXP_F32
| CALLEE_FREXP_F64
)
}

Expand Down Expand Up @@ -452,6 +478,14 @@ mod tests {
CALLEE_LOG1P_F64,
CALLEE_HYPOT_F32,
CALLEE_HYPOT_F64,
CALLEE_TGAMMA_F32,
CALLEE_TGAMMA_F64,
CALLEE_ILOGB_F32,
CALLEE_ILOGB_F64,
CALLEE_LDEXP_F32,
CALLEE_LDEXP_F64,
CALLEE_FREXP_F32,
CALLEE_FREXP_F64,
];

/// Every placeholder that is libdevice-backed only under the libNVVM
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use pliron::location::Location;
use pliron::operation::Operation;
use rustc_public::mir;

/// Floating-point math intrinsic from libcore.
/// Floating-point math intrinsic from core, std, or libm.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RustFloatMathIntrinsic {
/// `core::intrinsics::sqrtf32`.
Expand Down Expand Up @@ -161,6 +161,22 @@ pub enum RustFloatMathIntrinsic {
HypotF32,
/// `f64::hypot` / `std::sys::cmath::hypot` (binary).
HypotF64,
/// `libm::tgammaf`.
TgammaF32,
/// `libm::tgamma`.
TgammaF64,
/// `libm::ilogbf`.
IlogbF32,
/// `libm::ilogb`.
IlogbF64,
/// `libm::ldexpf`.
LdexpF32,
/// `libm::ldexp`.
LdexpF64,
/// `libm::frexpf`, returning `(f32, i32)`.
FrexpF32,
/// `libm::frexp`, returning `(f64, i32)`.
FrexpF64,
/// Generic `core::intrinsics::fadd_fast` (lowered to `llvm.fadd` + fast-math).
FaddFast,
/// Generic `core::intrinsics::fsub_fast` (lowered to `llvm.fsub` + fast-math).
Expand Down Expand Up @@ -341,6 +357,8 @@ impl RustFloatMathIntrinsic {
"std::sys::cmath::log1p" => Some(Self::Log1pF64),
"std::sys::cmath::hypotf" => Some(Self::HypotF32),
"std::sys::cmath::hypot" => Some(Self::HypotF64),
"std::sys::cmath::tgammaf" => Some(Self::TgammaF32),
"std::sys::cmath::tgamma" => Some(Self::TgammaF64),
other => Self::from_libm_path(other).or_else(|| Self::from_fast_intrinsic_path(other)),
}
}
Expand Down Expand Up @@ -428,6 +446,14 @@ impl RustFloatMathIntrinsic {
"log1p" => Some(Self::Log1pF64),
"hypotf" => Some(Self::HypotF32),
"hypot" => Some(Self::HypotF64),
"tgammaf" => Some(Self::TgammaF32),
"tgamma" => Some(Self::TgammaF64),
"ilogbf" => Some(Self::IlogbF32),
"ilogb" => Some(Self::IlogbF64),
"ldexpf" | "scalbnf" => Some(Self::LdexpF32),
"ldexp" | "scalbn" => Some(Self::LdexpF64),
"frexpf" => Some(Self::FrexpF32),
"frexp" => Some(Self::FrexpF64),
_ => None,
}
}
Expand Down Expand Up @@ -523,6 +549,14 @@ impl RustFloatMathIntrinsic {
Self::Log1pF64 => rust_intrinsics::CALLEE_LOG1P_F64,
Self::HypotF32 => rust_intrinsics::CALLEE_HYPOT_F32,
Self::HypotF64 => rust_intrinsics::CALLEE_HYPOT_F64,
Self::TgammaF32 => rust_intrinsics::CALLEE_TGAMMA_F32,
Self::TgammaF64 => rust_intrinsics::CALLEE_TGAMMA_F64,
Self::IlogbF32 => rust_intrinsics::CALLEE_ILOGB_F32,
Self::IlogbF64 => rust_intrinsics::CALLEE_ILOGB_F64,
Self::LdexpF32 => rust_intrinsics::CALLEE_LDEXP_F32,
Self::LdexpF64 => rust_intrinsics::CALLEE_LDEXP_F64,
Self::FrexpF32 => rust_intrinsics::CALLEE_FREXP_F32,
Self::FrexpF64 => rust_intrinsics::CALLEE_FREXP_F64,
Self::FaddFast => rust_intrinsics::CALLEE_FADD_FAST,
Self::FsubFast => rust_intrinsics::CALLEE_FSUB_FAST,
Self::FmulFast => rust_intrinsics::CALLEE_FMUL_FAST,
Expand All @@ -542,8 +576,8 @@ pub fn is_libm_path(name: &str) -> bool {
}

/// Recognize `libm::sincosf` / `libm::sincos` (glam's `nostd-libm` lowering of
/// `f32::sin_cos`). These return a `(sin, cos)` tuple, so they do not fit the
/// scalar `RustFloatMathIntrinsic` dispatch; [`emit_sincos`] handles them.
/// `f32::sin_cos`). [`emit_sincos`] handles these separately by emitting
/// two scalar placeholders and constructing their tuple in the importer.
/// Returns `Some(is_f64)` when `name` is a libm sincos function.
pub fn libm_sincos_is_f64(name: &str) -> Option<bool> {
if !is_libm_path(name) {
Expand Down Expand Up @@ -736,6 +770,87 @@ mod tests {
use super::*;
use dialect_mir::rust_intrinsics;

#[test]
fn frexp_paths_resolve_only_libm_entry_points() {
use RustFloatMathIntrinsic as I;
for (name, variant, placeholder) in [
("frexpf", I::FrexpF32, rust_intrinsics::CALLEE_FREXP_F32),
("frexp", I::FrexpF64, rust_intrinsics::CALLEE_FREXP_F64),
] {
for path in [
format!("libm::{name}"),
format!("libm::math::{name}::{name}"),
] {
assert_eq!(I::from_core_path(&path), Some(variant), "{path}");
assert_eq!(variant.placeholder_callee(), placeholder);
assert!(rust_intrinsics::is_libdevice_backed_placeholder(
placeholder
));
}
for root in [
"user::libm",
"libm_lookalike",
"std::sys::cmath",
"core::intrinsics",
] {
let path = format!("{root}::{name}");
assert_eq!(I::from_core_path(&path), None, "{path}");
}
}
assert_eq!(I::from_core_path("libm::sincos"), None);
assert_eq!(libm_sincos_is_f64("libm::sincos"), Some(true));
assert_eq!(I::from_core_path("libm::ldexp"), Some(I::LdexpF64));
}

#[test]
fn special_math_paths_resolve_to_typed_placeholders() {
use RustFloatMathIntrinsic as I;
for (name, intrinsic, callee) in [
("tgammaf", I::TgammaF32, rust_intrinsics::CALLEE_TGAMMA_F32),
("tgamma", I::TgammaF64, rust_intrinsics::CALLEE_TGAMMA_F64),
("ilogbf", I::IlogbF32, rust_intrinsics::CALLEE_ILOGB_F32),
("ilogb", I::IlogbF64, rust_intrinsics::CALLEE_ILOGB_F64),
("ldexpf", I::LdexpF32, rust_intrinsics::CALLEE_LDEXP_F32),
("ldexp", I::LdexpF64, rust_intrinsics::CALLEE_LDEXP_F64),
("scalbnf", I::LdexpF32, rust_intrinsics::CALLEE_LDEXP_F32),
("scalbn", I::LdexpF64, rust_intrinsics::CALLEE_LDEXP_F64),
] {
for path in [
format!("libm::{name}"),
format!("libm::math::{name}::{name}"),
] {
assert_eq!(I::from_core_path(&path), Some(intrinsic), "{path}");
assert_eq!(intrinsic.placeholder_callee(), callee);
}
for path in [
format!("my_app::libm_compat::{name}"),
format!("my_app::libm::{name}"),
format!("libm_lookalike::{name}"),
format!("std::sys::cmath::{name}_unsupported"),
] {
assert_eq!(I::from_core_path(&path), None, "{path}");
}
}
assert_eq!(
I::from_core_path("std::sys::cmath::tgammaf"),
Some(I::TgammaF32)
);
assert_eq!(
I::from_core_path("std::sys::cmath::tgamma"),
Some(I::TgammaF64)
);
// Existing scalar and tuple dispatch must keep their identities.
assert_eq!(I::from_core_path("libm::hypot"), Some(I::HypotF64));
assert_eq!(
I::from_core_path("core::intrinsics::powif32"),
Some(I::PowiF32)
);
assert_eq!(libm_sincos_is_f64("libm::sincosf"), Some(false));
for name in ["modf", "remquo", "lgamma_r", "tgammaf128"] {
assert_eq!(I::from_core_path(&format!("libm::{name}")), None);
}
}

#[test]
fn generic_float_intrinsics_resolve_only_the_declared_float_type() {
use RustFloatMathIntrinsic as I;
Expand Down
Loading