diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-07-23 22:56:45 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2018-07-23 22:56:45 +0000 |
commit | f66e4f7dbd66ff3a9fdd33c4f6b21166ed8c5095 (patch) | |
tree | 98e51c27610797c99b881533987bb7adb9d1dde5 /clang/lib/CodeGen | |
parent | a3a462e5ca57789a5bc9f892f27a4d120f03b4c3 (diff) | |
download | bcm5719-llvm-f66e4f7dbd66ff3a9fdd33c4f6b21166ed8c5095.tar.gz bcm5719-llvm-f66e4f7dbd66ff3a9fdd33c4f6b21166ed8c5095.zip |
Support lifetime-extension of conditional temporaries.
llvm-svn: 337767
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGCleanup.cpp | 15 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGDecl.cpp | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 239 |
3 files changed, 148 insertions, 109 deletions
diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp index 34bfd07caf8..cfd230997ed 100644 --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -281,7 +281,7 @@ void EHScopeStack::popNullFixups() { BranchFixups.pop_back(); } -void CodeGenFunction::initFullExprCleanup() { +Address CodeGenFunction::createCleanupActiveFlag() { // Create a variable to decide whether the cleanup needs to be run. Address active = CreateTempAllocaWithoutCast( Builder.getInt1Ty(), CharUnits::One(), "cleanup.cond"); @@ -293,10 +293,14 @@ void CodeGenFunction::initFullExprCleanup() { // Initialize it to true at the current location. Builder.CreateStore(Builder.getTrue(), active); + return active; +} + +void CodeGenFunction::initFullExprCleanupWithFlag(Address ActiveFlag) { // Set that as the active flag in the cleanup. EHCleanupScope &cleanup = cast<EHCleanupScope>(*EHStack.begin()); assert(!cleanup.hasActiveFlag() && "cleanup already has active flag?"); - cleanup.setActiveFlag(active); + cleanup.setActiveFlag(ActiveFlag); if (cleanup.isNormalCleanup()) cleanup.setTestFlagInNormalCleanup(); if (cleanup.isEHCleanup()) cleanup.setTestFlagInEHCleanup(); @@ -494,6 +498,13 @@ void CodeGenFunction::PopCleanupBlocks( &LifetimeExtendedCleanupStack[I], Header.getSize()); I += Header.getSize(); + + if (Header.isConditional()) { + Address ActiveFlag = + reinterpret_cast<Address &>(LifetimeExtendedCleanupStack[I]); + initFullExprCleanupWithFlag(ActiveFlag); + I += sizeof(ActiveFlag); + } } LifetimeExtendedCleanupStack.resize(OldLifetimeExtendedSize); } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 89c5789c3ea..16646f0a6a5 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1651,9 +1651,6 @@ void CodeGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) { void CodeGenFunction::pushLifetimeExtendedDestroy( CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray) { - assert(!isInConditionalBranch() && - "performing lifetime extension from within conditional"); - // Push an EH-only cleanup for the object now. // FIXME: When popping normal cleanups, we need to keep this EH cleanup // around in case a temporary's destructor throws an exception. diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 1fc445c66df..752d670a5f2 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -138,6 +138,88 @@ enum SanitizerHandler { #undef SANITIZER_CHECK }; +/// Helper class with most of the code for saving a value for a +/// conditional expression cleanup. +struct DominatingLLVMValue { + typedef llvm::PointerIntPair<llvm::Value*, 1, bool> saved_type; + + /// Answer whether the given value needs extra work to be saved. + static bool needsSaving(llvm::Value *value) { + // If it's not an instruction, we don't need to save. + if (!isa<llvm::Instruction>(value)) return false; + + // If it's an instruction in the entry block, we don't need to save. + llvm::BasicBlock *block = cast<llvm::Instruction>(value)->getParent(); + return (block != &block->getParent()->getEntryBlock()); + } + + static saved_type save(CodeGenFunction &CGF, llvm::Value *value); + static llvm::Value *restore(CodeGenFunction &CGF, saved_type value); +}; + +/// A partial specialization of DominatingValue for llvm::Values that +/// might be llvm::Instructions. +template <class T> struct DominatingPointer<T,true> : DominatingLLVMValue { + typedef T *type; + static type restore(CodeGenFunction &CGF, saved_type value) { + return static_cast<T*>(DominatingLLVMValue::restore(CGF, value)); + } +}; + +/// A specialization of DominatingValue for Address. +template <> struct DominatingValue<Address> { + typedef Address type; + + struct saved_type { + DominatingLLVMValue::saved_type SavedValue; + CharUnits Alignment; + }; + + static bool needsSaving(type value) { + return DominatingLLVMValue::needsSaving(value.getPointer()); + } + static saved_type save(CodeGenFunction &CGF, type value) { + return { DominatingLLVMValue::save(CGF, value.getPointer()), + value.getAlignment() }; + } + static type restore(CodeGenFunction &CGF, saved_type value) { + return Address(DominatingLLVMValue::restore(CGF, value.SavedValue), + value.Alignment); + } +}; + +/// A specialization of DominatingValue for RValue. +template <> struct DominatingValue<RValue> { + typedef RValue type; + class saved_type { + enum Kind { ScalarLiteral, ScalarAddress, AggregateLiteral, + AggregateAddress, ComplexAddress }; + + llvm::Value *Value; + unsigned K : 3; + unsigned Align : 29; + saved_type(llvm::Value *v, Kind k, unsigned a = 0) + : Value(v), K(k), Align(a) {} + + public: + static bool needsSaving(RValue value); + static saved_type save(CodeGenFunction &CGF, RValue value); + RValue restore(CodeGenFunction &CGF); + + // implementations in CGCleanup.cpp + }; + + static bool needsSaving(type value) { + return saved_type::needsSaving(value); + } + static saved_type save(CodeGenFunction &CGF, type value) { + return saved_type::save(CGF, value); + } + static type restore(CodeGenFunction &CGF, saved_type value) { + return value.restore(CGF); + } +}; + /// CodeGenFunction - This class organizes the per-function state that is used /// while generating LLVM code. class CodeGenFunction : public CodeGenTypeCache { @@ -427,10 +509,13 @@ public: /// The size of the following cleanup object. unsigned Size; /// The kind of cleanup to push: a value from the CleanupKind enumeration. - CleanupKind Kind; + unsigned Kind : 31; + /// Whether this is a conditional cleanup. + unsigned IsConditional : 1; size_t getSize() const { return Size; } - CleanupKind getKind() const { return Kind; } + CleanupKind getKind() const { return (CleanupKind)Kind; } + bool isConditional() const { return IsConditional; } }; /// i32s containing the indexes of the cleanup destinations. @@ -529,24 +614,48 @@ public: /// full-expression. template <class T, class... As> void pushCleanupAfterFullExpr(CleanupKind Kind, As... A) { - assert(!isInConditionalBranch() && "can't defer conditional cleanup"); + if (!isInConditionalBranch()) + return pushCleanupAfterFullExprImpl<T>(Kind, Address::invalid(), A...); + + Address ActiveFlag = createCleanupActiveFlag(); + assert(!DominatingValue<Address>::needsSaving(ActiveFlag) && + "cleanup active flag should never need saving"); + + typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple; + SavedTuple Saved{saveValueInCond(A)...}; + + typedef EHScopeStack::ConditionalCleanup<T, As...> CleanupType; + pushCleanupAfterFullExprImpl<CleanupType>(Kind, ActiveFlag, Saved); + } - LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind }; + template <class T, class... As> + void pushCleanupAfterFullExprImpl(CleanupKind Kind, Address ActiveFlag, + As... A) { + LifetimeExtendedCleanupHeader Header = {sizeof(T), Kind, + ActiveFlag.isValid()}; size_t OldSize = LifetimeExtendedCleanupStack.size(); LifetimeExtendedCleanupStack.resize( - LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size); + LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size + + (Header.IsConditional ? sizeof(ActiveFlag) : 0)); static_assert(sizeof(Header) % alignof(T) == 0, "Cleanup will be allocated on misaligned address"); char *Buffer = &LifetimeExtendedCleanupStack[OldSize]; new (Buffer) LifetimeExtendedCleanupHeader(Header); new (Buffer + sizeof(Header)) T(A...); + if (Header.IsConditional) + new (Buffer + sizeof(Header) + sizeof(T)) Address(ActiveFlag); } - /// Set up the last cleaup that was pushed as a conditional + /// Set up the last cleanup that was pushed as a conditional /// full-expression cleanup. - void initFullExprCleanup(); + void initFullExprCleanup() { + initFullExprCleanupWithFlag(createCleanupActiveFlag()); + } + + void initFullExprCleanupWithFlag(Address ActiveFlag); + Address createCleanupActiveFlag(); /// PushDestructorCleanup - Push a cleanup to call the /// complete-object destructor of an object of the given type at the @@ -4176,107 +4285,29 @@ private: FormResolverCondition(const TargetMultiVersionResolverOption &RO); }; -/// Helper class with most of the code for saving a value for a -/// conditional expression cleanup. -struct DominatingLLVMValue { - typedef llvm::PointerIntPair<llvm::Value*, 1, bool> saved_type; - - /// Answer whether the given value needs extra work to be saved. - static bool needsSaving(llvm::Value *value) { - // If it's not an instruction, we don't need to save. - if (!isa<llvm::Instruction>(value)) return false; - - // If it's an instruction in the entry block, we don't need to save. - llvm::BasicBlock *block = cast<llvm::Instruction>(value)->getParent(); - return (block != &block->getParent()->getEntryBlock()); - } - - /// Try to save the given value. - static saved_type save(CodeGenFunction &CGF, llvm::Value *value) { - if (!needsSaving(value)) return saved_type(value, false); - - // Otherwise, we need an alloca. - auto align = CharUnits::fromQuantity( - CGF.CGM.getDataLayout().getPrefTypeAlignment(value->getType())); - Address alloca = - CGF.CreateTempAlloca(value->getType(), align, "cond-cleanup.save"); - CGF.Builder.CreateStore(value, alloca); - - return saved_type(alloca.getPointer(), true); - } - - static llvm::Value *restore(CodeGenFunction &CGF, saved_type value) { - // If the value says it wasn't saved, trust that it's still dominating. - if (!value.getInt()) return value.getPointer(); - - // Otherwise, it should be an alloca instruction, as set up in save(). - auto alloca = cast<llvm::AllocaInst>(value.getPointer()); - return CGF.Builder.CreateAlignedLoad(alloca, alloca->getAlignment()); - } -}; - -/// A partial specialization of DominatingValue for llvm::Values that -/// might be llvm::Instructions. -template <class T> struct DominatingPointer<T,true> : DominatingLLVMValue { - typedef T *type; - static type restore(CodeGenFunction &CGF, saved_type value) { - return static_cast<T*>(DominatingLLVMValue::restore(CGF, value)); - } -}; - -/// A specialization of DominatingValue for Address. -template <> struct DominatingValue<Address> { - typedef Address type; +inline DominatingLLVMValue::saved_type +DominatingLLVMValue::save(CodeGenFunction &CGF, llvm::Value *value) { + if (!needsSaving(value)) return saved_type(value, false); - struct saved_type { - DominatingLLVMValue::saved_type SavedValue; - CharUnits Alignment; - }; + // Otherwise, we need an alloca. + auto align = CharUnits::fromQuantity( + CGF.CGM.getDataLayout().getPrefTypeAlignment(value->getType())); + Address alloca = + CGF.CreateTempAlloca(value->getType(), align, "cond-cleanup.save"); + CGF.Builder.CreateStore(value, alloca); - static bool needsSaving(type value) { - return DominatingLLVMValue::needsSaving(value.getPointer()); - } - static saved_type save(CodeGenFunction &CGF, type value) { - return { DominatingLLVMValue::save(CGF, value.getPointer()), - value.getAlignment() }; - } - static type restore(CodeGenFunction &CGF, saved_type value) { - return Address(DominatingLLVMValue::restore(CGF, value.SavedValue), - value.Alignment); - } -}; - -/// A specialization of DominatingValue for RValue. -template <> struct DominatingValue<RValue> { - typedef RValue type; - class saved_type { - enum Kind { ScalarLiteral, ScalarAddress, AggregateLiteral, - AggregateAddress, ComplexAddress }; - - llvm::Value *Value; - unsigned K : 3; - unsigned Align : 29; - saved_type(llvm::Value *v, Kind k, unsigned a = 0) - : Value(v), K(k), Align(a) {} - - public: - static bool needsSaving(RValue value); - static saved_type save(CodeGenFunction &CGF, RValue value); - RValue restore(CodeGenFunction &CGF); + return saved_type(alloca.getPointer(), true); +} - // implementations in CGCleanup.cpp - }; +inline llvm::Value *DominatingLLVMValue::restore(CodeGenFunction &CGF, + saved_type value) { + // If the value says it wasn't saved, trust that it's still dominating. + if (!value.getInt()) return value.getPointer(); - static bool needsSaving(type value) { - return saved_type::needsSaving(value); - } - static saved_type save(CodeGenFunction &CGF, type value) { - return saved_type::save(CGF, value); - } - static type restore(CodeGenFunction &CGF, saved_type value) { - return value.restore(CGF); - } -}; + // Otherwise, it should be an alloca instruction, as set up in save(). + auto alloca = cast<llvm::AllocaInst>(value.getPointer()); + return CGF.Builder.CreateAlignedLoad(alloca, alloca->getAlignment()); +} } // end namespace CodeGen } // end namespace clang |