Skip to content
Merged
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
33 changes: 23 additions & 10 deletions compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cc @bjorn3 if you want to look at clif changes but this generally LGTM

Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,6 @@ fn codegen_float_intrinsic_call<'tcx>(
sym::log10f32 => ("log10f", 1, fx.tcx.types.f32, types::F32),
sym::log10f64 => ("log10", 1, fx.tcx.types.f64, types::F64),
sym::log10f128 => ("log10f128", 1, fx.tcx.types.f128, types::F128),
sym::fabsf16 => ("fabsf16", 1, fx.tcx.types.f16, types::F16),
sym::fabsf32 => ("fabsf", 1, fx.tcx.types.f32, types::F32),
sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64, types::F64),
sym::fabsf128 => ("fabsf128", 1, fx.tcx.types.f128, types::F128),
sym::fmaf16 => ("fmaf16", 3, fx.tcx.types.f16, types::F16),
sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32, types::F32),
sym::fmaf64 => ("fma", 3, fx.tcx.types.f64, types::F64),
Expand Down Expand Up @@ -441,11 +437,7 @@ fn codegen_float_intrinsic_call<'tcx>(
sym::copysignf32 | sym::copysignf64 => {
CValue::by_val(fx.bcx.ins().fcopysign(args[0], args[1]), layout)
}
sym::fabsf16 => CValue::by_val(codegen_f16_f128::abs_f16(fx, args[0]), layout),
sym::fabsf128 => CValue::by_val(codegen_f16_f128::abs_f128(fx, args[0]), layout),
sym::fabsf32
| sym::fabsf64
| sym::floorf32
sym::floorf32
| sym::floorf64
| sym::ceilf32
| sym::ceilf64
Expand All @@ -456,7 +448,6 @@ fn codegen_float_intrinsic_call<'tcx>(
| sym::sqrtf32
| sym::sqrtf64 => {
let val = match intrinsic {
sym::fabsf32 | sym::fabsf64 => fx.bcx.ins().fabs(args[0]),
sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]),
sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]),
sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]),
Expand Down Expand Up @@ -1179,6 +1170,28 @@ fn codegen_regular_intrinsic_call<'tcx>(
ret.write_cvalue(fx, old);
}

sym::fabs => {
intrinsic_args!(fx, args => (arg); intrinsic);
let layout = arg.layout();
let ty::Float(float_ty) = layout.ty.kind() else {
span_bug!(
source_info.span,
"expected float type for fabs intrinsic: {:?}",
layout.ty
);
};
let x = arg.load_scalar(fx);
let val = match float_ty {
FloatTy::F32 | FloatTy::F64 => fx.bcx.ins().fabs(x),
// FIXME(bytecodealliance/wasmtime#8312): Use `fabsf16` once Cranelift
// backend lowerings are implemented.
FloatTy::F16 => codegen_f16_f128::abs_f16(fx, x),
FloatTy::F128 => codegen_f16_f128::abs_f128(fx, x),
};
let val = CValue::by_val(val, layout);
ret.write_cvalue(fx, val);
}

sym::minimumf16 => {
intrinsic_args!(fx, args => (a, b); intrinsic);
let a = a.load_scalar(fx);
Expand Down
105 changes: 60 additions & 45 deletions compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ use rustc_codegen_ssa::traits::{
IntrinsicCallBuilderMethods, LayoutTypeCodegenMethods,
};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;
#[cfg(feature = "master")]
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug};
use rustc_span::{Span, Symbol, sym};
use rustc_target::callconv::{ArgAbi, PassMode};

Expand Down Expand Up @@ -70,8 +70,6 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
// FIXME: calling `fma` from libc without FMA target feature uses expensive software emulation
sym::fmuladdf32 => "fmaf", // FIXME: use gcc intrinsic analogous to llvm.fmuladd.f32
sym::fmuladdf64 => "fma", // FIXME: use gcc intrinsic analogous to llvm.fmuladd.f64
sym::fabsf32 => "fabsf",
sym::fabsf64 => "fabs",
sym::minimumf32 => "fminimumf",
sym::minimumf64 => "fminimum",
sym::minimumf128 => {
Expand Down Expand Up @@ -194,58 +192,29 @@ fn get_simple_function<'gcc, 'tcx>(
}

fn get_simple_function_f128<'gcc, 'tcx>(
span: Span,
cx: &CodegenCx<'gcc, 'tcx>,
name: Symbol,
) -> Option<Function<'gcc>> {
if !cx.supports_f128_type {
return None;
}

) -> Function<'gcc> {
let f128_type = cx.type_f128();
let func_name = match name {
sym::ceilf128 => "ceilf128",
sym::fabsf128 => "fabsf128",
sym::fabs => "fabsf128",
sym::floorf128 => "floorf128",
sym::truncf128 => "truncf128",
sym::roundf128 => "roundf128",
sym::round_ties_even_f128 => "roundevenf128",
sym::sqrtf128 => "sqrtf128",
_ => return None,
_ => span_bug!(span, "used get_simple_function_f128 for non-unary f128 intrinsic"),
};
Some(cx.context.new_function(
cx.context.new_function(
None,
FunctionType::Extern,
f128_type,
&[cx.context.new_parameter(None, f128_type, "a")],
func_name,
false,
))
}

fn get_simple_function_f128_2args<'gcc, 'tcx>(
cx: &CodegenCx<'gcc, 'tcx>,
name: Symbol,
) -> Option<Function<'gcc>> {
if !cx.supports_f128_type {
return None;
}

let f128_type = cx.type_f128();
let func_name = match name {
sym::copysignf128 => "copysignf128",
_ => return None,
};
Some(cx.context.new_function(
None,
FunctionType::Extern,
f128_type,
&[
cx.context.new_parameter(None, f128_type, "a"),
cx.context.new_parameter(None, f128_type, "b"),
],
func_name,
false,
))
)
}

fn f16_builtin<'gcc, 'tcx>(
Expand All @@ -257,7 +226,7 @@ fn f16_builtin<'gcc, 'tcx>(
let builtin_name = match name {
sym::ceilf16 => "__builtin_ceilf",
sym::copysignf16 => "__builtin_copysignf",
sym::fabsf16 => "fabsf",
sym::fabs => "fabsf",
sym::floorf16 => "__builtin_floorf",
sym::fmaf16 => "fmaf",
sym::powf16 => "__builtin_powf",
Expand Down Expand Up @@ -297,11 +266,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
let fn_args = instance.args;

let simple = get_simple_intrinsic(self, name);
// FIXME(antoyo): Only call get_simple_function_f128 and get_simple_function_f128_2args when
// it is the symbols for the supported f128 builtins.
let simple_func = get_simple_function(self, name)
.or_else(|| get_simple_function_f128(self, name))
.or_else(|| get_simple_function_f128_2args(self, name));
let simple_func = get_simple_function(self, name);

let value = match name {
_ if simple.is_some() => {
Expand All @@ -322,7 +287,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
}
sym::ceilf16
| sym::copysignf16
| sym::fabsf16
| sym::floorf16
| sym::fmaf16
| sym::powf16
Expand All @@ -331,6 +295,40 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
| sym::round_ties_even_f16
| sym::sqrtf16
| sym::truncf16 => f16_builtin(self, name, args),
sym::ceilf128
| sym::floorf128
| sym::truncf128
| sym::roundf128
| sym::round_ties_even_f128
| sym::sqrtf128
if self.cx.supports_f128_type =>
{
let func = get_simple_function_f128(span, self, name);
self.cx.context.new_call(
self.location,
func,
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
)
}
sym::copysignf128 if self.cx.supports_f128_type => {
let f128_type = self.cx.type_f128();
let func = self.cx.context.new_function(
None,
FunctionType::Extern,
f128_type,
&[
self.cx.context.new_parameter(None, f128_type, "a"),
self.cx.context.new_parameter(None, f128_type, "b"),
],
"copysignf128",
false,
);
self.cx.context.new_call(
self.location,
func,
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
)
}
sym::fmaf128 => {
let f128_type = self.cx.type_f128();
let func = self.cx.context.new_function(
Expand Down Expand Up @@ -488,6 +486,23 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
}
}
}
sym::fabs => 'fabs: {
let ty = args[0].layout.ty;
let ty::Float(float_ty) = *ty.kind() else {
span_bug!(span, "expected float type for fabs intrinsic: {:?}", ty);
};
let func = match float_ty {
ty::FloatTy::F16 => break 'fabs f16_builtin(self, name, args),
ty::FloatTy::F32 => self.context.get_builtin_function("fabsf"),
ty::FloatTy::F64 => self.context.get_builtin_function("fabs"),
ty::FloatTy::F128 => get_simple_function_f128(span, self, name),
};
self.cx.context.new_call(
self.location,
func,
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
)
}

sym::raw_eq => {
use rustc_abi::BackendRepr::*;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
}};
}
let ty::Float(ref f) = *in_elem.kind() else {
return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
return_error!(InvalidMonomorphization::BasicFloatType { span, name, ty: in_ty });
};
let elem_ty = bx.cx.type_float_from_ty(*f);
let (elem_ty_str, elem_ty, cast_type) = match f.bit_width() {
Expand Down
21 changes: 15 additions & 6 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,6 @@ fn call_simple_intrinsic<'ll, 'tcx>(
sym::fmuladdf64 => ("llvm.fmuladd", &[bx.type_f64()]),
sym::fmuladdf128 => ("llvm.fmuladd", &[bx.type_f128()]),

sym::fabsf16 => ("llvm.fabs", &[bx.type_f16()]),
sym::fabsf32 => ("llvm.fabs", &[bx.type_f32()]),
sym::fabsf64 => ("llvm.fabs", &[bx.type_f64()]),
sym::fabsf128 => ("llvm.fabs", &[bx.type_f128()]),

// FIXME: LLVM currently mis-compile those intrinsics, re-enable them
// when llvm/llvm-project#{139380,139381,140445} are fixed.
//sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]),
Expand Down Expand Up @@ -502,6 +497,20 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
}
}

sym::fabs => {
let ty = args[0].layout.ty;
let ty::Float(f) = ty.kind() else {
span_bug!(span, "the `fabs` intrinsic requires a floating-point argument, got {:?}", ty);
};
let llty = self.type_float_from_ty(*f);
let llvm_name = "llvm.fabs";
self.call_intrinsic(
llvm_name,
&[llty],
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
)
}

sym::raw_eq => {
use BackendRepr::*;
let tp_ty = fn_args.type_at(0);
Expand Down Expand Up @@ -1936,7 +1945,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
}

let ty::Float(f) = in_elem.kind() else {
return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
return_error!(InvalidMonomorphization::BasicFloatType { span, name, ty: in_ty });
};
let elem_ty = bx.cx.type_float_from_ty(*f);

Expand Down
8 changes: 0 additions & 8 deletions compiler/rustc_codegen_ssa/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,14 +739,6 @@ pub enum InvalidMonomorphization<'tcx> {
in_ty: Ty<'tcx>,
},

#[diag("invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type", code = E0511)]
FloatingPointType {
#[primary_span]
span: Span,
name: Symbol,
in_ty: Ty<'tcx>,
},

#[diag("invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`", code = E0511)]
UnrecognizedIntrinsic {
#[primary_span]
Expand Down
51 changes: 33 additions & 18 deletions compiler/rustc_const_eval/src/interpret/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,10 +575,23 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
sym::copysignf64 => self.float_copysign_intrinsic::<Double>(args, dest)?,
sym::copysignf128 => self.float_copysign_intrinsic::<Quad>(args, dest)?,

sym::fabsf16 => self.float_abs_intrinsic::<Half>(args, dest)?,
sym::fabsf32 => self.float_abs_intrinsic::<Single>(args, dest)?,
sym::fabsf64 => self.float_abs_intrinsic::<Double>(args, dest)?,
sym::fabsf128 => self.float_abs_intrinsic::<Quad>(args, dest)?,
sym::fabs => {
let arg = self.read_immediate(&args[0])?;
let ty::Float(float_ty) = arg.layout.ty.kind() else {
span_bug!(
self.cur_span(),
"non-float type for float intrinsic: {}",
arg.layout.ty,
);
};
let out_val = match float_ty {
FloatTy::F16 => self.unop_float_intrinsic::<Half>(intrinsic_name, arg)?,
FloatTy::F32 => self.unop_float_intrinsic::<Single>(intrinsic_name, arg)?,
FloatTy::F64 => self.unop_float_intrinsic::<Double>(intrinsic_name, arg)?,
FloatTy::F128 => self.unop_float_intrinsic::<Quad>(intrinsic_name, arg)?,
};
self.write_scalar(out_val, dest)?;
}

sym::floorf16 => self.float_round_intrinsic::<Half>(
args,
Expand Down Expand Up @@ -1020,6 +1033,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes))
}

fn unop_float_intrinsic<F>(
&self,
name: Symbol,
arg: ImmTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, Scalar<M::Provenance>>
where
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
{
let x: F = arg.to_scalar().to_float()?;
match name {
// bitwise, no NaN adjustments
sym::fabs => interp_ok(x.abs().into()),
_ => bug!("not a unary float intrinsic: {}", name),
}
}

fn float_minmax<F>(
&self,
a: Scalar<M::Provenance>,
Expand Down Expand Up @@ -1078,20 +1107,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
interp_ok(())
}

fn float_abs_intrinsic<F>(
&mut self,
args: &[OpTy<'tcx, M::Provenance>],
dest: &PlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, ()>
where
F: rustc_apfloat::Float + rustc_apfloat::FloatConvert<F> + Into<Scalar<M::Provenance>>,
{
let x: F = self.read_scalar(&args[0])?.to_float()?;
// bitwise, no NaN adjustments
self.write_scalar(x.abs(), dest)?;
interp_ok(())
}

fn float_round<F>(
&mut self,
x: Scalar<M::Provenance>,
Expand Down
Loading
Loading