зеркало из https://github.com/microsoft/clang-1.git
Implement ARM static local initialization guards, which are more compact than
Itanium guards and use a slightly different compiled-in API. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@113330 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
607a1788d9
Коммит
5cd91b5134
|
@ -321,7 +321,7 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
|
|||
/// Implementation for CGCXXABI. Possibly this should be moved into
|
||||
/// the incomplete ABI implementations?
|
||||
|
||||
CGCXXABI::~CGCXXABI() {}
|
||||
void CGCXXABI::_anchor() {}
|
||||
|
||||
static void ErrorUnsupportedABI(CodeGenFunction &CGF,
|
||||
llvm::StringRef S) {
|
||||
|
@ -469,3 +469,9 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
|
|||
AllocPtr = llvm::Constant::getNullValue(CGF.Builder.getInt8PtrTy());
|
||||
CookieSize = CharUnits::Zero();
|
||||
}
|
||||
|
||||
void CGCXXABI::EmitStaticLocalInit(CodeGenFunction &CGF,
|
||||
const VarDecl &D,
|
||||
llvm::GlobalVariable *GV) {
|
||||
ErrorUnsupportedABI(CGF, "static local variable initialization");
|
||||
}
|
||||
|
|
|
@ -69,9 +69,11 @@ protected:
|
|||
|
||||
ASTContext &getContext() const { return CGM.getContext(); }
|
||||
|
||||
virtual void _anchor();
|
||||
|
||||
public:
|
||||
|
||||
virtual ~CGCXXABI();
|
||||
virtual ~CGCXXABI() {}
|
||||
|
||||
/// Gets the mangle context.
|
||||
virtual MangleContext &getMangleContext() = 0;
|
||||
|
@ -217,6 +219,14 @@ public:
|
|||
QualType ElementType, llvm::Value *&NumElements,
|
||||
llvm::Value *&AllocPtr, CharUnits &CookieSize);
|
||||
|
||||
/*************************** Static local guards ****************************/
|
||||
|
||||
/// Emits the initializer and destructor setup for the given static
|
||||
/// local variable, given that it's reachable and couldn't be
|
||||
/// emitted as a constant.
|
||||
virtual void EmitStaticLocalInit(CodeGenFunction &CGF, const VarDecl &D,
|
||||
llvm::GlobalVariable *DeclPtr);
|
||||
|
||||
};
|
||||
|
||||
/// Creates an instance of a C++ ABI class.
|
||||
|
|
|
@ -189,12 +189,12 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D,
|
|||
if (!Init) {
|
||||
if (!getContext().getLangOptions().CPlusPlus)
|
||||
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
|
||||
else {
|
||||
else if (Builder.GetInsertBlock()) {
|
||||
// Since we have a static initializer, this global variable can't
|
||||
// be constant.
|
||||
GV->setConstant(false);
|
||||
|
||||
EmitStaticCXXBlockVarDeclInit(D, GV);
|
||||
|
||||
EmitCXXStaticLocalInit(D, GV);
|
||||
}
|
||||
return GV;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
|
|||
}
|
||||
}
|
||||
|
||||
/// Emit code to cause the destruction of the given variable with
|
||||
/// static storage duration.
|
||||
static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
|
||||
llvm::Constant *DeclPtr) {
|
||||
CodeGenModule &CGM = CGF.CGM;
|
||||
|
@ -138,6 +140,11 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
|
|||
Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitCXXStaticLocalInit(const VarDecl &D,
|
||||
llvm::GlobalVariable *DeclPtr) {
|
||||
CGM.getCXXABI().EmitStaticLocalInit(*this, D, DeclPtr);
|
||||
}
|
||||
|
||||
static llvm::Function *
|
||||
CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
|
||||
const llvm::FunctionType *FTy,
|
||||
|
@ -283,143 +290,6 @@ void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
|
|||
FinishFunction();
|
||||
}
|
||||
|
||||
static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) {
|
||||
// int __cxa_guard_acquire(__int64_t *guard_object);
|
||||
|
||||
const llvm::Type *Int64PtrTy =
|
||||
llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
|
||||
|
||||
std::vector<const llvm::Type*> Args(1, Int64PtrTy);
|
||||
|
||||
const llvm::FunctionType *FTy =
|
||||
llvm::FunctionType::get(CGF.ConvertType(CGF.getContext().IntTy),
|
||||
Args, /*isVarArg=*/false);
|
||||
|
||||
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire");
|
||||
}
|
||||
|
||||
static llvm::Constant *getGuardReleaseFn(CodeGenFunction &CGF) {
|
||||
// void __cxa_guard_release(__int64_t *guard_object);
|
||||
|
||||
const llvm::Type *Int64PtrTy =
|
||||
llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
|
||||
|
||||
std::vector<const llvm::Type*> Args(1, Int64PtrTy);
|
||||
|
||||
const llvm::FunctionType *FTy =
|
||||
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
|
||||
Args, /*isVarArg=*/false);
|
||||
|
||||
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release");
|
||||
}
|
||||
|
||||
static llvm::Constant *getGuardAbortFn(CodeGenFunction &CGF) {
|
||||
// void __cxa_guard_abort(__int64_t *guard_object);
|
||||
|
||||
const llvm::Type *Int64PtrTy =
|
||||
llvm::Type::getInt64PtrTy(CGF.getLLVMContext());
|
||||
|
||||
std::vector<const llvm::Type*> Args(1, Int64PtrTy);
|
||||
|
||||
const llvm::FunctionType *FTy =
|
||||
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
|
||||
Args, /*isVarArg=*/false);
|
||||
|
||||
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort");
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct CallGuardAbort : EHScopeStack::Cleanup {
|
||||
llvm::GlobalVariable *Guard;
|
||||
CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
|
||||
|
||||
void Emit(CodeGenFunction &CGF, bool IsForEH) {
|
||||
// It shouldn't be possible for this to throw, but if it can,
|
||||
// this should allow for the possibility of an invoke.
|
||||
CGF.Builder.CreateCall(getGuardAbortFn(CGF), Guard)
|
||||
->setDoesNotThrow();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
|
||||
llvm::GlobalVariable *GV) {
|
||||
// Bail out early if this initializer isn't reachable.
|
||||
if (!Builder.GetInsertBlock()) return;
|
||||
|
||||
bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics;
|
||||
|
||||
llvm::SmallString<256> GuardVName;
|
||||
CGM.getCXXABI().getMangleContext().mangleGuardVariable(&D, GuardVName);
|
||||
|
||||
// Create the guard variable.
|
||||
llvm::GlobalVariable *GuardVariable =
|
||||
new llvm::GlobalVariable(CGM.getModule(), Int64Ty,
|
||||
false, GV->getLinkage(),
|
||||
llvm::Constant::getNullValue(Int64Ty),
|
||||
GuardVName.str());
|
||||
|
||||
// Load the first byte of the guard variable.
|
||||
const llvm::Type *PtrTy
|
||||
= llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
|
||||
llvm::Value *V =
|
||||
Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp");
|
||||
|
||||
llvm::BasicBlock *InitCheckBlock = createBasicBlock("init.check");
|
||||
llvm::BasicBlock *EndBlock = createBasicBlock("init.end");
|
||||
|
||||
// Check if the first byte of the guard variable is zero.
|
||||
Builder.CreateCondBr(Builder.CreateIsNull(V, "tobool"),
|
||||
InitCheckBlock, EndBlock);
|
||||
|
||||
EmitBlock(InitCheckBlock);
|
||||
|
||||
// Variables used when coping with thread-safe statics and exceptions.
|
||||
if (ThreadsafeStatics) {
|
||||
// Call __cxa_guard_acquire.
|
||||
V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable);
|
||||
|
||||
llvm::BasicBlock *InitBlock = createBasicBlock("init");
|
||||
|
||||
Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"),
|
||||
InitBlock, EndBlock);
|
||||
|
||||
// Call __cxa_guard_abort along the exceptional edge.
|
||||
if (Exceptions)
|
||||
EHStack.pushCleanup<CallGuardAbort>(EHCleanup, GuardVariable);
|
||||
|
||||
EmitBlock(InitBlock);
|
||||
}
|
||||
|
||||
if (D.getType()->isReferenceType()) {
|
||||
unsigned Alignment = getContext().getDeclAlign(&D).getQuantity();
|
||||
QualType T = D.getType();
|
||||
RValue RV = EmitReferenceBindingToExpr(D.getInit(), &D);
|
||||
EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, Alignment, T);
|
||||
} else
|
||||
EmitDeclInit(*this, D, GV);
|
||||
|
||||
if (ThreadsafeStatics) {
|
||||
// Pop the guard-abort cleanup if we pushed one.
|
||||
if (Exceptions)
|
||||
PopCleanupBlock();
|
||||
|
||||
// Call __cxa_guard_release. This cannot throw.
|
||||
Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);
|
||||
} else {
|
||||
llvm::Value *One =
|
||||
llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1);
|
||||
Builder.CreateStore(One, Builder.CreateBitCast(GuardVariable, PtrTy));
|
||||
}
|
||||
|
||||
// Register the call to the destructor.
|
||||
if (!D.getType()->isReferenceType())
|
||||
EmitDeclDestroy(*this, D, GV);
|
||||
|
||||
EmitBlock(EndBlock);
|
||||
}
|
||||
|
||||
/// GenerateCXXAggrDestructorHelper - Generates a helper function which when
|
||||
/// invoked, calls the default destructor on array elements in reverse order of
|
||||
/// construction.
|
||||
|
|
|
@ -1565,11 +1565,6 @@ public:
|
|||
llvm::GlobalVariable *GV);
|
||||
|
||||
|
||||
/// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ runtime
|
||||
/// initialized static block var decl.
|
||||
void EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
|
||||
llvm::GlobalVariable *GV);
|
||||
|
||||
/// EmitCXXGlobalVarDeclInit - Create the initializer for a C++
|
||||
/// variable with global storage.
|
||||
void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr);
|
||||
|
@ -1579,6 +1574,8 @@ public:
|
|||
void EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
|
||||
llvm::Constant *DeclPtr);
|
||||
|
||||
void EmitCXXStaticLocalInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr);
|
||||
|
||||
/// GenerateCXXGlobalInitFunc - Generates code for initializing global
|
||||
/// variables.
|
||||
void GenerateCXXGlobalInitFunc(llvm::Function *Fn,
|
||||
|
|
|
@ -119,6 +119,9 @@ public:
|
|||
void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
|
||||
QualType ElementType, llvm::Value *&NumElements,
|
||||
llvm::Value *&AllocPtr, CharUnits &CookieSize);
|
||||
|
||||
void EmitStaticLocalInit(CodeGenFunction &CGF, const VarDecl &D,
|
||||
llvm::GlobalVariable *DeclPtr);
|
||||
};
|
||||
|
||||
class ARMCXXABI : public ItaniumCXXABI {
|
||||
|
@ -1021,3 +1024,159 @@ void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
|
|||
NumElements = CGF.Builder.CreateLoad(NumElementsPtr);
|
||||
}
|
||||
|
||||
/*********************** Static local initialization **************************/
|
||||
|
||||
static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM,
|
||||
const llvm::PointerType *GuardPtrTy) {
|
||||
// int __cxa_guard_acquire(__guard *guard_object);
|
||||
|
||||
std::vector<const llvm::Type*> Args(1, GuardPtrTy);
|
||||
const llvm::FunctionType *FTy =
|
||||
llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy),
|
||||
Args, /*isVarArg=*/false);
|
||||
|
||||
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire");
|
||||
}
|
||||
|
||||
static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM,
|
||||
const llvm::PointerType *GuardPtrTy) {
|
||||
// void __cxa_guard_release(__guard *guard_object);
|
||||
|
||||
std::vector<const llvm::Type*> Args(1, GuardPtrTy);
|
||||
|
||||
const llvm::FunctionType *FTy =
|
||||
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
|
||||
Args, /*isVarArg=*/false);
|
||||
|
||||
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release");
|
||||
}
|
||||
|
||||
static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM,
|
||||
const llvm::PointerType *GuardPtrTy) {
|
||||
// void __cxa_guard_abort(__guard *guard_object);
|
||||
|
||||
std::vector<const llvm::Type*> Args(1, GuardPtrTy);
|
||||
|
||||
const llvm::FunctionType *FTy =
|
||||
llvm::FunctionType::get(llvm::Type::getVoidTy(CGM.getLLVMContext()),
|
||||
Args, /*isVarArg=*/false);
|
||||
|
||||
return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort");
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct CallGuardAbort : EHScopeStack::Cleanup {
|
||||
llvm::GlobalVariable *Guard;
|
||||
CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {}
|
||||
|
||||
void Emit(CodeGenFunction &CGF, bool IsForEH) {
|
||||
CGF.Builder.CreateCall(getGuardAbortFn(CGF.CGM, Guard->getType()), Guard)
|
||||
->setDoesNotThrow();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// The ARM code here follows the Itanium code closely enough that we
|
||||
/// just special-case it at particular places.
|
||||
void ItaniumCXXABI::EmitStaticLocalInit(CodeGenFunction &CGF,
|
||||
const VarDecl &D,
|
||||
llvm::GlobalVariable *GV) {
|
||||
CGBuilderTy &Builder = CGF.Builder;
|
||||
bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics;
|
||||
|
||||
// Guard variables are 64 bits in the generic ABI and 32 bits on ARM.
|
||||
const llvm::IntegerType *GuardTy
|
||||
= (IsARM ? Builder.getInt32Ty() : Builder.getInt64Ty());
|
||||
const llvm::PointerType *GuardPtrTy = GuardTy->getPointerTo();
|
||||
|
||||
// Create the guard variable.
|
||||
llvm::SmallString<256> GuardVName;
|
||||
getMangleContext().mangleItaniumGuardVariable(&D, GuardVName);
|
||||
llvm::GlobalVariable *GuardVariable =
|
||||
new llvm::GlobalVariable(CGM.getModule(), GuardTy,
|
||||
false, GV->getLinkage(),
|
||||
llvm::ConstantInt::get(GuardTy, 0),
|
||||
GuardVName.str());
|
||||
|
||||
// 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 (IsARM) {
|
||||
llvm::Value *V = Builder.CreateLoad(GuardVariable);
|
||||
V = Builder.CreateAnd(V, Builder.getInt32(1));
|
||||
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) {
|
||||
// if ( __cxa_guard_acquire (&obj_guard) ) {
|
||||
// try {
|
||||
// ... initialize the object ...;
|
||||
// } catch (...) {
|
||||
// __cxa_guard_abort (&obj_guard);
|
||||
// throw;
|
||||
// }
|
||||
// ... queue object destructor with __cxa_atexit() ...;
|
||||
// __cxa_guard_release (&obj_guard);
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
// Load the first byte of the guard variable.
|
||||
const llvm::Type *PtrTy = Builder.getInt8PtrTy();
|
||||
llvm::Value *V =
|
||||
Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp");
|
||||
|
||||
IsInitialized = Builder.CreateIsNull(V, "guard.uninitialized");
|
||||
}
|
||||
|
||||
llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check");
|
||||
llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end");
|
||||
|
||||
// Check if the first byte of the guard variable is zero.
|
||||
Builder.CreateCondBr(IsInitialized, InitCheckBlock, EndBlock);
|
||||
|
||||
CGF.EmitBlock(InitCheckBlock);
|
||||
|
||||
// Variables used when coping with thread-safe statics and exceptions.
|
||||
if (ThreadsafeStatics) {
|
||||
// Call __cxa_guard_acquire.
|
||||
llvm::Value *V
|
||||
= Builder.CreateCall(getGuardAcquireFn(CGM, GuardPtrTy), GuardVariable);
|
||||
|
||||
llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init");
|
||||
|
||||
Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"),
|
||||
InitBlock, EndBlock);
|
||||
|
||||
// Call __cxa_guard_abort along the exceptional edge.
|
||||
CGF.EHStack.pushCleanup<CallGuardAbort>(EHCleanup, GuardVariable);
|
||||
|
||||
CGF.EmitBlock(InitBlock);
|
||||
}
|
||||
|
||||
// Emit the initializer and add a global destructor if appropriate.
|
||||
CGF.EmitCXXGlobalVarDeclInit(D, GV);
|
||||
|
||||
if (ThreadsafeStatics) {
|
||||
// Pop the guard-abort cleanup if we pushed one.
|
||||
CGF.PopCleanupBlock();
|
||||
|
||||
// Call __cxa_guard_release. This cannot throw.
|
||||
Builder.CreateCall(getGuardReleaseFn(CGM, GuardPtrTy), GuardVariable);
|
||||
} else {
|
||||
Builder.CreateStore(llvm::ConstantInt::get(GuardTy, 1), GuardVariable);
|
||||
}
|
||||
|
||||
CGF.EmitBlock(EndBlock);
|
||||
}
|
||||
|
|
|
@ -2451,8 +2451,8 @@ MangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
|
|||
|
||||
/// mangleGuardVariable - Returns the mangled name for a guard variable
|
||||
/// for the passed in VarDecl.
|
||||
void MangleContext::mangleGuardVariable(const VarDecl *D,
|
||||
llvm::SmallVectorImpl<char> &Res) {
|
||||
void MangleContext::mangleItaniumGuardVariable(const VarDecl *D,
|
||||
llvm::SmallVectorImpl<char> &Res) {
|
||||
// <special-name> ::= GV <object name> # Guard variable for one-time
|
||||
// # initialization
|
||||
CXXNameMangler Mangler(*this, Res);
|
||||
|
|
|
@ -119,8 +119,6 @@ public:
|
|||
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
|
||||
const ThisAdjustment &ThisAdjustment,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
virtual void mangleGuardVariable(const VarDecl *D,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
virtual void mangleReferenceTemporary(const VarDecl *D,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
|
||||
|
@ -139,6 +137,10 @@ public:
|
|||
void mangleBlock(GlobalDecl GD,
|
||||
const BlockDecl *BD, llvm::SmallVectorImpl<char> &);
|
||||
|
||||
// This is pretty lame.
|
||||
void mangleItaniumGuardVariable(const VarDecl *D,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
|
||||
void mangleInitDiscriminator() {
|
||||
Discriminator = 0;
|
||||
}
|
||||
|
|
|
@ -91,8 +91,6 @@ public:
|
|||
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
|
||||
const ThisAdjustment &ThisAdjustment,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
virtual void mangleGuardVariable(const VarDecl *D,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
virtual void mangleCXXVTable(const CXXRecordDecl *RD,
|
||||
llvm::SmallVectorImpl<char> &);
|
||||
virtual void mangleCXXVTT(const CXXRecordDecl *RD,
|
||||
|
@ -1175,10 +1173,6 @@ void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
|
|||
llvm::SmallVectorImpl<char> &) {
|
||||
assert(false && "Can't yet mangle destructor thunks!");
|
||||
}
|
||||
void MicrosoftMangleContext::mangleGuardVariable(const VarDecl *D,
|
||||
llvm::SmallVectorImpl<char> &) {
|
||||
assert(false && "Can't yet mangle guard variables!");
|
||||
}
|
||||
void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
|
||||
llvm::SmallVectorImpl<char> &) {
|
||||
assert(false && "Can't yet mangle virtual tables!");
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
// RUN: %clang_cc1 %s -triple=thumbv7-apple-darwin3.0.0-iphoneos -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -o - -fexceptions | FileCheck %s
|
||||
|
||||
// CHECK: @_ZZN5test74testEvE1x = internal global i32 0, align 4
|
||||
// CHECK: @_ZGVZN5test74testEvE1x = internal global i32 0
|
||||
// CHECK: @_ZZN5test84testEvE1x = internal global [[TEST8A:.*]] zeroinitializer, align 1
|
||||
// CHECK: @_ZGVZN5test84testEvE1x = internal global i32 0
|
||||
|
||||
typedef typeof(sizeof(int)) size_t;
|
||||
|
||||
class foo {
|
||||
|
@ -277,6 +282,76 @@ namespace test6 {
|
|||
}
|
||||
}
|
||||
|
||||
namespace test7 {
|
||||
int foo();
|
||||
|
||||
// Static and guard tested at top of file
|
||||
|
||||
// CHECK: 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-NEXT: br i1 [[T2]]
|
||||
// -> fallthrough, end
|
||||
// CHECK: [[T3:%.*]] = call i32 @__cxa_guard_acquire(i32* @_ZGVZN5test74testEvE1x)
|
||||
// CHECK-NEXT: [[T4:%.*]] = icmp ne i32 [[T3]], 0
|
||||
// CHECK-NEXT: br i1 [[T4]]
|
||||
// -> fallthrough, end
|
||||
// CHECK: [[INIT:%.*]] = invoke i32 @_ZN5test73fooEv()
|
||||
// CHECK: store i32 [[INIT]], i32* @_ZZN5test74testEvE1x, align 4
|
||||
// CHECK-NEXT: call void @__cxa_guard_release(i32* @_ZGVZN5test74testEvE1x)
|
||||
// CHECK-NEXT: br label
|
||||
// -> end
|
||||
// end:
|
||||
// CHECK: ret void
|
||||
static int x = foo();
|
||||
|
||||
// CHECK: call i8* @llvm.eh.exception()
|
||||
// CHECK: call void @__cxa_guard_abort(i32* @_ZGVZN5test74testEvE1x)
|
||||
// CHECK: call void @_Unwind_Resume_or_Rethrow
|
||||
}
|
||||
}
|
||||
|
||||
namespace test8 {
|
||||
struct A {
|
||||
A();
|
||||
~A();
|
||||
};
|
||||
|
||||
// Static and guard tested at top of file
|
||||
|
||||
// CHECK: 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-NEXT: br i1 [[T2]]
|
||||
// -> fallthrough, end
|
||||
// CHECK: [[T3:%.*]] = call i32 @__cxa_guard_acquire(i32* @_ZGVZN5test84testEvE1x)
|
||||
// CHECK-NEXT: [[T4:%.*]] = icmp ne i32 [[T3]], 0
|
||||
// CHECK-NEXT: br i1 [[T4]]
|
||||
// -> fallthrough, end
|
||||
// CHECK: [[INIT:%.*]] = invoke [[TEST8A]]* @_ZN5test81AC1Ev([[TEST8A]]* @_ZZN5test84testEvE1x)
|
||||
|
||||
// FIXME: Here we register a global destructor that
|
||||
// unconditionally calls the destructor. That's what we've always
|
||||
// done for -fno-use-cxa-atexit here, but that's really not
|
||||
// semantically correct at all.
|
||||
|
||||
// CHECK: call void @__cxa_guard_release(i32* @_ZGVZN5test84testEvE1x)
|
||||
// CHECK-NEXT: br label
|
||||
// -> end
|
||||
// end:
|
||||
// CHECK: ret void
|
||||
static A x;
|
||||
|
||||
// CHECK: call i8* @llvm.eh.exception()
|
||||
// CHECK: call void @__cxa_guard_abort(i32* @_ZGVZN5test84testEvE1x)
|
||||
// CHECK: call void @_Unwind_Resume_or_Rethrow
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK: define linkonce_odr [[C:%.*]]* @_ZTv0_n12_N5test21CD1Ev(
|
||||
// CHECK: call [[C]]* @_ZN5test21CD1Ev(
|
||||
// CHECK: ret [[C]]* undef
|
||||
|
|
|
@ -14,8 +14,8 @@ struct A {
|
|||
void f() {
|
||||
// CHECK: call i32 @__cxa_guard_acquire
|
||||
// CHECK: call void @_ZN1AC1Ev
|
||||
// CHECK: call void @__cxa_guard_release
|
||||
// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @_ZZ1fvE1a, i32 0, i32 0), i8* bitcast (i8** @__dso_handle to i8*))
|
||||
// CHECK: call void @__cxa_guard_release
|
||||
static A a;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ struct Y { };
|
|||
void f() {
|
||||
// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ1fvE1x)
|
||||
// CHECK: invoke void @_ZN1XC1Ev
|
||||
// CHECK: call void @__cxa_guard_release(i64* @_ZGVZ1fvE1x)
|
||||
// CHECK-NEXT: call i32 @__cxa_atexit
|
||||
// CHECK: call i32 @__cxa_atexit
|
||||
// CHECK-NEXT: call void @__cxa_guard_release(i64* @_ZGVZ1fvE1x)
|
||||
// CHECK: br
|
||||
static X x;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче