From: Benjamin Kramer Date: Thu, 12 Mar 2015 23:41:40 +0000 (+0000) Subject: CodeGen: Base the conditional cleanup machinery on variadic templates X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=97d2f22e99206f772e504c2815cefde2c1b6e9fa;p=clang CodeGen: Base the conditional cleanup machinery on variadic templates This is complicated by the fact that we can't simply use side-effecting calls in an argument list without losing all guarantees about the order they're emitted. To keep things deterministic we use tuples and brace initialization, which thankfully guarantees evaluation order. No functionality change intended. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@232121 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 4c62a4914c..f93e556b58 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -368,84 +368,26 @@ public: /// 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 - void pushFullExprCleanup(CleanupKind kind, A0 a0) { + template + void pushFullExprCleanup(CleanupKind kind, As... A) { // If we're not in a conditional branch, or if none of the // arguments requires saving, then use the unconditional cleanup. if (!isInConditionalBranch()) - return EHStack.pushCleanup(kind, a0); + return EHStack.pushCleanup(kind, A...); - typename DominatingValue::saved_type a0_saved = saveValueInCond(a0); + // Stash values in a tuple so we can guarantee the order of saves. + typedef std::tuple::saved_type...> SavedTuple; + SavedTuple Saved{saveValueInCond(A)...}; - typedef EHScopeStack::ConditionalCleanup1 CleanupType; - EHStack.pushCleanup(kind, a0_saved); - initFullExprCleanup(); - } - - /// 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 - 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()) - return EHStack.pushCleanup(kind, a0, a1); - - typename DominatingValue::saved_type a0_saved = saveValueInCond(a0); - typename DominatingValue::saved_type a1_saved = saveValueInCond(a1); - - typedef EHScopeStack::ConditionalCleanup2 CleanupType; - EHStack.pushCleanup(kind, a0_saved, a1_saved); - initFullExprCleanup(); - } - - /// 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 - void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1, A2 a2) { - // If we're not in a conditional branch, or if none of the - // arguments requires saving, then use the unconditional cleanup. - if (!isInConditionalBranch()) { - return EHStack.pushCleanup(kind, a0, a1, a2); - } - - typename DominatingValue::saved_type a0_saved = saveValueInCond(a0); - typename DominatingValue::saved_type a1_saved = saveValueInCond(a1); - typename DominatingValue::saved_type a2_saved = saveValueInCond(a2); - - typedef EHScopeStack::ConditionalCleanup3 CleanupType; - EHStack.pushCleanup(kind, a0_saved, a1_saved, a2_saved); - initFullExprCleanup(); - } - - /// 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 - void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1, A2 a2, A3 a3) { - // If we're not in a conditional branch, or if none of the - // arguments requires saving, then use the unconditional cleanup. - if (!isInConditionalBranch()) { - return EHStack.pushCleanup(kind, a0, a1, a2, a3); - } - - typename DominatingValue::saved_type a0_saved = saveValueInCond(a0); - typename DominatingValue::saved_type a1_saved = saveValueInCond(a1); - typename DominatingValue::saved_type a2_saved = saveValueInCond(a2); - typename DominatingValue::saved_type a3_saved = saveValueInCond(a3); - - typedef EHScopeStack::ConditionalCleanup4 CleanupType; - EHStack.pushCleanup(kind, a0_saved, a1_saved, - a2_saved, a3_saved); + typedef EHScopeStack::ConditionalCleanup CleanupType; + EHStack.pushCleanup(kind, Saved); initFullExprCleanup(); } /// \brief Queue a cleanup to be pushed after finishing the current /// full-expression. - template - void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) { + template + void pushCleanupAfterFullExpr(CleanupKind Kind, As... A) { assert(!isInConditionalBranch() && "can't defer conditional cleanup"); LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind }; @@ -456,7 +398,7 @@ public: char *Buffer = &LifetimeExtendedCleanupStack[OldSize]; new (Buffer) LifetimeExtendedCleanupHeader(Header); - new (Buffer + sizeof(Header)) T(a0, a1, a2, a3); + new (Buffer + sizeof(Header)) T(A...); } /// Set up the last cleaup that was pushed as a conditional diff --git a/lib/CodeGen/EHScopeStack.h b/lib/CodeGen/EHScopeStack.h index 6535b76d92..08dad69e7d 100644 --- a/lib/CodeGen/EHScopeStack.h +++ b/lib/CodeGen/EHScopeStack.h @@ -17,6 +17,7 @@ #define LLVM_CLANG_LIB_CODEGEN_EHSCOPESTACK_H #include "clang/Basic/LLVM.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Instructions.h" @@ -181,84 +182,28 @@ public: virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0; }; - /// ConditionalCleanupN stores the saved form of its N parameters, + /// ConditionalCleanup stores the saved form of its parameters, /// then restores them and performs the cleanup. - template - class ConditionalCleanup1 : public Cleanup { - typedef typename DominatingValue::saved_type A0_saved; - A0_saved a0_saved; - - void Emit(CodeGenFunction &CGF, Flags flags) override { - A0 a0 = DominatingValue::restore(CGF, a0_saved); - T(a0).Emit(CGF, flags); - } - - public: - ConditionalCleanup1(A0_saved a0) - : a0_saved(a0) {} - }; - - template - class ConditionalCleanup2 : public Cleanup { - typedef typename DominatingValue::saved_type A0_saved; - typedef typename DominatingValue::saved_type A1_saved; - A0_saved a0_saved; - A1_saved a1_saved; - - void Emit(CodeGenFunction &CGF, Flags flags) override { - A0 a0 = DominatingValue::restore(CGF, a0_saved); - A1 a1 = DominatingValue::restore(CGF, a1_saved); - T(a0, a1).Emit(CGF, flags); + template class ConditionalCleanup : public Cleanup { + typedef std::tuple::saved_type...> SavedTuple; + SavedTuple Saved; + + template + T restore(CodeGenFunction &CGF, llvm::index_sequence) { + // It's important that the restores are emitted in order. The braced init + // list guarentees that. + return T{DominatingValue::restore(CGF, std::get(Saved))...}; } - public: - ConditionalCleanup2(A0_saved a0, A1_saved a1) - : a0_saved(a0), a1_saved(a1) {} - }; - - template - class ConditionalCleanup3 : public Cleanup { - typedef typename DominatingValue::saved_type A0_saved; - typedef typename DominatingValue::saved_type A1_saved; - typedef typename DominatingValue::saved_type A2_saved; - A0_saved a0_saved; - A1_saved a1_saved; - A2_saved a2_saved; - void Emit(CodeGenFunction &CGF, Flags flags) override { - A0 a0 = DominatingValue::restore(CGF, a0_saved); - A1 a1 = DominatingValue::restore(CGF, a1_saved); - A2 a2 = DominatingValue::restore(CGF, a2_saved); - T(a0, a1, a2).Emit(CGF, flags); + restore(CGF, llvm::index_sequence_for()).Emit(CGF, flags); } public: - ConditionalCleanup3(A0_saved a0, A1_saved a1, A2_saved a2) - : a0_saved(a0), a1_saved(a1), a2_saved(a2) {} - }; - - template - class ConditionalCleanup4 : public Cleanup { - typedef typename DominatingValue::saved_type A0_saved; - typedef typename DominatingValue::saved_type A1_saved; - typedef typename DominatingValue::saved_type A2_saved; - typedef typename DominatingValue::saved_type A3_saved; - A0_saved a0_saved; - A1_saved a1_saved; - A2_saved a2_saved; - A3_saved a3_saved; - - void Emit(CodeGenFunction &CGF, Flags flags) override { - A0 a0 = DominatingValue::restore(CGF, a0_saved); - A1 a1 = DominatingValue::restore(CGF, a1_saved); - A2 a2 = DominatingValue::restore(CGF, a2_saved); - A3 a3 = DominatingValue::restore(CGF, a3_saved); - T(a0, a1, a2, a3).Emit(CGF, flags); - } + ConditionalCleanup(typename DominatingValue::saved_type... A) + : Saved(A...) {} - public: - ConditionalCleanup4(A0_saved a0, A1_saved a1, A2_saved a2, A3_saved a3) - : a0_saved(a0), a1_saved(a1), a2_saved(a2), a3_saved(a3) {} + ConditionalCleanup(SavedTuple Tuple) : Saved(std::move(Tuple)) {} }; private: @@ -319,6 +264,14 @@ public: (void) Obj; } + /// Push a lazily-created cleanup on the stack. Tuple version. + template + void pushCleanup(CleanupKind Kind, std::tuple A) { + void *Buffer = pushCleanup(Kind, sizeof(T)); + Cleanup *Obj = new (Buffer) T(std::move(A)); + (void) Obj; + } + // Feel free to add more variants of the following: /// Push a cleanup with non-constant storage requirements on the