Skip to content

Commit 0517acd

Browse files
committed
Remove the -Zinsert-sideeffect
This removes all of the code we had in place to work-around LLVM's handling of forward progress. From this removal excluded is a workaround where we'd insert a `sideeffect` into clearly infinite loops such as `loop {}`. This code remains conditionally effective when the LLVM version is earlier than 12.0, which fixed the forward progress related miscompilations at their root.
1 parent 861872b commit 0517acd

File tree

11 files changed

+52
-87
lines changed

11 files changed

+52
-87
lines changed

compiler/rustc_codegen_llvm/src/intrinsic.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,11 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
334334
self.call(expect, &[cond, self.const_bool(expected)], None)
335335
}
336336

337-
fn sideeffect(&mut self, unconditional: bool) {
338-
if unconditional || self.tcx.sess.opts.debugging_opts.insert_sideeffect {
337+
fn sideeffect(&mut self) {
338+
// This kind of check would make a ton of sense in the caller, but currently the only
339+
// caller of this function is in `rustc_codegen_ssa`, which is agnostic to whether LLVM
340+
// codegen backend being used, and so is unable to check the LLVM version.
341+
if unsafe { llvm::LLVMRustVersionMajor() } < 12 {
339342
let fnname = self.get_intrinsic(&("llvm.sideeffect"));
340343
self.call(fnname, &[], None);
341344
}
@@ -390,7 +393,6 @@ fn codegen_msvc_try(
390393
) {
391394
let llfn = get_rust_try_fn(bx, &mut |mut bx| {
392395
bx.set_personality_fn(bx.eh_personality());
393-
bx.sideeffect(false);
394396

395397
let mut normal = bx.build_sibling_block("normal");
396398
let mut catchswitch = bx.build_sibling_block("catchswitch");
@@ -552,9 +554,6 @@ fn codegen_gnu_try(
552554
// (%ptr, _) = landingpad
553555
// call %catch_func(%data, %ptr)
554556
// ret 1
555-
556-
bx.sideeffect(false);
557-
558557
let mut then = bx.build_sibling_block("then");
559558
let mut catch = bx.build_sibling_block("catch");
560559

@@ -614,9 +613,6 @@ fn codegen_emcc_try(
614613
// %catch_data[1] = %is_rust_panic
615614
// call %catch_func(%data, %catch_data)
616615
// ret 1
617-
618-
bx.sideeffect(false);
619-
620616
let mut then = bx.build_sibling_block("then");
621617
let mut catch = bx.build_sibling_block("catch");
622618

compiler/rustc_codegen_ssa/src/mir/block.rs

+8-50
Original file line numberDiff line numberDiff line change
@@ -146,24 +146,6 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
146146
}
147147
}
148148
}
149-
150-
// Generate sideeffect intrinsic if jumping to any of the targets can form
151-
// a loop.
152-
fn maybe_sideeffect<Bx: BuilderMethods<'a, 'tcx>>(
153-
&self,
154-
mir: &'tcx mir::Body<'tcx>,
155-
bx: &mut Bx,
156-
targets: &[mir::BasicBlock],
157-
) {
158-
if bx.tcx().sess.opts.debugging_opts.insert_sideeffect {
159-
if targets.iter().any(|&target| {
160-
target <= self.bb
161-
&& target.start_location().is_predecessor_of(self.bb.start_location(), mir)
162-
}) {
163-
bx.sideeffect(false);
164-
}
165-
}
166-
}
167149
}
168150

169151
/// Codegen implementations for some terminator variants.
@@ -198,8 +180,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
198180
let discr = self.codegen_operand(&mut bx, &discr);
199181
// `switch_ty` is redundant, sanity-check that.
200182
assert_eq!(discr.layout.ty, switch_ty);
201-
helper.maybe_sideeffect(self.mir, &mut bx, targets.all_targets());
202-
203183
let mut target_iter = targets.iter();
204184
if target_iter.len() == 1 {
205185
// If there are two targets (one conditional, one fallback), emit br instead of switch
@@ -308,7 +288,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
308288

309289
if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
310290
// we don't actually need to drop anything.
311-
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
312291
helper.funclet_br(self, &mut bx, target);
313292
return;
314293
}
@@ -337,7 +316,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
337316
}
338317
_ => (bx.get_fn_addr(drop_fn), FnAbi::of_instance(&bx, drop_fn, &[])),
339318
};
340-
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
341319
helper.do_call(
342320
self,
343321
&mut bx,
@@ -379,7 +357,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
379357

380358
// Don't codegen the panic block if success if known.
381359
if const_cond == Some(expected) {
382-
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
383360
helper.funclet_br(self, &mut bx, target);
384361
return;
385362
}
@@ -390,7 +367,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
390367
// Create the failure block and the conditional branch to it.
391368
let lltarget = helper.llblock(self, target);
392369
let panic_block = self.new_block("panic");
393-
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
394370
if expected {
395371
bx.cond_br(cond, lltarget, panic_block.llbb());
396372
} else {
@@ -491,9 +467,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
491467
let fn_abi = FnAbi::of_instance(bx, instance, &[]);
492468
let llfn = bx.get_fn_addr(instance);
493469

494-
if let Some((_, target)) = destination.as_ref() {
495-
helper.maybe_sideeffect(self.mir, bx, &[*target]);
496-
}
497470
// Codegen the actual panic invoke/call.
498471
helper.do_call(
499472
self,
@@ -507,7 +480,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
507480
} else {
508481
// a NOP
509482
let target = destination.as_ref().unwrap().1;
510-
helper.maybe_sideeffect(self.mir, bx, &[target]);
511483
helper.funclet_br(self, bx, target)
512484
}
513485
true
@@ -551,7 +523,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
551523
if let Some(ty::InstanceDef::DropGlue(_, None)) = def {
552524
// Empty drop glue; a no-op.
553525
let &(_, target) = destination.as_ref().unwrap();
554-
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
555526
helper.funclet_br(self, &mut bx, target);
556527
return;
557528
}
@@ -586,7 +557,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
586557
if let Some(destination_ref) = destination.as_ref() {
587558
let &(dest, target) = destination_ref;
588559
self.codegen_transmute(&mut bx, &args[0], dest);
589-
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
590560
helper.funclet_br(self, &mut bx, target);
591561
} else {
592562
// If we are trying to transmute to an uninhabited type,
@@ -634,8 +604,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
634604
location.val.store(&mut bx, tmp);
635605
}
636606
self.store_return(&mut bx, ret_dest, &fn_abi.ret, location.immediate());
637-
638-
helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
639607
helper.funclet_br(self, &mut bx, *target);
640608
}
641609
return;
@@ -700,7 +668,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
700668
}
701669

702670
if let Some((_, target)) = *destination {
703-
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
704671
helper.funclet_br(self, &mut bx, target);
705672
} else {
706673
bx.unreachable();
@@ -817,9 +784,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
817784
_ => span_bug!(span, "no llfn for call"),
818785
};
819786

820-
if let Some((_, target)) = destination.as_ref() {
821-
helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
822-
}
823787
helper.do_call(
824788
self,
825789
&mut bx,
@@ -969,22 +933,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
969933

970934
mir::TerminatorKind::Goto { target } => {
971935
if bb == target {
972-
// This is an unconditional branch back to this same basic
973-
// block. That means we have something like a `loop {}`
974-
// statement. Currently LLVM miscompiles this because it
975-
// assumes forward progress. We want to prevent this in all
976-
// cases, but that has a fairly high cost to compile times
977-
// currently. Instead, try to handle this specific case
978-
// which comes up commonly in practice (e.g., in embedded
979-
// code).
936+
// This is an unconditional branch back to this same basic block. That means we
937+
// have something like a `loop {}` statement. LLVM versions before 12.0
938+
// miscompile this because they assume forward progress. For older versions
939+
// try to handle just this specific case which comes up commonly in practice
940+
// (e.g., in embedded code).
980941
//
981-
// The `true` here means we insert side effects regardless
982-
// of -Zinsert-sideeffect being passed on unconditional
983-
// branching to the same basic block.
984-
bx.sideeffect(true);
985-
} else {
986-
helper.maybe_sideeffect(self.mir, &mut bx, &[target]);
942+
// NB: the `sideeffect` currently checks for the LLVM version used internally.
943+
bx.sideeffect();
987944
}
945+
988946
helper.funclet_br(self, &mut bx, target);
989947
}
990948

compiler/rustc_codegen_ssa/src/mir/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,6 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
149149
bx.set_personality_fn(cx.eh_personality());
150150
}
151151

152-
bx.sideeffect(false);
153-
154152
let cleanup_kinds = analyze::cleanup_kinds(&mir);
155153
// Allocate a `Block` for every basic block, except
156154
// the start block, if nothing loops back to it.

compiler/rustc_codegen_ssa/src/traits/intrinsic.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes {
2020
fn abort(&mut self);
2121
fn assume(&mut self, val: Self::Value);
2222
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value;
23-
/// Normally, sideeffect is only emitted if -Zinsert-sideeffect is passed;
24-
/// in some cases though we want to emit it regardless.
25-
fn sideeffect(&mut self, unconditional: bool);
23+
/// Emits a forced side effect.
24+
///
25+
/// Currently has any effect only when LLVM versions prior to 12.0 are used as the backend.
26+
fn sideeffect(&mut self);
2627
/// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
2728
/// Rust defined C-variadic functions.
2829
fn va_start(&mut self, val: Self::Value) -> Self::Value;

compiler/rustc_interface/src/tests.rs

-1
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,6 @@ fn test_debugging_options_tracking_hash() {
560560
tracked!(inline_mir, Some(true));
561561
tracked!(inline_mir_threshold, Some(123));
562562
tracked!(inline_mir_hint_threshold, Some(123));
563-
tracked!(insert_sideeffect, true);
564563
tracked!(instrument_coverage, true);
565564
tracked!(instrument_mcount, true);
566565
tracked!(link_only, true);

compiler/rustc_session/src/options.rs

-4
Original file line numberDiff line numberDiff line change
@@ -967,10 +967,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
967967
"control whether `#[inline]` functions are in all CGUs"),
968968
input_stats: bool = (false, parse_bool, [UNTRACKED],
969969
"gather statistics about the input (default: no)"),
970-
insert_sideeffect: bool = (false, parse_bool, [TRACKED],
971-
"fix undefined behavior when a thread doesn't eventually make progress \
972-
(such as entering an empty infinite loop) by inserting llvm.sideeffect \
973-
(default: no)"),
974970
instrument_coverage: bool = (false, parse_bool, [TRACKED],
975971
"instrument the generated code to support LLVM source-based code coverage \
976972
reports (note, the compiler build config must include `profiler = true`, \

src/test/codegen/loop.rs

-15
This file was deleted.

src/test/codegen/non-terminate/infinite-loop-1.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// compile-flags: -C opt-level=3 -Z insert-sideeffect
1+
// min-llvm-version: 12.0
2+
// compile-flags: -C opt-level=3
23

34
#![crate_type = "lib"]
45

src/test/codegen/non-terminate/infinite-loop-2.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// compile-flags: -C opt-level=3 -Z insert-sideeffect
1+
// min-llvm-version: 12.0
2+
// compile-flags: -C opt-level=3
23

34
#![crate_type = "lib"]
45

src/test/codegen/non-terminate/infinite-recursion.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// compile-flags: -C opt-level=3 -Z insert-sideeffect
1+
// min-llvm-version: 12.0
2+
// compile-flags: -C opt-level=3
23

34
#![crate_type = "lib"]
45

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// min-llvm-version: 12.0
2+
// compile-flags: -C opt-level=3
3+
4+
#![crate_type = "lib"]
5+
6+
// Verify that we don't miscompile this even if rustc didn't apply the trivial loop detection to
7+
// insert the sideeffect intrinsic.
8+
9+
fn infinite_loop() -> u8 {
10+
let mut x = 0;
11+
// CHECK-NOT: sideeffect
12+
loop {
13+
if x == 42 {
14+
x = 0;
15+
} else {
16+
x = 42;
17+
}
18+
}
19+
}
20+
21+
// CHECK-LABEL: @test
22+
#[no_mangle]
23+
fn test() -> u8 {
24+
// CHECK-NOT: unreachable
25+
// CHECK: br label %{{.+}}
26+
// CHECK-NOT: unreachable
27+
let x = infinite_loop();
28+
x
29+
}

0 commit comments

Comments
 (0)