From 51680bccdaa74f82f7095a5bdf40fac811deb0d2 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Thu, 12 Mar 2015 23:41:40 +0000 Subject: [PATCH] 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. llvm-svn: 232121 --- clang/lib/CodeGen/CodeGenFunction.h | 80 ++++-------------------- clang/lib/CodeGen/EHScopeStack.h | 95 ++++++++--------------------- 2 files changed, 35 insertions(+), 140 deletions(-) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 4c62a4914ce2..f93e556b588f 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/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/clang/lib/CodeGen/EHScopeStack.h b/clang/lib/CodeGen/EHScopeStack.h index 6535b76d9258..08dad69e7da3 100644 --- a/clang/lib/CodeGen/EHScopeStack.h +++ b/clang/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; + 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))...}; + } void Emit(CodeGenFunction &CGF, Flags flags) override { - A0 a0 = DominatingValue::restore(CGF, a0_saved); - T(a0).Emit(CGF, flags); + restore(CGF, llvm::index_sequence_for()).Emit(CGF, flags); } public: - ConditionalCleanup1(A0_saved a0) - : a0_saved(a0) {} - }; + ConditionalCleanup(typename DominatingValue::saved_type... A) + : Saved(A...) {} - 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); - } - - 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); - } - - 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); - } - - 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