diff options
| -rw-r--r-- | clang/lib/CodeGen/ItaniumCXXABI.cpp | 80 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/aarch64-cxxabi.cpp | 4 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/arm.cpp | 12 |
3 files changed, 47 insertions, 49 deletions
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 27825ab85d6..4b1c1c255af 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -1393,25 +1393,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, } // Test whether the variable has completed initialization. - llvm::Value *isInitialized; - - // ARM C++ ABI 3.2.3.1: - // To support the potential use of initialization guard variables - // as semaphores that are the target of ARM SWP and LDREX/STREX - // synchronizing instructions we define a static initialization - // guard variable to be a 4-byte aligned, 4- byte word with the - // following inline access protocol. - // #define INITIALIZED 1 - // if ((obj_guard & INITIALIZED) != INITIALIZED) { - // if (__cxa_guard_acquire(&obj_guard)) - // ... - // } - if (UseARMGuardVarABI && !useInt8GuardVariable) { - llvm::Value *V = Builder.CreateLoad(guard); - llvm::Value *Test1 = llvm::ConstantInt::get(guardTy, 1); - V = Builder.CreateAnd(V, Test1); - isInitialized = Builder.CreateIsNull(V, "guard.uninitialized"); - + // // Itanium C++ ABI 3.3.2: // The following is pseudo-code showing how these functions can be used: // if (obj_guard.first_byte == 0) { @@ -1427,29 +1409,45 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // } // } - // ARM64 C++ ABI 3.2.2: - // This ABI instead only specifies the value bit 0 of the static guard - // variable; all other bits are platform defined. Bit 0 shall be 0 when the - // variable is not initialized and 1 when it is. - // FIXME: Reading one bit is no more efficient than reading one byte so - // the codegen is same as generic Itanium ABI. - } else { - // Load the first byte of the guard variable. - llvm::LoadInst *LI = + // Load the first byte of the guard variable. + llvm::LoadInst *LI = Builder.CreateLoad(Builder.CreateBitCast(guard, CGM.Int8PtrTy)); - LI->setAlignment(1); - - // Itanium ABI: - // An implementation supporting thread-safety on multiprocessor - // systems must also guarantee that references to the initialized - // object do not occur before the load of the initialization flag. - // - // In LLVM, we do this by marking the load Acquire. - if (threadsafe) - LI->setAtomic(llvm::Acquire); - - isInitialized = Builder.CreateIsNull(LI, "guard.uninitialized"); - } + LI->setAlignment(1); + + // Itanium ABI: + // An implementation supporting thread-safety on multiprocessor + // systems must also guarantee that references to the initialized + // object do not occur before the load of the initialization flag. + // + // In LLVM, we do this by marking the load Acquire. + if (threadsafe) + LI->setAtomic(llvm::Acquire); + + // For ARM, we should only check the first bit, rather than the entire byte: + // + // ARM C++ ABI 3.2.3.1: + // To support the potential use of initialization guard variables + // as semaphores that are the target of ARM SWP and LDREX/STREX + // synchronizing instructions we define a static initialization + // guard variable to be a 4-byte aligned, 4-byte word with the + // following inline access protocol. + // #define INITIALIZED 1 + // if ((obj_guard & INITIALIZED) != INITIALIZED) { + // if (__cxa_guard_acquire(&obj_guard)) + // ... + // } + // + // and similarly for ARM64: + // + // ARM64 C++ ABI 3.2.2: + // This ABI instead only specifies the value bit 0 of the static guard + // variable; all other bits are platform defined. Bit 0 shall be 0 when the + // variable is not initialized and 1 when it is. + llvm::Value *V = + (UseARMGuardVarABI && !useInt8GuardVariable) + ? Builder.CreateAnd(LI, llvm::ConstantInt::get(CGM.Int8Ty, 1)) + : LI; + llvm::Value *isInitialized = Builder.CreateIsNull(V, "guard.uninitialized"); llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); diff --git a/clang/test/CodeGenCXX/aarch64-cxxabi.cpp b/clang/test/CodeGenCXX/aarch64-cxxabi.cpp index 04d9493ae6b..c7d910d5f00 100644 --- a/clang/test/CodeGenCXX/aarch64-cxxabi.cpp +++ b/clang/test/CodeGenCXX/aarch64-cxxabi.cpp @@ -40,8 +40,8 @@ public: void guard_variables(int a) { static Guarded mine(a); -// CHECK: [[GUARDBIT:%[0-9]+]] = and i64 {{%[0-9]+}}, 1 -// CHECK: icmp eq i64 [[GUARDBIT]], 0 +// CHECK: [[GUARDBIT:%[0-9]+]] = and i8 {{%[0-9]+}}, 1 +// CHECK: icmp eq i8 [[GUARDBIT]], 0 // As guards are 64-bit, these helpers should take 64-bit pointers. // CHECK: call i32 @__cxa_guard_acquire(i64* diff --git a/clang/test/CodeGenCXX/arm.cpp b/clang/test/CodeGenCXX/arm.cpp index 2790199446d..b8d95991e2d 100644 --- a/clang/test/CodeGenCXX/arm.cpp +++ b/clang/test/CodeGenCXX/arm.cpp @@ -292,9 +292,9 @@ namespace test7 { // CHECK-LABEL: define void @_ZN5test74testEv() void test() { - // CHECK: [[T0:%.*]] = load i32* @_ZGVZN5test74testEvE1x - // CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], 1 - // CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0 + // CHECK: [[T0:%.*]] = load atomic i8* bitcast (i32* @_ZGVZN5test74testEvE1x to i8*) acquire, align 1 + // CHECK-NEXT: [[T1:%.*]] = and i8 [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = icmp eq i8 [[T1]], 0 // CHECK-NEXT: br i1 [[T2]] // -> fallthrough, end // CHECK: [[T3:%.*]] = call i32 @__cxa_guard_acquire(i32* @_ZGVZN5test74testEvE1x) @@ -327,9 +327,9 @@ namespace test8 { // CHECK-LABEL: define void @_ZN5test84testEv() void test() { - // CHECK: [[T0:%.*]] = load i32* @_ZGVZN5test84testEvE1x - // CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], 1 - // CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0 + // CHECK: [[T0:%.*]] = load atomic i8* bitcast (i32* @_ZGVZN5test84testEvE1x to i8*) acquire, align 1 + // CHECK-NEXT: [[T1:%.*]] = and i8 [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = icmp eq i8 [[T1]], 0 // CHECK-NEXT: br i1 [[T2]] // -> fallthrough, end // CHECK: [[T3:%.*]] = call i32 @__cxa_guard_acquire(i32* @_ZGVZN5test84testEvE1x) |

