From: Anders Carlsson Date: Wed, 23 Sep 2009 16:07:23 +0000 (+0000) Subject: Basic support for new[]. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a4d4c019bf477ce6ff7b01517e690f6c5fd6ad71;p=clang Basic support for new[]. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82628 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXXExpr.cpp b/lib/CodeGen/CGCXXExpr.cpp index 706bd8ff2d..bf08caa3b4 100644 --- a/lib/CodeGen/CGCXXExpr.cpp +++ b/lib/CodeGen/CGCXXExpr.cpp @@ -15,8 +15,107 @@ using namespace clang; using namespace CodeGen; +static uint64_t CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { + QualType T = E->getAllocatedType(); + + const RecordType *RT = T->getAs(); + if (!RT) + return 0; + + const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); + if (!RD) + return 0; + + // Check if the class has a trivial destructor. + if (RD->hasTrivialDestructor()) { + // FIXME: Check for a two-argument delete. + return 0; + } + + // Padding is the maximum of sizeof(size_t) and alignof(T) + return std::max(Ctx.getTypeSize(Ctx.getSizeType()), + static_cast(Ctx.getTypeAlign(T))); +} + +static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, + const CXXNewExpr *E, + llvm::Value *& NumElements) { + QualType Type = E->getAllocatedType(); + uint64_t TypeSizeInBytes = CGF.getContext().getTypeSize(Type) / 8; + const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); + + if (!E->isArray()) + return llvm::ConstantInt::get(SizeTy, TypeSizeInBytes); + + uint64_t CookiePadding = CalculateCookiePadding(CGF.getContext(), E); + + Expr::EvalResult Result; + if (E->getArraySize()->Evaluate(Result, CGF.getContext()) && + !Result.HasSideEffects && Result.Val.isInt()) { + + uint64_t AllocSize = + Result.Val.getInt().getZExtValue() * TypeSizeInBytes + CookiePadding; + + NumElements = + llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue()); + + return llvm::ConstantInt::get(SizeTy, AllocSize); + } + + // Emit the array size expression. + NumElements = CGF.EmitScalarExpr(E->getArraySize()); + + // Multiply with the type size. + llvm::Value *V = + CGF.Builder.CreateMul(NumElements, + llvm::ConstantInt::get(SizeTy, TypeSizeInBytes)); + + // And add the cookie padding if necessary. + if (CookiePadding) + V = CGF.Builder.CreateAdd(V, llvm::ConstantInt::get(SizeTy, CookiePadding)); + + return V; +} + +static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, + llvm::Value *NewPtr, + llvm::Value *NumElements) { + QualType AllocType = E->getAllocatedType(); + + if (!E->isArray()) { + if (CXXConstructorDecl *Ctor = E->getConstructor()) { + CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, + E->constructor_arg_begin(), + E->constructor_arg_end()); + + return; + } + + // We have a POD type. + if (E->getNumConstructorArgs() == 0) + return; + + assert(E->getNumConstructorArgs() == 1 && + "Can only have one argument to initializer of POD type."); + + const Expr *Init = E->getConstructorArg(0); + + if (!CGF.hasAggregateLLVMType(AllocType)) + CGF.Builder.CreateStore(CGF.EmitScalarExpr(Init), NewPtr); + else if (AllocType->isAnyComplexType()) + CGF.EmitComplexExprIntoAddr(Init, NewPtr, + AllocType.isVolatileQualified()); + else + CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified()); + return; + } + + if (CXXConstructorDecl *Ctor = E->getConstructor()) + CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr); +} + llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { - if (E->isArray()) { + if (E->isArray() && CalculateCookiePadding(getContext(), E)) { ErrorUnsupported(E, "new[] expression"); return llvm::UndefValue::get(ConvertType(E->getType())); } @@ -29,10 +128,10 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // The allocation size is the first argument. QualType SizeTy = getContext().getSizeType(); - llvm::Value *AllocSize = - llvm::ConstantInt::get(ConvertType(SizeTy), - getContext().getTypeSize(AllocType) / 8); + llvm::Value *NumElements = 0; + llvm::Value *AllocSize = EmitCXXNewAllocSize(*this, E, NumElements); + NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy)); // Emit the rest of the arguments. @@ -102,28 +201,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); - if (AllocType->isPODType()) { - if (E->getNumConstructorArgs() > 0) { - assert(E->getNumConstructorArgs() == 1 && - "Can only have one argument to initializer of POD type."); - - const Expr *Init = E->getConstructorArg(0); - - if (!hasAggregateLLVMType(AllocType)) - Builder.CreateStore(EmitScalarExpr(Init), NewPtr); - else if (AllocType->isAnyComplexType()) - EmitComplexExprIntoAddr(Init, NewPtr, AllocType.isVolatileQualified()); - else - EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified()); - } - } else { - // Call the constructor. - CXXConstructorDecl *Ctor = E->getConstructor(); - - EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr, - E->constructor_arg_begin(), - E->constructor_arg_end()); - } + EmitNewInitializer(*this, E, NewPtr, NumElements); if (NullCheckResult) { Builder.CreateBr(NewEnd); diff --git a/test/CodeGenCXX/new.cpp b/test/CodeGenCXX/new.cpp index 480bbcefc0..2cb3b00edf 100644 --- a/test/CodeGenCXX/new.cpp +++ b/test/CodeGenCXX/new.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc %s -emit-llvm -o %t && +// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s void t1() { int* a = new int; @@ -32,7 +32,7 @@ struct T { }; void t4() { - // RUN: grep "call void @_ZN1TC1Ev" %t | count 1 && + // CHECK: call void @_ZN1TC1Ev T *t = new T; } @@ -42,7 +42,7 @@ struct T2 { }; void t5() { - // RUN: grep "call void @_ZN2T2C1Eii" %t | count 1 + // CHECK: call void @_ZN2T2C1Eii T2 *t2 = new T2(10, 10); } @@ -54,3 +54,12 @@ int *t6() { void t7() { new int(); } + +void t8(int n) { + new int[10]; + new int[n]; + + // Non-POD + new T[10]; + new T[n]; +}