2009-11-24 13:51:11 +08:00
|
|
|
//===--- CGExprCXX.cpp - Emit LLVM Code for C++ expressions ---------------===//
|
2009-09-23 06:53:17 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This contains code dealing with code generation of C++ expressions
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "CodeGenFunction.h"
|
|
|
|
using namespace clang;
|
|
|
|
using namespace CodeGen;
|
|
|
|
|
2010-01-02 04:29:01 +08:00
|
|
|
RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
|
|
|
|
llvm::Value *Callee,
|
|
|
|
ReturnValueSlot ReturnValue,
|
|
|
|
llvm::Value *This,
|
2010-01-02 09:01:18 +08:00
|
|
|
llvm::Value *VTT,
|
2010-01-02 04:29:01 +08:00
|
|
|
CallExpr::const_arg_iterator ArgBeg,
|
|
|
|
CallExpr::const_arg_iterator ArgEnd) {
|
|
|
|
assert(MD->isInstance() &&
|
|
|
|
"Trying to emit a member call expr on a static method!");
|
|
|
|
|
|
|
|
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
|
|
|
|
|
|
|
CallArgList Args;
|
|
|
|
|
|
|
|
// Push the this ptr.
|
|
|
|
Args.push_back(std::make_pair(RValue::get(This),
|
|
|
|
MD->getThisType(getContext())));
|
|
|
|
|
2010-01-02 09:01:18 +08:00
|
|
|
// If there is a VTT parameter, emit it.
|
|
|
|
if (VTT) {
|
|
|
|
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
|
|
|
|
Args.push_back(std::make_pair(RValue::get(VTT), T));
|
|
|
|
}
|
|
|
|
|
2010-01-02 04:29:01 +08:00
|
|
|
// And the rest of the call args
|
|
|
|
EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
|
|
|
|
|
2010-02-06 05:31:56 +08:00
|
|
|
QualType ResultType = FPT->getResultType();
|
|
|
|
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
|
2010-03-31 04:24:48 +08:00
|
|
|
FPT->getExtInfo()),
|
|
|
|
Callee, ReturnValue, Args, MD);
|
2010-01-02 04:29:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
|
|
|
|
/// expr can be devirtualized.
|
|
|
|
static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
|
|
|
|
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
|
|
|
|
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
|
|
|
|
// This is a record decl. We know the type and can devirtualize it.
|
|
|
|
return VD->getType()->isRecordType();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We can always devirtualize calls on temporary object expressions.
|
2010-02-01 04:58:15 +08:00
|
|
|
if (isa<CXXConstructExpr>(Base))
|
2010-01-02 04:29:01 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
// And calls on bound temporaries.
|
|
|
|
if (isa<CXXBindTemporaryExpr>(Base))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Check if this is a call expr that returns a record type.
|
|
|
|
if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
|
|
|
|
return CE->getCallReturnType()->isRecordType();
|
|
|
|
|
|
|
|
// We can't devirtualize the call.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
|
|
|
ReturnValueSlot ReturnValue) {
|
|
|
|
if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens()))
|
|
|
|
return EmitCXXMemberPointerCallExpr(CE, ReturnValue);
|
|
|
|
|
|
|
|
const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens());
|
|
|
|
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
|
|
|
|
|
|
|
|
if (MD->isStatic()) {
|
|
|
|
// The method is static, emit it as we would a regular call.
|
|
|
|
llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
|
|
|
|
return EmitCall(getContext().getPointerType(MD->getType()), Callee,
|
|
|
|
ReturnValue, CE->arg_begin(), CE->arg_end());
|
|
|
|
}
|
|
|
|
|
|
|
|
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
|
|
|
|
|
|
|
const llvm::Type *Ty =
|
|
|
|
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
|
|
|
|
FPT->isVariadic());
|
|
|
|
llvm::Value *This;
|
|
|
|
|
|
|
|
if (ME->isArrow())
|
|
|
|
This = EmitScalarExpr(ME->getBase());
|
|
|
|
else {
|
|
|
|
LValue BaseLV = EmitLValue(ME->getBase());
|
|
|
|
This = BaseLV.getAddress();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MD->isCopyAssignment() && MD->isTrivial()) {
|
|
|
|
// We don't like to generate the trivial copy assignment operator when
|
|
|
|
// it isn't necessary; just produce the proper effect here.
|
|
|
|
llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
|
|
|
|
EmitAggregateCopy(This, RHS, CE->getType());
|
|
|
|
return RValue::get(This);
|
|
|
|
}
|
|
|
|
|
|
|
|
// C++ [class.virtual]p12:
|
|
|
|
// Explicit qualification with the scope operator (5.1) suppresses the
|
|
|
|
// virtual call mechanism.
|
|
|
|
//
|
|
|
|
// We also don't emit a virtual call if the base expression has a record type
|
|
|
|
// because then we know what the type is.
|
|
|
|
llvm::Value *Callee;
|
|
|
|
if (const CXXDestructorDecl *Destructor
|
|
|
|
= dyn_cast<CXXDestructorDecl>(MD)) {
|
|
|
|
if (Destructor->isTrivial())
|
|
|
|
return RValue::get(0);
|
|
|
|
if (MD->isVirtual() && !ME->hasQualifier() &&
|
|
|
|
!canDevirtualizeMemberFunctionCalls(ME->getBase())) {
|
|
|
|
Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty);
|
|
|
|
} else {
|
|
|
|
Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
|
|
|
|
}
|
|
|
|
} else if (MD->isVirtual() && !ME->hasQualifier() &&
|
|
|
|
!canDevirtualizeMemberFunctionCalls(ME->getBase())) {
|
|
|
|
Callee = BuildVirtualCall(MD, This, Ty);
|
|
|
|
} else {
|
|
|
|
Callee = CGM.GetAddrOfFunction(MD, Ty);
|
|
|
|
}
|
|
|
|
|
2010-01-02 09:01:18 +08:00
|
|
|
return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
|
2010-01-02 04:29:01 +08:00
|
|
|
CE->arg_begin(), CE->arg_end());
|
|
|
|
}
|
|
|
|
|
|
|
|
RValue
|
|
|
|
CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
|
|
|
|
ReturnValueSlot ReturnValue) {
|
|
|
|
const BinaryOperator *BO =
|
|
|
|
cast<BinaryOperator>(E->getCallee()->IgnoreParens());
|
|
|
|
const Expr *BaseExpr = BO->getLHS();
|
|
|
|
const Expr *MemFnExpr = BO->getRHS();
|
|
|
|
|
|
|
|
const MemberPointerType *MPT =
|
|
|
|
MemFnExpr->getType()->getAs<MemberPointerType>();
|
|
|
|
const FunctionProtoType *FPT =
|
|
|
|
MPT->getPointeeType()->getAs<FunctionProtoType>();
|
|
|
|
const CXXRecordDecl *RD =
|
|
|
|
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
|
|
|
|
|
|
|
|
const llvm::FunctionType *FTy =
|
|
|
|
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
|
|
|
|
FPT->isVariadic());
|
|
|
|
|
2010-02-05 01:08:48 +08:00
|
|
|
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
|
2010-01-02 04:29:01 +08:00
|
|
|
|
|
|
|
// Get the member function pointer.
|
2010-02-09 10:48:28 +08:00
|
|
|
llvm::Value *MemFnPtr = CreateMemTemp(MemFnExpr->getType(), "mem.fn");
|
2010-01-02 04:29:01 +08:00
|
|
|
EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
|
|
|
|
|
|
|
|
// Emit the 'this' pointer.
|
|
|
|
llvm::Value *This;
|
|
|
|
|
|
|
|
if (BO->getOpcode() == BinaryOperator::PtrMemI)
|
|
|
|
This = EmitScalarExpr(BaseExpr);
|
|
|
|
else
|
|
|
|
This = EmitLValue(BaseExpr).getAddress();
|
|
|
|
|
|
|
|
// Adjust it.
|
|
|
|
llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1);
|
|
|
|
Adj = Builder.CreateLoad(Adj, "mem.fn.adj");
|
|
|
|
|
|
|
|
llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr");
|
|
|
|
Ptr = Builder.CreateGEP(Ptr, Adj, "adj");
|
|
|
|
|
|
|
|
This = Builder.CreateBitCast(Ptr, This->getType(), "this");
|
|
|
|
|
|
|
|
llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr");
|
|
|
|
|
|
|
|
const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
|
|
|
|
|
|
|
|
llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn");
|
|
|
|
|
|
|
|
// If the LSB in the function pointer is 1, the function pointer points to
|
|
|
|
// a virtual function.
|
|
|
|
llvm::Value *IsVirtual
|
|
|
|
= Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1),
|
|
|
|
"and");
|
|
|
|
|
|
|
|
IsVirtual = Builder.CreateTrunc(IsVirtual,
|
|
|
|
llvm::Type::getInt1Ty(VMContext));
|
|
|
|
|
|
|
|
llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual");
|
|
|
|
llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual");
|
|
|
|
llvm::BasicBlock *FnEnd = createBasicBlock("fn.end");
|
|
|
|
|
|
|
|
Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
|
|
|
|
EmitBlock(FnVirtual);
|
|
|
|
|
2010-04-18 04:15:18 +08:00
|
|
|
const llvm::Type *VTableTy =
|
2010-02-05 01:08:48 +08:00
|
|
|
FTy->getPointerTo()->getPointerTo();
|
2010-01-02 04:29:01 +08:00
|
|
|
|
2010-04-18 04:15:18 +08:00
|
|
|
llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo());
|
|
|
|
VTable = Builder.CreateLoad(VTable);
|
2010-01-02 04:29:01 +08:00
|
|
|
|
2010-04-18 04:15:18 +08:00
|
|
|
VTable = Builder.CreateBitCast(VTable, Int8PtrTy);
|
|
|
|
llvm::Value *VTableOffset =
|
2010-02-05 01:08:48 +08:00
|
|
|
Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1));
|
2010-01-02 04:29:01 +08:00
|
|
|
|
2010-04-18 04:15:18 +08:00
|
|
|
VTable = Builder.CreateGEP(VTable, VTableOffset, "fn");
|
|
|
|
VTable = Builder.CreateBitCast(VTable, VTableTy);
|
2010-01-02 04:29:01 +08:00
|
|
|
|
2010-04-18 04:15:18 +08:00
|
|
|
llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
|
2010-01-02 04:29:01 +08:00
|
|
|
|
|
|
|
EmitBranch(FnEnd);
|
|
|
|
EmitBlock(FnNonVirtual);
|
|
|
|
|
|
|
|
// If the function is not virtual, just load the pointer.
|
|
|
|
llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn");
|
|
|
|
NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo());
|
|
|
|
|
|
|
|
EmitBlock(FnEnd);
|
|
|
|
|
|
|
|
llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo());
|
|
|
|
Callee->reserveOperandSpace(2);
|
|
|
|
Callee->addIncoming(VirtualFn, FnVirtual);
|
|
|
|
Callee->addIncoming(NonVirtualFn, FnNonVirtual);
|
|
|
|
|
|
|
|
CallArgList Args;
|
|
|
|
|
|
|
|
QualType ThisType =
|
|
|
|
getContext().getPointerType(getContext().getTagDeclType(RD));
|
|
|
|
|
|
|
|
// Push the this ptr.
|
|
|
|
Args.push_back(std::make_pair(RValue::get(This), ThisType));
|
|
|
|
|
|
|
|
// And the rest of the call args
|
|
|
|
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
|
2010-02-06 05:31:56 +08:00
|
|
|
const FunctionType *BO_FPT = BO->getType()->getAs<FunctionProtoType>();
|
|
|
|
return EmitCall(CGM.getTypes().getFunctionInfo(Args, BO_FPT), Callee,
|
2010-01-02 04:29:01 +08:00
|
|
|
ReturnValue, Args);
|
|
|
|
}
|
|
|
|
|
|
|
|
RValue
|
|
|
|
CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
|
|
|
|
const CXXMethodDecl *MD,
|
|
|
|
ReturnValueSlot ReturnValue) {
|
|
|
|
assert(MD->isInstance() &&
|
|
|
|
"Trying to emit a member call expr on a static method!");
|
|
|
|
|
|
|
|
if (MD->isCopyAssignment()) {
|
|
|
|
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
|
|
|
|
if (ClassDecl->hasTrivialCopyAssignment()) {
|
|
|
|
assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
|
|
|
|
"EmitCXXOperatorMemberCallExpr - user declared copy assignment");
|
2010-05-11 06:57:35 +08:00
|
|
|
LValue LV = EmitLValue(E->getArg(0));
|
|
|
|
llvm::Value *This;
|
|
|
|
if (LV.isPropertyRef()) {
|
|
|
|
RValue RV = EmitLoadOfPropertyRefLValue(LV, E->getArg(0)->getType());
|
|
|
|
assert (!RV.isScalar() && "EmitCXXOperatorMemberCallExpr");
|
|
|
|
This = RV.getAggregateAddr();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
This = LV.getAddress();
|
|
|
|
|
2010-01-02 04:29:01 +08:00
|
|
|
llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
|
|
|
|
QualType Ty = E->getType();
|
|
|
|
EmitAggregateCopy(This, Src, Ty);
|
|
|
|
return RValue::get(This);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
|
|
|
const llvm::Type *Ty =
|
|
|
|
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
|
|
|
|
FPT->isVariadic());
|
2010-05-08 02:56:13 +08:00
|
|
|
LValue LV = EmitLValue(E->getArg(0));
|
|
|
|
llvm::Value *This;
|
|
|
|
if (LV.isPropertyRef()) {
|
|
|
|
RValue RV = EmitLoadOfPropertyRefLValue(LV, E->getArg(0)->getType());
|
2010-05-08 02:59:54 +08:00
|
|
|
assert (!RV.isScalar() && "EmitCXXOperatorMemberCallExpr");
|
|
|
|
This = RV.getAggregateAddr();
|
2010-05-08 02:56:13 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
This = LV.getAddress();
|
2010-01-02 04:29:01 +08:00
|
|
|
|
|
|
|
llvm::Value *Callee;
|
|
|
|
if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0)))
|
|
|
|
Callee = BuildVirtualCall(MD, This, Ty);
|
|
|
|
else
|
|
|
|
Callee = CGM.GetAddrOfFunction(MD, Ty);
|
|
|
|
|
2010-01-02 09:01:18 +08:00
|
|
|
return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
|
2010-01-02 04:29:01 +08:00
|
|
|
E->arg_begin() + 1, E->arg_end());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
|
|
|
|
const CXXConstructExpr *E) {
|
|
|
|
assert(Dest && "Must have a destination!");
|
|
|
|
const CXXConstructorDecl *CD = E->getConstructor();
|
|
|
|
const ConstantArrayType *Array =
|
|
|
|
getContext().getAsConstantArrayType(E->getType());
|
|
|
|
// For a copy constructor, even if it is trivial, must fall thru so
|
|
|
|
// its argument is code-gen'ed.
|
|
|
|
if (!CD->isCopyConstructor()) {
|
|
|
|
QualType InitType = E->getType();
|
|
|
|
if (Array)
|
|
|
|
InitType = getContext().getBaseElementType(Array);
|
|
|
|
const CXXRecordDecl *RD =
|
|
|
|
cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl());
|
|
|
|
if (RD->hasTrivialConstructor())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Code gen optimization to eliminate copy constructor and return
|
|
|
|
// its first argument instead.
|
|
|
|
if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
|
Rework our handling of copy construction of temporaries, which was a
poor (and wrong) approximation of the actual rules governing when to
build a copy and when it can be elided.
The correct implementation is actually simpler than the
approximation. When we only enumerate constructors as part of
initialization (e.g., for direct initialization or when we're copying
from a class type or one of its derived classes), we don't create a
copy. When we enumerate all conversion functions, we do create a
copy. Before, we created some extra copies and missed some
others. The new test copy-initialization.cpp shows a case where we
missed creating a (required, non-elidable) copy as part of a
user-defined conversion, which resulted in a miscompile. This commit
also fixes PR6757, where the missing copy made us reject well-formed
code in the ternary operator.
This commit also cleans up our handling of copy elision in the case
where we create an extra copy of a temporary object, which became
necessary now that we produce the right copies. The code that seeks to
find the temporary object being copied has moved into
Expr::getTemporaryObject(); it used to have two different
not-quite-the-same implementations, one in Sema and one in CodeGen.
Note that we still do not attempt to perform the named return value
optimization, so we miss copy elisions for return values and throw
expressions.
llvm-svn: 100196
2010-04-03 02:24:57 +08:00
|
|
|
const Expr *Arg = E->getArg(0)->getTemporaryObject();
|
2010-01-02 04:29:01 +08:00
|
|
|
EmitAggExpr(Arg, Dest, false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (Array) {
|
|
|
|
QualType BaseElementTy = getContext().getBaseElementType(Array);
|
|
|
|
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
|
|
|
|
BasePtr = llvm::PointerType::getUnqual(BasePtr);
|
|
|
|
llvm::Value *BaseAddrPtr =
|
2010-05-02 01:02:18 +08:00
|
|
|
Builder.CreateBitCast(Dest, BasePtr);
|
2010-01-02 04:29:01 +08:00
|
|
|
|
|
|
|
EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
|
|
|
|
E->arg_begin(), E->arg_end());
|
|
|
|
}
|
2010-05-03 07:20:53 +08:00
|
|
|
else {
|
|
|
|
CXXCtorType Type =
|
|
|
|
(E->getConstructionKind() == CXXConstructExpr::CK_Complete)
|
|
|
|
? Ctor_Complete : Ctor_Base;
|
|
|
|
bool ForVirtualBase =
|
|
|
|
E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase;
|
|
|
|
|
2010-01-02 04:29:01 +08:00
|
|
|
// Call the constructor.
|
2010-05-03 07:20:53 +08:00
|
|
|
EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest,
|
2010-01-02 04:29:01 +08:00
|
|
|
E->arg_begin(), E->arg_end());
|
2010-05-03 07:20:53 +08:00
|
|
|
}
|
2010-01-02 04:29:01 +08:00
|
|
|
}
|
|
|
|
|
2010-01-27 03:44:24 +08:00
|
|
|
static CharUnits CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
|
2009-12-14 04:04:38 +08:00
|
|
|
const RecordType *RT = ElementType->getAs<RecordType>();
|
2009-09-24 00:07:23 +08:00
|
|
|
if (!RT)
|
2010-01-27 03:44:24 +08:00
|
|
|
return CharUnits::Zero();
|
2009-09-24 00:07:23 +08:00
|
|
|
|
|
|
|
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
|
|
|
|
if (!RD)
|
2010-01-27 03:44:24 +08:00
|
|
|
return CharUnits::Zero();
|
2009-09-24 00:07:23 +08:00
|
|
|
|
|
|
|
// Check if the class has a trivial destructor.
|
|
|
|
if (RD->hasTrivialDestructor()) {
|
2009-12-14 04:04:38 +08:00
|
|
|
// Check if the usual deallocation function takes two arguments.
|
2009-12-14 04:10:12 +08:00
|
|
|
const CXXMethodDecl *UsualDeallocationFunction = 0;
|
|
|
|
|
2009-12-14 04:04:38 +08:00
|
|
|
DeclarationName OpName =
|
|
|
|
Ctx.DeclarationNames.getCXXOperatorName(OO_Array_Delete);
|
|
|
|
DeclContext::lookup_const_iterator Op, OpEnd;
|
|
|
|
for (llvm::tie(Op, OpEnd) = RD->lookup(OpName);
|
|
|
|
Op != OpEnd; ++Op) {
|
2009-12-14 04:10:12 +08:00
|
|
|
const CXXMethodDecl *Delete = cast<CXXMethodDecl>(*Op);
|
2009-12-14 04:04:38 +08:00
|
|
|
|
|
|
|
if (Delete->isUsualDeallocationFunction()) {
|
2009-12-14 04:10:12 +08:00
|
|
|
UsualDeallocationFunction = Delete;
|
2009-12-14 04:04:38 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-12-14 04:10:12 +08:00
|
|
|
|
|
|
|
// No usual deallocation function, we don't need a cookie.
|
|
|
|
if (!UsualDeallocationFunction)
|
2010-01-27 03:44:24 +08:00
|
|
|
return CharUnits::Zero();
|
2009-12-14 04:10:12 +08:00
|
|
|
|
|
|
|
// The usual deallocation function doesn't take a size_t argument, so we
|
|
|
|
// don't need a cookie.
|
|
|
|
if (UsualDeallocationFunction->getNumParams() == 1)
|
2010-01-27 03:44:24 +08:00
|
|
|
return CharUnits::Zero();
|
2009-12-14 04:10:12 +08:00
|
|
|
|
|
|
|
assert(UsualDeallocationFunction->getNumParams() == 2 &&
|
|
|
|
"Unexpected deallocation function type!");
|
|
|
|
}
|
2009-09-24 00:07:23 +08:00
|
|
|
|
2009-12-14 04:04:38 +08:00
|
|
|
// Padding is the maximum of sizeof(size_t) and alignof(ElementType)
|
2010-01-27 03:44:24 +08:00
|
|
|
return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()),
|
|
|
|
Ctx.getTypeAlignInChars(ElementType));
|
2009-12-14 04:04:38 +08:00
|
|
|
}
|
|
|
|
|
2010-01-27 03:44:24 +08:00
|
|
|
static CharUnits CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
|
2009-12-14 04:04:38 +08:00
|
|
|
if (!E->isArray())
|
2010-01-27 03:44:24 +08:00
|
|
|
return CharUnits::Zero();
|
2009-12-14 04:04:38 +08:00
|
|
|
|
2009-12-14 04:34:34 +08:00
|
|
|
// No cookie is required if the new operator being used is
|
|
|
|
// ::operator new[](size_t, void*).
|
|
|
|
const FunctionDecl *OperatorNew = E->getOperatorNew();
|
|
|
|
if (OperatorNew->getDeclContext()->getLookupContext()->isFileContext()) {
|
|
|
|
if (OperatorNew->getNumParams() == 2) {
|
|
|
|
CanQualType ParamType =
|
|
|
|
Ctx.getCanonicalType(OperatorNew->getParamDecl(1)->getType());
|
|
|
|
|
|
|
|
if (ParamType == Ctx.VoidPtrTy)
|
2010-01-27 03:44:24 +08:00
|
|
|
return CharUnits::Zero();
|
2009-12-14 04:34:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-14 04:04:38 +08:00
|
|
|
return CalculateCookiePadding(Ctx, E->getAllocatedType());
|
2009-09-24 00:07:23 +08:00
|
|
|
}
|
|
|
|
|
2010-03-25 00:57:01 +08:00
|
|
|
static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context,
|
|
|
|
CodeGenFunction &CGF,
|
2009-09-24 00:07:23 +08:00
|
|
|
const CXXNewExpr *E,
|
|
|
|
llvm::Value *& NumElements) {
|
|
|
|
QualType Type = E->getAllocatedType();
|
2010-01-27 03:44:24 +08:00
|
|
|
CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(Type);
|
2009-09-24 00:07:23 +08:00
|
|
|
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
|
|
|
|
|
|
|
|
if (!E->isArray())
|
2010-01-27 03:44:24 +08:00
|
|
|
return llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity());
|
2009-09-24 00:07:23 +08:00
|
|
|
|
2010-01-27 03:44:24 +08:00
|
|
|
CharUnits CookiePadding = CalculateCookiePadding(CGF.getContext(), E);
|
2009-09-24 00:07:23 +08:00
|
|
|
|
|
|
|
Expr::EvalResult Result;
|
|
|
|
if (E->getArraySize()->Evaluate(Result, CGF.getContext()) &&
|
|
|
|
!Result.HasSideEffects && Result.Val.isInt()) {
|
|
|
|
|
2010-01-27 03:44:24 +08:00
|
|
|
CharUnits AllocSize =
|
|
|
|
Result.Val.getInt().getZExtValue() * TypeSize + CookiePadding;
|
2009-09-24 00:07:23 +08:00
|
|
|
|
|
|
|
NumElements =
|
|
|
|
llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue());
|
2010-03-25 00:57:01 +08:00
|
|
|
while (const ArrayType *AType = Context.getAsArrayType(Type)) {
|
|
|
|
const llvm::ArrayType *llvmAType =
|
|
|
|
cast<llvm::ArrayType>(CGF.ConvertType(Type));
|
|
|
|
NumElements =
|
|
|
|
CGF.Builder.CreateMul(NumElements,
|
|
|
|
llvm::ConstantInt::get(
|
|
|
|
SizeTy, llvmAType->getNumElements()));
|
|
|
|
Type = AType->getElementType();
|
|
|
|
}
|
2009-09-24 00:07:23 +08:00
|
|
|
|
2010-01-27 03:44:24 +08:00
|
|
|
return llvm::ConstantInt::get(SizeTy, AllocSize.getQuantity());
|
2009-09-24 00:07:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the array size expression.
|
|
|
|
NumElements = CGF.EmitScalarExpr(E->getArraySize());
|
|
|
|
|
|
|
|
// Multiply with the type size.
|
|
|
|
llvm::Value *V =
|
|
|
|
CGF.Builder.CreateMul(NumElements,
|
2010-01-27 03:44:24 +08:00
|
|
|
llvm::ConstantInt::get(SizeTy,
|
|
|
|
TypeSize.getQuantity()));
|
2010-03-25 00:57:01 +08:00
|
|
|
|
|
|
|
while (const ArrayType *AType = Context.getAsArrayType(Type)) {
|
|
|
|
const llvm::ArrayType *llvmAType =
|
|
|
|
cast<llvm::ArrayType>(CGF.ConvertType(Type));
|
|
|
|
NumElements =
|
|
|
|
CGF.Builder.CreateMul(NumElements,
|
|
|
|
llvm::ConstantInt::get(
|
|
|
|
SizeTy, llvmAType->getNumElements()));
|
|
|
|
Type = AType->getElementType();
|
|
|
|
}
|
2009-09-24 00:07:23 +08:00
|
|
|
|
|
|
|
// And add the cookie padding if necessary.
|
2010-01-27 03:44:24 +08:00
|
|
|
if (!CookiePadding.isZero())
|
|
|
|
V = CGF.Builder.CreateAdd(V,
|
|
|
|
llvm::ConstantInt::get(SizeTy, CookiePadding.getQuantity()));
|
2009-09-24 00:07:23 +08:00
|
|
|
|
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
|
|
|
|
llvm::Value *NewPtr,
|
|
|
|
llvm::Value *NumElements) {
|
2009-11-25 02:43:52 +08:00
|
|
|
if (E->isArray()) {
|
2010-05-03 23:09:17 +08:00
|
|
|
if (CXXConstructorDecl *Ctor = E->getConstructor()) {
|
|
|
|
if (!Ctor->getParent()->hasTrivialConstructor())
|
|
|
|
CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
|
|
|
|
E->constructor_arg_begin(),
|
|
|
|
E->constructor_arg_end());
|
|
|
|
return;
|
|
|
|
}
|
2009-11-25 02:43:52 +08:00
|
|
|
}
|
|
|
|
|
2009-09-24 00:07:23 +08:00
|
|
|
QualType AllocType = E->getAllocatedType();
|
|
|
|
|
2009-11-25 02:43:52 +08:00
|
|
|
if (CXXConstructorDecl *Ctor = E->getConstructor()) {
|
2010-05-03 07:20:53 +08:00
|
|
|
CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false,
|
|
|
|
NewPtr, E->constructor_arg_begin(),
|
2009-11-25 02:43:52 +08:00
|
|
|
E->constructor_arg_end());
|
2009-09-24 00:07:23 +08:00
|
|
|
|
2009-11-25 02:43:52 +08:00
|
|
|
return;
|
|
|
|
}
|
2009-09-24 00:07:23 +08:00
|
|
|
|
2009-11-25 02:43:52 +08:00
|
|
|
// We have a POD type.
|
|
|
|
if (E->getNumConstructorArgs() == 0)
|
|
|
|
return;
|
2009-09-24 00:07:23 +08:00
|
|
|
|
2009-11-25 02:43:52 +08:00
|
|
|
assert(E->getNumConstructorArgs() == 1 &&
|
|
|
|
"Can only have one argument to initializer of POD type.");
|
2009-09-24 00:07:23 +08:00
|
|
|
|
2009-11-25 02:43:52 +08:00
|
|
|
const Expr *Init = E->getConstructorArg(0);
|
2009-09-24 00:07:23 +08:00
|
|
|
|
2009-11-25 02:43:52 +08:00
|
|
|
if (!CGF.hasAggregateLLVMType(AllocType))
|
|
|
|
CGF.EmitStoreOfScalar(CGF.EmitScalarExpr(Init), NewPtr,
|
|
|
|
AllocType.isVolatileQualified(), AllocType);
|
|
|
|
else if (AllocType->isAnyComplexType())
|
|
|
|
CGF.EmitComplexExprIntoAddr(Init, NewPtr,
|
|
|
|
AllocType.isVolatileQualified());
|
|
|
|
else
|
|
|
|
CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified());
|
2009-09-24 00:07:23 +08:00
|
|
|
}
|
|
|
|
|
2009-09-23 06:53:17 +08:00
|
|
|
llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
|
|
|
|
QualType AllocType = E->getAllocatedType();
|
|
|
|
FunctionDecl *NewFD = E->getOperatorNew();
|
|
|
|
const FunctionProtoType *NewFTy = NewFD->getType()->getAs<FunctionProtoType>();
|
|
|
|
|
|
|
|
CallArgList NewArgs;
|
|
|
|
|
|
|
|
// The allocation size is the first argument.
|
|
|
|
QualType SizeTy = getContext().getSizeType();
|
|
|
|
|
2009-09-24 00:07:23 +08:00
|
|
|
llvm::Value *NumElements = 0;
|
2010-03-25 00:57:01 +08:00
|
|
|
llvm::Value *AllocSize = EmitCXXNewAllocSize(getContext(),
|
|
|
|
*this, E, NumElements);
|
2009-09-24 00:07:23 +08:00
|
|
|
|
2009-09-23 06:53:17 +08:00
|
|
|
NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy));
|
|
|
|
|
|
|
|
// Emit the rest of the arguments.
|
|
|
|
// FIXME: Ideally, this should just use EmitCallArgs.
|
|
|
|
CXXNewExpr::const_arg_iterator NewArg = E->placement_arg_begin();
|
|
|
|
|
|
|
|
// First, use the types from the function type.
|
|
|
|
// We start at 1 here because the first argument (the allocation size)
|
|
|
|
// has already been emitted.
|
|
|
|
for (unsigned i = 1, e = NewFTy->getNumArgs(); i != e; ++i, ++NewArg) {
|
|
|
|
QualType ArgType = NewFTy->getArgType(i);
|
|
|
|
|
|
|
|
assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
|
|
|
|
getTypePtr() ==
|
|
|
|
getContext().getCanonicalType(NewArg->getType()).getTypePtr() &&
|
|
|
|
"type mismatch in call argument!");
|
|
|
|
|
|
|
|
NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType),
|
|
|
|
ArgType));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Either we've emitted all the call args, or we have a call to a
|
|
|
|
// variadic function.
|
|
|
|
assert((NewArg == E->placement_arg_end() || NewFTy->isVariadic()) &&
|
|
|
|
"Extra arguments in non-variadic function!");
|
|
|
|
|
|
|
|
// If we still have any arguments, emit them using the type of the argument.
|
|
|
|
for (CXXNewExpr::const_arg_iterator NewArgEnd = E->placement_arg_end();
|
|
|
|
NewArg != NewArgEnd; ++NewArg) {
|
|
|
|
QualType ArgType = NewArg->getType();
|
|
|
|
NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType),
|
|
|
|
ArgType));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the call to new.
|
|
|
|
RValue RV =
|
2010-02-06 05:31:56 +08:00
|
|
|
EmitCall(CGM.getTypes().getFunctionInfo(NewArgs, NewFTy),
|
2009-12-25 03:25:24 +08:00
|
|
|
CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD);
|
2009-09-23 06:53:17 +08:00
|
|
|
|
|
|
|
// If an allocation function is declared with an empty exception specification
|
|
|
|
// it returns null to indicate failure to allocate storage. [expr.new]p13.
|
|
|
|
// (We don't need to check for null when there's no new initializer and
|
|
|
|
// we're allocating a POD type).
|
|
|
|
bool NullCheckResult = NewFTy->hasEmptyExceptionSpec() &&
|
|
|
|
!(AllocType->isPODType() && !E->hasInitializer());
|
|
|
|
|
|
|
|
llvm::BasicBlock *NewNull = 0;
|
|
|
|
llvm::BasicBlock *NewNotNull = 0;
|
|
|
|
llvm::BasicBlock *NewEnd = 0;
|
|
|
|
|
|
|
|
llvm::Value *NewPtr = RV.getScalarVal();
|
|
|
|
|
|
|
|
if (NullCheckResult) {
|
|
|
|
NewNull = createBasicBlock("new.null");
|
|
|
|
NewNotNull = createBasicBlock("new.notnull");
|
|
|
|
NewEnd = createBasicBlock("new.end");
|
|
|
|
|
|
|
|
llvm::Value *IsNull =
|
|
|
|
Builder.CreateICmpEQ(NewPtr,
|
|
|
|
llvm::Constant::getNullValue(NewPtr->getType()),
|
|
|
|
"isnull");
|
|
|
|
|
|
|
|
Builder.CreateCondBr(IsNull, NewNull, NewNotNull);
|
|
|
|
EmitBlock(NewNotNull);
|
|
|
|
}
|
2010-01-27 03:44:24 +08:00
|
|
|
|
|
|
|
CharUnits CookiePadding = CalculateCookiePadding(getContext(), E);
|
|
|
|
if (!CookiePadding.isZero()) {
|
|
|
|
CharUnits CookieOffset =
|
|
|
|
CookiePadding - getContext().getTypeSizeInChars(SizeTy);
|
2009-09-24 02:59:48 +08:00
|
|
|
|
|
|
|
llvm::Value *NumElementsPtr =
|
2010-01-27 03:44:24 +08:00
|
|
|
Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset.getQuantity());
|
2009-09-24 02:59:48 +08:00
|
|
|
|
|
|
|
NumElementsPtr = Builder.CreateBitCast(NumElementsPtr,
|
|
|
|
ConvertType(SizeTy)->getPointerTo());
|
|
|
|
Builder.CreateStore(NumElements, NumElementsPtr);
|
|
|
|
|
|
|
|
// Now add the padding to the new ptr.
|
2010-01-27 03:44:24 +08:00
|
|
|
NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr,
|
|
|
|
CookiePadding.getQuantity());
|
2009-09-24 02:59:48 +08:00
|
|
|
}
|
|
|
|
|
2010-03-25 00:57:01 +08:00
|
|
|
if (AllocType->isArrayType()) {
|
|
|
|
while (const ArrayType *AType = getContext().getAsArrayType(AllocType))
|
|
|
|
AllocType = AType->getElementType();
|
|
|
|
NewPtr =
|
|
|
|
Builder.CreateBitCast(NewPtr,
|
|
|
|
ConvertType(getContext().getPointerType(AllocType)));
|
|
|
|
EmitNewInitializer(*this, E, NewPtr, NumElements);
|
|
|
|
NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
|
|
|
|
EmitNewInitializer(*this, E, NewPtr, NumElements);
|
|
|
|
}
|
|
|
|
|
2009-09-23 06:53:17 +08:00
|
|
|
if (NullCheckResult) {
|
|
|
|
Builder.CreateBr(NewEnd);
|
2009-11-11 06:39:09 +08:00
|
|
|
NewNotNull = Builder.GetInsertBlock();
|
2009-09-23 06:53:17 +08:00
|
|
|
EmitBlock(NewNull);
|
|
|
|
Builder.CreateBr(NewEnd);
|
|
|
|
EmitBlock(NewEnd);
|
|
|
|
|
|
|
|
llvm::PHINode *PHI = Builder.CreatePHI(NewPtr->getType());
|
|
|
|
PHI->reserveOperandSpace(2);
|
|
|
|
PHI->addIncoming(NewPtr, NewNotNull);
|
|
|
|
PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()), NewNull);
|
|
|
|
|
|
|
|
NewPtr = PHI;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewPtr;
|
|
|
|
}
|
|
|
|
|
2009-12-14 04:04:38 +08:00
|
|
|
static std::pair<llvm::Value *, llvm::Value *>
|
|
|
|
GetAllocatedObjectPtrAndNumElements(CodeGenFunction &CGF,
|
|
|
|
llvm::Value *Ptr, QualType DeleteTy) {
|
|
|
|
QualType SizeTy = CGF.getContext().getSizeType();
|
|
|
|
const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
|
|
|
|
|
2010-01-27 03:44:24 +08:00
|
|
|
CharUnits DeleteTypeAlign = CGF.getContext().getTypeAlignInChars(DeleteTy);
|
|
|
|
CharUnits CookiePadding =
|
|
|
|
std::max(CGF.getContext().getTypeSizeInChars(SizeTy),
|
|
|
|
DeleteTypeAlign);
|
|
|
|
assert(!CookiePadding.isZero() && "CookiePadding should not be 0.");
|
2009-12-14 04:04:38 +08:00
|
|
|
|
|
|
|
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
|
2010-01-27 03:44:24 +08:00
|
|
|
CharUnits CookieOffset =
|
|
|
|
CookiePadding - CGF.getContext().getTypeSizeInChars(SizeTy);
|
2009-12-14 04:04:38 +08:00
|
|
|
|
|
|
|
llvm::Value *AllocatedObjectPtr = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy);
|
|
|
|
AllocatedObjectPtr =
|
|
|
|
CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
|
2010-01-27 03:44:24 +08:00
|
|
|
-CookiePadding.getQuantity());
|
2009-12-14 04:04:38 +08:00
|
|
|
|
|
|
|
llvm::Value *NumElementsPtr =
|
|
|
|
CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
|
2010-01-27 03:44:24 +08:00
|
|
|
CookieOffset.getQuantity());
|
2009-12-14 04:04:38 +08:00
|
|
|
NumElementsPtr =
|
|
|
|
CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo());
|
|
|
|
|
|
|
|
llvm::Value *NumElements = CGF.Builder.CreateLoad(NumElementsPtr);
|
|
|
|
NumElements =
|
|
|
|
CGF.Builder.CreateIntCast(NumElements, SizeLTy, /*isSigned=*/false);
|
|
|
|
|
|
|
|
return std::make_pair(AllocatedObjectPtr, NumElements);
|
|
|
|
}
|
|
|
|
|
2009-11-18 08:50:08 +08:00
|
|
|
void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
|
|
|
|
llvm::Value *Ptr,
|
|
|
|
QualType DeleteTy) {
|
|
|
|
const FunctionProtoType *DeleteFTy =
|
|
|
|
DeleteFD->getType()->getAs<FunctionProtoType>();
|
|
|
|
|
|
|
|
CallArgList DeleteArgs;
|
|
|
|
|
2009-12-14 04:04:38 +08:00
|
|
|
// Check if we need to pass the size to the delete operator.
|
|
|
|
llvm::Value *Size = 0;
|
|
|
|
QualType SizeTy;
|
2009-11-18 08:50:08 +08:00
|
|
|
if (DeleteFTy->getNumArgs() == 2) {
|
2009-12-14 04:04:38 +08:00
|
|
|
SizeTy = DeleteFTy->getArgType(1);
|
2010-01-27 03:59:28 +08:00
|
|
|
CharUnits DeleteTypeSize = getContext().getTypeSizeInChars(DeleteTy);
|
|
|
|
Size = llvm::ConstantInt::get(ConvertType(SizeTy),
|
|
|
|
DeleteTypeSize.getQuantity());
|
2009-12-14 04:04:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (DeleteFD->getOverloadedOperator() == OO_Array_Delete &&
|
2010-01-27 03:44:24 +08:00
|
|
|
!CalculateCookiePadding(getContext(), DeleteTy).isZero()) {
|
2009-12-14 04:04:38 +08:00
|
|
|
// We need to get the number of elements in the array from the cookie.
|
|
|
|
llvm::Value *AllocatedObjectPtr;
|
|
|
|
llvm::Value *NumElements;
|
|
|
|
llvm::tie(AllocatedObjectPtr, NumElements) =
|
|
|
|
GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy);
|
2009-12-14 02:48:07 +08:00
|
|
|
|
2009-12-14 04:04:38 +08:00
|
|
|
// Multiply the size with the number of elements.
|
|
|
|
if (Size)
|
2009-12-14 02:48:07 +08:00
|
|
|
Size = Builder.CreateMul(NumElements, Size);
|
2009-12-14 04:04:38 +08:00
|
|
|
|
|
|
|
Ptr = AllocatedObjectPtr;
|
2009-11-18 08:50:08 +08:00
|
|
|
}
|
2009-12-14 04:04:38 +08:00
|
|
|
|
|
|
|
QualType ArgTy = DeleteFTy->getArgType(0);
|
|
|
|
llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
|
|
|
|
DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy));
|
|
|
|
|
|
|
|
if (Size)
|
|
|
|
DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy));
|
2009-11-18 08:50:08 +08:00
|
|
|
|
|
|
|
// Emit the call to delete.
|
2010-02-06 05:31:56 +08:00
|
|
|
EmitCall(CGM.getTypes().getFunctionInfo(DeleteArgs, DeleteFTy),
|
2009-12-25 03:25:24 +08:00
|
|
|
CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(),
|
2009-11-18 08:50:08 +08:00
|
|
|
DeleteArgs, DeleteFD);
|
|
|
|
}
|
|
|
|
|
2009-09-23 06:53:17 +08:00
|
|
|
void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
|
2009-11-14 03:27:47 +08:00
|
|
|
|
2009-09-30 02:16:17 +08:00
|
|
|
// Get at the argument before we performed the implicit conversion
|
|
|
|
// to void*.
|
|
|
|
const Expr *Arg = E->getArgument();
|
|
|
|
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
|
|
|
|
if (ICE->getCastKind() != CastExpr::CK_UserDefinedConversion &&
|
|
|
|
ICE->getType()->isVoidPointerType())
|
|
|
|
Arg = ICE->getSubExpr();
|
2009-10-01 13:49:51 +08:00
|
|
|
else
|
|
|
|
break;
|
2009-09-30 02:16:17 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
QualType DeleteTy = Arg->getType()->getAs<PointerType>()->getPointeeType();
|
2009-09-23 06:53:17 +08:00
|
|
|
|
2009-09-30 02:16:17 +08:00
|
|
|
llvm::Value *Ptr = EmitScalarExpr(Arg);
|
2009-09-23 06:53:17 +08:00
|
|
|
|
|
|
|
// Null check the pointer.
|
|
|
|
llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull");
|
|
|
|
llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end");
|
|
|
|
|
|
|
|
llvm::Value *IsNull =
|
|
|
|
Builder.CreateICmpEQ(Ptr, llvm::Constant::getNullValue(Ptr->getType()),
|
|
|
|
"isnull");
|
|
|
|
|
|
|
|
Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull);
|
|
|
|
EmitBlock(DeleteNotNull);
|
2009-11-13 12:45:41 +08:00
|
|
|
|
|
|
|
bool ShouldCallDelete = true;
|
|
|
|
|
2009-09-23 06:53:17 +08:00
|
|
|
// Call the destructor if necessary.
|
|
|
|
if (const RecordType *RT = DeleteTy->getAs<RecordType>()) {
|
|
|
|
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
|
|
|
|
if (!RD->hasTrivialDestructor()) {
|
|
|
|
const CXXDestructorDecl *Dtor = RD->getDestructor(getContext());
|
2009-11-14 03:27:47 +08:00
|
|
|
if (E->isArrayForm()) {
|
2009-12-14 04:04:38 +08:00
|
|
|
llvm::Value *AllocatedObjectPtr;
|
|
|
|
llvm::Value *NumElements;
|
|
|
|
llvm::tie(AllocatedObjectPtr, NumElements) =
|
|
|
|
GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy);
|
|
|
|
|
2009-12-14 02:48:07 +08:00
|
|
|
EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr);
|
|
|
|
} else if (Dtor->isVirtual()) {
|
2009-09-23 06:53:17 +08:00
|
|
|
const llvm::Type *Ty =
|
|
|
|
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor),
|
|
|
|
/*isVariadic=*/false);
|
|
|
|
|
2009-11-13 12:45:41 +08:00
|
|
|
llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty);
|
2010-01-02 09:01:18 +08:00
|
|
|
EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0,
|
|
|
|
0, 0);
|
2009-11-13 12:45:41 +08:00
|
|
|
|
|
|
|
// The dtor took care of deleting the object.
|
|
|
|
ShouldCallDelete = false;
|
2009-09-23 06:53:17 +08:00
|
|
|
} else
|
2010-05-03 07:29:11 +08:00
|
|
|
EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false,
|
|
|
|
Ptr);
|
2009-09-23 06:53:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-18 08:50:08 +08:00
|
|
|
if (ShouldCallDelete)
|
|
|
|
EmitDeleteCall(E->getOperatorDelete(), Ptr, DeleteTy);
|
2009-09-23 06:53:17 +08:00
|
|
|
|
|
|
|
EmitBlock(DeleteEnd);
|
|
|
|
}
|
2009-11-15 16:09:41 +08:00
|
|
|
|
|
|
|
llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
|
|
|
|
QualType Ty = E->getType();
|
|
|
|
const llvm::Type *LTy = ConvertType(Ty)->getPointerTo();
|
2009-12-11 10:46:30 +08:00
|
|
|
|
2009-12-17 15:09:17 +08:00
|
|
|
if (E->isTypeOperand()) {
|
|
|
|
llvm::Constant *TypeInfo =
|
|
|
|
CGM.GetAddrOfRTTIDescriptor(E->getTypeOperand());
|
|
|
|
return Builder.CreateBitCast(TypeInfo, LTy);
|
|
|
|
}
|
|
|
|
|
2009-11-15 16:09:41 +08:00
|
|
|
Expr *subE = E->getExprOperand();
|
2009-11-18 06:33:00 +08:00
|
|
|
Ty = subE->getType();
|
|
|
|
CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
|
|
|
|
Ty = CanTy.getUnqualifiedType().getNonReferenceType();
|
2009-11-15 16:09:41 +08:00
|
|
|
if (const RecordType *RT = Ty->getAs<RecordType>()) {
|
|
|
|
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
|
|
|
if (RD->isPolymorphic()) {
|
|
|
|
// FIXME: if subE is an lvalue do
|
|
|
|
LValue Obj = EmitLValue(subE);
|
|
|
|
llvm::Value *This = Obj.getAddress();
|
2009-11-16 00:52:53 +08:00
|
|
|
LTy = LTy->getPointerTo()->getPointerTo();
|
|
|
|
llvm::Value *V = Builder.CreateBitCast(This, LTy);
|
|
|
|
// We need to do a zero check for *p, unless it has NonNullAttr.
|
|
|
|
// FIXME: PointerType->hasAttr<NonNullAttr>()
|
|
|
|
bool CanBeZero = false;
|
2009-11-17 08:45:21 +08:00
|
|
|
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(subE->IgnoreParens()))
|
2009-11-16 00:52:53 +08:00
|
|
|
if (UO->getOpcode() == UnaryOperator::Deref)
|
|
|
|
CanBeZero = true;
|
|
|
|
if (CanBeZero) {
|
|
|
|
llvm::BasicBlock *NonZeroBlock = createBasicBlock();
|
|
|
|
llvm::BasicBlock *ZeroBlock = createBasicBlock();
|
|
|
|
|
|
|
|
llvm::Value *Zero = llvm::Constant::getNullValue(LTy);
|
|
|
|
Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
|
|
|
|
NonZeroBlock, ZeroBlock);
|
|
|
|
EmitBlock(ZeroBlock);
|
|
|
|
/// Call __cxa_bad_typeid
|
|
|
|
const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
|
|
|
|
const llvm::FunctionType *FTy;
|
|
|
|
FTy = llvm::FunctionType::get(ResultType, false);
|
|
|
|
llvm::Value *F = CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
|
2009-11-16 14:50:58 +08:00
|
|
|
Builder.CreateCall(F)->setDoesNotReturn();
|
2009-11-16 00:52:53 +08:00
|
|
|
Builder.CreateUnreachable();
|
|
|
|
EmitBlock(NonZeroBlock);
|
|
|
|
}
|
2009-11-15 16:09:41 +08:00
|
|
|
V = Builder.CreateLoad(V, "vtable");
|
|
|
|
V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL);
|
|
|
|
V = Builder.CreateLoad(V);
|
|
|
|
return V;
|
2009-12-17 15:09:17 +08:00
|
|
|
}
|
2009-11-15 16:09:41 +08:00
|
|
|
}
|
2009-12-17 15:09:17 +08:00
|
|
|
return Builder.CreateBitCast(CGM.GetAddrOfRTTIDescriptor(Ty), LTy);
|
2009-11-15 16:09:41 +08:00
|
|
|
}
|
2009-11-16 14:50:58 +08:00
|
|
|
|
|
|
|
llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
|
|
|
|
const CXXDynamicCastExpr *DCE) {
|
2009-12-17 15:09:17 +08:00
|
|
|
QualType SrcTy = DCE->getSubExpr()->getType();
|
|
|
|
QualType DestTy = DCE->getTypeAsWritten();
|
|
|
|
QualType InnerType = DestTy->getPointeeType();
|
|
|
|
|
2009-11-16 14:50:58 +08:00
|
|
|
const llvm::Type *LTy = ConvertType(DCE->getType());
|
2009-11-17 06:52:20 +08:00
|
|
|
|
2009-11-16 14:50:58 +08:00
|
|
|
bool CanBeZero = false;
|
|
|
|
bool ToVoid = false;
|
2009-11-17 06:52:20 +08:00
|
|
|
bool ThrowOnBad = false;
|
2009-12-17 15:09:17 +08:00
|
|
|
if (DestTy->isPointerType()) {
|
2009-11-16 14:50:58 +08:00
|
|
|
// FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this
|
|
|
|
CanBeZero = true;
|
|
|
|
if (InnerType->isVoidType())
|
|
|
|
ToVoid = true;
|
|
|
|
} else {
|
|
|
|
LTy = LTy->getPointerTo();
|
|
|
|
ThrowOnBad = true;
|
|
|
|
}
|
|
|
|
|
2009-12-17 15:09:17 +08:00
|
|
|
if (SrcTy->isPointerType() || SrcTy->isReferenceType())
|
|
|
|
SrcTy = SrcTy->getPointeeType();
|
|
|
|
SrcTy = SrcTy.getUnqualifiedType();
|
|
|
|
|
2009-12-18 22:55:04 +08:00
|
|
|
if (DestTy->isPointerType() || DestTy->isReferenceType())
|
2009-12-17 15:09:17 +08:00
|
|
|
DestTy = DestTy->getPointeeType();
|
|
|
|
DestTy = DestTy.getUnqualifiedType();
|
2009-11-16 14:50:58 +08:00
|
|
|
|
|
|
|
llvm::BasicBlock *ContBlock = createBasicBlock();
|
|
|
|
llvm::BasicBlock *NullBlock = 0;
|
|
|
|
llvm::BasicBlock *NonZeroBlock = 0;
|
|
|
|
if (CanBeZero) {
|
|
|
|
NonZeroBlock = createBasicBlock();
|
|
|
|
NullBlock = createBasicBlock();
|
2009-12-17 15:09:17 +08:00
|
|
|
Builder.CreateCondBr(Builder.CreateIsNotNull(V), NonZeroBlock, NullBlock);
|
2009-11-16 14:50:58 +08:00
|
|
|
EmitBlock(NonZeroBlock);
|
|
|
|
}
|
|
|
|
|
2009-11-17 06:52:20 +08:00
|
|
|
llvm::BasicBlock *BadCastBlock = 0;
|
2009-11-16 14:50:58 +08:00
|
|
|
|
2009-12-17 15:09:17 +08:00
|
|
|
const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
|
2009-11-16 14:50:58 +08:00
|
|
|
|
2009-11-17 06:52:20 +08:00
|
|
|
// See if this is a dynamic_cast(void*)
|
|
|
|
if (ToVoid) {
|
|
|
|
llvm::Value *This = V;
|
|
|
|
V = Builder.CreateBitCast(This, PtrDiffTy->getPointerTo()->getPointerTo());
|
|
|
|
V = Builder.CreateLoad(V, "vtable");
|
|
|
|
V = Builder.CreateConstInBoundsGEP1_64(V, -2ULL);
|
|
|
|
V = Builder.CreateLoad(V, "offset to top");
|
|
|
|
This = Builder.CreateBitCast(This, llvm::Type::getInt8PtrTy(VMContext));
|
|
|
|
V = Builder.CreateInBoundsGEP(This, V);
|
|
|
|
V = Builder.CreateBitCast(V, LTy);
|
|
|
|
} else {
|
|
|
|
/// Call __dynamic_cast
|
|
|
|
const llvm::Type *ResultType = llvm::Type::getInt8PtrTy(VMContext);
|
|
|
|
const llvm::FunctionType *FTy;
|
|
|
|
std::vector<const llvm::Type*> ArgTys;
|
|
|
|
const llvm::Type *PtrToInt8Ty
|
|
|
|
= llvm::Type::getInt8Ty(VMContext)->getPointerTo();
|
|
|
|
ArgTys.push_back(PtrToInt8Ty);
|
|
|
|
ArgTys.push_back(PtrToInt8Ty);
|
|
|
|
ArgTys.push_back(PtrToInt8Ty);
|
|
|
|
ArgTys.push_back(PtrDiffTy);
|
|
|
|
FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
|
|
|
|
|
|
|
|
// FIXME: Calculate better hint.
|
|
|
|
llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL);
|
2009-12-17 15:09:17 +08:00
|
|
|
|
|
|
|
assert(SrcTy->isRecordType() && "Src type must be record type!");
|
|
|
|
assert(DestTy->isRecordType() && "Dest type must be record type!");
|
|
|
|
|
2009-12-24 06:04:40 +08:00
|
|
|
llvm::Value *SrcArg
|
|
|
|
= CGM.GetAddrOfRTTIDescriptor(SrcTy.getUnqualifiedType());
|
|
|
|
llvm::Value *DestArg
|
|
|
|
= CGM.GetAddrOfRTTIDescriptor(DestTy.getUnqualifiedType());
|
2009-12-17 15:09:17 +08:00
|
|
|
|
2009-11-17 06:52:20 +08:00
|
|
|
V = Builder.CreateBitCast(V, PtrToInt8Ty);
|
|
|
|
V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"),
|
2009-12-17 15:09:17 +08:00
|
|
|
V, SrcArg, DestArg, hint);
|
2009-11-17 06:52:20 +08:00
|
|
|
V = Builder.CreateBitCast(V, LTy);
|
|
|
|
|
|
|
|
if (ThrowOnBad) {
|
|
|
|
BadCastBlock = createBasicBlock();
|
|
|
|
|
2009-12-17 15:09:17 +08:00
|
|
|
Builder.CreateCondBr(Builder.CreateIsNotNull(V), ContBlock, BadCastBlock);
|
2009-11-17 06:52:20 +08:00
|
|
|
EmitBlock(BadCastBlock);
|
|
|
|
/// Call __cxa_bad_cast
|
|
|
|
ResultType = llvm::Type::getVoidTy(VMContext);
|
|
|
|
const llvm::FunctionType *FBadTy;
|
2009-11-17 11:01:03 +08:00
|
|
|
FBadTy = llvm::FunctionType::get(ResultType, false);
|
2009-11-17 06:52:20 +08:00
|
|
|
llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast");
|
|
|
|
Builder.CreateCall(F)->setDoesNotReturn();
|
2009-11-17 08:08:50 +08:00
|
|
|
Builder.CreateUnreachable();
|
2009-11-17 06:52:20 +08:00
|
|
|
}
|
2009-11-16 14:50:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (CanBeZero) {
|
|
|
|
Builder.CreateBr(ContBlock);
|
|
|
|
EmitBlock(NullBlock);
|
|
|
|
Builder.CreateBr(ContBlock);
|
|
|
|
}
|
|
|
|
EmitBlock(ContBlock);
|
|
|
|
if (CanBeZero) {
|
|
|
|
llvm::PHINode *PHI = Builder.CreatePHI(LTy);
|
2009-11-17 08:10:05 +08:00
|
|
|
PHI->reserveOperandSpace(2);
|
2009-11-16 14:50:58 +08:00
|
|
|
PHI->addIncoming(V, NonZeroBlock);
|
|
|
|
PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock);
|
|
|
|
V = PHI;
|
|
|
|
}
|
|
|
|
|
|
|
|
return V;
|
|
|
|
}
|