aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CGExprCXX.cpp205
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp25
-rw-r--r--lib/CodeGen/CodeGenFunction.h4
3 files changed, 216 insertions, 18 deletions
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index 584f6c099b..4dbfa7ee4f 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -675,6 +675,105 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
StoreAnyExprIntoOneUnit(CGF, E, NewPtr);
}
+/// A utility class for saving an rvalue.
+class SavedRValue {
+public:
+ enum Kind { ScalarLiteral, ScalarAddress,
+ AggregateLiteral, AggregateAddress,
+ Complex };
+
+private:
+ llvm::Value *Value;
+ Kind K;
+
+ SavedRValue(llvm::Value *V, Kind K) : Value(V), K(K) {}
+
+public:
+ SavedRValue() {}
+
+ static SavedRValue forScalarLiteral(llvm::Value *V) {
+ return SavedRValue(V, ScalarLiteral);
+ }
+
+ static SavedRValue forScalarAddress(llvm::Value *Addr) {
+ return SavedRValue(Addr, ScalarAddress);
+ }
+
+ static SavedRValue forAggregateLiteral(llvm::Value *V) {
+ return SavedRValue(V, AggregateLiteral);
+ }
+
+ static SavedRValue forAggregateAddress(llvm::Value *Addr) {
+ return SavedRValue(Addr, AggregateAddress);
+ }
+
+ static SavedRValue forComplexAddress(llvm::Value *Addr) {
+ return SavedRValue(Addr, Complex);
+ }
+
+ Kind getKind() const { return K; }
+ llvm::Value *getValue() const { return Value; }
+};
+
+/// Given an r-value, perform the code necessary to make sure that a
+/// future RestoreRValue will be able to load the value without
+/// domination concerns.
+static SavedRValue SaveRValue(CodeGenFunction &CGF, RValue RV) {
+ if (RV.isScalar()) {
+ llvm::Value *V = RV.getScalarVal();
+
+ // These automatically dominate and don't need to be saved.
+ if (isa<llvm::Constant>(V) || isa<llvm::AllocaInst>(V))
+ return SavedRValue::forScalarLiteral(V);
+
+ // Everything else needs an alloca.
+ llvm::Value *Addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue");
+ CGF.Builder.CreateStore(V, Addr);
+ return SavedRValue::forScalarAddress(Addr);
+ }
+
+ if (RV.isComplex()) {
+ CodeGenFunction::ComplexPairTy V = RV.getComplexVal();
+ const llvm::Type *ComplexTy =
+ llvm::StructType::get(CGF.getLLVMContext(),
+ V.first->getType(), V.second->getType(),
+ (void*) 0);
+ llvm::Value *Addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex");
+ CGF.StoreComplexToAddr(V, Addr, /*volatile*/ false);
+ return SavedRValue::forComplexAddress(Addr);
+ }
+
+ assert(RV.isAggregate());
+ llvm::Value *V = RV.getAggregateAddr(); // TODO: volatile?
+ if (isa<llvm::Constant>(V) || isa<llvm::AllocaInst>(V))
+ return SavedRValue::forAggregateLiteral(V);
+
+ llvm::Value *Addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue");
+ CGF.Builder.CreateStore(V, Addr);
+ return SavedRValue::forAggregateAddress(Addr);
+}
+
+/// Given a saved r-value produced by SaveRValue, perform the code
+/// necessary to restore it to usability at the current insertion
+/// point.
+static RValue RestoreRValue(CodeGenFunction &CGF, SavedRValue RV) {
+ switch (RV.getKind()) {
+ case SavedRValue::ScalarLiteral:
+ return RValue::get(RV.getValue());
+ case SavedRValue::ScalarAddress:
+ return RValue::get(CGF.Builder.CreateLoad(RV.getValue()));
+ case SavedRValue::AggregateLiteral:
+ return RValue::getAggregate(RV.getValue());
+ case SavedRValue::AggregateAddress:
+ return RValue::getAggregate(CGF.Builder.CreateLoad(RV.getValue()));
+ case SavedRValue::Complex:
+ return RValue::getComplex(CGF.LoadComplexFromAddr(RV.getValue(), false));
+ }
+
+ llvm_unreachable("bad saved r-value kind");
+ return RValue();
+}
+
namespace {
/// A cleanup to call the given 'operator delete' function upon
/// abnormal exit from a new expression.
@@ -729,6 +828,104 @@ namespace {
ReturnValueSlot(), DeleteArgs, OperatorDelete);
}
};
+
+ /// A cleanup to call the given 'operator delete' function upon
+ /// abnormal exit from a new expression when the new expression is
+ /// conditional.
+ class CallDeleteDuringConditionalNew : public EHScopeStack::Cleanup {
+ size_t NumPlacementArgs;
+ const FunctionDecl *OperatorDelete;
+ SavedRValue Ptr;
+ SavedRValue AllocSize;
+
+ SavedRValue *getPlacementArgs() {
+ return reinterpret_cast<SavedRValue*>(this+1);
+ }
+
+ public:
+ static size_t getExtraSize(size_t NumPlacementArgs) {
+ return NumPlacementArgs * sizeof(SavedRValue);
+ }
+
+ CallDeleteDuringConditionalNew(size_t NumPlacementArgs,
+ const FunctionDecl *OperatorDelete,
+ SavedRValue Ptr,
+ SavedRValue AllocSize)
+ : NumPlacementArgs(NumPlacementArgs), OperatorDelete(OperatorDelete),
+ Ptr(Ptr), AllocSize(AllocSize) {}
+
+ void setPlacementArg(unsigned I, SavedRValue Arg) {
+ assert(I < NumPlacementArgs && "index out of range");
+ getPlacementArgs()[I] = Arg;
+ }
+
+ void Emit(CodeGenFunction &CGF, bool IsForEH) {
+ const FunctionProtoType *FPT
+ = OperatorDelete->getType()->getAs<FunctionProtoType>();
+ assert(FPT->getNumArgs() == NumPlacementArgs + 1 ||
+ (FPT->getNumArgs() == 2 && NumPlacementArgs == 0));
+
+ CallArgList DeleteArgs;
+
+ // The first argument is always a void*.
+ FunctionProtoType::arg_type_iterator AI = FPT->arg_type_begin();
+ DeleteArgs.push_back(std::make_pair(RestoreRValue(CGF, Ptr), *AI++));
+
+ // A member 'operator delete' can take an extra 'size_t' argument.
+ if (FPT->getNumArgs() == NumPlacementArgs + 2) {
+ RValue RV = RestoreRValue(CGF, AllocSize);
+ DeleteArgs.push_back(std::make_pair(RV, *AI++));
+ }
+
+ // Pass the rest of the arguments, which must match exactly.
+ for (unsigned I = 0; I != NumPlacementArgs; ++I) {
+ RValue RV = RestoreRValue(CGF, getPlacementArgs()[I]);
+ DeleteArgs.push_back(std::make_pair(RV, *AI++));
+ }
+
+ // Call 'operator delete'.
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(DeleteArgs, FPT),
+ CGF.CGM.GetAddrOfFunction(OperatorDelete),
+ ReturnValueSlot(), DeleteArgs, OperatorDelete);
+ }
+ };
+}
+
+/// Enter a cleanup to call 'operator delete' if the initializer in a
+/// new-expression throws.
+static void EnterNewDeleteCleanup(CodeGenFunction &CGF,
+ const CXXNewExpr *E,
+ llvm::Value *NewPtr,
+ llvm::Value *AllocSize,
+ const CallArgList &NewArgs) {
+ // If we're not inside a conditional branch, then the cleanup will
+ // dominate and we can do the easier (and more efficient) thing.
+ if (!CGF.isInConditionalBranch()) {
+ CallDeleteDuringNew *Cleanup = CGF.EHStack
+ .pushCleanupWithExtra<CallDeleteDuringNew>(EHCleanup,
+ E->getNumPlacementArgs(),
+ E->getOperatorDelete(),
+ NewPtr, AllocSize);
+ for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I)
+ Cleanup->setPlacementArg(I, NewArgs[I+1].first);
+
+ return;
+ }
+
+ // Otherwise, we need to save all this stuff.
+ SavedRValue SavedNewPtr = SaveRValue(CGF, RValue::get(NewPtr));
+ SavedRValue SavedAllocSize = SaveRValue(CGF, RValue::get(AllocSize));
+
+ CallDeleteDuringConditionalNew *Cleanup = CGF.EHStack
+ .pushCleanupWithExtra<CallDeleteDuringConditionalNew>(InactiveEHCleanup,
+ E->getNumPlacementArgs(),
+ E->getOperatorDelete(),
+ SavedNewPtr,
+ SavedAllocSize);
+ for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I)
+ Cleanup->setPlacementArg(I, SaveRValue(CGF, NewArgs[I+1].first));
+
+ CGF.ActivateCleanupBlock(CGF.EHStack.stable_begin());
}
llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
@@ -827,13 +1024,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// exception is thrown.
EHScopeStack::stable_iterator CallOperatorDelete;
if (E->getOperatorDelete()) {
- CallDeleteDuringNew *Cleanup = CGF.EHStack
- .pushCleanupWithExtra<CallDeleteDuringNew>(EHCleanup,
- E->getNumPlacementArgs(),
- E->getOperatorDelete(),
- NewPtr, AllocSize);
- for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I)
- Cleanup->setPlacementArg(I, NewArgs[I+1].first);
+ EnterNewDeleteCleanup(*this, E, NewPtr, AllocSize, NewArgs);
CallOperatorDelete = EHStack.stable_begin();
}
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 0dbc6120ed..aae8ecf667 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -1431,9 +1431,11 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF,
EHScopeStack::stable_iterator C,
ForActivation_t Kind) {
EHCleanupScope &Scope = cast<EHCleanupScope>(*CGF.EHStack.find(C));
- assert(!Scope.getActiveFlag() && "scope already has activation flag");
- bool NeedFlag = false;
+ // We always need the flag if we're activating the cleanup, because
+ // we have to assume that the current location doesn't necessarily
+ // dominate all future uses of the cleanup.
+ bool NeedFlag = (Kind == ForActivation);
// Calculate whether the cleanup was used:
@@ -1452,16 +1454,17 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF,
// If it hasn't yet been used as either, we're done.
if (!NeedFlag) return;
- llvm::AllocaInst *Var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty());
- Scope.setActiveFlag(Var);
+ llvm::AllocaInst *Var = Scope.getActiveFlag();
+ if (!Var) {
+ Var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "cleanup.isactive");
+ Scope.setActiveFlag(Var);
- if (Kind == ForActivation) {
- CGF.InitTempAlloca(Var, CGF.Builder.getFalse());
- CGF.Builder.CreateStore(CGF.Builder.getTrue(), Var);
- } else {
- CGF.InitTempAlloca(Var, CGF.Builder.getTrue());
- CGF.Builder.CreateStore(CGF.Builder.getFalse(), Var);
+ // Initialize to true or false depending on whether it was
+ // active up to this point.
+ CGF.InitTempAlloca(Var, CGF.Builder.getInt1(Kind == ForDeactivation));
}
+
+ CGF.Builder.CreateStore(CGF.Builder.getInt1(Kind == ForActivation), Var);
}
/// Activate a cleanup that was created in an inactivated state.
@@ -1479,7 +1482,7 @@ void CodeGenFunction::ActivateCleanupBlock(EHScopeStack::stable_iterator C) {
void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C) {
assert(C != EHStack.stable_end() && "deactivating bottom of stack?");
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(C));
- assert(Scope.isActive() && "double activation");
+ assert(Scope.isActive() && "double deactivation");
// If it's the top of the stack, just pop it.
if (C == EHStack.stable_begin()) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 26b262ccb1..a77044324a 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -674,6 +674,10 @@ public:
--ConditionalBranchLevel;
}
+ /// isInConditionalBranch - Return true if we're currently emitting
+ /// one branch or the other of a conditional expression.
+ bool isInConditionalBranch() const { return ConditionalBranchLevel != 0; }
+
private:
CGDebugInfo *DebugInfo;