diff options
Diffstat (limited to 'test/Profile')
30 files changed, 1665 insertions, 0 deletions
diff --git a/test/Profile/Inputs/c-attributes.proftext b/test/Profile/Inputs/c-attributes.proftext new file mode 100644 index 0000000000000..e4d4694a8d922 --- /dev/null +++ b/test/Profile/Inputs/c-attributes.proftext @@ -0,0 +1,34 @@ +hot_100_percent +2 +2 +100000 +4999950000 + +hot_40_percent +2 +2 +40000 +799980000 + +normal_func +2 +2 +20000 +199990000 + +cold_func +2 +2 +500 +124750 + +main +219169028 +6 +1 +0 +100000 +40000 +20000 +500 + diff --git a/test/Profile/Inputs/c-captured.proftext b/test/Profile/Inputs/c-captured.proftext new file mode 100644 index 0000000000000..c1baefc894b5f --- /dev/null +++ b/test/Profile/Inputs/c-captured.proftext @@ -0,0 +1,25 @@ +c-captured.c:__captured_stmt +10 +2 +1 +1 + +c-captured.c:__captured_stmt1 +266 +3 +1 +10 +1 + +main +0 +1 +1 + +debug_captured +650 +3 +1 +1 +1 + diff --git a/test/Profile/Inputs/c-counter-overflows.proftext b/test/Profile/Inputs/c-counter-overflows.proftext new file mode 100644 index 0000000000000..5a3633ecfc78c --- /dev/null +++ b/test/Profile/Inputs/c-counter-overflows.proftext @@ -0,0 +1,12 @@ +main +285734896137 +8 +1 +68719476720 +64424509425 +68719476720 +21474836475 +21474836475 +21474836475 +4294967295 + diff --git a/test/Profile/Inputs/c-general.proftext b/test/Profile/Inputs/c-general.proftext new file mode 100644 index 0000000000000..19e5bd3db442b --- /dev/null +++ b/test/Profile/Inputs/c-general.proftext @@ -0,0 +1,157 @@ +simple_loops +16515 +4 +1 +100 +100 +75 + +conditionals +74917022372782735 +11 +1 +100 +50 +50 +33 +33 +16 +99 +100 +99 +100 + +early_exits +44128811889290 +9 +1 +0 +51 +1 +25 +1 +25 +1 +0 + +jumps +2016037664281362839 +22 +1 +1 +0 +1 +0 +0 +1 +0 +1 +2 +3 +2 +0 +3 +0 +1 +1 +1 +10 +0 +10 +9 + +switches +2745195701975551402 +19 +1 +1 +1 +15 +7 +1 +0 +2 +2 +3 +3 +4 +4 +0 +4 +4 +5 +1 +0 + +big_switch +10218718452081869619 +17 +1 +32 +32 +1 +0 +1 +1 +11 +11 +1 +1 +15 +15 +1 +1 +2 +2 + +boolean_operators +291222909838 +8 +1 +100 +34 +66 +17 +34 +33 +50 + +boolop_loops +9760565944591 +9 +1 +50 +51 +50 +26 +50 +51 +50 +26 + +conditional_operator +848 +3 +1 +0 +1 + +do_fallthrough +16586 +4 +1 +10 +2 +8 + +main +0 +1 +1 + +c-general.c:static_func +4 +2 +1 +10 + diff --git a/test/Profile/Inputs/c-outdated-data.proftext b/test/Profile/Inputs/c-outdated-data.proftext new file mode 100644 index 0000000000000..d57a6e9d06916 --- /dev/null +++ b/test/Profile/Inputs/c-outdated-data.proftext @@ -0,0 +1,12 @@ +no_usable_data +650 +3 +1 +0 +0 + +main +0 +1 +1 + diff --git a/test/Profile/Inputs/c-unprofiled-blocks.proftext b/test/Profile/Inputs/c-unprofiled-blocks.proftext new file mode 100644 index 0000000000000..87b48e13fbbe7 --- /dev/null +++ b/test/Profile/Inputs/c-unprofiled-blocks.proftext @@ -0,0 +1,32 @@ +never_called +44257542701577 +9 +0 +0 +0 +0 +0 +0 +0 +0 +0 + +main +1 +1 +1 + +dead_code +2859007309808137 +10 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 + diff --git a/test/Profile/Inputs/c-unprofiled.proftext b/test/Profile/Inputs/c-unprofiled.proftext new file mode 100644 index 0000000000000..d2ef7ae301d86 --- /dev/null +++ b/test/Profile/Inputs/c-unprofiled.proftext @@ -0,0 +1,10 @@ +function_in_header +10 +2 +1 +0 + +main +0 +1 +1 diff --git a/test/Profile/Inputs/cxx-class.proftext b/test/Profile/Inputs/cxx-class.proftext new file mode 100644 index 0000000000000..b4645edf93335 --- /dev/null +++ b/test/Profile/Inputs/cxx-class.proftext @@ -0,0 +1,41 @@ +_Z14simple_wrapperv +4 +2 +1 +100 + +main +0 +1 +1 + +_ZN6SimpleD1Ev +10 +2 +0 +0 + +_ZN6SimpleD2Ev +10 +2 +100 +99 + +_ZN6Simple6methodEv +10 +2 +100 +99 + +_ZN6SimpleC1Ei +10 +2 +0 +0 + +_ZN6SimpleC2Ei +10 +2 +100 +99 + diff --git a/test/Profile/Inputs/cxx-lambda.proftext b/test/Profile/Inputs/cxx-lambda.proftext new file mode 100644 index 0000000000000..36646b5ab37c1 --- /dev/null +++ b/test/Profile/Inputs/cxx-lambda.proftext @@ -0,0 +1,20 @@ +cxx-lambda.cpp:_ZZ7lambdasvENK3$_0clEi +654 +3 +10 +9 +9 + +main +0 +1 +1 + +_Z7lambdasv +41226 +4 +1 +1 +10 +1 + diff --git a/test/Profile/Inputs/cxx-templates.proftext b/test/Profile/Inputs/cxx-templates.proftext new file mode 100644 index 0000000000000..5ea840038d595 --- /dev/null +++ b/test/Profile/Inputs/cxx-templates.proftext @@ -0,0 +1,17 @@ +main +0 +1 +1 + +_Z4loopILj0EEvv +4 +2 +1 +0 + +_Z4loopILj100EEvv +4 +2 +1 +100 + diff --git a/test/Profile/Inputs/cxx-throws.proftext b/test/Profile/Inputs/cxx-throws.proftext new file mode 100644 index 0000000000000..4016eca2ac866 --- /dev/null +++ b/test/Profile/Inputs/cxx-throws.proftext @@ -0,0 +1,18 @@ +_Z6throwsv +18359008150154 +9 +1 +100 +100 +66 +33 +17 +50 +33 +100 + +main +0 +1 +1 + diff --git a/test/Profile/Inputs/objc-general.proftext b/test/Profile/Inputs/objc-general.proftext new file mode 100644 index 0000000000000..8d6771f9b324f --- /dev/null +++ b/test/Profile/Inputs/objc-general.proftext @@ -0,0 +1,17 @@ +objc-general.m:__13+[A foreach:]_block_invoke +10 +2 +2 +1 + +objc-general.m:+[A foreach:] +6 +2 +1 +2 + +main +0 +1 +1 + diff --git a/test/Profile/Inputs/profiled_header.h b/test/Profile/Inputs/profiled_header.h new file mode 100644 index 0000000000000..fa649d4b59954 --- /dev/null +++ b/test/Profile/Inputs/profiled_header.h @@ -0,0 +1,3 @@ +void function_in_header(int i) { + if (i) {} +} diff --git a/test/Profile/README b/test/Profile/README new file mode 100644 index 0000000000000..3b66765711f21 --- /dev/null +++ b/test/Profile/README @@ -0,0 +1,16 @@ +These are tests for instrumentation based profiling. This specifically means +the -fprofile-instr-generate and -fprofile-instr-use driver flags. + +Tests in this directory should usually test both: + + - the generation of instrumentation (-fprofile-instr-generate), and + - the use of profile data from instrumented runs (-fprofile-instr-use). + +In order to test -fprofile-instr-use without actually running an instrumented +program, .profdata files are checked into Inputs/. + +The input source files must include a main function such that building with +-fprofile-instr-generate and running the resulting program generates the same +.profdata file that is consumed by the tests for -fprofile-instr-use. Even +tests that only check -fprofile-instr-use should include such a main function, +so that profile data can be regenerated as the .profdata file format evolves. diff --git a/test/Profile/c-attributes.c b/test/Profile/c-attributes.c new file mode 100644 index 0000000000000..2dcc180624cef --- /dev/null +++ b/test/Profile/c-attributes.c @@ -0,0 +1,48 @@ +// Test that instrumentation based profiling sets function attributes correctly. + +// RUN: llvm-profdata merge %S/Inputs/c-attributes.proftext -o %t.profdata +// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-instr-use=%t.profdata | FileCheck %s + +extern int atoi(const char *); + +// CHECK: hot_100_percent(i32{{.*}}%i) [[HOT:#[0-9]+]] +void hot_100_percent(int i) { + while (i > 0) + i--; +} + +// CHECK: hot_40_percent(i32{{.*}}%i) [[HOT]] +void hot_40_percent(int i) { + while (i > 0) + i--; +} + +// CHECK: normal_func(i32{{.*}}%i) [[NORMAL:#[0-9]+]] +void normal_func(int i) { + while (i > 0) + i--; +} + +// CHECK: cold_func(i32{{.*}}%i) [[COLD:#[0-9]+]] +void cold_func(int i) { + while (i > 0) + i--; +} + +// CHECK: attributes [[HOT]] = { inlinehint nounwind {{.*}} } +// CHECK: attributes [[NORMAL]] = { nounwind {{.*}} } +// CHECK: attributes [[COLD]] = { cold nounwind {{.*}} } + +int main(int argc, const char *argv[]) { + int max = atoi(argv[1]); + int i; + for (i = 0; i < max; i++) + hot_100_percent(i); + for (i = 0; i < max * 4 / 10; i++) + hot_40_percent(i); + for (i = 0; i < max * 2 / 10; i++) + normal_func(i); + for (i = 0; i < max / 200; i++) + cold_func(i); + return 0; +} diff --git a/test/Profile/c-captured.c b/test/Profile/c-captured.c new file mode 100644 index 0000000000000..ef7fb318508db --- /dev/null +++ b/test/Profile/c-captured.c @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-captured.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck -check-prefix=PGOGEN -check-prefix=PGOALL %s + +// RUN: llvm-profdata merge %S/Inputs/c-captured.proftext -o %t.profdata +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-captured.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE -check-prefix=PGOALL %s + +// PGOGEN: @[[DCC:__llvm_profile_counters_debug_captured]] = hidden global [3 x i64] zeroinitializer +// PGOGEN: @[[CSC:__llvm_profile_counters___captured_stmt]] = internal global [2 x i64] zeroinitializer +// PGOGEN: @[[C1C:__llvm_profile_counters___captured_stmt1]] = internal global [3 x i64] zeroinitializer + +// PGOALL-LABEL: define void @debug_captured() +// PGOGEN: store {{.*}} @[[DCC]], i64 0, i64 0 +void debug_captured() { + int x = 10; + + // Check both debug_captured counters, so we can do this all in one pass + // PGOGEN: store {{.*}} @[[DCC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[DC1:[0-9]+]] + // PGOGEN: store {{.*}} @[[DCC]], i64 0, i64 2 + // PGOUSE: br {{.*}} !prof ![[DC2:[0-9]+]] + // PGOALL: ret + + // PGOALL-LABEL: define internal void @__captured_stmt( + // PGOGEN: store {{.*}} @[[CSC]], i64 0, i64 0 + #pragma clang __debug captured + { + // PGOGEN: store {{.*}} @[[CSC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[CS1:[0-9]+]] + if (x) {} + // PGOALL: ret + } + + if (x) {} // This is DC1. Checked above. + + // PGOALL-LABEL: define internal void @__captured_stmt1( + // PGOGEN: store {{.*}} @[[C1C]], i64 0, i64 0 + #pragma clang __debug captured + { + // PGOGEN: store {{.*}} @[[C1C]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[C11:[0-9]+]] + for (int i = 0; i < x; ++i) {} + // PGOGEN: store {{.*}} @[[C1C]], i64 0, i64 2 + // PGOUSE: br {{.*}} !prof ![[C12:[0-9]+]] + if (x) {} + // PGOALL: ret + } + + if (x) {} // This is DC2. Checked above. +} + +// PGOUSE-DAG: ![[DC1]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// PGOUSE-DAG: ![[DC2]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// PGOUSE-DAG: ![[CS1]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// PGOUSE-DAG: ![[C11]] = metadata !{metadata !"branch_weights", i32 11, i32 2} +// PGOUSE-DAG: ![[C12]] = metadata !{metadata !"branch_weights", i32 2, i32 1} + +int main(int argc, const char *argv[]) { + debug_captured(); + return 0; +} diff --git a/test/Profile/c-counter-overflows.c b/test/Profile/c-counter-overflows.c new file mode 100644 index 0000000000000..f6f8f73fd9494 --- /dev/null +++ b/test/Profile/c-counter-overflows.c @@ -0,0 +1,49 @@ +// Test that big branch weights get scaled down to 32-bits, rather than just +// truncated. + +// RUN: llvm-profdata merge %S/Inputs/c-counter-overflows.proftext -o %t.profdata +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-counter-overflows.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck %s + +typedef unsigned long long uint64_t; + +int main(int argc, const char *argv[]) { + // Need counts higher than 32-bits. + // CHECK: br {{.*}} !prof ![[FOR:[0-9]+]] + // max = 0xffffffff0 + // scale = 0xffffffff0 / 0xffffffff + 1 = 17 + // loop-body: 0xffffffff0 / 17 + 1 = 0xf0f0f0f0 + 1 = 4042322161 => -252645135 + // loop-exit: 0x000000001 / 17 + 1 = 0x00000000 + 1 = 1 => 1 + for (uint64_t I = 0; I < 0xffffffff0; ++I) { + // max = 0xffffffff * 15 = 0xefffffff1 + // scale = 0xefffffff1 / 0xffffffff + 1 = 16 + // CHECK: br {{.*}} !prof ![[IF:[0-9]+]] + if (I & 0xf) { + // 0xefffffff1 / 16 + 1 = 0xefffffff + 1 = 4026531840 => -268435456 + } else { + // 0x0ffffffff / 16 + 1 = 0x0fffffff + 1 = 268435456 => 268435456 + } + + // max = 0xffffffff * 5 = 0x4fffffffb + // scale = 0x4fffffffb / 0xffffffff + 1 = 6 + // CHECK: ], !prof ![[SWITCH:[0-9]+]] + switch ((I & 0xf) / 5) { + case 0: + // 0x4fffffffb / 6 = 0xd5555554 + 1 = 3579139413 => -715827883 + break; + case 1: + // 0x4fffffffb / 6 = 0xd5555554 + 1 = 3579139413 => -715827883 + break; + case 2: + // 0x4fffffffb / 6 = 0xd5555554 + 1 = 3579139413 => -715827883 + break; + default: + // 0x0ffffffff / 6 = 0x2aaaaaaa + 1 = 715827883 => 715827883 + break; + } + } + return 0; +} + +// CHECK-DAG: ![[FOR]] = metadata !{metadata !"branch_weights", i32 -252645135, i32 1} +// CHECK-DAG: ![[IF]] = metadata !{metadata !"branch_weights", i32 -268435456, i32 268435456} +// CHECK-DAG: ![[SWITCH]] = metadata !{metadata !"branch_weights", i32 715827883, i32 -715827883, i32 -715827883, i32 -715827883} diff --git a/test/Profile/c-general.c b/test/Profile/c-general.c new file mode 100644 index 0000000000000..442fdd336c7cc --- /dev/null +++ b/test/Profile/c-general.c @@ -0,0 +1,544 @@ +// Test instrumentation of general constructs in C. + +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck -check-prefix=PGOGEN %s + +// RUN: llvm-profdata merge %S/Inputs/c-general.proftext -o %t.profdata +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-general.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE %s + +// PGOGEN: @[[SLC:__llvm_profile_counters_simple_loops]] = hidden global [4 x i64] zeroinitializer +// PGOGEN: @[[IFC:__llvm_profile_counters_conditionals]] = hidden global [11 x i64] zeroinitializer +// PGOGEN: @[[EEC:__llvm_profile_counters_early_exits]] = hidden global [9 x i64] zeroinitializer +// PGOGEN: @[[JMC:__llvm_profile_counters_jumps]] = hidden global [22 x i64] zeroinitializer +// PGOGEN: @[[SWC:__llvm_profile_counters_switches]] = hidden global [19 x i64] zeroinitializer +// PGOGEN: @[[BSC:__llvm_profile_counters_big_switch]] = hidden global [17 x i64] zeroinitializer +// PGOGEN: @[[BOC:__llvm_profile_counters_boolean_operators]] = hidden global [8 x i64] zeroinitializer +// PGOGEN: @[[BLC:__llvm_profile_counters_boolop_loops]] = hidden global [9 x i64] zeroinitializer +// PGOGEN: @[[COC:__llvm_profile_counters_conditional_operator]] = hidden global [3 x i64] zeroinitializer +// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = hidden global [1 x i64] zeroinitializer +// PGOGEN: @[[STC:__llvm_profile_counters_static_func]] = internal global [2 x i64] zeroinitializer + +// PGOGEN-LABEL: @simple_loops() +// PGOUSE-LABEL: @simple_loops() +// PGOGEN: store {{.*}} @[[SLC]], i64 0, i64 0 +void simple_loops() { + int i; + // PGOGEN: store {{.*}} @[[SLC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[SL1:[0-9]+]] + for (i = 0; i < 100; ++i) { + } + // PGOGEN: store {{.*}} @[[SLC]], i64 0, i64 2 + // PGOUSE: br {{.*}} !prof ![[SL2:[0-9]+]] + while (i > 0) + i--; + // PGOGEN: store {{.*}} @[[SLC]], i64 0, i64 3 + // PGOUSE: br {{.*}} !prof ![[SL3:[0-9]+]] + do {} while (i++ < 75); + + // PGOGEN-NOT: store {{.*}} @[[SLC]], + // PGOUSE-NOT: br {{.*}} !prof ![0-9]+ +} + +// PGOGEN-LABEL: @conditionals() +// PGOUSE-LABEL: @conditionals() +// PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 0 +void conditionals() { + // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[IF1:[0-9]+]] + for (int i = 0; i < 100; ++i) { + // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 2 + // PGOUSE: br {{.*}} !prof ![[IF2:[0-9]+]] + if (i % 2) { + // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 3 + // PGOUSE: br {{.*}} !prof ![[IF3:[0-9]+]] + if (i) {} + // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 4 + // PGOUSE: br {{.*}} !prof ![[IF4:[0-9]+]] + } else if (i % 3) { + // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 5 + // PGOUSE: br {{.*}} !prof ![[IF5:[0-9]+]] + if (i) {} + } else { + // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 6 + // PGOUSE: br {{.*}} !prof ![[IF6:[0-9]+]] + if (i) {} + } + + // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 8 + // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 7 + // PGOUSE: br {{.*}} !prof ![[IF7:[0-9]+]] + if (1 && i) {} + // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 10 + // PGOGEN: store {{.*}} @[[IFC]], i64 0, i64 9 + // PGOUSE: br {{.*}} !prof ![[IF8:[0-9]+]] + if (0 || i) {} + } + + // PGOGEN-NOT: store {{.*}} @[[IFC]], + // PGOUSE-NOT: br {{.*}} !prof ![0-9]+ +} + +// PGOGEN-LABEL: @early_exits() +// PGOUSE-LABEL: @early_exits() +// PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 0 +void early_exits() { + int i = 0; + + // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[EE1:[0-9]+]] + if (i) {} + + // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 2 + // PGOUSE: br {{.*}} !prof ![[EE2:[0-9]+]] + while (i < 100) { + i++; + // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 3 + // PGOUSE: br {{.*}} !prof ![[EE3:[0-9]+]] + if (i > 50) + break; + // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 4 + // PGOUSE: br {{.*}} !prof ![[EE4:[0-9]+]] + if (i % 2) + continue; + } + + // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 5 + // PGOUSE: br {{.*}} !prof ![[EE5:[0-9]+]] + if (i) {} + + // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 6 + do { + // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 7 + // PGOUSE: br {{.*}} !prof ![[EE6:[0-9]+]] + if (i > 75) + return; + else + i++; + // PGOUSE: br {{.*}} !prof ![[EE7:[0-9]+]] + } while (i < 100); + + // PGOGEN: store {{.*}} @[[EEC]], i64 0, i64 8 + // Never reached -> no weights + if (i) {} + + // PGOGEN-NOT: store {{.*}} @[[EEC]], + // PGOUSE-NOT: br {{.*}} !prof ![0-9]+ +} + +// PGOGEN-LABEL: @jumps() +// PGOUSE-LABEL: @jumps() +// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 0 +void jumps() { + int i; + + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[JM1:[0-9]+]] + for (i = 0; i < 2; ++i) { + goto outofloop; + // Never reached -> no weights + if (i) {} + } +// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 3 +outofloop: + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 4 + // PGOUSE: br {{.*}} !prof ![[JM2:[0-9]+]] + if (i) {} + + goto loop1; + + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 5 + // PGOUSE: br {{.*}} !prof ![[JM3:[0-9]+]] + while (i) { + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 6 + loop1: + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 7 + // PGOUSE: br {{.*}} !prof ![[JM4:[0-9]+]] + if (i) {} + } + + goto loop2; +// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 8 +first: +// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 9 +second: +// PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 10 +third: + i++; + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 11 + // PGOUSE: br {{.*}} !prof ![[JM5:[0-9]+]] + if (i < 3) + goto loop2; + + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 12 + // PGOUSE: br {{.*}} !prof ![[JM6:[0-9]+]] + while (i < 3) { + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 13 + loop2: + // PGOUSE: switch {{.*}} [ + // PGOUSE: ], !prof ![[JM7:[0-9]+]] + switch (i) { + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 15 + case 0: + goto first; + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 16 + case 1: + goto second; + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 17 + case 2: + goto third; + } + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 14 + } + + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 18 + // PGOUSE: br {{.*}} !prof ![[JM8:[0-9]+]] + for (i = 0; i < 10; ++i) { + goto withinloop; + // never reached -> no weights + if (i) {} + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 20 + withinloop: + // PGOGEN: store {{.*}} @[[JMC]], i64 0, i64 21 + // PGOUSE: br {{.*}} !prof ![[JM9:[0-9]+]] + if (i) {} + } + + // PGOGEN-NOT: store {{.*}} @[[JMC]], + // PGOUSE-NOT: br {{.*}} !prof ![0-9]+ +} + +// PGOGEN-LABEL: @switches() +// PGOUSE-LABEL: @switches() +// PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 0 +void switches() { + static int weights[] = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5}; + + // No cases -> no weights + switch (weights[0]) { + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 2 + default: + break; + } + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 1 + + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 3 + // PGOUSE: br {{.*}} !prof ![[SW1:[0-9]+]] + for (int i = 0, len = sizeof(weights) / sizeof(weights[0]); i < len; ++i) { + // PGOUSE: switch {{.*}} [ + // PGOUSE: ], !prof ![[SW2:[0-9]+]] + switch (i[weights]) { + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 5 + case 1: + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 6 + // PGOUSE: br {{.*}} !prof ![[SW3:[0-9]+]] + if (i) {} + // fallthrough + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 7 + case 2: + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 8 + // PGOUSE: br {{.*}} !prof ![[SW4:[0-9]+]] + if (i) {} + break; + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 9 + case 3: + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 10 + // PGOUSE: br {{.*}} !prof ![[SW5:[0-9]+]] + if (i) {} + continue; + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 11 + case 4: + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 12 + // PGOUSE: br {{.*}} !prof ![[SW6:[0-9]+]] + if (i) {} + // PGOUSE: switch {{.*}} [ + // PGOUSE: ], !prof ![[SW7:[0-9]+]] + switch (i) { + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 14 + case 6 ... 9: + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 15 + // PGOUSE: br {{.*}} !prof ![[SW8:[0-9]+]] + if (i) {} + continue; + } + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 13 + + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 16 + default: + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 17 + // PGOUSE: br {{.*}} !prof ![[SW9:[0-9]+]] + if (i == len - 1) + return; + } + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 4 + } + + // PGOGEN: store {{.*}} @[[SWC]], i64 0, i64 18 + // Never reached -> no weights + if (weights[0]) {} + + // PGOGEN-NOT: store {{.*}} @[[SWC]], + // PGOUSE-NOT: br {{.*}} !prof ![0-9]+ +} + +// PGOGEN-LABEL: @big_switch() +// PGOUSE-LABEL: @big_switch() +// PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 0 +void big_switch() { + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[BS1:[0-9]+]] + for (int i = 0; i < 32; ++i) { + // PGOUSE: switch {{.*}} [ + // PGOUSE: ], !prof ![[BS2:[0-9]+]] + switch (1 << i) { + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 3 + case (1 << 0): + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 4 + // PGOUSE: br {{.*}} !prof ![[BS3:[0-9]+]] + if (i) {} + // fallthrough + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 5 + case (1 << 1): + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 6 + // PGOUSE: br {{.*}} !prof ![[BS4:[0-9]+]] + if (i) {} + break; + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 7 + case (1 << 2) ... (1 << 12): + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 8 + // PGOUSE: br {{.*}} !prof ![[BS5:[0-9]+]] + if (i) {} + break; + // The branch for the large case range above appears after the case body + // PGOUSE: br {{.*}} !prof ![[BS6:[0-9]+]] + + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 9 + case (1 << 13): + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 10 + // PGOUSE: br {{.*}} !prof ![[BS7:[0-9]+]] + if (i) {} + break; + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 11 + case (1 << 14) ... (1 << 28): + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 12 + // PGOUSE: br {{.*}} !prof ![[BS8:[0-9]+]] + if (i) {} + break; + // The branch for the large case range above appears after the case body + // PGOUSE: br {{.*}} !prof ![[BS9:[0-9]+]] + + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 13 + case (1 << 29) ... ((1 << 29) + 1): + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 14 + // PGOUSE: br {{.*}} !prof ![[BS10:[0-9]+]] + if (i) {} + break; + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 15 + default: + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 16 + // PGOUSE: br {{.*}} !prof ![[BS11:[0-9]+]] + if (i) {} + break; + } + // PGOGEN: store {{.*}} @[[BSC]], i64 0, i64 2 + } + + // PGOGEN-NOT: store {{.*}} @[[BSC]], + // PGOUSE-NOT: br {{.*}} !prof ![0-9]+ + // PGOUSE: ret void +} + +// PGOGEN-LABEL: @boolean_operators() +// PGOUSE-LABEL: @boolean_operators() +// PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 0 +void boolean_operators() { + int v; + // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[BO1:[0-9]+]] + for (int i = 0; i < 100; ++i) { + // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 2 + // PGOUSE: br {{.*}} !prof ![[BO2:[0-9]+]] + v = i % 3 || i; + + // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 3 + // PGOUSE: br {{.*}} !prof ![[BO3:[0-9]+]] + v = i % 3 && i; + + // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 5 + // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 4 + // PGOUSE: br {{.*}} !prof ![[BO4:[0-9]+]] + // PGOUSE: br {{.*}} !prof ![[BO5:[0-9]+]] + v = i % 3 || i % 2 || i; + + // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 7 + // PGOGEN: store {{.*}} @[[BOC]], i64 0, i64 6 + // PGOUSE: br {{.*}} !prof ![[BO6:[0-9]+]] + // PGOUSE: br {{.*}} !prof ![[BO7:[0-9]+]] + v = i % 2 && i % 3 && i; + } + + // PGOGEN-NOT: store {{.*}} @[[BOC]], + // PGOUSE-NOT: br {{.*}} !prof ![0-9]+ +} + +// PGOGEN-LABEL: @boolop_loops() +// PGOUSE-LABEL: @boolop_loops() +// PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 0 +void boolop_loops() { + int i = 100; + + // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 2 + // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[BL1:[0-9]+]] + // PGOUSE: br {{.*}} !prof ![[BL2:[0-9]+]] + while (i && i > 50) + i--; + + // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 4 + // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 3 + // PGOUSE: br {{.*}} !prof ![[BL3:[0-9]+]] + // PGOUSE: br {{.*}} !prof ![[BL4:[0-9]+]] + while ((i % 2) || (i > 0)) + i--; + + // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 6 + // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 5 + // PGOUSE: br {{.*}} !prof ![[BL5:[0-9]+]] + // PGOUSE: br {{.*}} !prof ![[BL6:[0-9]+]] + for (i = 100; i && i > 50; --i); + + // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 8 + // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 7 + // PGOUSE: br {{.*}} !prof ![[BL7:[0-9]+]] + // PGOUSE: br {{.*}} !prof ![[BL8:[0-9]+]] + for (; (i % 2) || (i > 0); --i); + + // PGOGEN-NOT: store {{.*}} @[[BLC]], + // PGOUSE-NOT: br {{.*}} !prof ![0-9]+ +} + +// PGOGEN-LABEL: @conditional_operator() +// PGOUSE-LABEL: @conditional_operator() +// PGOGEN: store {{.*}} @[[COC]], i64 0, i64 0 +void conditional_operator() { + int i = 100; + + // PGOGEN: store {{.*}} @[[COC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[CO1:[0-9]+]] + int j = i < 50 ? i : 1; + + // PGOGEN: store {{.*}} @[[COC]], i64 0, i64 2 + // PGOUSE: br {{.*}} !prof ![[CO2:[0-9]+]] + int k = i ?: 0; + + // PGOGEN-NOT: store {{.*}} @[[COC]], + // PGOUSE-NOT: br {{.*}} !prof ![0-9]+ +} + +void do_fallthrough() { + for (int i = 0; i < 10; ++i) { + int j = 0; + do { + // The number of exits out of this do-loop via the break statement + // exceeds the counter value for the loop (which does not include the + // fallthrough count). Make sure that does not violate any assertions. + if (i < 8) break; + j++; + } while (j < 2); + } +} + +// PGOGEN-LABEL: @static_func() +// PGOUSE-LABEL: @static_func() +// PGOGEN: store {{.*}} @[[STC]], i64 0, i64 0 +static void static_func() { + // PGOGEN: store {{.*}} @[[STC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[ST1:[0-9]+]] + for (int i = 0; i < 10; ++i) { + } +} + +// PGOUSE-DAG: ![[SL1]] = metadata !{metadata !"branch_weights", i32 101, i32 2} +// PGOUSE-DAG: ![[SL2]] = metadata !{metadata !"branch_weights", i32 101, i32 2} +// PGOUSE-DAG: ![[SL3]] = metadata !{metadata !"branch_weights", i32 76, i32 2} + +// PGOUSE-DAG: ![[EE1]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// PGOUSE-DAG: ![[EE2]] = metadata !{metadata !"branch_weights", i32 52, i32 1} +// PGOUSE-DAG: ![[EE3]] = metadata !{metadata !"branch_weights", i32 2, i32 51} +// PGOUSE-DAG: ![[EE4]] = metadata !{metadata !"branch_weights", i32 26, i32 26} +// PGOUSE-DAG: ![[EE5]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// PGOUSE-DAG: ![[EE6]] = metadata !{metadata !"branch_weights", i32 2, i32 26} +// PGOUSE-DAG: ![[EE7]] = metadata !{metadata !"branch_weights", i32 26, i32 1} + +// PGOUSE-DAG: ![[IF1]] = metadata !{metadata !"branch_weights", i32 101, i32 2} +// PGOUSE-DAG: ![[IF2]] = metadata !{metadata !"branch_weights", i32 51, i32 51} +// PGOUSE-DAG: ![[IF3]] = metadata !{metadata !"branch_weights", i32 51, i32 1} +// PGOUSE-DAG: ![[IF4]] = metadata !{metadata !"branch_weights", i32 34, i32 18} +// PGOUSE-DAG: ![[IF5]] = metadata !{metadata !"branch_weights", i32 34, i32 1} +// PGOUSE-DAG: ![[IF6]] = metadata !{metadata !"branch_weights", i32 17, i32 2} +// PGOUSE-DAG: ![[IF7]] = metadata !{metadata !"branch_weights", i32 100, i32 2} +// PGOUSE-DAG: ![[IF8]] = metadata !{metadata !"branch_weights", i32 100, i32 2} + +// PGOUSE-DAG: ![[JM1]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// PGOUSE-DAG: ![[JM2]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// PGOUSE-DAG: ![[JM3]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// PGOUSE-DAG: ![[JM4]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// PGOUSE-DAG: ![[JM5]] = metadata !{metadata !"branch_weights", i32 3, i32 2} +// PGOUSE-DAG: ![[JM6]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// PGOUSE-DAG: ![[JM7]] = metadata !{metadata !"branch_weights", i32 1, i32 2, i32 2, i32 2} +// PGOUSE-DAG: ![[JM8]] = metadata !{metadata !"branch_weights", i32 11, i32 2} +// PGOUSE-DAG: ![[JM9]] = metadata !{metadata !"branch_weights", i32 10, i32 2} + +// PGOUSE-DAG: ![[SW1]] = metadata !{metadata !"branch_weights", i32 16, i32 1} +// PGOUSE-DAG: ![[SW2]] = metadata !{metadata !"branch_weights", i32 6, i32 2, i32 3, i32 4, i32 5} +// PGOUSE-DAG: ![[SW3]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// PGOUSE-DAG: ![[SW4]] = metadata !{metadata !"branch_weights", i32 3, i32 2} +// PGOUSE-DAG: ![[SW5]] = metadata !{metadata !"branch_weights", i32 4, i32 1} +// PGOUSE-DAG: ![[SW6]] = metadata !{metadata !"branch_weights", i32 5, i32 1} +// PGOUSE-DAG: ![[SW7]] = metadata !{metadata !"branch_weights", i32 1, i32 2, i32 2, i32 2, i32 2} +// PGOUSE-DAG: ![[SW8]] = metadata !{metadata !"branch_weights", i32 5, i32 1} +// PGOUSE-DAG: ![[SW9]] = metadata !{metadata !"branch_weights", i32 2, i32 5} + +// PGOUSE-DAG: ![[BS1]] = metadata !{metadata !"branch_weights", i32 33, i32 2} +// PGOUSE-DAG: ![[BS2]] = metadata !{metadata !"branch_weights", i32 29, i32 2, i32 2, i32 2, i32 2, i32 1} +// PGOUSE-DAG: ![[BS3]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// PGOUSE-DAG: ![[BS4]] = metadata !{metadata !"branch_weights", i32 2, i32 2} +// PGOUSE-DAG: ![[BS5]] = metadata !{metadata !"branch_weights", i32 12, i32 1} +// PGOUSE-DAG: ![[BS6]] = metadata !{metadata !"branch_weights", i32 12, i32 3} +// PGOUSE-DAG: ![[BS7]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// PGOUSE-DAG: ![[BS8]] = metadata !{metadata !"branch_weights", i32 16, i32 1} +// PGOUSE-DAG: ![[BS9]] = metadata !{metadata !"branch_weights", i32 16, i32 14} +// PGOUSE-DAG: ![[BS10]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// PGOUSE-DAG: ![[BS11]] = metadata !{metadata !"branch_weights", i32 3, i32 1} + +// PGOUSE-DAG: ![[BO1]] = metadata !{metadata !"branch_weights", i32 101, i32 2} +// PGOUSE-DAG: ![[BO2]] = metadata !{metadata !"branch_weights", i32 67, i32 35} +// PGOUSE-DAG: ![[BO3]] = metadata !{metadata !"branch_weights", i32 67, i32 35} +// PGOUSE-DAG: ![[BO4]] = metadata !{metadata !"branch_weights", i32 67, i32 35} +// PGOUSE-DAG: ![[BO5]] = metadata !{metadata !"branch_weights", i32 18, i32 18} +// PGOUSE-DAG: ![[BO6]] = metadata !{metadata !"branch_weights", i32 51, i32 51} +// PGOUSE-DAG: ![[BO7]] = metadata !{metadata !"branch_weights", i32 34, i32 18} +// PGOUSE-DAG: ![[BL1]] = metadata !{metadata !"branch_weights", i32 52, i32 1} +// PGOUSE-DAG: ![[BL2]] = metadata !{metadata !"branch_weights", i32 51, i32 2} +// PGOUSE-DAG: ![[BL3]] = metadata !{metadata !"branch_weights", i32 26, i32 27} +// PGOUSE-DAG: ![[BL4]] = metadata !{metadata !"branch_weights", i32 51, i32 2} +// PGOUSE-DAG: ![[BL5]] = metadata !{metadata !"branch_weights", i32 52, i32 1} +// PGOUSE-DAG: ![[BL6]] = metadata !{metadata !"branch_weights", i32 51, i32 2} +// PGOUSE-DAG: ![[BL7]] = metadata !{metadata !"branch_weights", i32 26, i32 27} +// PGOUSE-DAG: ![[BL8]] = metadata !{metadata !"branch_weights", i32 51, i32 2} +// PGOUSE-DAG: ![[CO1]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// PGOUSE-DAG: ![[CO2]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// PGOUSE-DAG: ![[ST1]] = metadata !{metadata !"branch_weights", i32 11, i32 2} + +int main(int argc, const char *argv[]) { + simple_loops(); + conditionals(); + early_exits(); + jumps(); + switches(); + big_switch(); + boolean_operators(); + boolop_loops(); + conditional_operator(); + do_fallthrough(); + static_func(); + return 0; +} diff --git a/test/Profile/c-linkage-available_externally.c b/test/Profile/c-linkage-available_externally.c new file mode 100644 index 0000000000000..aa1080b2b4436 --- /dev/null +++ b/test/Profile/c-linkage-available_externally.c @@ -0,0 +1,12 @@ +// Make sure instrementation data from available_externally functions doesn't +// get thrown out. +// RUN: %clang_cc1 -O2 -triple x86_64-apple-macosx10.9 -main-file-name c-linkage-available_externally.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck %s + +// CHECK: @__llvm_profile_counters_foo = linkonce_odr hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +// CHECK: @__llvm_profile_name_foo = linkonce_odr hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1 +// CHECK: @__llvm_profile_data_foo = linkonce_odr hidden constant { i32, i32, i64, i8*, i64* } { i32 3, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_foo, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 +inline int foo(void) { return 1; } + +int main(void) { + return foo(); +} diff --git a/test/Profile/c-linkage.c b/test/Profile/c-linkage.c new file mode 100644 index 0000000000000..3b0fa1a5a6ba1 --- /dev/null +++ b/test/Profile/c-linkage.c @@ -0,0 +1,37 @@ +// Check the data structures emitted by instrumentation. +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-linkage.c %s -o - -emit-llvm -fprofile-instr-generate | FileCheck %s + +// CHECK: @__llvm_profile_runtime = external global i32 +// CHECK: @__llvm_profile_counters_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +// CHECK: @__llvm_profile_name_foo = hidden constant [3 x i8] c"foo", section "__DATA,__llvm_prf_names", align 1 +// CHECK: @__llvm_profile_data_foo = hidden constant { i32, i32, i64, i8*, i64* } { i32 3, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([3 x i8]* @__llvm_profile_name_foo, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_foo, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 +void foo(void) { } + +// CHECK: @__llvm_profile_counters_foo_weak = weak hidden global [5 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +// CHECK: @__llvm_profile_name_foo_weak = weak hidden constant [8 x i8] c"foo_weak", section "__DATA,__llvm_prf_names", align 1 +// CHECK: @__llvm_profile_data_foo_weak = weak hidden constant { i32, i32, i64, i8*, i64* } { i32 8, i32 5, i64 {{[0-9]+}}, i8* getelementptr inbounds ([8 x i8]* @__llvm_profile_name_foo_weak, i32 0, i32 0), i64* getelementptr inbounds ([5 x i64]* @__llvm_profile_counters_foo_weak, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 +void foo_weak(void) __attribute__((weak)); +void foo_weak(void) { if (0){} if (0){} if (0){} if (0){} } + +// CHECK: @__llvm_profile_counters_main = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +// CHECK: @__llvm_profile_name_main = hidden constant [4 x i8] c"main", section "__DATA,__llvm_prf_names", align 1 +// CHECK: @__llvm_profile_data_main = hidden constant { i32, i32, i64, i8*, i64* } { i32 4, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([4 x i8]* @__llvm_profile_name_main, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_main, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 +static void foo_internal(void); +int main(void) { + foo(); + foo_internal(); + foo_weak(); + return 0; +} + +// CHECK: @__llvm_profile_counters_foo_internal = internal global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +// CHECK: @__llvm_profile_name_foo_internal = internal constant [24 x i8] c"c-linkage.c:foo_internal", section "__DATA,__llvm_prf_names", align 1 +// CHECK: @__llvm_profile_data_foo_internal = internal constant { i32, i32, i64, i8*, i64* } { i32 24, i32 3, i64 {{[0-9]+}}, i8* getelementptr inbounds ([24 x i8]* @__llvm_profile_name_foo_internal, i32 0, i32 0), i64* getelementptr inbounds ([3 x i64]* @__llvm_profile_counters_foo_internal, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 +static void foo_internal(void) { if (0){} if (0){} } + +// CHECK: @llvm.used = appending global [5 x i8*] [i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_weak to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_foo_internal to i8*)], section "llvm.metadata" + +// CHECK: define linkonce_odr i32 @__llvm_profile_runtime_user() {{.*}} { +// CHECK: %[[REG:.*]] = load i32* @__llvm_profile_runtime +// CHECK: ret i32 %[[REG]] +// CHECK: } diff --git a/test/Profile/c-outdated-data.c b/test/Profile/c-outdated-data.c new file mode 100644 index 0000000000000..d0503acdb6eaf --- /dev/null +++ b/test/Profile/c-outdated-data.c @@ -0,0 +1,28 @@ +// Test that outdated data is ignored. + +// FIXME: It would be nice to use -verify here instead of FileCheck, but -verify +// doesn't play well with warnings that have no line number. + +// RUN: llvm-profdata merge %S/Inputs/c-outdated-data.proftext -o %t.profdata +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-outdated-data.c %s -o /dev/null -emit-llvm -fprofile-instr-use=%t.profdata -Wprofile-instr-dropped 2>&1 | FileCheck %s +// CHECK: warning: profile data may be out of date: of 3 functions, 1 has no data and 1 has mismatched data that will be ignored + +void no_usable_data() { + int i = 0; + + if (i) {} + +#ifdef GENERATE_OUTDATED_DATA + if (i) {} +#endif +} + +#ifndef GENERATE_OUTDATED_DATA +void no_data() { +} +#endif + +int main(int argc, const char *argv[]) { + no_usable_data(); + return 0; +} diff --git a/test/Profile/c-unprofiled-blocks.c b/test/Profile/c-unprofiled-blocks.c new file mode 100644 index 0000000000000..58bef9e2962d1 --- /dev/null +++ b/test/Profile/c-unprofiled-blocks.c @@ -0,0 +1,69 @@ +// Blocks that we have no profile data for (ie, it was never reached in training +// runs) shouldn't have any branch weight metadata added. + +// RUN: llvm-profdata merge %S/Inputs/c-unprofiled-blocks.proftext -o %t.profdata +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-unprofiled-blocks.c %s -o - -emit-llvm -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE %s + +// PGOUSE-LABEL: @never_called(i32 %i) +int never_called(int i) { + // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} + if (i) {} + + // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} + for (i = 0; i < 100; ++i) { + } + + // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} + while (--i) {} + + // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} + do {} while (i++ < 75); + + // PGOUSE: switch {{.*}} [ + // PGOUSE-NEXT: i32 12 + // PGOUSE-NEXT: i32 82 + // PGOUSE-NEXT: ]{{$}} + switch (i) { + case 12: return 3; + case 82: return 0; + default: return 89; + } +} + +// PGOUSE-LABEL: @dead_code(i32 %i) +int dead_code(int i) { + // PGOUSE: br {{.*}}, !prof !{{[0-9]+}} + if (i) { + // This branch is never reached. + + // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} + if (!i) {} + + // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} + for (i = 0; i < 100; ++i) { + } + + // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} + while (--i) {} + + // PGOUSE: br i1 %{{[^,]*}}, label %{{[^,]*}}, label %{{[^,]*}}{{$}} + do {} while (i++ < 75); + + // PGOUSE: switch {{.*}} [ + // PGOUSE-NEXT: i32 12 + // PGOUSE-NEXT: i32 82 + // PGOUSE-NEXT: ]{{$}} + switch (i) { + case 12: return 3; + case 82: return 0; + default: return 89; + } + } + return 2; +} + +// PGOUSE-LABEL: @main(i32 %argc, i8** %argv) +int main(int argc, const char *argv[]) { + dead_code(0); + return 0; +} diff --git a/test/Profile/c-unprofiled.c b/test/Profile/c-unprofiled.c new file mode 100644 index 0000000000000..275cd2d1458d7 --- /dev/null +++ b/test/Profile/c-unprofiled.c @@ -0,0 +1,26 @@ +// Test that unprofiled files are recognized. Here, we have two functions in the +// profile, main() and function_in_header, but we use the profile on a file that +// has the profile-less some_unprofiled_function so that the only profiled code +// in #included in a header. + +// FIXME: It would be nice to use -verify here instead of FileCheck, but -verify +// doesn't play well with warnings that have no line number. + +// RUN: llvm-profdata merge %S/Inputs/c-unprofiled.proftext -o %t.profdata +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-unprofiled.c -I %S/Inputs/ %s -o /dev/null -emit-llvm -fprofile-instr-use=%t.profdata -Wprofile-instr-unprofiled 2>&1 | FileCheck %s + +// CHECK: warning: no profile data available for file "c-unprofiled.c" + +#include "profiled_header.h" + +#ifdef GENERATE_OUTDATED_DATA +int main(int argc, const char *argv[]) { + function_in_header(0); + return 0; +} +#else +void some_unprofiled_function(int i) { + if (i) + function_in_header(i); +} +#endif diff --git a/test/Profile/cxx-class.cpp b/test/Profile/cxx-class.cpp new file mode 100644 index 0000000000000..1a0c84bdccea4 --- /dev/null +++ b/test/Profile/cxx-class.cpp @@ -0,0 +1,78 @@ +// Tests for instrumentation of C++ methods, constructors, and destructors. + +// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-generate -fno-exceptions -target %itanium_abi_triple > %tgen +// RUN: FileCheck --input-file=%tgen -check-prefix=CTRGEN %s +// RUN: FileCheck --input-file=%tgen -check-prefix=DTRGEN %s +// RUN: FileCheck --input-file=%tgen -check-prefix=MTHGEN %s +// RUN: FileCheck --input-file=%tgen -check-prefix=WRPGEN %s + +// RUN: llvm-profdata merge %S/Inputs/cxx-class.proftext -o %t.profdata +// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%t.profdata -fno-exceptions -target %itanium_abi_triple > %tuse +// RUN: FileCheck --input-file=%tuse -check-prefix=CTRUSE %s +// RUN: FileCheck --input-file=%tuse -check-prefix=DTRUSE %s +// RUN: FileCheck --input-file=%tuse -check-prefix=MTHUSE %s +// RUN: FileCheck --input-file=%tuse -check-prefix=WRPUSE %s + +class Simple { + int Member; +public: + // CTRGEN-LABEL: define {{.*}} @_ZN6SimpleC2Ei( + // CTRUSE-LABEL: define {{.*}} @_ZN6SimpleC2Ei( + // CTRGEN: store {{.*}} @[[SCC:__llvm_profile_counters__ZN6SimpleC2Ei]], i64 0, i64 0 + explicit Simple(int Member) : Member(Member) { + // CTRGEN: store {{.*}} @[[SCC]], i64 0, i64 1 + // CTRUSE: br {{.*}} !prof ![[SC1:[0-9]+]] + if (Member) {} + // CTRGEN-NOT: store {{.*}} @[[SCC]], + // CTRUSE-NOT: br {{.*}} !prof ![0-9]+ + // CTRUSE: ret + } + // CTRUSE: ![[SC1]] = metadata !{metadata !"branch_weights", i32 100, i32 2} + + // DTRGEN-LABEL: define {{.*}} @_ZN6SimpleD2Ev( + // DTRUSE-LABEL: define {{.*}} @_ZN6SimpleD2Ev( + // DTRGEN: store {{.*}} @[[SDC:__llvm_profile_counters__ZN6SimpleD2Ev]], i64 0, i64 0 + ~Simple() { + // DTRGEN: store {{.*}} @[[SDC]], i64 0, i64 1 + // DTRUSE: br {{.*}} !prof ![[SD1:[0-9]+]] + if (Member) {} + // DTRGEN-NOT: store {{.*}} @[[SDC]], + // DTRUSE-NOT: br {{.*}} !prof ![0-9]+ + // DTRUSE: ret + } + // DTRUSE: ![[SD1]] = metadata !{metadata !"branch_weights", i32 100, i32 2} + + // MTHGEN-LABEL: define {{.*}} @_ZN6Simple6methodEv( + // MTHUSE-LABEL: define {{.*}} @_ZN6Simple6methodEv( + // MTHGEN: store {{.*}} @[[SMC:__llvm_profile_counters__ZN6Simple6methodEv]], i64 0, i64 0 + void method() { + // MTHGEN: store {{.*}} @[[SMC]], i64 0, i64 1 + // MTHUSE: br {{.*}} !prof ![[SM1:[0-9]+]] + if (Member) {} + // MTHGEN-NOT: store {{.*}} @[[SMC]], + // MTHUSE-NOT: br {{.*}} !prof ![0-9]+ + // MTHUSE: ret + } + // MTHUSE: ![[SM1]] = metadata !{metadata !"branch_weights", i32 100, i32 2} +}; + +// WRPGEN-LABEL: define {{.*}} @_Z14simple_wrapperv( +// WRPUSE-LABEL: define {{.*}} @_Z14simple_wrapperv( +// WRPGEN: store {{.*}} @[[SWC:__llvm_profile_counters__Z14simple_wrapperv]], i64 0, i64 0 +void simple_wrapper() { + // WRPGEN: store {{.*}} @[[SWC]], i64 0, i64 1 + // WRPUSE: br {{.*}} !prof ![[SW1:[0-9]+]] + for (int I = 0; I < 100; ++I) { + Simple S(I); + S.method(); + } + // WRPGEN-NOT: store {{.*}} @[[SWC]], + // WRPUSE-NOT: br {{.*}} !prof ![0-9]+ + // WRPUSE: ret +} +// WRPUSE: ![[SW1]] = metadata !{metadata !"branch_weights", i32 101, i32 2} + +int main(int argc, const char *argv[]) { + simple_wrapper(); + return 0; +} diff --git a/test/Profile/cxx-implicit.cpp b/test/Profile/cxx-implicit.cpp new file mode 100644 index 0000000000000..79840ad938566 --- /dev/null +++ b/test/Profile/cxx-implicit.cpp @@ -0,0 +1,17 @@ +// Ensure that implicit methods aren't instrumented. + +// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-implicit.cpp -o - -emit-llvm -fprofile-instr-generate | FileCheck %s + +// An implicit constructor is generated for Base. We should not emit counters +// for it. +// CHECK-NOT: @__llvm_profile_counters__ZN4BaseC2Ev = + +struct Base { + virtual void foo(); +}; + +struct Derived : public Base { + Derived(); +}; + +Derived::Derived() {} diff --git a/test/Profile/cxx-lambda.cpp b/test/Profile/cxx-lambda.cpp new file mode 100644 index 0000000000000..6c37a863e5c1f --- /dev/null +++ b/test/Profile/cxx-lambda.cpp @@ -0,0 +1,58 @@ +// Tests for instrumentation of C++11 lambdas + +// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-lambda.cpp -std=c++11 -o - -emit-llvm -fprofile-instr-generate > %tgen +// RUN: FileCheck --input-file=%tgen -check-prefix=PGOGEN %s +// RUN: FileCheck --input-file=%tgen -check-prefix=LMBGEN %s + +// RUN: llvm-profdata merge %S/Inputs/cxx-lambda.proftext -o %t.profdata +// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-lambda.cpp -std=c++11 -o - -emit-llvm -fprofile-instr-use=%t.profdata > %tuse +// RUN: FileCheck --input-file=%tuse -check-prefix=PGOUSE %s +// RUN: FileCheck --input-file=%tuse -check-prefix=LMBUSE %s + +// PGOGEN: @[[LWC:__llvm_profile_counters__Z7lambdasv]] = hidden global [4 x i64] zeroinitializer +// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = hidden global [1 x i64] zeroinitializer +// LMBGEN: @[[LFC:"__llvm_profile_counters__ZZ7lambdasvENK3\$_0clEi"]] = internal global [3 x i64] zeroinitializer + +// PGOGEN-LABEL: define void @_Z7lambdasv() +// PGOUSE-LABEL: define void @_Z7lambdasv() +// PGOGEN: store {{.*}} @[[LWC]], i64 0, i64 0 +void lambdas() { + int i = 1; + + // LMBGEN-LABEL: define internal{{( zeroext)?}} i1 @"_ZZ7lambdasvENK3$_0clEi"( + // LMBUSE-LABEL: define internal{{( zeroext)?}} i1 @"_ZZ7lambdasvENK3$_0clEi"( + // LMBGEN: store {{.*}} @[[LFC]], i64 0, i64 0 + auto f = [&i](int k) { + // LMBGEN: store {{.*}} @[[LFC]], i64 0, i64 1 + // LMBUSE: br {{.*}} !prof ![[LF1:[0-9]+]] + if (i > 0) {} + // LMBGEN: store {{.*}} @[[LFC]], i64 0, i64 2 + // LMBUSE: br {{.*}} !prof ![[LF2:[0-9]+]] + return k && i; + }; + + // PGOGEN: store {{.*}} @[[LWC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[LW1:[0-9]+]] + if (i) {} + + // PGOGEN: store {{.*}} @[[LWC]], i64 0, i64 2 + // PGOUSE: br {{.*}} !prof ![[LW2:[0-9]+]] + for (i = 0; i < 10; ++i) + f(9 - i); + + // PGOGEN: store {{.*}} @[[LWC]], i64 0, i64 3 + // PGOUSE: br {{.*}} !prof ![[LW3:[0-9]+]] + if (i) {} +} + +// PGOUSE-DAG: ![[LW1]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// PGOUSE-DAG: ![[LW2]] = metadata !{metadata !"branch_weights", i32 11, i32 2} +// PGOUSE-DAG: ![[LW3]] = metadata !{metadata !"branch_weights", i32 2, i32 1} + +// LMBUSE-DAG: ![[LF1]] = metadata !{metadata !"branch_weights", i32 10, i32 2} +// LMBUSE-DAG: ![[LF2]] = metadata !{metadata !"branch_weights", i32 10, i32 2} + +int main(int argc, const char *argv[]) { + lambdas(); + return 0; +} diff --git a/test/Profile/cxx-linkage.cpp b/test/Profile/cxx-linkage.cpp new file mode 100644 index 0000000000000..df896e7a78f20 --- /dev/null +++ b/test/Profile/cxx-linkage.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9.0 -emit-llvm -main-file-name cxx-linkage.cpp %s -o - -fprofile-instr-generate | FileCheck %s + +// CHECK: @__llvm_profile_runtime = external global i32 +// CHECK: @__llvm_profile_counters__Z3foov = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +// CHECK: @__llvm_profile_name__Z3foov = hidden constant [7 x i8] c"_Z3foov", section "__DATA,__llvm_prf_names", align 1 +// CHECK: @__llvm_profile_data__Z3foov = hidden constant { i32, i32, i64, i8*, i64* } { i32 7, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([7 x i8]* @__llvm_profile_name__Z3foov, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters__Z3foov, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 +void foo(void) { } + +// CHECK: @__llvm_profile_counters__Z8foo_weakv = weak hidden global [5 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +// CHECK: @__llvm_profile_name__Z8foo_weakv = weak hidden constant [12 x i8] c"_Z8foo_weakv", section "__DATA,__llvm_prf_names", align 1 +// CHECK: @__llvm_profile_data__Z8foo_weakv = weak hidden constant { i32, i32, i64, i8*, i64* } { i32 12, i32 5, i64 {{[0-9]+}}, i8* getelementptr inbounds ([12 x i8]* @__llvm_profile_name__Z8foo_weakv, i32 0, i32 0), i64* getelementptr inbounds ([5 x i64]* @__llvm_profile_counters__Z8foo_weakv, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 +void foo_weak(void) __attribute__((weak)); +void foo_weak(void) { if (0){} if (0){} if (0){} if (0){} } + +// CHECK: @__llvm_profile_counters_main = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +// CHECK: @__llvm_profile_name_main = hidden constant [4 x i8] c"main", section "__DATA,__llvm_prf_names", align 1 +// CHECK: @__llvm_profile_data_main = hidden constant { i32, i32, i64, i8*, i64* } { i32 4, i32 1, i64 {{[0-9]+}}, i8* getelementptr inbounds ([4 x i8]* @__llvm_profile_name_main, i32 0, i32 0), i64* getelementptr inbounds ([1 x i64]* @__llvm_profile_counters_main, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 +inline void foo_inline(void); +int main(void) { + foo(); + foo_inline(); + foo_weak(); + return 0; +} + +// CHECK: @__llvm_profile_counters__Z10foo_inlinev = linkonce_odr hidden global [7 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 +// CHECK: @__llvm_profile_name__Z10foo_inlinev = linkonce_odr hidden constant [15 x i8] c"_Z10foo_inlinev", section "__DATA,__llvm_prf_names", align 1 +// CHECK: @__llvm_profile_data__Z10foo_inlinev = linkonce_odr hidden constant { i32, i32, i64, i8*, i64* } { i32 15, i32 7, i64 {{[0-9]+}}, i8* getelementptr inbounds ([15 x i8]* @__llvm_profile_name__Z10foo_inlinev, i32 0, i32 0), i64* getelementptr inbounds ([7 x i64]* @__llvm_profile_counters__Z10foo_inlinev, i32 0, i32 0) }, section "__DATA,__llvm_prf_data", align 8 +inline void foo_inline(void) { if (0){} if (0){} if (0){} if (0){} if (0){} if (0){}} + +// CHECK: @llvm.used = appending global [5 x i8*] [i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z3foov to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z8foo_weakv to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data_main to i8*), i8* bitcast ({ i32, i32, i64, i8*, i64* }* @__llvm_profile_data__Z10foo_inlinev to i8*)], section "llvm.metadata" + +// CHECK: define linkonce_odr i32 @__llvm_profile_runtime_user() {{.*}} { +// CHECK: %[[REG:.*]] = load i32* @__llvm_profile_runtime +// CHECK: ret i32 %[[REG]] +// CHECK: } diff --git a/test/Profile/cxx-templates.cpp b/test/Profile/cxx-templates.cpp new file mode 100644 index 0000000000000..55ab36fe560d4 --- /dev/null +++ b/test/Profile/cxx-templates.cpp @@ -0,0 +1,42 @@ +// Tests for instrumentation of templated code. Each instantiation of a template +// should be instrumented separately. + +// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-templates.cpp -std=c++11 -o - -emit-llvm -fprofile-instr-generate > %tgen +// RUN: FileCheck --input-file=%tgen -check-prefix=T0GEN -check-prefix=ALL %s +// RUN: FileCheck --input-file=%tgen -check-prefix=T100GEN -check-prefix=ALL %s + +// RUN: llvm-profdata merge %S/Inputs/cxx-templates.proftext -o %t.profdata +// RUN: %clang_cc1 -x c++ %s -triple %itanium_abi_triple -main-file-name cxx-templates.cpp -std=c++11 -o - -emit-llvm -fprofile-instr-use=%t.profdata > %tuse +// RUN: FileCheck --input-file=%tuse -check-prefix=T0USE -check-prefix=ALL %s +// RUN: FileCheck --input-file=%tuse -check-prefix=T100USE -check-prefix=ALL %s + +// T0GEN: @[[T0C:__llvm_profile_counters__Z4loopILj0EEvv]] = linkonce_odr hidden global [2 x i64] zeroinitializer +// T100GEN: @[[T100C:__llvm_profile_counters__Z4loopILj100EEvv]] = linkonce_odr hidden global [2 x i64] zeroinitializer + +// T0GEN-LABEL: define linkonce_odr void @_Z4loopILj0EEvv() +// T0USE-LABEL: define linkonce_odr void @_Z4loopILj0EEvv() +// T100GEN-LABEL: define linkonce_odr void @_Z4loopILj100EEvv() +// T100USE-LABEL: define linkonce_odr void @_Z4loopILj100EEvv() +template <unsigned N> void loop() { + // ALL-NOT: ret + // T0GEN: store {{.*}} @[[T0C]], i64 0, i64 0 + // T100GEN: store {{.*}} @[[T100C]], i64 0, i64 0 + + // ALL-NOT: ret + // T0GEN: store {{.*}} @[[T0C]], i64 0, i64 1 + // T0USE: br {{.*}} !prof ![[T01:[0-9]+]] + // T100GEN: store {{.*}} @[[T100C]], i64 0, i64 1 + // T100USE: br {{.*}} !prof ![[T1001:[0-9]+]] + for (unsigned I = 0; I < N; ++I) {} + + // ALL: ret +} + +// T0USE-DAG: ![[T01]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// T100USE-DAG: ![[T1001]] = metadata !{metadata !"branch_weights", i32 101, i32 2} + +int main(int argc, const char *argv[]) { + loop<0>(); + loop<100>(); + return 0; +} diff --git a/test/Profile/cxx-throws.cpp b/test/Profile/cxx-throws.cpp new file mode 100644 index 0000000000000..9ea5ace4b74ab --- /dev/null +++ b/test/Profile/cxx-throws.cpp @@ -0,0 +1,73 @@ +// Test instrumentation of C++ exception handling constructs. + +// FIXME: Don't seek bb labels, like "if.else" +// REQUIRES: asserts + +// RUN: %clangxx %s -o - -emit-llvm -S -fprofile-instr-generate -target %itanium_abi_triple | FileCheck -check-prefix=PGOGEN %s +// RUN: %clangxx %s -o - -emit-llvm -S -fprofile-instr-generate -target %itanium_abi_triple | FileCheck -check-prefix=PGOGEN-EXC %s + +// RUN: llvm-profdata merge %S/Inputs/cxx-throws.proftext -o %t.profdata +// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%t.profdata -target %itanium_abi_triple | FileCheck -check-prefix=PGOUSE %s +// RUN: %clang %s -o - -emit-llvm -S -fprofile-instr-use=%t.profdata -target %itanium_abi_triple | FileCheck -check-prefix=PGOUSE-EXC %s + +// PGOGEN: @[[THC:__llvm_profile_counters__Z6throwsv]] = hidden global [9 x i64] zeroinitializer +// PGOGEN-EXC: @[[THC:__llvm_profile_counters__Z6throwsv]] = hidden global [9 x i64] zeroinitializer + +// PGOGEN-LABEL: @_Z6throwsv() +// PGOUSE-LABEL: @_Z6throwsv() +// PGOGEN: store {{.*}} @[[THC]], i64 0, i64 0 +void throws() { + // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[TH1:[0-9]+]] + for (int i = 0; i < 100; ++i) { + try { + // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 3 + // PGOUSE: br {{.*}} !prof ![[TH2:[0-9]+]] + if (i % 3) { + // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 4 + // PGOUSE: br {{.*}} !prof ![[TH3:[0-9]+]] + if (i < 50) + throw 1; + } else { + // The catch block may be emitted after the throw above, we can skip it + // by looking for an else block, but this will break if anyone puts an + // else in the catch + // PGOUSE: if.else{{.*}}: + // PGOGEN: if.else{{.*}}: + + // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 5 + // PGOUSE: br {{.*}} !prof ![[TH4:[0-9]+]] + if (i >= 50) + throw 0; + } + } catch (int e) { + // PGOUSE-EXC: catch{{.*}}: + // PGOGEN-EXC: catch{{.*}}: + + // PGOGEN-EXC: store {{.*}} @[[THC]], i64 0, i64 6 + // PGOGEN-EXC: store {{.*}} @[[THC]], i64 0, i64 7 + // PGOUSE-EXC: br {{.*}} !prof ![[TH5:[0-9]+]] + if (e) {} + } + // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 2 + + // PGOGEN: store {{.*}} @[[THC]], i64 0, i64 8 + // PGOUSE: br {{.*}} !prof ![[TH6:[0-9]+]] + if (i < 100) {} + } + + // PGOUSE-NOT: br {{.*}} !prof ![0-9]+ + // PGOUSE: ret void +} + +// PGOUSE-DAG: ![[TH1]] = metadata !{metadata !"branch_weights", i32 101, i32 2} +// PGOUSE-DAG: ![[TH2]] = metadata !{metadata !"branch_weights", i32 67, i32 35} +// PGOUSE-DAG: ![[TH3]] = metadata !{metadata !"branch_weights", i32 34, i32 34} +// PGOUSE-DAG: ![[TH4]] = metadata !{metadata !"branch_weights", i32 18, i32 18} +// PGOUSE-EXC: ![[TH5]] = metadata !{metadata !"branch_weights", i32 34, i32 18} +// PGOUSE-DAG: ![[TH6]] = metadata !{metadata !"branch_weights", i32 101, i32 1} + +int main(int argc, const char *argv[]) { + throws(); + return 0; +} diff --git a/test/Profile/objc-general.m b/test/Profile/objc-general.m new file mode 100644 index 0000000000000..ba06f91a7f984 --- /dev/null +++ b/test/Profile/objc-general.m @@ -0,0 +1,75 @@ +// Test instrumentation of general constructs in objective C. + +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instr-generate | FileCheck -check-prefix=PGOGEN %s + +// RUN: llvm-profdata merge %S/Inputs/objc-general.proftext -o %t.profdata +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name objc-general.m %s -o - -emit-llvm -fblocks -fprofile-instr-use=%t.profdata | FileCheck -check-prefix=PGOUSE %s + +#ifdef HAVE_FOUNDATION + +// Use this to build an instrumented version to regenerate the input file. +#import <Foundation/Foundation.h> + +#else + +// Minimal definitions to get this to compile without Foundation.h. + +@protocol NSObject +@end + +@interface NSObject <NSObject> +- (id)init; ++ (id)alloc; +@end + +struct NSFastEnumerationState; +@interface NSArray : NSObject +- (unsigned long) countByEnumeratingWithState: (struct NSFastEnumerationState*) state + objects: (id*) buffer + count: (unsigned long) bufferSize; ++(NSArray*) arrayWithObjects: (id) first, ...; +@end; +#endif + +// PGOGEN: @[[FRC:"__llvm_profile_counters_\+\[A foreach:\]"]] = internal global [2 x i64] zeroinitializer +// PGOGEN: @[[BLC:"__llvm_profile_counters___13\+\[A foreach:\]_block_invoke"]] = internal global [2 x i64] zeroinitializer +// PGOGEN: @[[MAC:__llvm_profile_counters_main]] = hidden global [1 x i64] zeroinitializer + +@interface A : NSObject ++ (void)foreach: (NSArray *)array; +@end + +@implementation A +// PGOGEN: define {{.*}}+[A foreach:] +// PGOUSE: define {{.*}}+[A foreach:] +// PGOGEN: store {{.*}} @[[FRC]], i64 0, i64 0 ++ (void)foreach: (NSArray *)array +{ + __block id result; + // PGOGEN: store {{.*}} @[[FRC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[FR1:[0-9]+]] + // PGOUSE: br {{.*}} !prof ![[FR2:[0-9]+]] + for (id x in array) { + // PGOGEN: define {{.*}}_block_invoke + // PGOUSE: define {{.*}}_block_invoke + // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 0 + ^{ static int init = 0; + // PGOGEN: store {{.*}} @[[BLC]], i64 0, i64 1 + // PGOUSE: br {{.*}} !prof ![[BL1:[0-9]+]] + if (init) + result = x; + init = 1; }(); + } +} +@end + +// PGOUSE-DAG: ![[FR1]] = metadata !{metadata !"branch_weights", i32 2, i32 3} +// PGOUSE-DAG: ![[FR2]] = metadata !{metadata !"branch_weights", i32 3, i32 2} +// PGOUSE-DAG: ![[BL1]] = metadata !{metadata !"branch_weights", i32 2, i32 2} + +int main(int argc, const char *argv[]) { + A *a = [[A alloc] init]; + NSArray *array = [NSArray arrayWithObjects: @"0", @"1", (void*)0]; + [A foreach: array]; + return 0; +} |
