Skip to content

Commit 68785d9

Browse files
PGO: Add regression test for indirect call promotion.
1 parent 0675d65 commit 68785d9

File tree

5 files changed

+129
-0
lines changed

5 files changed

+129
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# needs-profiler-support
2+
3+
-include ../tools.mk
4+
5+
# This test makes sure that indirect call promotion is performed. The test
6+
# programs calls the same function a thousand times through a function pointer.
7+
# Only PGO data provides the information that it actually always is the same
8+
# function. We verify that the indirect call promotion pass inserts a check
9+
# whether it can make a direct call instead of the indirect call.
10+
11+
# LLVM doesn't support instrumenting binaries that use SEH:
12+
# https://github.com/rust-lang/rust/issues/61002
13+
#
14+
# Things work fine with -Cpanic=abort though.
15+
ifdef IS_MSVC
16+
COMMON_FLAGS=-Cpanic=abort
17+
endif
18+
19+
all:
20+
# We don't compile `opaque` with either optimizations or instrumentation.
21+
# We don't compile `opaque` with either optimizations or instrumentation.
22+
$(RUSTC) $(COMMON_FLAGS) opaque.rs
23+
# Compile the test program with instrumentation
24+
mkdir -p "$(TMPDIR)"/prof_data_dir
25+
$(RUSTC) $(COMMON_FLAGS) interesting.rs \
26+
-Cprofile-generate="$(TMPDIR)"/prof_data_dir -O -Ccodegen-units=1
27+
$(RUSTC) $(COMMON_FLAGS) main.rs -Cprofile-generate="$(TMPDIR)"/prof_data_dir -O
28+
# The argument below generates to the expected branch weights
29+
$(call RUN,main) || exit 1
30+
"$(LLVM_BIN_DIR)"/llvm-profdata merge \
31+
-o "$(TMPDIR)"/prof_data_dir/merged.profdata \
32+
"$(TMPDIR)"/prof_data_dir
33+
$(RUSTC) $(COMMON_FLAGS) interesting.rs \
34+
-Cprofile-use="$(TMPDIR)"/prof_data_dir/merged.profdata -O \
35+
-Ccodegen-units=1 --emit=llvm-ir
36+
cat "$(TMPDIR)"/interesting.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CHECK: define void @call_a_bunch_of_functions({{.*}} {
2+
3+
# Make sure that indirect call promotion inserted a check against the most
4+
# frequently called function.
5+
CHECK: %{{.*}} = icmp eq void ()* %{{.*}}, @function_called_always
6+
7+
# Check that the call to `function_called_always` was inlined, so that we
8+
# directly call `opaque_f1` from the upstream crate.
9+
CHECK: call void @opaque_f1()
10+
11+
12+
# Same checks as above, repeated for the trait object case
13+
14+
CHECK: define void @call_a_bunch_of_trait_methods({{.*}}
15+
CHECK: %{{.*}} = icmp eq void ({}*)* %{{.*}}, {{.*}} @foo
16+
CHECK: tail call void @opaque_f2()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#![crate_name="interesting"]
2+
#![crate_type="rlib"]
3+
4+
extern crate opaque;
5+
6+
#[no_mangle]
7+
pub fn function_called_always() {
8+
opaque::opaque_f1();
9+
}
10+
11+
#[no_mangle]
12+
pub fn function_called_never() {
13+
opaque::opaque_f2();
14+
}
15+
16+
#[no_mangle]
17+
pub fn call_a_bunch_of_functions(fns: &[fn()]) {
18+
19+
// Indirect call promotion transforms the below into something like
20+
//
21+
// for f in fns {
22+
// if f == function_called_always {
23+
// function_called_always()
24+
// } else {
25+
// f();
26+
// }
27+
// }
28+
//
29+
// where `function_called_always` actually gets inlined too.
30+
31+
for f in fns {
32+
f();
33+
}
34+
}
35+
36+
37+
pub trait Foo {
38+
fn foo(&self);
39+
}
40+
41+
impl Foo for u32 {
42+
43+
#[no_mangle]
44+
fn foo(&self) {
45+
opaque::opaque_f2();
46+
}
47+
}
48+
49+
#[no_mangle]
50+
pub fn call_a_bunch_of_trait_methods(trait_objects: &[&dyn Foo]) {
51+
52+
// Same as above, just with vtables in between
53+
for x in trait_objects {
54+
x.foo();
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
extern crate interesting;
2+
3+
fn main() {
4+
// function pointer case
5+
let fns: Vec<_> = std::iter::repeat(interesting::function_called_always as fn())
6+
.take(1000)
7+
.collect();
8+
interesting::call_a_bunch_of_functions(&fns[..]);
9+
10+
// Trait object case
11+
let trait_objects = vec![0u32; 1000];
12+
let trait_objects: Vec<_> = trait_objects.iter().map(|x| x as &dyn interesting::Foo).collect();
13+
interesting::call_a_bunch_of_trait_methods(&trait_objects[..]);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![crate_name="opaque"]
2+
#![crate_type="rlib"]
3+
4+
#[no_mangle]
5+
pub fn opaque_f1() {}
6+
#[no_mangle]
7+
pub fn opaque_f2() {}

0 commit comments

Comments
 (0)