// 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}