Skip to content

Commit 40a2216

Browse files
Auto merge of #117192 - saethlin:leaves-can-assert, r=<try>
Don't treat asserts as a call in cross-crate inlining try-job: i686-msvc-1 try-job: i686-msvc-2 try-job: x86_64-msvc-1 try-job: x86_64-msvc-2
2 parents 25d319a + 31e94ff commit 40a2216

File tree

7 files changed

+57
-69
lines changed

7 files changed

+57
-69
lines changed

compiler/rustc_mir_transform/src/cross_crate_inline.rs

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_hir::attrs::InlineAttr;
22
use rustc_hir::def::DefKind;
33
use rustc_hir::def_id::LocalDefId;
4+
use rustc_middle::bug;
45
use rustc_middle::mir::visit::Visitor;
56
use rustc_middle::mir::*;
67
use rustc_middle::query::Providers;
@@ -102,6 +103,15 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
102103
&& checker.statements <= threshold
103104
}
104105

106+
// The threshold that CostChecker computes is balancing the desire to make more things
107+
// inlinable cross crates against the growth in incremental CGU size that happens when too many
108+
// things in the sysroot are made inlinable.
109+
// Permitting calls causes the size of some incremental CGUs to grow, because more functions are
110+
// made inlinable out of the sysroot or dependencies.
111+
// Assert terminators are similar to calls, but do not have the same impact on compile time, so
112+
// those are just treated as statements.
113+
// A threshold exists at all because we don't want to blindly mark a huge function as inlinable.
114+
105115
struct CostChecker<'b, 'tcx> {
106116
tcx: TyCtxt<'tcx>,
107117
callee_body: &'b Body<'tcx>,
@@ -121,9 +131,10 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
121131
}
122132

123133
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _: Location) {
134+
self.statements += 1;
124135
let tcx = self.tcx;
125-
match terminator.kind {
126-
TerminatorKind::Drop { ref place, unwind, .. } => {
136+
match &terminator.kind {
137+
TerminatorKind::Drop { place, unwind, .. } => {
127138
let ty = place.ty(self.callee_body, tcx).ty;
128139
if !ty.is_trivially_pure_clone_copy() {
129140
self.calls += 1;
@@ -132,7 +143,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
132143
}
133144
}
134145
}
135-
TerminatorKind::Call { ref func, unwind, .. } => {
146+
TerminatorKind::Call { func, unwind, .. } => {
136147
// We track calls because they make our function not a leaf (and in theory, the
137148
// number of calls indicates how likely this function is to perturb other CGUs).
138149
// But intrinsics don't have a body that gets assigned to a CGU, so they are
@@ -147,21 +158,31 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
147158
self.landing_pads += 1;
148159
}
149160
}
150-
TerminatorKind::Assert { unwind, .. } => {
161+
TerminatorKind::TailCall { .. } => {
151162
self.calls += 1;
163+
}
164+
TerminatorKind::Assert { unwind, .. } => {
152165
if let UnwindAction::Cleanup(_) = unwind {
153166
self.landing_pads += 1;
154167
}
155168
}
156169
TerminatorKind::UnwindResume => self.resumes += 1,
157170
TerminatorKind::InlineAsm { unwind, .. } => {
158-
self.statements += 1;
159171
if let UnwindAction::Cleanup(_) = unwind {
160172
self.landing_pads += 1;
161173
}
162174
}
163-
TerminatorKind::Return => {}
164-
_ => self.statements += 1,
175+
TerminatorKind::Return
176+
| TerminatorKind::Goto { .. }
177+
| TerminatorKind::SwitchInt { .. }
178+
| TerminatorKind::Unreachable
179+
| TerminatorKind::UnwindTerminate(_) => {}
180+
kind @ (TerminatorKind::FalseUnwind { .. }
181+
| TerminatorKind::FalseEdge { .. }
182+
| TerminatorKind::Yield { .. }
183+
| TerminatorKind::CoroutineDrop) => {
184+
bug!("{kind:?} should not be in runtime MIR");
185+
}
165186
}
166187
}
167188
}

tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//@ [strong] compile-flags: -Z stack-protector=strong
88
//@ [basic] compile-flags: -Z stack-protector=basic
99
//@ [none] compile-flags: -Z stack-protector=none
10-
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled
10+
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort
1111

1212
#![crate_type = "lib"]
1313
#![allow(internal_features)]
@@ -143,26 +143,11 @@ pub fn local_string_addr_taken(f: fn(&String)) {
143143
f(&x);
144144

145145
// Taking the address of the local variable `x` leads to stack smash
146-
// protection with the `strong` heuristic, but not with the `basic`
147-
// heuristic. It does not matter that the reference is not mut.
148-
//
149-
// An interesting note is that a similar function in C++ *would* be
150-
// protected by the `basic` heuristic, because `std::string` has a char
151-
// array internally as a small object optimization:
152-
// ```
153-
// cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk
154-
// #include <string>
155-
// void f(void (*g)(const std::string&)) {
156-
// std::string x;
157-
// g(x);
158-
// }
159-
// EOF
160-
// ```
161-
//
146+
// protection. It does not matter that the reference is not mut.
162147

163148
// all: __security_check_cookie
164-
// strong-NOT: __security_check_cookie
165-
// basic-NOT: __security_check_cookie
149+
// strong: __security_check_cookie
150+
// basic: __security_check_cookie
166151
// none-NOT: __security_check_cookie
167152
// missing-NOT: __security_check_cookie
168153
}
@@ -346,13 +331,8 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
346331
// alloca, and is therefore not protected by the `strong` or `basic`
347332
// heuristics.
348333

349-
// We should have a __security_check_cookie call in `all` and `strong` modes but
350-
// LLVM does not support generating stack protectors in functions with funclet
351-
// based EH personalities.
352-
// https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
353-
// all-NOT: __security_check_cookie
354-
// strong-NOT: __security_check_cookie
355-
334+
// all: __security_check_cookie
335+
// strong: __security_check_cookie
356336
// basic-NOT: __security_check_cookie
357337
// none-NOT: __security_check_cookie
358338
// missing-NOT: __security_check_cookie

tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//@ [strong] compile-flags: -Z stack-protector=strong
88
//@ [basic] compile-flags: -Z stack-protector=basic
99
//@ [none] compile-flags: -Z stack-protector=none
10-
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled
10+
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort
1111

1212
#![crate_type = "lib"]
1313
#![feature(unsized_fn_params)]
@@ -138,40 +138,17 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) {
138138
// CHECK-LABEL: local_string_addr_taken
139139
#[no_mangle]
140140
pub fn local_string_addr_taken(f: fn(&String)) {
141-
// CHECK-DAG: .seh_endprologue
142141
let x = String::new();
143142
f(&x);
144143

145144
// Taking the address of the local variable `x` leads to stack smash
146-
// protection with the `strong` heuristic, but not with the `basic`
147-
// heuristic. It does not matter that the reference is not mut.
148-
//
149-
// An interesting note is that a similar function in C++ *would* be
150-
// protected by the `basic` heuristic, because `std::string` has a char
151-
// array internally as a small object optimization:
152-
// ```
153-
// cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk
154-
// #include <string>
155-
// void f(void (*g)(const std::string&)) {
156-
// std::string x;
157-
// g(x);
158-
// }
159-
// EOF
160-
// ```
161-
//
145+
// protection. It does not matter that the reference is not mut.
162146

163-
// We should have a __security_check_cookie call in `all` and `strong` modes but
164-
// LLVM does not support generating stack protectors in functions with funclet
165-
// based EH personalities.
166-
// https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
167-
// all-NOT: __security_check_cookie
168-
// strong-NOT: __security_check_cookie
169-
170-
// basic-NOT: __security_check_cookie
147+
// all: __security_check_cookie
148+
// strong: __security_check_cookie
149+
// basic: __security_check_cookie
171150
// none-NOT: __security_check_cookie
172151
// missing-NOT: __security_check_cookie
173-
174-
// CHECK-DAG: .seh_endproc
175152
}
176153

177154
pub trait SelfByRef {
@@ -353,13 +330,8 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
353330
// alloca, and is therefore not protected by the `strong` or `basic`
354331
// heuristics.
355332

356-
// We should have a __security_check_cookie call in `all` and `strong` modes but
357-
// LLVM does not support generating stack protectors in functions with funclet
358-
// based EH personalities.
359-
// https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
360-
// all-NOT: __security_check_cookie
361-
// strong-NOT: __security_check_cookie
362-
333+
// all: __security_check_cookie
334+
// strong: __security_check_cookie
363335
// basic-NOT: __security_check_cookie
364336
// none-NOT: __security_check_cookie
365337
// missing-NOT: __security_check_cookie

tests/assembly-llvm/stack-protector/stack-protector-target-support.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@
173173
//@ [r84] needs-llvm-components: x86
174174
//@ [r85] compile-flags: --target x86_64-unknown-redox
175175
//@ [r85] needs-llvm-components: x86
176-
//@ compile-flags: -Z stack-protector=all
176+
//@ compile-flags: -Z stack-protector=all -Cpanic=abort
177177
//@ compile-flags: -C opt-level=2
178178

179179
#![crate_type = "lib"]

tests/codegen-llvm/cross-crate-inlining/auxiliary/leaf.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,8 @@ fn inner() -> String {
2323
pub fn leaf_with_intrinsic(a: &[u64; 2], b: &[u64; 2]) -> bool {
2424
a == b
2525
}
26+
27+
// This function's optimized MIR contains assert terminators, not calls.
28+
pub fn leaf_with_assert(a: i32, b: i32) -> i32 {
29+
a / b
30+
}

tests/codegen-llvm/cross-crate-inlining/leaf-inlining.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,12 @@ pub fn leaf_with_intrinsic_outer(a: &[u64; 2], b: &[u64; 2]) -> bool {
2525
// CHECK-NOT: call {{.*}}leaf_with_intrinsic
2626
leaf::leaf_with_intrinsic(a, b)
2727
}
28+
29+
// Check that we inline functions with assert terminators
30+
#[no_mangle]
31+
pub fn leaf_with_assert(a: i32, b: i32) -> i32 {
32+
// CHECK-NOT: call {{.*}}leaf_with_assert
33+
// CHECK: sdiv i32 %a, %b
34+
// CHECK-NOT: call {{.*}}leaf_with_assert
35+
leaf::leaf_with_assert(a, b)
36+
}

tests/codegen-units/item-collection/implicit-panic-call.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// rust-lang/rust#90405
22
// Ensure implicit panic calls are collected
3+
//@ compile-flags: -Zcross-crate-inline-threshold=never
34

45
#![feature(lang_items)]
56
#![feature(no_core)]

0 commit comments

Comments
 (0)