PGO: Add regression test for indirect call promotion.
This commit is contained in:
parent
0675d65093
commit
68785d9614
5 changed files with 129 additions and 0 deletions
|
@ -0,0 +1,36 @@
|
|||
# needs-profiler-support
|
||||
|
||||
-include ../tools.mk
|
||||
|
||||
# This test makes sure that indirect call promotion is performed. The test
|
||||
# programs calls the same function a thousand times through a function pointer.
|
||||
# Only PGO data provides the information that it actually always is the same
|
||||
# function. We verify that the indirect call promotion pass inserts a check
|
||||
# whether it can make a direct call instead of the indirect call.
|
||||
|
||||
# LLVM doesn't support instrumenting binaries that use SEH:
|
||||
# https://github.com/rust-lang/rust/issues/61002
|
||||
#
|
||||
# Things work fine with -Cpanic=abort though.
|
||||
ifdef IS_MSVC
|
||||
COMMON_FLAGS=-Cpanic=abort
|
||||
endif
|
||||
|
||||
all:
|
||||
# We don't compile `opaque` with either optimizations or instrumentation.
|
||||
# We don't compile `opaque` with either optimizations or instrumentation.
|
||||
$(RUSTC) $(COMMON_FLAGS) opaque.rs
|
||||
# Compile the test program with instrumentation
|
||||
mkdir -p "$(TMPDIR)"/prof_data_dir
|
||||
$(RUSTC) $(COMMON_FLAGS) interesting.rs \
|
||||
-Cprofile-generate="$(TMPDIR)"/prof_data_dir -O -Ccodegen-units=1
|
||||
$(RUSTC) $(COMMON_FLAGS) main.rs -Cprofile-generate="$(TMPDIR)"/prof_data_dir -O
|
||||
# The argument below generates to the expected branch weights
|
||||
$(call RUN,main) || exit 1
|
||||
"$(LLVM_BIN_DIR)"/llvm-profdata merge \
|
||||
-o "$(TMPDIR)"/prof_data_dir/merged.profdata \
|
||||
"$(TMPDIR)"/prof_data_dir
|
||||
$(RUSTC) $(COMMON_FLAGS) interesting.rs \
|
||||
-Cprofile-use="$(TMPDIR)"/prof_data_dir/merged.profdata -O \
|
||||
-Ccodegen-units=1 --emit=llvm-ir
|
||||
cat "$(TMPDIR)"/interesting.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt
|
|
@ -0,0 +1,16 @@
|
|||
CHECK: define void @call_a_bunch_of_functions({{.*}} {
|
||||
|
||||
# Make sure that indirect call promotion inserted a check against the most
|
||||
# frequently called function.
|
||||
CHECK: %{{.*}} = icmp eq void ()* %{{.*}}, @function_called_always
|
||||
|
||||
# Check that the call to `function_called_always` was inlined, so that we
|
||||
# directly call `opaque_f1` from the upstream crate.
|
||||
CHECK: call void @opaque_f1()
|
||||
|
||||
|
||||
# Same checks as above, repeated for the trait object case
|
||||
|
||||
CHECK: define void @call_a_bunch_of_trait_methods({{.*}}
|
||||
CHECK: %{{.*}} = icmp eq void ({}*)* %{{.*}}, {{.*}} @foo
|
||||
CHECK: tail call void @opaque_f2()
|
|
@ -0,0 +1,56 @@
|
|||
#![crate_name="interesting"]
|
||||
#![crate_type="rlib"]
|
||||
|
||||
extern crate opaque;
|
||||
|
||||
#[no_mangle]
|
||||
pub fn function_called_always() {
|
||||
opaque::opaque_f1();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn function_called_never() {
|
||||
opaque::opaque_f2();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn call_a_bunch_of_functions(fns: &[fn()]) {
|
||||
|
||||
// Indirect call promotion transforms the below into something like
|
||||
//
|
||||
// for f in fns {
|
||||
// if f == function_called_always {
|
||||
// function_called_always()
|
||||
// } else {
|
||||
// f();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// where `function_called_always` actually gets inlined too.
|
||||
|
||||
for f in fns {
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub trait Foo {
|
||||
fn foo(&self);
|
||||
}
|
||||
|
||||
impl Foo for u32 {
|
||||
|
||||
#[no_mangle]
|
||||
fn foo(&self) {
|
||||
opaque::opaque_f2();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn call_a_bunch_of_trait_methods(trait_objects: &[&dyn Foo]) {
|
||||
|
||||
// Same as above, just with vtables in between
|
||||
for x in trait_objects {
|
||||
x.foo();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
extern crate interesting;
|
||||
|
||||
fn main() {
|
||||
// function pointer case
|
||||
let fns: Vec<_> = std::iter::repeat(interesting::function_called_always as fn())
|
||||
.take(1000)
|
||||
.collect();
|
||||
interesting::call_a_bunch_of_functions(&fns[..]);
|
||||
|
||||
// Trait object case
|
||||
let trait_objects = vec![0u32; 1000];
|
||||
let trait_objects: Vec<_> = trait_objects.iter().map(|x| x as &dyn interesting::Foo).collect();
|
||||
interesting::call_a_bunch_of_trait_methods(&trait_objects[..]);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#![crate_name="opaque"]
|
||||
#![crate_type="rlib"]
|
||||
|
||||
#[no_mangle]
|
||||
pub fn opaque_f1() {}
|
||||
#[no_mangle]
|
||||
pub fn opaque_f2() {}
|
Loading…
Add table
Reference in a new issue