Improvement on sized deallocation from r230160:
Do not declare sized deallocation functions dependently on whether it is found in global scope. Instead, enforce the branching in emitted code by (1) declaring the functions extern_weak and (2) emitting sized delete expressions as a branching between both forms delete.
llvm-svn: 230580
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 6852d3a..425a968 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1422,6 +1422,71 @@
OperatorDelete, ElementType);
}
+static void EmitDelete(CodeGenFunction &CGF,
+ const CXXDeleteExpr *DE,
+ llvm::Value *Ptr,
+ QualType ElementType);
+
+static void EmitSizedDelete(CodeGenFunction &CGF,
+ const CXXDeleteExpr *DE,
+ llvm::Value *Ptr,
+ QualType ElementType,
+ FunctionDecl* UnsizedDealloc) {
+
+ if (CGF.getLangOpts().DefineSizedDeallocation) {
+ // The delete operator in use is fixed. So simply emit the delete expr.
+ EmitDelete(CGF, DE, Ptr, ElementType);
+ return;
+ }
+
+ assert(UnsizedDealloc && "We must be emiting a 'sized' delete expr");
+
+ // Branch off over the value of operator delete:
+ // Use the sized form if available, and default on the unsized form otherwise.
+ llvm::BasicBlock *ThenBlock = CGF.createBasicBlock("if.then");
+ llvm::BasicBlock *ContBlock = CGF.createBasicBlock("if.end");
+ llvm::BasicBlock *ElseBlock = CGF.createBasicBlock("if.else");
+
+ // Emit the condition.
+ const FunctionDecl *OpDelFD = DE->getOperatorDelete();
+ llvm::Value *OpDelAddr = CGF.CGM.GetAddrOfFunction(OpDelFD);
+ //llvm::Function *OpDel = dyn_cast<llvm::Function>(OpDelAddr);
+ llvm::Value *SDE = CGF.Builder.CreateIsNotNull(OpDelAddr, "sized.del.exists");
+ CGF.Builder.CreateCondBr(SDE, ThenBlock, ElseBlock);
+
+ // Emit the 'then' code.
+ CGF.EmitBlock(ThenBlock);
+ EmitDelete(CGF, DE, Ptr, ElementType);
+ CGF.EmitBranch(ContBlock);
+
+ // Compute the 'unsized' delete expr.
+ CXXDeleteExpr * E = const_cast<CXXDeleteExpr*>(DE);
+ CXXDeleteExpr *UnsizedDE =
+ new (CGF.getContext()) CXXDeleteExpr(CGF.getContext().VoidTy,
+ E->isGlobalDelete(),
+ E->isArrayForm(),
+ E->isArrayFormAsWritten(),
+ E->doesUsualArrayDeleteWantSize(),
+ UnsizedDealloc,
+ E->getArgument(),
+ E->getLocStart());
+ // Emit the 'else' code.
+ {
+ // There is no need to emit line number for an unconditional branch.
+ auto NL = ApplyDebugLocation::CreateEmpty(CGF);
+ CGF.EmitBlock(ElseBlock);
+ }
+ EmitDelete(CGF, UnsizedDE, Ptr, ElementType);
+ {
+ // There is no need to emit line number for an unconditional branch.
+ auto NL = ApplyDebugLocation::CreateEmpty(CGF);
+ CGF.EmitBranch(ContBlock);
+ }
+
+ // Emit the continuation block for code after the if.
+ CGF.EmitBlock(ContBlock, true);
+}
+
/// Emit the code for deleting a single object.
static void EmitObjectDelete(CodeGenFunction &CGF,
const CXXDeleteExpr *DE,
@@ -1581,6 +1646,17 @@
CGF.PopCleanupBlock();
}
+static void EmitDelete(CodeGenFunction &CGF,
+ const CXXDeleteExpr *DE,
+ llvm::Value *Ptr,
+ QualType ElementType) {
+ if (DE->isArrayForm()) {
+ EmitArrayDelete(CGF, DE, Ptr, ElementType);
+ } else {
+ EmitObjectDelete(CGF, DE, Ptr, ElementType);
+ }
+}
+
void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
const Expr *Arg = E->getArgument();
llvm::Value *Ptr = EmitScalarExpr(Arg);
@@ -1620,11 +1696,12 @@
assert(ConvertTypeForMem(DeleteTy) ==
cast<llvm::PointerType>(Ptr->getType())->getElementType());
- if (E->isArrayForm()) {
- EmitArrayDelete(*this, E, Ptr, DeleteTy);
- } else {
- EmitObjectDelete(*this, E, Ptr, DeleteTy);
- }
+ const FunctionDecl *Dealloc = E->getOperatorDelete();
+ if (FunctionDecl* UnsizedDealloc =
+ Dealloc->getCorrespondingUnsizedGlobalDeallocationFunction())
+ EmitSizedDelete(*this, E, Ptr, DeleteTy, UnsizedDealloc);
+ else
+ EmitDelete(*this, E, Ptr, DeleteTy);
EmitBlock(DeleteEnd);
}