reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
// 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
// REQUIRES: asserts

struct S {
  S();
  ~S();
};

// CHECK-DAG: @"?s@?1??f@@YAAAUS@@XZ@4U2@A" = linkonce_odr dso_local thread_local global %struct.S zeroinitializer
// CHECK-DAG: @"??__J?1??f@@YAAAUS@@XZ@51" = linkonce_odr thread_local global i32 0
// CHECK-DAG: @"?s@?1??g@@YAAAUS@@XZ@4U2@A" = linkonce_odr dso_local global %struct.S zeroinitializer
// CHECK-DAG: @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA" = linkonce_odr global i32 0
// CHECK-DAG: @_Init_thread_epoch = external thread_local global i32, align 4
// CHECK-DAG: @"?j@?1??h@@YAAAUS@@_N@Z@4U2@A" = linkonce_odr dso_local thread_local global %struct.S zeroinitializer
// CHECK-DAG: @"??__J?1??h@@YAAAUS@@_N@Z@51" = linkonce_odr thread_local global i32 0
// CHECK-DAG: @"?i@?1??h@@YAAAUS@@_N@Z@4U2@A" = linkonce_odr dso_local global %struct.S zeroinitializer
// CHECK-DAG: @"?$TSS0@?1??h@@YAAAUS@@_N@Z@4HA" = linkonce_odr global i32 0
// CHECK-DAG: @"?i@?1??g1@@YAHXZ@4HA" = internal global i32 0, align 4
// CHECK-DAG: @"?$TSS0@?1??g1@@YAHXZ@4HA" = internal global i32 0, align 4

// CHECK-LABEL: define {{.*}} @"?f@@YAAAUS@@XZ"()
// CHECK-SAME:  personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
extern inline S &f() {
  static thread_local S s;
// CHECK:       %[[guard:.*]] = load i32, i32* @"??__J?1??f@@YAAAUS@@XZ@51"
// CHECK-NEXT:  %[[mask:.*]] = and i32 %[[guard]], 1
// CHECK-NEXT:  %[[cmp:.*]] = icmp eq i32 %[[mask]], 0
// CHECK-NEXT:  br i1 %[[cmp]], label %[[init:.*]], label %[[init_end:.*]], !prof ![[unlikely_threadlocal:.*]]
//
// CHECK:     [[init]]:
// CHECK-NEXT:  %[[or:.*]] = or i32 %[[guard]], 1
// CHECK-NEXT:  store i32 %[[or]], i32* @"??__J?1??f@@YAAAUS@@XZ@51"
// CHECK-NEXT:  invoke {{.*}} @"??0S@@QAE@XZ"(%struct.S* @"?s@?1??f@@YAAAUS@@XZ@4U2@A")
// CHECK-NEXT:    to label %[[invoke_cont:.*]] unwind label %[[lpad:.*]]
//
// CHECK:     [[invoke_cont]]:
// CHECK-NEXT:  call i32 @__tlregdtor(void ()* @"??__Fs@?1??f@@YAAAUS@@XZ@YAXXZ")
// CHECK-NEXT:  br label %[[init_end:.*]]

// CHECK:     [[init_end]]:
// CHECK-NEXT:  ret %struct.S* @"?s@?1??f@@YAAAUS@@XZ@4U2@A"

// CHECK:     [[lpad:.*]]:
// CHECK-NEXT: cleanuppad within none []
// CHECK:       %[[guard:.*]] = load i32, i32* @"??__J?1??f@@YAAAUS@@XZ@51"
// CHECK-NEXT:  %[[mask:.*]] = and i32 %[[guard]], -2
// CHECK-NEXT:  store i32 %[[mask]], i32* @"??__J?1??f@@YAAAUS@@XZ@51"
// CHECK-NEXT:  cleanupret {{.*}} unwind to caller
  return s;
}


// CHECK-LABEL: define {{.*}} @"?g@@YAAAUS@@XZ"()
extern inline S &g() {
  static S s;
// CHECK:  %[[guard:.*]] = load atomic i32, i32* @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA" unordered, align 4
// CHECK-NEXT:  %[[epoch:.*]] = load i32, i32* @_Init_thread_epoch
// CHECK-NEXT:  %[[cmp:.*]] = icmp sgt i32 %[[guard]], %[[epoch]]
// CHECK-NEXT:  br i1 %[[cmp]], label %[[init_attempt:.*]], label %[[init_end:.*]], !prof ![[unlikely_staticlocal:.*]]
//
// CHECK:     [[init_attempt]]:
// CHECK-NEXT:  call void @_Init_thread_header(i32* @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA")
// CHECK-NEXT:  %[[guard2:.*]] = load atomic i32, i32* @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA" unordered, align 4
// CHECK-NEXT:  %[[cmp2:.*]] = icmp eq i32 %[[guard2]], -1
// CHECK-NEXT:  br i1 %[[cmp2]], label %[[init:.*]], label %[[init_end:.*]]
//
// CHECK:     [[init]]:
// CHECK-NEXT:  invoke {{.*}} @"??0S@@QAE@XZ"(%struct.S* @"?s@?1??g@@YAAAUS@@XZ@4U2@A")
// CHECK-NEXT:    to label %[[invoke_cont:.*]] unwind label %[[lpad:.*]]
//
// CHECK:     [[invoke_cont]]:
// CHECK-NEXT:  call i32 @atexit(void ()* @"??__Fs@?1??g@@YAAAUS@@XZ@YAXXZ")
// CHECK-NEXT:  call void @_Init_thread_footer(i32* @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA")
// CHECK-NEXT:  br label %init.end
//
// CHECK:     [[init_end]]:
// CHECK-NEXT:  ret %struct.S* @"?s@?1??g@@YAAAUS@@XZ@4U2@A"
//
// CHECK:     [[lpad]]:
// CHECK-NEXT: cleanuppad within none []
// CHECK:       call void @_Init_thread_abort(i32* @"?$TSS0@?1??g@@YAAAUS@@XZ@4HA")
// CHECK-NEXT:  cleanupret {{.*}} unwind to caller
  return s;
}

extern inline S&h(bool b) {
  static thread_local S j;
  static S i;
  return b ? j : i;
}

// CHECK-LABEL: define dso_local i32 @"?g1@@YAHXZ"()
int f1();
int g1() {
  static int i = f1();
  return i;
}

// CHECK-DAG: ![[unlikely_threadlocal]] = !{!"branch_weights", i32 1, i32 1023}
// CHECK-DAG: ![[unlikely_staticlocal]] = !{!"branch_weights", i32 1, i32 1048575}