ldc/tests/PGO/functions.d

256 lines
9.9 KiB
D

// Test PGO for different kinds of functions
//
// The tests should not test function name mangling, therefore the functionname
// matching strings contain regexp wildcards.
// RUN: %ldc -c -output-ll -fprofile-instr-generate -of=%t.ll %s && FileCheck %s --check-prefix=PROFGEN < %t.ll
// RUN: %ldc -fprofile-instr-generate=%t.profraw -run %s \
// RUN: && %profdata merge %t.profraw -o %t.profdata \
// RUN: && %ldc -c -output-ll -of=%t2.ll -fprofile-instr-use=%t.profdata %s \
// RUN: && FileCheck %s -check-prefix=PROFUSE < %t2.ll
// PROFGEN-DAG: @[[SMPL:__(llvm_profile_counters|profc).*simplefunction[A-Za-z0-9]*]] ={{[A-Za-z ]*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[TMPL:__(llvm_profile_counters|profc).*templatefunc[A-Za-z0-9]*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[OUTR:__(llvm_profile_counters|profc).*outerfunc[A-Za-z0-9]*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[NEST:__(llvm_profile_counters|profc).*nestedfunc[A-Za-z0-9]*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[LMBD:__(llvm_profile_counters|profc).*testanonymous.*lambda.*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[KCTR:__(llvm_profile_counters|profc).*Klass.*__ctor.*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[KMTH:__(llvm_profile_counters|profc).*Klass.*stdmethod.*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[KDTR:__(llvm_profile_counters|profc).*Klass.*__dtor.*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[KSTC:__(llvm_profile_counters|profc).*Klass.*staticmethod.*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[SCTR:__(llvm_profile_counters|profc).*Strukt.*__ctor.*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[SMTH:__(llvm_profile_counters|profc).*Strukt.*stdmethod.*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[SDTR:__(llvm_profile_counters|profc).*Strukt.*__dtor.*]] ={{.*}} [2 x i64] zeroinitializer
// PROFGEN-DAG: @[[CNTR:__(llvm_profile_counters|profc).*contractprog.*]] ={{.*}} [5 x i64] zeroinitializer
// PROFGEN-NOT: @{{__llvm_profile_counters_.*fwddecl.*}}
// PROFGEN-NOT: @{{__profc.*fwddecl.*}}
// PROFGEN-LABEL: define {{.*}} @{{.*}}simplefunction{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}simplefunction{{.*}}(
// PROFGEN: store {{.*}} @[[SMPL]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[SMPL0:[0-9]+]]
void simplefunction(int i) {
// PROFGEN: store {{.*}} @[[SMPL]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[SMPL1:[0-9]+]]
if (i % 3) {}
}
// PROFGEN-LABEL: define {{.*}} @{{.*}}templatefunc{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}templatefunc{{.*}}(
// PROFGEN: store {{.*}} @[[TMPL]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[TMPL0:[0-9]+]]
void templatefunc(T)(T i) {
// PROFGEN: store {{.*}} @[[TMPL]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[TMPL1:[0-9]+]]
if (i % 3) {}
}
// The purpose of this function is to pin the location of the instantiation of
// templatefunc at a defined location in IR.
void call_templatefunc(int i) {
templatefunc!uint(i);
}
// PROFGEN-LABEL: define {{.*}} @{{.*}}outerfunc{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}outerfunc{{.*}}(
// PROFGEN: store {{.*}} @[[OUTR]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[OUTR0:[0-9]+]]
// PROFGEN: store {{.*}} @[[OUTR]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[OUTR1:[0-9]+]]
// PROFGEN-LABEL: define {{.*}} @{{.*}}nestedfunc{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}nestedfunc{{.*}}(
// PROFGEN: store {{.*}} @[[NEST]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[NEST0:[0-9]+]]
// PROFGEN: store {{.*}} @[[NEST]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[NEST1:[0-9]+]]
void outerfunc(int i) {
void nestedfunc(int i) {
if (!(i % 3)) {}
}
nestedfunc(i);
if (i % 3) {}
}
void takedelegate(int i, int delegate(int) fd) {
if (fd(i) % 3) {}
}
// PROFGEN-LABEL: define {{.*}} @{{.*}}testanonymous{{.*}}lambda{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}testanonymous{{.*}}lambda{{.*}}(
// PROFGEN: store {{.*}} @[[LMBD]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[LMBD0:[0-9]+]]
// PROFGEN: store {{.*}} @[[LMBD]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[LMBD1:[0-9]+]]
void testanonymous(int i) {
takedelegate(i, (i) { if (i % 5) {} return i+1;} );
}
class Klass {
int a;
// PROFGEN-LABEL: define {{.*}} @{{.*}}Klass{{.*}}__ctor{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}Klass{{.*}}__ctor{{.*}}(
// PROFGEN: store {{.*}} @[[KCTR]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[KCTR0:[0-9]+]]
// PROFGEN: store {{.*}} @[[KCTR]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[KCTR1:[0-9]+]]
this(int i) {
a = i;
if (a % 3) {}
}
// PROFGEN-LABEL: define {{.*}} @{{.*}}Klass{{.*}}__dtor{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}Klass{{.*}}__dtor{{.*}}(
// PROFGEN: store {{.*}} @[[KDTR]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[KDTR0:[0-9]+]]
// PROFGEN: store {{.*}} @[[KDTR]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[KDTR1:[0-9]+]]
~this() {
if (!(a % 3)) {}
}
// PROFGEN-LABEL: define {{.*}} @{{.*}}Klass{{.*}}stdmethod{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}Klass{{.*}}stdmethod{{.*}}(
// PROFGEN: store {{.*}} @[[KMTH]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[KMTH0:[0-9]+]]
// Explicitly test that the assert(this) branch is *not* profiled
// PROFUSE: br i1 %{{.*}}, label %assertPassed, label %assertFailed{{$}}
// PROFGEN: store {{.*}} @[[KMTH]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[KMTH1:[0-9]+]]
void stdmethod() {
if (a % 4) {}
}
// PROFGEN-LABEL: define {{.*}} @{{.*}}Klass{{.*}}staticmethod{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}Klass{{.*}}staticmethod{{.*}}(
// PROFGEN: store {{.*}} @[[KSTC]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[KSTC0:[0-9]+]]
// PROFGEN: store {{.*}} @[[KSTC]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[KSTC1:[0-9]+]]
static void staticmethod(int i) {
if (i % 2) {}
}
}
struct Strukt {
int a;
// PROFGEN-LABEL: define {{.*}} @{{.*}}Strukt{{.*}}__ctor{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}Strukt{{.*}}__ctor{{.*}}(
// PROFGEN: store {{.*}} @[[SCTR]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[SCTR0:[0-9]+]]
// PROFGEN: store {{.*}} @[[SCTR]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[SCTR1:[0-9]+]]
this(int i) {
a = i;
if (a % 3) {}
}
// PROFGEN-LABEL: define {{.*}} @{{.*}}Strukt{{.*}}stdmethod{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}Strukt{{.*}}stdmethod{{.*}}(
// PROFGEN: store {{.*}} @[[SMTH]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[SMTH0:[0-9]+]]
// Explicitly test that the assert(this) branch is *not* profiled
// PROFUSE: br i1 %{{.*}}, label %assertPassed, label %assertFailed{{$}}
// PROFGEN: store {{.*}} @[[SMTH]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[SMTH1:[0-9]+]]
void stdmethod() {
if (a % 4) {}
}
// PROFGEN-LABEL: define {{.*}} @{{.*}}Strukt{{.*}}__dtor{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}Strukt{{.*}}__dtor{{.*}}(
// PROFGEN: store {{.*}} @[[SDTR]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[SDTR0:[0-9]+]]
// PROFGEN: store {{.*}} @[[SDTR]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[SDTR1:[0-9]+]]
~this() {
if (!(a % 3)) {}
}
}
// PROFGEN-LABEL: define {{.*}} @{{.*}}contractprog{{.*}}(
// PROFUSE-LABEL: define {{.*}} @{{.*}}contractprog{{.*}}(
// PROFGEN: store {{.*}} @[[CNTR]], i64 0, i64 0
// PROFUSE-SAME: !prof ![[CNTR0:[0-9]+]]
void contractprog(int i)
in {
// PROFGEN: store {{.*}} @[[CNTR]], i64 0, i64 1
// PROFUSE: br {{.*}} !prof ![[CNTR1:[0-9]+]]
if (i < 3) {}
}
out {
if (i < 6) {}
}
body {
// PROFGEN: store {{.*}} @[[CNTR]], i64 0, i64 2
// PROFUSE: br {{.*}} !prof ![[CNTR2:[0-9]+]]
if (i % 2) {}
}
// Out label+body:
// PROFGEN: store {{.*}} @[[CNTR]], i64 0, i64 3
// PROFGEN: store {{.*}} @[[CNTR]], i64 0, i64 4
// PROFUSE: br {{.*}} !prof ![[CNTR4:[0-9]+]]
// Check that no code is generated for function declarations without definition.
// PROFGEN-NOT: define {{.*}} @fwddecl(
// PROFUSE-NOT: define {{.*}} @fwddecl(
extern (C) void fwddecl(int);
void main() {
foreach (int i; 0..10) {
simplefunction(i);
call_templatefunc(i);
outerfunc(i);
testanonymous(i);
auto k = new Klass(i);
k.stdmethod();
Klass.staticmethod(i);
auto s = Strukt(i);
s.stdmethod();
contractprog(i);
}
}
// PROFUSE-DAG: ![[SMPL0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[SMPL1]] = !{!"branch_weights", i32 7, i32 5}
// PROFUSE-DAG: ![[TMPL0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[TMPL1]] = !{!"branch_weights", i32 7, i32 5}
// PROFUSE-DAG: ![[OUTR0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[OUTR1]] = !{!"branch_weights", i32 7, i32 5}
// PROFUSE-DAG: ![[NEST0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[NEST1]] = !{!"branch_weights", i32 5, i32 7}
// PROFUSE-DAG: ![[LMBD0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[LMBD1]] = !{!"branch_weights", i32 9, i32 3}
// PROFUSE-DAG: ![[KCTR0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[KCTR1]] = !{!"branch_weights", i32 7, i32 5}
// PROFUSE-DAG: ![[KMTH0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[KMTH1]] = !{!"branch_weights", i32 8, i32 4}
// PROFUSE-DAG: ![[KDTR0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[KDTR1]] = !{!"branch_weights", i32 5, i32 7}
// PROFUSE-DAG: ![[KSTC0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[KSTC1]] = !{!"branch_weights", i32 6, i32 6}
// PROFUSE-DAG: ![[SCTR0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[SCTR1]] = !{!"branch_weights", i32 7, i32 5}
// PROFUSE-DAG: ![[SMTH0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[SMTH1]] = !{!"branch_weights", i32 8, i32 4}
// PROFUSE-DAG: ![[SDTR0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[SDTR1]] = !{!"branch_weights", i32 5, i32 7}
// PROFUSE-DAG: ![[CNTR0]] = !{!"function_entry_count", i64 10}
// PROFUSE-DAG: ![[CNTR1]] = !{!"branch_weights", i32 4, i32 8}
// PROFUSE-DAG: ![[CNTR2]] = !{!"branch_weights", i32 6, i32 6}
// PROFUSE-DAG: ![[CNTR4]] = !{!"branch_weights", i32 7, i32 5}