jamieschmeiser updated this revision to Diff 356705.
jamieschmeiser added a comment.

Fix formatting problem.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D104420/new/

https://reviews.llvm.org/D104420

Files:
  clang/lib/CodeGen/ItaniumCXXABI.cpp
  clang/test/CodeGenCXX/cxx11-thread-local-reference.cpp
  clang/test/CodeGenCXX/cxx11-thread-local-visibility.cpp
  clang/test/CodeGenCXX/cxx11-thread-local.cpp

Index: clang/test/CodeGenCXX/cxx11-thread-local.cpp
===================================================================
--- clang/test/CodeGenCXX/cxx11-thread-local.cpp
+++ clang/test/CodeGenCXX/cxx11-thread-local.cpp
@@ -9,11 +9,13 @@
 // RUN: %clang_cc1 -std=c++11 -fno-use-cxa-atexit -femulated-tls -emit-llvm %s -o - \
 // RUN:     -triple x86_64-linux-gnu 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=LINUX %s
 // RUN: %clang_cc1 -std=c++11 -fno-use-cxa-atexit -emit-llvm %s -o - -triple x86_64-apple-darwin12 | FileCheck --check-prefix=CHECK --check-prefix=DARWIN %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple powerpc64-unknown-aix-xcoff | FileCheck --check-prefix=CHECK --check-prefix=AIX %s
 
 int f();
 int g();
 
 // LINUX-DAG: @a ={{.*}} thread_local global i32 0
+// AIX-DAG: @a ={{.*}} thread_local global i32 0
 // DARWIN-DAG: @a = internal thread_local global i32 0
 thread_local int a = f();
 extern thread_local int b;
@@ -24,6 +26,7 @@
 
 struct U { static thread_local int m; };
 // LINUX-DAG: @_ZN1U1mE ={{.*}} thread_local global i32 0
+// AIX-DAG: @_ZN1U1mE ={{.*}} thread_local global i32 0
 // DARWIN-DAG: @_ZN1U1mE = internal thread_local global i32 0
 thread_local int U::m = f();
 
@@ -90,8 +93,10 @@
 // CHECK-DAG: @llvm.global_ctors = appending global {{.*}} @[[GLOBAL_INIT:[^ ]*]]
 
 // LINUX-DAG: @_ZTH1a ={{.*}} alias void (), void ()* @__tls_init
+// AIX-DAG: @_ZTH1a ={{.*}} alias void (), void ()* @__tls_init
 // DARWIN-DAG: @_ZTH1a = internal alias void (), void ()* @__tls_init
 // LINUX-DAG: @_ZTHN1U1mE ={{.*}} alias void (), void ()* @__tls_init
+// AIX-DAG: @_ZTHN1U1mE ={{.*}} alias void (), void ()* @__tls_init
 // DARWIN-DAG: @_ZTHN1U1mE = internal alias void (), void ()* @__tls_init
 // CHECK-DAG: @_ZTHN1VIiE1mE = linkonce_odr alias void (), void ()* @[[V_M_INIT:[^, ]*]]
 // CHECK-DAG: @_ZTHN1XIiE1mE = linkonce_odr alias void (), void ()* @[[X_M_INIT:[^, ]*]]
@@ -106,16 +111,16 @@
 // Individual variable initialization functions:
 
 // CHECK: define {{.*}} @[[A_INIT:.*]]()
-// CHECK: call i32 @_Z1fv()
+// CHECK: call{{.*}} i32 @_Z1fv()
 // CHECK-NEXT: store i32 {{.*}}, i32* @a, align 4
 
 // CHECK-LABEL: define{{.*}} i32 @_Z1fv()
 int f() {
   // CHECK: %[[GUARD:.*]] = load i8, i8* @_ZGVZ1fvE1n, align 1
   // CHECK: %[[NEED_INIT:.*]] = icmp eq i8 %[[GUARD]], 0
-  // CHECK: br i1 %[[NEED_INIT]]
+  // CHECK: br i1 %[[NEED_INIT]]{{.*}}
 
-  // CHECK: %[[CALL:.*]] = call i32 @_Z1gv()
+  // CHECK: %[[CALL:.*]] = call{{.*}} i32 @_Z1gv()
   // CHECK: store i32 %[[CALL]], i32* @_ZZ1fvE1n, align 4
   // CHECK: store i8 1, i8* @_ZGVZ1fvE1n
   // CHECK: br label
@@ -127,54 +132,67 @@
 
 // CHECK: define {{.*}} @[[C_INIT:.*]]()
 // LINUX: call i32* @_ZTW1b()
+// AIX: call i32* @_ZTW1b()
 // DARWIN: call cxx_fast_tlscc i32* @_ZTW1b()
 // CHECK-NEXT: load i32, i32* %{{.*}}, align 4
 // CHECK-NEXT: store i32 %{{.*}}, i32* @c, align 4
 
 // LINUX-LABEL: define linkonce_odr hidden i32* @_ZTW1b()
+// AIX-LABEL: define linkonce_odr hidden i32* @_ZTW1b()
 // LINUX: br i1 icmp ne (void ()* @_ZTH1b, void ()* null),
 // not null:
 // LINUX: call void @_ZTH1b()
+// AIX-NOT: br i1 icmp ne (void ()* @_ZTH1b, void ()* null),
+// AIX: call void @_ZTH1b()
 // LINUX: br label
 // finally:
 // LINUX: ret i32* @b
+// AIX: ret i32* @b
 // DARWIN-LABEL: declare cxx_fast_tlscc i32* @_ZTW1b()
 // There is no definition of the thread wrapper on Darwin for external TLV.
 
 // CHECK: define {{.*}} @[[D_INIT:.*]]()
-// CHECK: call i32 @_Z1gv()
+// CHECK: call{{.*}} i32 @_Z1gv()
 // CHECK-NEXT: store i32 %{{.*}}, i32* @_ZL1d, align 4
 
 // CHECK: define {{.*}} @[[U_M_INIT:.*]]()
-// CHECK: call i32 @_Z1fv()
+// CHECK: call{{.*}} i32 @_Z1fv()
 // CHECK-NEXT: store i32 %{{.*}}, i32* @_ZN1U1mE, align 4
 
 // CHECK: define {{.*}} @[[E_INIT:.*]]()
 // LINUX: call i32* @_ZTWN1VIiE1mE()
+// AIX: call i32* @_ZTWN1VIiE1mE()
 // DARWIN: call cxx_fast_tlscc i32* @_ZTWN1VIiE1mE()
 // CHECK-NEXT: load i32, i32* %{{.*}}, align 4
 // LINUX: call {{.*}}* @_ZTWN1XIiE1mE()
+// AIX: call {{.*}}* @_ZTWN1XIiE1mE()
 // DARWIN: call cxx_fast_tlscc {{.*}}* @_ZTWN1XIiE1mE()
 // CHECK: store {{.*}} @e
 
 // LINUX-LABEL: define weak_odr hidden i32* @_ZTWN1VIiE1mE()
+// AIX-LABEL: define weak_odr hidden i32* @_ZTWN1VIiE1mE()
 // DARWIN-LABEL: define weak_odr hidden cxx_fast_tlscc i32* @_ZTWN1VIiE1mE()
 // LINUX: call void @_ZTHN1VIiE1mE()
+// AIX: call void @_ZTHN1VIiE1mE()
 // DARWIN: call cxx_fast_tlscc void @_ZTHN1VIiE1mE()
 // CHECK: ret i32* @_ZN1VIiE1mE
 
 // LINUX-LABEL: define weak_odr hidden i32* @_ZTWN1WIiE1mE()
+// AIX-LABEL: define weak_odr hidden i32* @_ZTWN1WIiE1mE()
 // DARWIN-LABEL: define weak_odr hidden cxx_fast_tlscc i32* @_ZTWN1WIiE1mE()
 // CHECK-NOT: call
 // CHECK: ret i32* @_ZN1WIiE1mE
 
 // LINUX-LABEL: define weak_odr hidden {{.*}}* @_ZTWN1XIiE1mE()
+// AIX-LABEL: define weak_odr hidden {{.*}}* @_ZTWN1XIiE1mE()
 // DARWIN-LABEL: define weak_odr hidden cxx_fast_tlscc {{.*}}* @_ZTWN1XIiE1mE()
 // LINUX: call void @_ZTHN1XIiE1mE()
+// AIX: call void @_ZTHN1XIiE1mE()
 // DARWIN: call cxx_fast_tlscc void @_ZTHN1XIiE1mE()
 // CHECK: ret {{.*}}* @_ZN1XIiE1mE
 
 // LINUX: define internal void @[[VF_M_INIT]]()
+// AIX: define internal void @[[VF_M_INIT]]()
 // DARWIN: define internal cxx_fast_tlscc void @[[VF_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1VIfE1mE)
 // DARWIN-NOT: comdat
@@ -182,12 +200,13 @@
 // CHECK: %[[VF_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0
 // CHECK: br i1 %[[VF_M_INITIALIZED]],
 // need init:
-// CHECK: call i32 @_Z1gv()
+// CHECK: call{{.*}} i32 @_Z1gv()
 // CHECK: store i32 %{{.*}}, i32* @_ZN1VIfE1mE, align 4
 // CHECK: store i8 1, i8* bitcast (i64* @_ZGVN1VIfE1mE to i8*)
 // CHECK: br label
 
 // LINUX: define internal void @[[XF_M_INIT]]()
+// AIX: define internal void @[[XF_M_INIT]]()
 // DARWIN: define internal cxx_fast_tlscc void @[[XF_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1XIfE1mE)
 // DARWIN-NOT: comdat
@@ -196,30 +215,43 @@
 // CHECK: br i1 %[[XF_M_INITIALIZED]],
 // need init:
 // LINUX: call {{.*}}__cxa_thread_atexit
+// AIX: call {{.*}}__pt_atexit_np
 // DARWIN: call {{.*}}_tlv_atexit
 // CHECK: store i8 1, i8* bitcast (i64* @_ZGVN1XIfE1mE to i8*)
 // CHECK: br label
 
 // LINUX: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*)
+// AIX: declare i32 @__pt_atexit_np(i32, i32 (i32, ...)*, ...)
 // DARWIN: declare i32 @_tlv_atexit(void (i8*)*, i8*, i8*)
 
 // DARWIN: declare cxx_fast_tlscc i32* @_ZTWN1VIcE1mE()
 // LINUX: define linkonce_odr hidden i32* @_ZTWN1VIcE1mE() {{#[0-9]+}} comdat {
+// AIX: define linkonce_odr hidden i32* @_ZTWN1VIcE1mE() {{#[0-9]+}} {
 // LINUX: br i1 icmp ne (void ()* @_ZTHN1VIcE1mE,
 // LINUX: call void @_ZTHN1VIcE1mE()
+// AIX-NOT: br i1 icmp ne (void ()* @_ZTHN1VIcE1mE
+// AIX: call void @_ZTHN1VIcE1mE()
 // LINUX: ret i32* @_ZN1VIcE1mE
+// AIX: ret i32* @_ZN1VIcE1mE
 
 // DARWIN: declare cxx_fast_tlscc i32* @_ZTWN1WIcE1mE()
 // LINUX: define linkonce_odr hidden i32* @_ZTWN1WIcE1mE() {{#[0-9]+}} comdat {
+// AIX: define linkonce_odr hidden i32* @_ZTWN1WIcE1mE() {{#[0-9]+}} {
 // LINUX: br i1 icmp ne (void ()* @_ZTHN1WIcE1mE,
 // LINUX: call void @_ZTHN1WIcE1mE()
+// AIX-NOT: br i1 icmp ne (void ()* @_ZTHN1WIcE1mE,
+// AIX: call void @_ZTHN1WIcE1mE()
 // LINUX: ret i32* @_ZN1WIcE1mE
+// AIX: ret i32* @_ZN1WIcE1mE
 
 // DARWIN: declare cxx_fast_tlscc {{.*}}* @_ZTWN1XIcE1mE()
 // LINUX: define linkonce_odr hidden {{.*}}* @_ZTWN1XIcE1mE() {{#[0-9]+}} comdat {
 // LINUX: br i1 icmp ne (void ()* @_ZTHN1XIcE1mE,
 // LINUX: call void @_ZTHN1XIcE1mE()
+// AIX-NOT: br i1 icmp ne (void ()* @_ZTHN1XIcE1mE,
+// AIX: call void @_ZTHN1XIcE1mE()
 // LINUX: ret {{.*}}* @_ZN1XIcE1mE
+// AIX: ret {{.*}}* @_ZN1XIcE1mE
 
 struct S { S(); ~S(); };
 struct T { ~T(); };
@@ -229,6 +261,7 @@
   // CHECK: load i8, i8* @_ZGVZ8tls_dtorvE1s
   // CHECK: call void @_ZN1SC1Ev(%struct.S* {{[^,]*}} @_ZZ8tls_dtorvE1s)
   // LINUX: call i32 @__cxa_thread_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZZ8tls_dtorvE1s{{.*}} @__dso_handle
+  // AIX: call i32 (i32, i32 (i32, ...)*, ...) @__pt_atexit_np(i32 0, {{.*}}@_ZN1SD1Ev {{.*}})
   // DARWIN: call i32 @_tlv_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZZ8tls_dtorvE1s{{.*}} @__dso_handle
   // CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1s
   static thread_local S s;
@@ -236,6 +269,7 @@
   // CHECK: load i8, i8* @_ZGVZ8tls_dtorvE1t
   // CHECK-NOT: _ZN1T
   // LINUX: call i32 @__cxa_thread_atexit({{.*}}@_ZN1TD1Ev {{.*}}@_ZZ8tls_dtorvE1t{{.*}} @__dso_handle
+  // AIX: call i32 (i32, i32 (i32, ...)*, ...) @__pt_atexit_np(i32 0, {{.*}}@_ZN1TD1Ev {{.*}})
   // DARWIN: call i32 @_tlv_atexit({{.*}}@_ZN1TD1Ev {{.*}}@_ZZ8tls_dtorvE1t{{.*}} @__dso_handle
   // CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1t
   static thread_local T t;
@@ -243,6 +277,7 @@
   // CHECK: load i8, i8* @_ZGVZ8tls_dtorvE1u
   // CHECK: call void @_ZN1SC1Ev(%struct.S* {{[^,]*}} @_ZGRZ8tls_dtorvE1u_)
   // LINUX: call i32 @__cxa_thread_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZGRZ8tls_dtorvE1u_{{.*}} @__dso_handle
+  // AIX: call i32 (i32, i32 (i32, ...)*, ...) @__pt_atexit_np(i32 0, {{.*}}@_ZN1SD1Ev {{.*}})
   // DARWIN: call i32 @_tlv_atexit({{.*}}@_ZN1SD1Ev {{.*}} @_ZGRZ8tls_dtorvE1u_{{.*}} @__dso_handle
   // CHECK: store i8 1, i8* @_ZGVZ8tls_dtorvE1u
   static thread_local const S &u = S();
@@ -262,6 +297,7 @@
 // CHECK: define {{.*}} @_ZN7PR192541fEv(
 int PR19254::f() {
   // LINUX: call void @_ZTHN7PR192541nE(
+  // AIX: call void @_ZTHN7PR192541nE(
   // DARWIN: call cxx_fast_tlscc i32* @_ZTWN7PR192541nE(
   return this->n;
 }
@@ -273,9 +309,11 @@
   anon_i = 2;
 }
 // LINUX-LABEL: define internal i32* @_ZTWN12_GLOBAL__N_16anon_iE()
+// AIX-LABEL: define internal i32* @_ZTWN12_GLOBAL__N_16anon_iE()
 // DARWIN-LABEL: define internal cxx_fast_tlscc i32* @_ZTWN12_GLOBAL__N_16anon_iE()
 
 // LINUX: define internal void @[[V_M_INIT]]()
+// AIX: define internal void @[[V_M_INIT]]()
 // DARWIN: define internal cxx_fast_tlscc void @[[V_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1VIiE1mE)
 // DARWIN-NOT: comdat
@@ -283,12 +321,13 @@
 // CHECK: %[[V_M_INITIALIZED:.*]] = icmp eq i8 %{{.*}}, 0
 // CHECK: br i1 %[[V_M_INITIALIZED]],
 // need init:
-// CHECK: call i32 @_Z1gv()
+// CHECK: call{{.*}} i32 @_Z1gv()
 // CHECK: store i32 %{{.*}}, i32* @_ZN1VIiE1mE, align 4
 // CHECK: store i8 1, i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*)
 // CHECK: br label
 
 // LINUX: define internal void @[[X_M_INIT]]()
+// AIX: define internal void @[[X_M_INIT]]()
 // DARWIN: define internal cxx_fast_tlscc void @[[X_M_INIT]]()
 // LINUX-SAME: comdat($_ZN1XIiE1mE)
 // DARWIN-NOT: comdat
@@ -297,6 +336,7 @@
 // CHECK: br i1 %[[X_M_INITIALIZED]],
 // need init:
 // LINUX: call {{.*}}__cxa_thread_atexit
+// AIX: call {{.*}}__pt_atexit_np
 // DARWIN: call {{.*}}_tlv_atexit
 // CHECK: store i8 1, i8* bitcast (i64* @_ZGVN1XIiE1mE to i8*)
 // CHECK: br label
@@ -323,8 +363,10 @@
 
 
 // LINUX: define weak_odr hidden i32* @_ZTW1a()
+// AIX: define weak_odr hidden i32* @_ZTW1a()
 // DARWIN: define cxx_fast_tlscc i32* @_ZTW1a()
 // LINUX:   call void @_ZTH1a()
+// AIX:   call void @_ZTH1a()
 // DARWIN: call cxx_fast_tlscc void @_ZTH1a()
 // CHECK:   ret i32* @a
 // CHECK: }
@@ -336,11 +378,23 @@
 // CHECK-NOT: define {{.*}} @_ZTWL1d()
 
 // LINUX-LABEL: define weak_odr hidden i32* @_ZTWN1U1mE()
+// AIX-LABEL: define weak_odr hidden i32* @_ZTWN1U1mE()
 // DARWIN-LABEL: define cxx_fast_tlscc i32* @_ZTWN1U1mE()
 // LINUX: call void @_ZTHN1U1mE()
+// AIX: call void @_ZTHN1U1mE()
 // DARWIN: call cxx_fast_tlscc void @_ZTHN1U1mE()
 // CHECK: ret i32* @_ZN1U1mE
 
 // LINUX: declare extern_weak void @_ZTH1b() [[ATTR:#[0-9]+]]
+// AIX: declare extern_weak void @_ZTH1b() [[ATTR:#[0-9]+]]
+
+// AIX: define extern_weak void @_ZTHN1WIiE1mE(){{.*}} {
+// AIX-NEXT: ret void
+// AIX-NEXT: }
+// CHECK-NOT: @_ZTHN1WIfE1mE =
+// AIX: define extern_weak void @_ZTHN1WIfE1mE(){{.*}} {
+// AIX-NEXT: ret void
+// AIX-NEXT: }
 
 // LINUX: attributes [[ATTR]] = { {{.+}} }
+// AIX: attributes [[ATTR]] = { {{.+}} }
Index: clang/test/CodeGenCXX/cxx11-thread-local-visibility.cpp
===================================================================
--- clang/test/CodeGenCXX/cxx11-thread-local-visibility.cpp
+++ clang/test/CodeGenCXX/cxx11-thread-local-visibility.cpp
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck --check-prefix=LINUX %s
 // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-apple-darwin12 | FileCheck --check-prefix=DARWIN %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple powerpc64-unknown-aix-xcoff | FileCheck --check-prefix=AIX %s
 
 // Regression test for PR40327
 
@@ -12,6 +13,11 @@
 // DARWIN: @hidden_tls = internal thread_local global i32
 // DARWIN: define cxx_fast_tlscc i32* @_ZTW11default_tls()
 // DARWIN: define hidden cxx_fast_tlscc i32* @_ZTW10hidden_tls()
+//
+// AIX: @default_tls = thread_local global i32
+// AIX: @hidden_tls = thread_local global i32
+// AIX: define weak_odr hidden i32* @_ZTW11default_tls()
+// AIX: define weak_odr hidden i32* @_ZTW10hidden_tls()
 
 __attribute__((visibility("default"))) thread_local int default_tls;
 __attribute__((visibility("hidden"))) thread_local int hidden_tls;
Index: clang/test/CodeGenCXX/cxx11-thread-local-reference.cpp
===================================================================
--- clang/test/CodeGenCXX/cxx11-thread-local-reference.cpp
+++ clang/test/CodeGenCXX/cxx11-thread-local-reference.cpp
@@ -1,13 +1,16 @@
 // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-linux-gnu | FileCheck --check-prefix=CHECK --check-prefix=LINUX %s
 // RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple x86_64-apple-darwin12 | FileCheck --check-prefix=CHECK --check-prefix=DARWIN %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple powerpc64-unknown-aix-xcoff | FileCheck --check-prefix=CHECK --check-prefix=AIX %s
 
 int &f();
 
 // LINUX: @r ={{.*}} thread_local global i32* null
+// AIX: @r ={{.*}} thread_local global i32* null
 // DARWIN: @r = internal thread_local global i32* null
 thread_local int &r = f();
 
 // LINUX: @_ZTH1r ={{.*}} alias void (), void ()* @__tls_init
+// AIXX: @_ZTH1r ={{.*}} alias void (), void ()* @__tls_init
 // DARWIN: @_ZTH1r = internal alias void (), void ()* @__tls_init
 
 int &g() { return r; }
@@ -18,19 +21,24 @@
 
 // CHECK-LABEL: define{{.*}} nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) i32* @_Z1gv()
 // LINUX: call i32* @_ZTW1r()
+// AIX: call i32* @_ZTW1r()
 // DARWIN: call cxx_fast_tlscc i32* @_ZTW1r()
 // CHECK: ret i32* %{{.*}}
 
 // LINUX: define weak_odr hidden i32* @_ZTW1r() [[ATTR0:#[0-9]+]] comdat {
+// AIX: define weak_odr hidden i32* @_ZTW1r() [[ATTR0:#[0-9]+]] {
 // DARWIN: define cxx_fast_tlscc i32* @_ZTW1r() [[ATTR1:#[0-9]+]] {
 // LINUX: call void @_ZTH1r()
+// AIX: call void @_ZTH1r()
 // DARWIN: call cxx_fast_tlscc void @_ZTH1r()
 // CHECK: load i32*, i32** @r, align 8
 // CHECK: ret i32* %{{.*}}
 
 // LINUX-LABEL: define internal void @__tls_init()
+// AIX-LABEL: define internal void @__tls_init()
 // DARWIN-LABEL: define internal cxx_fast_tlscc void @__tls_init()
 // CHECK: call void @[[R_INIT]]()
 
 // LINUX: attributes [[ATTR0]] = { {{.*}}"target-features"{{.*}} }
+// AIX: attributes [[ATTR0]] = { {{.*}}"target-features"{{.*}} }
 // DARWIN: attributes [[ATTR1]] = { {{.*}}nounwind{{.*}}"target-features"{{.*}}  }
Index: clang/lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -337,14 +337,16 @@
   /// Determine whether we will definitely emit this variable with a constant
   /// initializer, either because the language semantics demand it or because
   /// we know that the initializer is a constant.
-  bool isEmittedWithConstantInitializer(const VarDecl *VD) const {
+  // Ignore all attributes except ConstInit when IgnoreAttrs is true.
+  bool isEmittedWithConstantInitializer(const VarDecl *VD,
+                                        bool IgnoreAttrs = false) const {
     VD = VD->getMostRecentDecl();
     if (VD->hasAttr<ConstInitAttr>())
       return true;
 
     // All later checks examine the initializer specified on the variable. If
     // the variable is weak, such examination would not be correct.
-    if (VD->isWeak() || VD->hasAttr<SelectAnyAttr>())
+    if (!IgnoreAttrs && (VD->isWeak() || VD->hasAttr<SelectAnyAttr>()))
       return false;
 
     const VarDecl *InitDecl = VD->getInitializingDeclaration();
@@ -2551,6 +2553,8 @@
 static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
                                         llvm::FunctionCallee dtor,
                                         llvm::Constant *addr, bool TLS) {
+  assert(!CGF.getTarget().getTriple().isOSAIX() &&
+         "unexpected call to emitGlobalDtorWithCXAAtExit");
   assert((TLS || CGF.getTypes().getCodeGenOpts().CXAAtExit) &&
          "__cxa_atexit is disabled");
   const char *Name = "__cxa_atexit";
@@ -2956,6 +2960,32 @@
     }
 
     llvm::LLVMContext &Context = CGM.getModule().getContext();
+
+    // The linker on AIX is not happy with missing weak symbols.  However,
+    // other TUs will not know whether the initialization routine exists
+    // so create a weak, empty, init function to satisfy the linker.
+    // This is needed whenever a thread wrapper function is not used, and
+    // also when the symbol is weak.
+    if (CGM.getTriple().isOSAIX() &&
+        isEmittedWithConstantInitializer(VD, true) &&
+        !VD->needsDestruction(getContext())) {
+      // Emit a weak global function referring to the initialization function.
+      // This function will not exist if the TU defining the thread_local
+      // variable in question does not need any dynamic initialization for
+      // its thread_local variables.
+      llvm::Function *Func = llvm::Function::Create(
+          InitFnTy, llvm::GlobalVariable::ExternalWeakLinkage, InitFnName.str(),
+          &CGM.getModule());
+      const CGFunctionInfo &FI = CGM.getTypes().arrangeNullaryFunction();
+      CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI,
+                                    cast<llvm::Function>(Func),
+                                    /*IsThunk=*/false);
+      // Create a function body that just returns
+      llvm::BasicBlock *Entry = llvm::BasicBlock::Create(Context, "", Func);
+      CGBuilderTy Builder(CGM, Entry);
+      Builder.CreateRetVoid();
+    }
+
     llvm::BasicBlock *Entry = llvm::BasicBlock::Create(Context, "", Wrapper);
     CGBuilderTy Builder(CGM, Entry);
     if (HasConstantInitialization) {
@@ -2970,7 +3000,14 @@
           Fn->setCallingConv(llvm::CallingConv::CXX_FAST_TLS);
         }
       }
-    } else {
+    } else if (CGM.getTriple().isOSAIX())
+      // On AIX, all thread_local vars will have init routines regardless of
+      // whether they are const-initialized or not.  Since the routine is
+      // guaranteed to exist, we can unconditionally call it without testing
+      // for its existance.  This avoids potentially unresolved weak symbols
+      // which the AIX linker isn't happy with.
+      Builder.CreateCall(InitFnTy, Init);
+    else {
       // Don't know whether we have an init function. Call it if it exists.
       llvm::Value *Have = Builder.CreateIsNotNull(Init);
       llvm::BasicBlock *InitBB = llvm::BasicBlock::Create(Context, "", Wrapper);
@@ -4733,8 +4770,27 @@
 void XLCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
                                   llvm::FunctionCallee dtor,
                                   llvm::Constant *addr) {
-  if (D.getTLSKind() != VarDecl::TLS_None)
-    llvm::report_fatal_error("thread local storage not yet implemented on AIX");
+  if (D.getTLSKind() != VarDecl::TLS_None) {
+    // atexit routine expects "int(*)(int,...)"
+    llvm::Type *FpTy =
+        llvm::FunctionType::get(CGM.IntTy, CGM.IntTy, true)->getPointerTo();
+
+    // extern "C" int __pt_atexit_np(int flags, int(*)(int,...), ...);
+    llvm::FunctionType *AtExitTy =
+        llvm::FunctionType::get(CGM.IntTy, {CGM.IntTy, FpTy}, true);
+
+    // Fetch the actual function.
+    llvm::FunctionCallee AtExit =
+        CGM.CreateRuntimeFunction(AtExitTy, "__pt_atexit_np");
+
+    // First param is flags and must be 0
+    llvm::Value *Arg1 = llvm::Constant::getNullValue(CGM.IntTy);
+    // Second param is function ptr
+    llvm::Value *Arg2 = llvm::ConstantExpr::getBitCast(
+        cast<llvm::Constant>(dtor.getCallee()), FpTy);
+    CGF.EmitNounwindRuntimeCall(AtExit, {Arg1, Arg2});
+    return;
+  }
 
   // Create __dtor function for the var decl.
   llvm::Function *dtorStub = CGF.createAtExitStub(D, dtor, addr);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to