| 1 | // RUN: %clang_cc1 -fexceptions -fcxx-exceptions -fms-extensions -fms-compatibility -fms-compatibility-version=19 -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s |
| 2 | // REQUIRES: asserts |
| 3 | |
| 4 | struct S { |
| 5 | S(); |
| 6 | ~S(); |
| 7 | }; |
| 8 | |
| 9 | // CHECK-DAG: @"?s@?1??f@@YAAAUS@@XZ@4U2@A" = linkonce_odr dso_local thread_local global %struct.S zeroinitializer |
| 10 | // CHECK-DAG: @"??__J?1??f@@YAAAUS@@XZ@51" = linkonce_odr thread_local global i32 0 |
| 11 | // CHECK-DAG: @"?s@?1??g@@YAAAUS@@XZ@4U2@A" = linkonce_odr dso_local global %struct.S zeroinitializer |
| 12 | // CHECK-DAG: @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA" = linkonce_odr global i32 0 |
| 13 | // CHECK-DAG: @_Init_thread_epoch = external thread_local global i32, align 4 |
| 14 | // CHECK-DAG: @"?j@?1??h@@YAAAUS@@_N@Z@4U2@A" = linkonce_odr dso_local thread_local global %struct.S zeroinitializer |
| 15 | // CHECK-DAG: @"??__J?1??h@@YAAAUS@@_N@Z@51" = linkonce_odr thread_local global i32 0 |
| 16 | // CHECK-DAG: @"?i@?1??h@@YAAAUS@@_N@Z@4U2@A" = linkonce_odr dso_local global %struct.S zeroinitializer |
| 17 | // CHECK-DAG: @"?$TSS0@?1??h@@YAAAUS@@_N@Z@4HA" = linkonce_odr global i32 0 |
| 18 | // CHECK-DAG: @"?i@?1??g1@@YAHXZ@4HA" = internal global i32 0, align 4 |
| 19 | // CHECK-DAG: @"?$TSS0@?1??g1@@YAHXZ@4HA" = internal global i32 0, align 4 |
| 20 | |
| 21 | // CHECK-LABEL: define {{.*}} @"?f@@YAAAUS@@XZ"() |
| 22 | // CHECK-SAME: personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) |
| 23 | extern inline S &f() { |
| 24 | static thread_local S s; |
| 25 | // CHECK: %[[guard:.*]] = load i32, i32* @"??__J?1??f@@YAAAUS@@XZ@51" |
| 26 | // CHECK-NEXT: %[[mask:.*]] = and i32 %[[guard]], 1 |
| 27 | // CHECK-NEXT: %[[cmp:.*]] = icmp eq i32 %[[mask]], 0 |
| 28 | // CHECK-NEXT: br i1 %[[cmp]], label %[[init:.*]], label %[[init_end:.*]], !prof ![[unlikely_threadlocal:.*]] |
| 29 | // |
| 30 | // CHECK: [[init]]: |
| 31 | // CHECK-NEXT: %[[or:.*]] = or i32 %[[guard]], 1 |
| 32 | // CHECK-NEXT: store i32 %[[or]], i32* @"??__J?1??f@@YAAAUS@@XZ@51" |
| 33 | // CHECK-NEXT: invoke {{.*}} @"??0S@@QAE@XZ"(%struct.S* @"?s@?1??f@@YAAAUS@@XZ@4U2@A") |
| 34 | // CHECK-NEXT: to label %[[invoke_cont:.*]] unwind label %[[lpad:.*]] |
| 35 | // |
| 36 | // CHECK: [[invoke_cont]]: |
| 37 | // CHECK-NEXT: call i32 @__tlregdtor(void ()* @"??__Fs@?1??f@@YAAAUS@@XZ@YAXXZ") |
| 38 | // CHECK-NEXT: br label %[[init_end:.*]] |
| 39 | |
| 40 | // CHECK: [[init_end]]: |
| 41 | // CHECK-NEXT: ret %struct.S* @"?s@?1??f@@YAAAUS@@XZ@4U2@A" |
| 42 | |
| 43 | // CHECK: [[lpad:.*]]: |
| 44 | // CHECK-NEXT: cleanuppad within none [] |
| 45 | // CHECK: %[[guard:.*]] = load i32, i32* @"??__J?1??f@@YAAAUS@@XZ@51" |
| 46 | // CHECK-NEXT: %[[mask:.*]] = and i32 %[[guard]], -2 |
| 47 | // CHECK-NEXT: store i32 %[[mask]], i32* @"??__J?1??f@@YAAAUS@@XZ@51" |
| 48 | // CHECK-NEXT: cleanupret {{.*}} unwind to caller |
| 49 | return s; |
| 50 | } |
| 51 | |
| 52 | |
| 53 | // CHECK-LABEL: define {{.*}} @"?g@@YAAAUS@@XZ"() |
| 54 | extern inline S &g() { |
| 55 | static S s; |
| 56 | // CHECK: %[[guard:.*]] = load atomic i32, i32* @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA" unordered, align 4 |
| 57 | // CHECK-NEXT: %[[epoch:.*]] = load i32, i32* @_Init_thread_epoch |
| 58 | // CHECK-NEXT: %[[cmp:.*]] = icmp sgt i32 %[[guard]], %[[epoch]] |
| 59 | // CHECK-NEXT: br i1 %[[cmp]], label %[[init_attempt:.*]], label %[[init_end:.*]], !prof ![[unlikely_staticlocal:.*]] |
| 60 | // |
| 61 | // CHECK: [[init_attempt]]: |
| 62 | // CHECK-NEXT: call void @_Init_thread_header(i32* @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA") |
| 63 | // CHECK-NEXT: %[[guard2:.*]] = load atomic i32, i32* @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA" unordered, align 4 |
| 64 | // CHECK-NEXT: %[[cmp2:.*]] = icmp eq i32 %[[guard2]], -1 |
| 65 | // CHECK-NEXT: br i1 %[[cmp2]], label %[[init:.*]], label %[[init_end:.*]] |
| 66 | // |
| 67 | // CHECK: [[init]]: |
| 68 | // CHECK-NEXT: invoke {{.*}} @"??0S@@QAE@XZ"(%struct.S* @"?s@?1??g@@YAAAUS@@XZ@4U2@A") |
| 69 | // CHECK-NEXT: to label %[[invoke_cont:.*]] unwind label %[[lpad:.*]] |
| 70 | // |
| 71 | // CHECK: [[invoke_cont]]: |
| 72 | // CHECK-NEXT: call i32 @atexit(void ()* @"??__Fs@?1??g@@YAAAUS@@XZ@YAXXZ") |
| 73 | // CHECK-NEXT: call void @_Init_thread_footer(i32* @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA") |
| 74 | // CHECK-NEXT: br label %init.end |
| 75 | // |
| 76 | // CHECK: [[init_end]]: |
| 77 | // CHECK-NEXT: ret %struct.S* @"?s@?1??g@@YAAAUS@@XZ@4U2@A" |
| 78 | // |
| 79 | // CHECK: [[lpad]]: |
| 80 | // CHECK-NEXT: cleanuppad within none [] |
| 81 | // CHECK: call void @_Init_thread_abort(i32* @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA") |
| 82 | // CHECK-NEXT: cleanupret {{.*}} unwind to caller |
| 83 | return s; |
| 84 | } |
| 85 | |
| 86 | extern inline S&h(bool b) { |
| 87 | static thread_local S j; |
| 88 | static S i; |
| 89 | return b ? j : i; |
| 90 | } |
| 91 | |
| 92 | // CHECK-LABEL: define dso_local i32 @"?g1@@YAHXZ"() |
| 93 | int f1(); |
| 94 | int g1() { |
| 95 | static int i = f1(); |
| 96 | return i; |
| 97 | } |
| 98 | |
| 99 | // CHECK-DAG: ![[unlikely_threadlocal]] = !{!"branch_weights", i32 1, i32 1023} |
| 100 | // CHECK-DAG: ![[unlikely_staticlocal]] = !{!"branch_weights", i32 1, i32 1048575} |
| 101 | |