Skip to content

Commit c50336a

Browse files
committed
Genericize ceil, floor, trunc, round, round_ties_even
1 parent 5ac6a6b commit c50336a

16 files changed

Lines changed: 218 additions & 457 deletions

File tree

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -359,26 +359,6 @@ fn codegen_float_intrinsic_call<'tcx>(
359359
sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32, types::F32),
360360
sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64, types::F64),
361361
sym::copysignf128 => ("copysignf128", 2, fx.tcx.types.f128, types::F128),
362-
sym::floorf16 => ("floorf16", 1, fx.tcx.types.f16, types::F16),
363-
sym::floorf32 => ("floorf", 1, fx.tcx.types.f32, types::F32),
364-
sym::floorf64 => ("floor", 1, fx.tcx.types.f64, types::F64),
365-
sym::floorf128 => ("floorf128", 1, fx.tcx.types.f128, types::F128),
366-
sym::ceilf16 => ("ceilf16", 1, fx.tcx.types.f16, types::F16),
367-
sym::ceilf32 => ("ceilf", 1, fx.tcx.types.f32, types::F32),
368-
sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64, types::F64),
369-
sym::ceilf128 => ("ceilf128", 1, fx.tcx.types.f128, types::F128),
370-
sym::truncf16 => ("truncf16", 1, fx.tcx.types.f16, types::F16),
371-
sym::truncf32 => ("truncf", 1, fx.tcx.types.f32, types::F32),
372-
sym::truncf64 => ("trunc", 1, fx.tcx.types.f64, types::F64),
373-
sym::truncf128 => ("truncf128", 1, fx.tcx.types.f128, types::F128),
374-
sym::round_ties_even_f16 => ("rintf16", 1, fx.tcx.types.f16, types::F16),
375-
sym::round_ties_even_f32 => ("rintf", 1, fx.tcx.types.f32, types::F32),
376-
sym::round_ties_even_f64 => ("rint", 1, fx.tcx.types.f64, types::F64),
377-
sym::round_ties_even_f128 => ("rintf128", 1, fx.tcx.types.f128, types::F128),
378-
sym::roundf16 => ("roundf16", 1, fx.tcx.types.f16, types::F16),
379-
sym::roundf32 => ("roundf", 1, fx.tcx.types.f32, types::F32),
380-
sym::roundf64 => ("round", 1, fx.tcx.types.f64, types::F64),
381-
sym::roundf128 => ("roundf128", 1, fx.tcx.types.f128, types::F128),
382362
sym::sinf16 => ("sinf16", 1, fx.tcx.types.f16, types::F16),
383363
sym::sinf32 => ("sinf", 1, fx.tcx.types.f32, types::F32),
384364
sym::sinf64 => ("sin", 1, fx.tcx.types.f64, types::F64),
@@ -429,10 +409,6 @@ fn codegen_float_intrinsic_call<'tcx>(
429409
sym::copysignf16 => codegen_f16_f128::copysign_f16(fx, args[0], args[1]),
430410
sym::copysignf128 => codegen_f16_f128::copysign_f128(fx, args[0], args[1]),
431411
sym::copysignf32 | sym::copysignf64 => fx.bcx.ins().fcopysign(args[0], args[1]),
432-
sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]),
433-
sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]),
434-
sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]),
435-
sym::round_ties_even_f32 | sym::round_ties_even_f64 => fx.bcx.ins().nearest(args[0]),
436412
sym::sqrtf32 | sym::sqrtf64 => fx.bcx.ins().sqrt(args[0]),
437413

438414
// These intrinsics aren't supported natively by Cranelift.
@@ -1143,24 +1119,54 @@ fn codegen_regular_intrinsic_call<'tcx>(
11431119
ret.write_cvalue(fx, old);
11441120
}
11451121

1146-
sym::fabs => {
1122+
// Float unop intrinsics
1123+
sym::fabs
1124+
| sym::floor
1125+
| sym::ceil
1126+
| sym::trunc
1127+
| sym::round_ties_even
1128+
| sym::round => {
11471129
intrinsic_args!(fx, args => (arg); intrinsic);
11481130
let layout = arg.layout();
11491131
let ty::Float(float_ty) = layout.ty.kind() else {
11501132
span_bug!(
11511133
source_info.span,
1152-
"expected float type for fabs intrinsic: {:?}",
1134+
"expected float type for float unop intrinsic {:?}: {:?}",
1135+
intrinsic,
11531136
layout.ty
11541137
);
11551138
};
11561139
let x = arg.load_scalar(fx);
1157-
let val = match float_ty {
1158-
FloatTy::F32 | FloatTy::F64 => fx.bcx.ins().fabs(x),
1140+
1141+
use FloatTy::*;
1142+
let val = match (intrinsic, float_ty) {
1143+
(sym::fabs, F32 | F64) => Ok(fx.bcx.ins().fabs(x)),
11591144
// FIXME(bytecodealliance/wasmtime#8312): Use `fabsf16` once Cranelift
11601145
// backend lowerings are implemented.
1161-
FloatTy::F16 => codegen_f16_f128::abs_f16(fx, x),
1162-
FloatTy::F128 => codegen_f16_f128::abs_f128(fx, x),
1146+
(sym::fabs, F16) => Ok(codegen_f16_f128::abs_f16(fx, x)),
1147+
(sym::fabs, F128) => Ok(codegen_f16_f128::abs_f128(fx, x)),
1148+
(sym::floor, F32 | F64) => Ok(fx.bcx.ins().floor(x)),
1149+
(sym::floor, F16) => Err("floorf16"),
1150+
(sym::floor, F128) => Err("floorf128"),
1151+
(sym::ceil, F32 | F64) => Ok(fx.bcx.ins().ceil(x)),
1152+
(sym::ceil, F16) => Err("ceilf16"),
1153+
(sym::ceil, F128) => Err("ceilf128"),
1154+
(sym::trunc, F32 | F64) => Ok(fx.bcx.ins().trunc(x)),
1155+
(sym::trunc, F16) => Err("truncf16"),
1156+
(sym::trunc, F128) => Err("truncf128"),
1157+
(sym::round_ties_even, F32 | F64) => Ok(fx.bcx.ins().nearest(x)),
1158+
(sym::round_ties_even, F16) => Err("rintf16"),
1159+
(sym::round_ties_even, F128) => Err("rintf128"),
1160+
(sym::round, F16) => Err("roundf16"),
1161+
(sym::round, F32) => Err("roundf"),
1162+
(sym::round, F64) => Err("round"),
1163+
(sym::round, F128) => Err("roundf128"),
1164+
_ => unreachable!(),
11631165
};
1166+
let val = val.unwrap_or_else(|name| {
1167+
let ty = fx.clif_type(layout.ty).unwrap();
1168+
fx.lib_call(name, vec![AbiParam::new(ty)], vec![AbiParam::new(ty)], &[x])[0]
1169+
});
11641170
let val = CValue::by_val(val, layout);
11651171
ret.write_cvalue(fx, val);
11661172
}

compiler/rustc_codegen_gcc/src/intrinsic/mod.rs

Lines changed: 81 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,6 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
108108
}
109109
sym::copysignf32 => "copysignf",
110110
sym::copysignf64 => "copysign",
111-
sym::floorf32 => "floorf",
112-
sym::floorf64 => "floor",
113-
sym::ceilf32 => "ceilf",
114-
sym::ceilf64 => "ceil",
115-
sym::truncf32 => "truncf",
116-
sym::truncf64 => "trunc",
117-
// We match the LLVM backend and lower this to `rint`.
118-
sym::round_ties_even_f32 => "rintf",
119-
sym::round_ties_even_f64 => "rint",
120-
sym::roundf32 => "roundf",
121-
sym::roundf64 => "round",
122111
sym::abort => "abort",
123112
_ => return None,
124113
};
@@ -198,12 +187,6 @@ fn get_simple_function_f128<'gcc, 'tcx>(
198187
) -> Function<'gcc> {
199188
let f128_type = cx.type_f128();
200189
let func_name = match name {
201-
sym::ceilf128 => "ceilf128",
202-
sym::fabs => "fabsf128",
203-
sym::floorf128 => "floorf128",
204-
sym::truncf128 => "truncf128",
205-
sym::roundf128 => "roundf128",
206-
sym::round_ties_even_f128 => "roundevenf128",
207190
sym::sqrtf128 => "sqrtf128",
208191
_ => span_bug!(span, "used get_simple_function_f128 for non-unary f128 intrinsic"),
209192
};
@@ -224,10 +207,7 @@ fn f16_builtin<'gcc, 'tcx>(
224207
) -> RValue<'gcc> {
225208
let f32_type = cx.type_f32();
226209
let builtin_name = match name {
227-
sym::ceilf16 => "__builtin_ceilf",
228210
sym::copysignf16 => "__builtin_copysignf",
229-
sym::fabs => "fabsf",
230-
sym::floorf16 => "__builtin_floorf",
231211
sym::fmaf16 => "fmaf",
232212
sym::powf16 => "__builtin_powf",
233213
sym::powif16 => {
@@ -237,10 +217,7 @@ fn f16_builtin<'gcc, 'tcx>(
237217
let result = cx.context.new_call(None, func, &args);
238218
return cx.context.new_cast(None, result, cx.type_f16());
239219
}
240-
sym::roundf16 => "__builtin_roundf",
241-
sym::round_ties_even_f16 => "__builtin_rintf",
242220
sym::sqrtf16 => "__builtin_sqrtf",
243-
sym::truncf16 => "__builtin_truncf",
244221
_ => unreachable!(),
245222
};
246223

@@ -486,22 +463,92 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
486463
}
487464
}
488465
}
489-
sym::fabs => 'fabs: {
466+
// float unary intrinsics
467+
sym::fabs
468+
| sym::floor
469+
| sym::ceil
470+
| sym::trunc
471+
| sym::round_ties_even
472+
| sym::round => {
473+
enum IntrinsicKind {
474+
Builtin(&'static str),
475+
Extern(&'static str),
476+
BuiltinF16Cast(&'static str),
477+
Fallback,
478+
}
479+
use IntrinsicKind::*;
490480
let ty = args[0].layout.ty;
491481
let ty::Float(float_ty) = *ty.kind() else {
492482
span_bug!(span, "expected float type for fabs intrinsic: {:?}", ty);
493483
};
494-
let func = match float_ty {
495-
ty::FloatTy::F16 => break 'fabs f16_builtin(self, name, args),
496-
ty::FloatTy::F32 => self.context.get_builtin_function("fabsf"),
497-
ty::FloatTy::F64 => self.context.get_builtin_function("fabs"),
498-
ty::FloatTy::F128 => get_simple_function_f128(span, self, name),
484+
485+
use ty::FloatTy::*;
486+
let func = match (name, float_ty) {
487+
(_, F128) if !self.cx.supports_f128_type => Fallback,
488+
(sym::fabs, F16) => BuiltinF16Cast("fabsf"),
489+
(sym::fabs, F32) => Builtin("fabsf"),
490+
(sym::fabs, F64) => Builtin("fabs"),
491+
(sym::fabs, F128) => Extern("fabsf128"),
492+
(sym::floor, F16) => BuiltinF16Cast("__builtin_floorf"),
493+
(sym::floor, F32) => Builtin("floorf"),
494+
(sym::floor, F64) => Builtin("floor"),
495+
(sym::floor, F128) => Extern("floorf128"),
496+
(sym::ceil, F16) => BuiltinF16Cast("__builtin_ceilf"),
497+
(sym::ceil, F32) => Builtin("ceilf"),
498+
(sym::ceil, F64) => Builtin("ceil"),
499+
(sym::ceil, F128) => Extern("ceilf128"),
500+
(sym::trunc, F16) => BuiltinF16Cast("__builtin_truncf"),
501+
(sym::trunc, F32) => Builtin("truncf"),
502+
(sym::trunc, F64) => Builtin("trunc"),
503+
(sym::trunc, F128) => Extern("truncf128"),
504+
// We match the LLVM backend and lower this to `rint`.
505+
(sym::round_ties_even, F16) => BuiltinF16Cast("__builtin_rintf"),
506+
(sym::round_ties_even, F32) => Builtin("rintf"),
507+
(sym::round_ties_even, F64) => Builtin("rint"),
508+
(sym::round_ties_even, F128) => Extern("roundevenf128"),
509+
(sym::round, F16) => BuiltinF16Cast("__builtin_roundf"),
510+
(sym::round, F32) => Builtin("roundf"),
511+
(sym::round, F64) => Builtin("round"),
512+
(sym::round, F128) => Extern("roundf128"),
513+
_ => Fallback,
499514
};
500-
self.cx.context.new_call(
501-
self.location,
502-
func,
503-
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
504-
)
515+
match func {
516+
Builtin(name) => self.cx.context.new_call(
517+
self.location,
518+
self.context.get_builtin_function(name),
519+
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
520+
),
521+
Extern(name) => {
522+
let ty = self.cx.type_float_from_ty(float_ty);
523+
let func = self.cx.context.new_function(
524+
None,
525+
FunctionType::Extern,
526+
ty,
527+
&[self.cx.context.new_parameter(None, ty, "a")],
528+
name,
529+
false,
530+
);
531+
self.cx.context.new_call(
532+
self.location,
533+
func,
534+
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
535+
)
536+
}
537+
BuiltinF16Cast(name) => {
538+
let func = self.cx.context.get_builtin_function(name);
539+
let args: Vec<_> = args
540+
.iter()
541+
.map(|arg| {
542+
self.cx.context.new_cast(None, arg.immediate(), self.cx.type_f32())
543+
})
544+
.collect();
545+
let result = self.cx.context.new_call(None, func, &args);
546+
self.cx.context.new_cast(None, result, self.cx.type_f16())
547+
}
548+
Fallback => {
549+
return Err(Instance::new_raw(instance.def_id(), instance.args));
550+
}
551+
}
505552
}
506553

507554
sym::raw_eq => {

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -127,35 +127,6 @@ fn call_simple_intrinsic<'ll, 'tcx>(
127127
sym::copysignf64 => ("llvm.copysign", &[bx.type_f64()]),
128128
sym::copysignf128 => ("llvm.copysign", &[bx.type_f128()]),
129129

130-
sym::floorf16 => ("llvm.floor", &[bx.type_f16()]),
131-
sym::floorf32 => ("llvm.floor", &[bx.type_f32()]),
132-
sym::floorf64 => ("llvm.floor", &[bx.type_f64()]),
133-
sym::floorf128 => ("llvm.floor", &[bx.type_f128()]),
134-
135-
sym::ceilf16 => ("llvm.ceil", &[bx.type_f16()]),
136-
sym::ceilf32 => ("llvm.ceil", &[bx.type_f32()]),
137-
sym::ceilf64 => ("llvm.ceil", &[bx.type_f64()]),
138-
sym::ceilf128 => ("llvm.ceil", &[bx.type_f128()]),
139-
140-
sym::truncf16 => ("llvm.trunc", &[bx.type_f16()]),
141-
sym::truncf32 => ("llvm.trunc", &[bx.type_f32()]),
142-
sym::truncf64 => ("llvm.trunc", &[bx.type_f64()]),
143-
sym::truncf128 => ("llvm.trunc", &[bx.type_f128()]),
144-
145-
// We could use any of `rint`, `nearbyint`, or `roundeven`
146-
// for this -- they are all identical in semantics when
147-
// assuming the default FP environment.
148-
// `rint` is what we used for $forever.
149-
sym::round_ties_even_f16 => ("llvm.rint", &[bx.type_f16()]),
150-
sym::round_ties_even_f32 => ("llvm.rint", &[bx.type_f32()]),
151-
sym::round_ties_even_f64 => ("llvm.rint", &[bx.type_f64()]),
152-
sym::round_ties_even_f128 => ("llvm.rint", &[bx.type_f128()]),
153-
154-
sym::roundf16 => ("llvm.round", &[bx.type_f16()]),
155-
sym::roundf32 => ("llvm.round", &[bx.type_f32()]),
156-
sym::roundf64 => ("llvm.round", &[bx.type_f64()]),
157-
sym::roundf128 => ("llvm.round", &[bx.type_f128()]),
158-
159130
_ => return None,
160131
};
161132
Some(bx.call_intrinsic(
@@ -498,13 +469,30 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
498469
}
499470
}
500471

501-
sym::fabs => {
472+
sym::fabs
473+
| sym::floor
474+
| sym::ceil
475+
| sym::trunc
476+
| sym::round_ties_even
477+
| sym::round => {
502478
let ty = args[0].layout.ty;
503479
let ty::Float(f) = ty.kind() else {
504480
span_bug!(span, "the `fabs` intrinsic requires a floating-point argument, got {:?}", ty);
505481
};
506482
let llty = self.type_float_from_ty(*f);
507-
let llvm_name = "llvm.fabs";
483+
let llvm_name = match name {
484+
sym::fabs => "llvm.fabs",
485+
sym::floor => "llvm.floor",
486+
sym::ceil => "llvm.ceil",
487+
sym::trunc => "llvm.trunc",
488+
// We could use any of `rint`, `nearbyint`, or `roundeven`
489+
// for this -- they are all identical in semantics when
490+
// assuming the default FP environment.
491+
// `rint` is what we used for $forever.
492+
sym::round_ties_even => "llvm.rint",
493+
sym::round => "llvm.round",
494+
_ => bug!(),
495+
};
508496
self.call_intrinsic(
509497
llvm_name,
510498
&[llty],

0 commit comments

Comments
 (0)