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
11 changes: 11 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
result_place: Option<PlaceValue<Bx::Value>>,
source_info: SourceInfo,
) -> IntrinsicResult<'tcx, Bx::Value> {
// When `-Zforce-intrinsic-fallback` is enabled, always use the fallback body if it exists,
if bx.tcx().sess.opts.unstable_opts.force_intrinsic_fallback
&& let Some(def) = bx.tcx().intrinsic(instance.def_id())
&& !def.must_be_overridden
{
return IntrinsicResult::Fallback(ty::Instance::new_raw(
instance.def_id(),
instance.args,
));
}

let span = source_info.span;

let name = bx.tcx().item_name(instance.def_id());
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -995,11 +995,18 @@ fn visit_instance_use<'tcx>(
output.push(create_fn_mono_item(tcx, panic_instance, source));
}
} else if !intrinsic.must_be_overridden
&& !tcx.sess.replaced_intrinsics.contains(&intrinsic.name)
&& (tcx.sess.opts.unstable_opts.force_intrinsic_fallback
|| !tcx.sess.replaced_intrinsics.contains(&intrinsic.name))
{
// Codegen the fallback body of intrinsics with fallback bodies.
// We have to skip this otherwise as there's no body to codegen.
// We also skip intrinsics the backend handles, to reduce monomorphizations.
//
// We also skip `replaced_intrinsics` which are always replaced by the backend and hence
// monomorphizing the fallback body would be pointless.
//
// However, when -Zforce-intrinsic-fallback is set (e.g. to test the fallback
// implementations) we ignore the optimization hint and do monomorphize
// the fallback body.
let instance = ty::Instance::new_raw(instance.def_id(), instance.args);
if tcx.should_codegen_locally(instance) {
output.push(create_fn_mono_item(tcx, instance, source));
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2417,6 +2417,9 @@ options! {
fmt_debug: FmtDebug = (FmtDebug::Full, parse_fmt_debug, [TRACKED],
"how detailed `#[derive(Debug)]` should be. `full` prints types recursively, \
`shallow` prints only type names, `none` prints nothing and disables `{:?}`. (default: `full`)"),
force_intrinsic_fallback: bool = (false, parse_bool, [TRACKED],
"always use the fallback body of an intrinsic, if it has one, instead of lowering \
the intrinsic in the codegen backend (default: no)."),
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
"force all crates to be `rustc_private` unstable (default: no)"),
function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
## `force-intrinsic-fallback`

Configures codegen to always use the fallback body of an intrinsic, if it has one,
instead of lowering the intrinsic in the codegen backend.

This is useful for testing the fallback implementation.
38 changes: 38 additions & 0 deletions tests/codegen-llvm/force-intrinsic-fallback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//@ compile-flags: --crate-type=lib -C no-prepopulate-passes -Copt-level=3
//
//@ revisions: NORMAL FALLBACK
//@ [FALLBACK] compile-flags: -Zforce-intrinsic-fallback
#![feature(core_intrinsics, funnel_shifts)]

// Check the effect of `-Zforce-intrinsic-fallback`.
//
// Without the flag, the dedicated backend lowering of the intrinsic is used.
// With the flag, the fallback body is called instead.

#[no_mangle]
pub fn call_minimumf32(x: f32, y: f32) -> f32 {
// CHECK-LABEL: @call_minimumf32

// NORMAL: call float @llvm.minimum.f32
// NORMAL-NOT: minimumf32

// FALLBACK-NOT: @llvm.minimum
// FALLBACK: call {{.*}}minimumf32
core::intrinsics::minimumf32(x, y)
}

// Codegen backends can return a list of `replaced_intrinsics`, for which codegen of the fallback is
// normally skipped. `unchecked_funnel_shl` is in that list for the LLVM backend, so we test it here
// to ensure that with the flag enabled the fallback body is actually code generated and called.

#[no_mangle]
pub fn call_funnel_shl(a: u32, b: u32, shift: u32) -> u32 {
// CHECK-LABEL: @call_funnel_shl

// NORMAL: call i32 @llvm.fshl.i32
// NORMAL-NOT: funnel_shl

// FALLBACK-NOT: @llvm.fshl
// FALLBACK: call {{.*}}funnel_shl
unsafe { core::intrinsics::unchecked_funnel_shl(a, b, shift) }
}
Loading