[FE] Manipulate the first byte of guard variable type in both load and store operation

As Itanium ABI[http://itanium-cxx-abi.github.io/cxx-abi/abi.html#once-ctor]
points out:

"The size of the guard variable is 64 bits. The first byte (i.e. the byte at
the address of the full variable) shall contain the value 0 prior to
initialization of the associated variable, and 1 after initialization is complete."

Differential Revision: https://reviews.llvm.org/D95822
This commit is contained in:
Xiangling Liao 2021-02-08 11:14:23 -05:00
parent ecc8ac3f08
commit 6b1e2fc893
6 changed files with 21 additions and 14 deletions

View File

@ -2472,7 +2472,10 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
CGF.EmitNounwindRuntimeCall(getGuardReleaseFn(CGM, guardPtrTy),
guardAddr.getPointer());
} else {
Builder.CreateStore(llvm::ConstantInt::get(guardTy, 1), guardAddr);
// Store 1 into the first byte of the guard variable after initialization is
// complete.
Builder.CreateStore(llvm::ConstantInt::get(CGM.Int8Ty, 1),
Builder.CreateElementBitCast(guardAddr, CGM.Int8Ty));
}
CGF.EmitBlock(EndBlock);

View File

@ -44,6 +44,9 @@ template <>
A<int> A<int>::instance = bar();
} // namespace test2
// CHECK: @_ZGVN5test12t2E = linkonce_odr global i64 0, align 8
// CHECK: @_ZGVN5test21AIvE8instanceE = weak_odr global i64 0, align 8
// CHECK: @_ZGVN5test12t1IiEE = linkonce_odr global i64 0, align 8
// CHECK: @llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.1, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.2, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.4, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I__, i8* null }]
// CHECK: @llvm.global_dtors = appending global [4 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__finalize__ZN5test12t2E, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__finalize__ZN5test21AIvE8instanceE, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @__finalize__ZN5test12t1IiEE, i8* null }, { i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__D_a, i8* null }]
@ -77,7 +80,7 @@ A<int> A<int>::instance = bar();
// CHECK: define internal void @__cxx_global_var_init.1() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: %0 = load atomic i8, i8* bitcast (i64* @_ZGVN5test12t2E to i8*) acquire
// CHECK: %0 = load atomic i8, i8* bitcast (i64* @_ZGVN5test12t2E to i8*) acquire, align 8
// CHECK: %guard.uninitialized = icmp eq i8 %0, 0
// CHECK: br i1 %guard.uninitialized, label %init.check, label %init.end
@ -119,14 +122,14 @@ A<int> A<int>::instance = bar();
// CHECK: define internal void @__cxx_global_var_init.2() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: %0 = load i8, i8* bitcast (i64* @_ZGVN5test21AIvE8instanceE to i8*)
// CHECK: %0 = load i8, i8* bitcast (i64* @_ZGVN5test21AIvE8instanceE to i8*), align 8
// CHECK: %guard.uninitialized = icmp eq i8 %0, 0
// CHECK: br i1 %guard.uninitialized, label %init.check, label %init.end
// CHECK: init.check:
// CHECK: call void @_ZN5test21AIvEC1Ev(%"struct.test2::A"* {{[^,]*}} @_ZN5test21AIvE8instanceE)
// CHECK: %1 = call i32 @atexit(void ()* @__dtor__ZN5test21AIvE8instanceE)
// CHECK: store i64 1, i64* @_ZGVN5test21AIvE8instanceE
// CHECK: store i8 1, i8* bitcast (i64* @_ZGVN5test21AIvE8instanceE to i8*), align 8
// CHECK: br label %init.end
// CHECK: init.end:
@ -182,7 +185,7 @@ A<int> A<int>::instance = bar();
// CHECK: define internal void @__cxx_global_var_init.4() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: %0 = load i8, i8* bitcast (i64* @_ZGVN5test12t1IiEE to i8*)
// CHECK: %0 = load i8, i8* bitcast (i64* @_ZGVN5test12t1IiEE to i8*), align 8
// CHECK: %guard.uninitialized = icmp eq i8 %0, 0
// CHECK: br i1 %guard.uninitialized, label %init.check, label %init.end
@ -190,7 +193,7 @@ A<int> A<int>::instance = bar();
// CHECK32: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* {{[^,]*}} @_ZN5test12t1IiEE, i32 2)
// CHECK64: call void @_ZN5test15Test1C1Ei(%"struct.test1::Test1"* {{[^,]*}} @_ZN5test12t1IiEE, i32 signext 2)
// CHECK: %1 = call i32 @atexit(void ()* @__dtor__ZN5test12t1IiEE)
// CHECK: store i64 1, i64* @_ZGVN5test12t1IiEE
// CHECK: store i8 1, i8* bitcast (i64* @_ZGVN5test12t1IiEE to i8*), align 8
// CHECK: br label %init.end
// CHECK: init.end:

View File

@ -38,6 +38,7 @@ namespace test4 {
}
} // namespace test4
// CHECK: @_ZGVZN5test41fEvE11staticLocal = internal global i64 0, align 8
// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__sub_I__, i8* null }]
// CHECK: @llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @_GLOBAL__D_a, i8* null }]
@ -135,7 +136,7 @@ namespace test4 {
// CHECK: define void @_ZN5test41fEv() [[ATTR:#[0-9]+]] {
// CHECK: entry:
// CHECK: %0 = load atomic i8, i8* bitcast (i64* @_ZGVZN5test41fEvE11staticLocal to i8*) acquire
// CHECK: %0 = load atomic i8, i8* bitcast (i64* @_ZGVZN5test41fEvE11staticLocal to i8*) acquire, align 8
// CHECK: %guard.uninitialized = icmp eq i8 %0, 0
// CHECK: br i1 %guard.uninitialized, label %init.check, label %init.end

View File

@ -184,7 +184,7 @@ int f() {
// need init:
// CHECK: call i32 @_Z1gv()
// CHECK: store i32 %{{.*}}, i32* @_ZN1VIfE1mE, align 4
// CHECK: store i64 1, i64* @_ZGVN1VIfE1mE
// CHECK: store i8 1, i8* bitcast (i64* @_ZGVN1VIfE1mE to i8*)
// CHECK: br label
// LINUX: define internal void @[[XF_M_INIT]]()
@ -197,7 +197,7 @@ int f() {
// need init:
// LINUX: call {{.*}}__cxa_thread_atexit
// DARWIN: call {{.*}}_tlv_atexit
// CHECK: store i64 1, i64* @_ZGVN1XIfE1mE
// CHECK: store i8 1, i8* bitcast (i64* @_ZGVN1XIfE1mE to i8*)
// CHECK: br label
// LINUX: declare i32 @__cxa_thread_atexit(void (i8*)*, i8*, i8*)
@ -285,7 +285,7 @@ void set_anon_i() {
// need init:
// CHECK: call i32 @_Z1gv()
// CHECK: store i32 %{{.*}}, i32* @_ZN1VIiE1mE, align 4
// CHECK: store i64 1, i64* @_ZGVN1VIiE1mE
// CHECK: store i8 1, i8* bitcast (i64* @_ZGVN1VIiE1mE to i8*)
// CHECK: br label
// LINUX: define internal void @[[X_M_INIT]]()
@ -298,7 +298,7 @@ void set_anon_i() {
// need init:
// LINUX: call {{.*}}__cxa_thread_atexit
// DARWIN: call {{.*}}_tlv_atexit
// CHECK: store i64 1, i64* @_ZGVN1XIiE1mE
// CHECK: store i8 1, i8* bitcast (i64* @_ZGVN1XIiE1mE to i8*)
// CHECK: br label
// CHECK: define {{.*}}@[[GLOBAL_INIT:.*]]()

View File

@ -78,10 +78,10 @@ namespace test4 {
extern int foo();
// This needs an initialization function and guard variables.
// CHECK: load i8, i8* bitcast (i64* @_ZGVN5test41xE
// CHECK: load i8, i8* bitcast (i64* @_ZGVN5test41xE to i8*)
// CHECK: [[CALL:%.*]] = call i32 @_ZN5test43fooEv
// CHECK-NEXT: store i32 [[CALL]], i32* @_ZN5test41xE
// CHECK-NEXT: store i64 1, i64* @_ZGVN5test41xE
// CHECK-NEXT: store i8 1, i8* bitcast (i64* @_ZGVN5test41xE to i8*)
__attribute__((weak)) int x = foo();
}

View File

@ -72,7 +72,7 @@ namespace test3 {
// CHECK-NEXT: br i1 [[UNINITIALIZED]]
// CHECK: [[TMP:%.*]] = call i32 @_ZN5test33fooEv()
// CHECK-NEXT: store i32 [[TMP]], i32* @_ZN5test31AIiE1xE, align 4
// CHECK-NEXT: store i64 1, i64* @_ZGVN5test31AIiE1xE
// CHECK-NEXT: store i8 1, i8* bitcast (i64* @_ZGVN5test31AIiE1xE to i8*)
// CHECK-NEXT: br label
// CHECK: ret void
}