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
This commit is contained in:
Benjamin Kramer 2015-03-12 23:41:40 +00:00
parent 4339abe66f
commit 51680bccda
2 changed files with 35 additions and 140 deletions

View File

@ -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 <class T, class A0>
void pushFullExprCleanup(CleanupKind kind, A0 a0) {
template <class T, class... As>
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<T>(kind, a0);
return EHStack.pushCleanup<T>(kind, A...);
typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
// Stash values in a tuple so we can guarantee the order of saves.
typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple;
SavedTuple Saved{saveValueInCond(A)...};
typedef EHScopeStack::ConditionalCleanup1<T, A0> CleanupType;
EHStack.pushCleanup<CleanupType>(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 <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())
return EHStack.pushCleanup<T>(kind, a0, a1);
typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1);
typedef EHScopeStack::ConditionalCleanup2<T, A0, A1> CleanupType;
EHStack.pushCleanup<CleanupType>(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 <class T, class A0, class A1, class A2>
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<T>(kind, a0, a1, a2);
}
typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1);
typename DominatingValue<A2>::saved_type a2_saved = saveValueInCond(a2);
typedef EHScopeStack::ConditionalCleanup3<T, A0, A1, A2> CleanupType;
EHStack.pushCleanup<CleanupType>(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 <class T, class A0, class A1, class A2, class A3>
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<T>(kind, a0, a1, a2, a3);
}
typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1);
typename DominatingValue<A2>::saved_type a2_saved = saveValueInCond(a2);
typename DominatingValue<A3>::saved_type a3_saved = saveValueInCond(a3);
typedef EHScopeStack::ConditionalCleanup4<T, A0, A1, A2, A3> CleanupType;
EHStack.pushCleanup<CleanupType>(kind, a0_saved, a1_saved,
a2_saved, a3_saved);
typedef EHScopeStack::ConditionalCleanup<T, As...> CleanupType;
EHStack.pushCleanup<CleanupType>(kind, Saved);
initFullExprCleanup();
}
/// \brief Queue a cleanup to be pushed after finishing the current
/// full-expression.
template <class T, class A0, class A1, class A2, class A3>
void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) {
template <class T, class... As>
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

View File

@ -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 T, class A0>
class ConditionalCleanup1 : public Cleanup {
typedef typename DominatingValue<A0>::saved_type A0_saved;
A0_saved a0_saved;
template <class T, class... As> class ConditionalCleanup : public Cleanup {
typedef std::tuple<typename DominatingValue<As>::saved_type...> SavedTuple;
SavedTuple Saved;
template <std::size_t... Is>
T restore(CodeGenFunction &CGF, llvm::index_sequence<Is...>) {
// It's important that the restores are emitted in order. The braced init
// list guarentees that.
return T{DominatingValue<As>::restore(CGF, std::get<Is>(Saved))...};
}
void Emit(CodeGenFunction &CGF, Flags flags) override {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
T(a0).Emit(CGF, flags);
restore(CGF, llvm::index_sequence_for<As...>()).Emit(CGF, flags);
}
public:
ConditionalCleanup1(A0_saved a0)
: a0_saved(a0) {}
};
ConditionalCleanup(typename DominatingValue<As>::saved_type... A)
: Saved(A...) {}
template <class T, class A0, class A1>
class ConditionalCleanup2 : public Cleanup {
typedef typename DominatingValue<A0>::saved_type A0_saved;
typedef typename DominatingValue<A1>::saved_type A1_saved;
A0_saved a0_saved;
A1_saved a1_saved;
void Emit(CodeGenFunction &CGF, Flags flags) override {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::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 T, class A0, class A1, class A2>
class ConditionalCleanup3 : public Cleanup {
typedef typename DominatingValue<A0>::saved_type A0_saved;
typedef typename DominatingValue<A1>::saved_type A1_saved;
typedef typename DominatingValue<A2>::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<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
A2 a2 = DominatingValue<A2>::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 T, class A0, class A1, class A2, class A3>
class ConditionalCleanup4 : public Cleanup {
typedef typename DominatingValue<A0>::saved_type A0_saved;
typedef typename DominatingValue<A1>::saved_type A1_saved;
typedef typename DominatingValue<A2>::saved_type A2_saved;
typedef typename DominatingValue<A3>::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<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
A3 a3 = DominatingValue<A3>::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 <class T, class... As>
void pushCleanup(CleanupKind Kind, std::tuple<As...> 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