aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CodeGenFunction.h
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-01-26 04:00:11 +0000
committerJohn McCall <rjmccall@apple.com>2011-01-26 04:00:11 +0000
commit150b462afc7a713edd19bcbbbb22381fe060d4f5 (patch)
treed90a44bc497a080b64d9143f25f9ef32b6c1228f /lib/CodeGen/CodeGenFunction.h
parent83f51722ed2b8134810cb178f39e44da811de7cd (diff)
Better framework for conditional cleanups; untested as yet.
I'm separately committing this because it incidentally changes some block orderings and minor IR issues, like using a phi instead of an unnecessary alloca. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124277 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CodeGenFunction.h')
-rw-r--r--lib/CodeGen/CodeGenFunction.h210
1 files changed, 187 insertions, 23 deletions
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 7686b33365..ea362d3bf1 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -97,6 +97,24 @@ struct BranchFixup {
llvm::BranchInst *InitialBranch;
};
+/// A metaprogramming class which decides whether a type is a subclass
+/// of llvm::Value that needs to be saved if it's used in a
+/// conditional cleanup.
+template
+ <class T,
+ bool mustSave =
+ llvm::is_base_of<llvm::Value, llvm::remove_pointer<T> >::value
+ && !llvm::is_base_of<llvm::Constant, llvm::remove_pointer<T> >::value
+ && !llvm::is_base_of<llvm::BasicBlock, llvm::remove_pointer<T> >::value>
+struct SavedValueInCond {
+ typedef T type;
+ typedef T saved_type;
+ static bool needsSaving(type value) { return false; }
+ static saved_type save(CodeGenFunction &CGF, type value) { return value; }
+ static type restore(CodeGenFunction &CGF, saved_type value) { return value; }
+};
+// Partial specialization for true arguments at end of file.
+
enum CleanupKind {
EHCleanup = 0x1,
NormalCleanup = 0x2,
@@ -175,6 +193,52 @@ public:
virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) = 0;
};
+ /// A helper class for cleanups that execute conditionally.
+ class ConditionalCleanup : public Cleanup {
+ /// Either an i1 which directly indicates whether the cleanup
+ /// should be run or an i1* from which that should be loaded.
+ llvm::Value *cond;
+
+ public:
+ virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup);
+
+ protected:
+ ConditionalCleanup(llvm::Value *cond) : cond(cond) {}
+
+ /// Emit the non-conditional code for the cleanup.
+ virtual void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) = 0;
+ };
+
+ /// UnconditionalCleanupN stores its N parameters and just passes
+ /// them to the real cleanup function.
+ template <class T, class A0, class A1>
+ class UnconditionalCleanup2 : public Cleanup {
+ A0 a0; A1 a1;
+ UnconditionalCleanup2(A0 a0, A1 a1) : a0(a0), a1(a1) {}
+ void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ T::Emit(CGF, IsForEHCleanup, a0, a1);
+ }
+ };
+
+ /// ConditionalCleanupN stores the saved form of its N parameters,
+ /// then restores them and performs the cleanup.
+ template <class T, class A0, class A1>
+ class ConditionalCleanup2 : public ConditionalCleanup {
+ typedef typename SavedValueInCond<A0>::saved_type A0_saved;
+ typedef typename SavedValueInCond<A1>::saved_type A1_saved;
+ A0_saved a0; A1_saved a1;
+
+ void EmitImpl(CodeGenFunction &CGF, bool IsForEHCleanup) {
+ A0 a0 = SavedValueInCond<A0>::restore(CGF, a0);
+ A1 a1 = SavedValueInCond<A1>::restore(CGF, a1);
+ T::Emit(CGF, IsForEHCleanup, a0, a1);
+ }
+
+ public:
+ ConditionalCleanup2(llvm::Value *cond, A0_saved a0, A1_saved a1)
+ : ConditionalCleanup(cond), a0(a0), a1(a1) {}
+ };
+
private:
// The implementation for this class is in CGException.h and
// CGException.cpp; the definition is here because it's used as a
@@ -536,6 +600,14 @@ public:
llvm::BasicBlock *getInvokeDestImpl();
+ /// Sets up a condition for a full-expression cleanup.
+ llvm::Value *initFullExprCleanup();
+
+ template <class T>
+ typename SavedValueInCond<T>::saved_type saveValueInCond(T value) {
+ return SavedValueInCond<T>::save(*this, value);
+ }
+
public:
/// ObjCEHValueStack - Stack of Objective-C exception values, used for
/// rethrows.
@@ -552,6 +624,28 @@ public:
llvm::Constant *RethrowFn);
void ExitFinallyBlock(FinallyInfo &FinallyInfo);
+ /// pushFullExprCleanup - Push a cleanup to be run at the end of the
+ /// current full-expression. Safe against the possibility that
+ /// we're currently inside a conditionally-evaluated expression.
+ template <class T, class A0, class A1>
+ void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1) {
+ // If we're not in a conditional branch, or if none of the
+ // arguments requires saving, then use the unconditional cleanup.
+ if (!(isInConditionalBranch() ||
+ SavedValueInCond<A0>::needsSaving(a0) ||
+ SavedValueInCond<A1>::needsSaving(a1))) {
+ typedef EHScopeStack::UnconditionalCleanup2<T, A0, A1> CleanupType;
+ return EHStack.pushCleanup<CleanupType>(kind, a0, a1);
+ }
+
+ llvm::Value *condVar = initFullExprCleanup();
+ typename SavedValueInCond<A0>::saved_type a0_saved = saveValueInCond(a0);
+ typename SavedValueInCond<A1>::saved_type a1_saved = saveValueInCond(a1);
+
+ typedef EHScopeStack::ConditionalCleanup2<T, A0, A1> CleanupType;
+ EHStack.pushCleanup<CleanupType>(kind, condVar, a0_saved, a1_saved);
+ }
+
/// PushDestructorCleanup - Push a cleanup to call the
/// complete-object destructor of an object of the given type at the
/// given address. Does nothing if T is not a C++ class type with a
@@ -659,30 +753,58 @@ public:
/// destination.
UnwindDest getRethrowDest();
- /// BeginConditionalBranch - Should be called before a conditional part of an
- /// expression is emitted. For example, before the RHS of the expression below
- /// is emitted:
- ///
- /// b && f(T());
- ///
- /// This is used to make sure that any temporaries created in the conditional
- /// branch are only destroyed if the branch is taken.
- void BeginConditionalBranch() {
- ++ConditionalBranchLevel;
- }
+ /// An object to manage conditionally-evaluated expressions.
+ class ConditionalEvaluation {
+ llvm::BasicBlock *StartBB;
- /// EndConditionalBranch - Should be called after a conditional part of an
- /// expression has been emitted.
- void EndConditionalBranch() {
- assert(ConditionalBranchLevel != 0 &&
- "Conditional branch mismatch!");
+ public:
+ ConditionalEvaluation(CodeGenFunction &CGF)
+ : StartBB(CGF.Builder.GetInsertBlock()) {}
- --ConditionalBranchLevel;
- }
+ void begin(CodeGenFunction &CGF) {
+ assert(CGF.OutermostConditional != this);
+ if (!CGF.OutermostConditional)
+ CGF.OutermostConditional = this;
+ }
+
+ void end(CodeGenFunction &CGF) {
+ assert(CGF.OutermostConditional != 0);
+ if (CGF.OutermostConditional == this)
+ CGF.OutermostConditional = 0;
+ }
+
+ /// Returns a block which will be executed prior to each
+ /// evaluation of the conditional code.
+ llvm::BasicBlock *getStartingBlock() const {
+ return StartBB;
+ }
+ };
/// isInConditionalBranch - Return true if we're currently emitting
/// one branch or the other of a conditional expression.
- bool isInConditionalBranch() const { return ConditionalBranchLevel != 0; }
+ bool isInConditionalBranch() const { return OutermostConditional != 0; }
+
+ /// An RAII object to record that we're evaluating a statement
+ /// expression.
+ class StmtExprEvaluation {
+ CodeGenFunction &CGF;
+
+ /// We have to save the outermost conditional: cleanups in a
+ /// statement expression aren't conditional just because the
+ /// StmtExpr is.
+ ConditionalEvaluation *SavedOutermostConditional;
+
+ public:
+ StmtExprEvaluation(CodeGenFunction &CGF)
+ : CGF(CGF), SavedOutermostConditional(CGF.OutermostConditional) {
+ CGF.OutermostConditional = 0;
+ }
+
+ ~StmtExprEvaluation() {
+ CGF.OutermostConditional = SavedOutermostConditional;
+ CGF.EnsureInsertPoint();
+ }
+ };
/// getByrefValueFieldNumber - Given a declaration, returns the LLVM field
/// number that holds the value.
@@ -750,10 +872,10 @@ private:
ImplicitParamDecl *CXXVTTDecl;
llvm::Value *CXXVTTValue;
- /// ConditionalBranchLevel - Contains the nesting level of the current
- /// conditional branch. This is used so that we know if a temporary should be
- /// destroyed conditionally.
- unsigned ConditionalBranchLevel;
+ /// OutermostConditional - Points to the outermost active
+ /// conditional control. This is used so that we know if a
+ /// temporary should be destroyed conditionally.
+ ConditionalEvaluation *OutermostConditional;
/// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
@@ -1786,6 +1908,48 @@ private:
void EmitDeclMetadata();
};
+/// Helper class with most of the code for saving a value for a
+/// conditional expression cleanup.
+struct SavedValueInCondImpl {
+ 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.
+ llvm::Value *alloca =
+ CGF.CreateTempAlloca(value->getType(), "cond-cleanup.save");
+ CGF.Builder.CreateStore(value, alloca);
+
+ return saved_type(alloca, true);
+ }
+
+ static llvm::Value *restore(CodeGenFunction &CGF, saved_type value) {
+ if (!value.getInt()) return value.getPointer();
+ return CGF.Builder.CreateLoad(value.getPointer());
+ }
+};
+
+/// Partial specialization of SavedValueInCond for when a value really
+/// requires saving.
+template <class T> struct SavedValueInCond<T,true> : SavedValueInCondImpl {
+ typedef T type;
+ static type restore(CodeGenFunction &CGF, saved_type value) {
+ return static_cast<T>(SavedValueInCondImpl::restore(CGF, value));
+ }
+};
+
/// CGBlockInfo - Information to generate a block literal.
class CGBlockInfo {
public: