diff options
author | dim <dim@FreeBSD.org> | 2011-06-12 15:46:16 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-06-12 15:46:16 +0000 |
commit | c49018d9cce52d8c9f34b44865ec3ba8e89a1488 (patch) | |
tree | c5e9e10bc189de0058aa763c47b9920a8351b7df /lib/CodeGen/CGExprCXX.cpp | |
parent | 110eaaceddcec790f7e6a5e3bf1261c9aa1e73ab (diff) | |
download | FreeBSD-src-c49018d9cce52d8c9f34b44865ec3ba8e89a1488.zip FreeBSD-src-c49018d9cce52d8c9f34b44865ec3ba8e89a1488.tar.gz |
Vendor import of clang trunk r132879:
http://llvm.org/svn/llvm-project/cfe/trunk@132879
Diffstat (limited to 'lib/CodeGen/CGExprCXX.cpp')
-rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 437 |
1 files changed, 247 insertions, 190 deletions
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index bdaa873..81fee67 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -345,18 +345,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, } } - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); - llvm::Value *Callee; - if (MD->isVirtual() && - !canDevirtualizeMemberFunctionCalls(getContext(), - E->getArg(0), MD)) - Callee = BuildVirtualCall(MD, This, Ty); - else - Callee = CGM.GetAddrOfFunction(MD, Ty); - + llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This); return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0, E->arg_begin() + 1, E->arg_end()); } @@ -403,18 +392,26 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, E->arg_begin(), E->arg_end()); } else { - CXXCtorType Type; - CXXConstructExpr::ConstructionKind K = E->getConstructionKind(); - if (K == CXXConstructExpr::CK_Delegating) { + CXXCtorType Type = Ctor_Complete; + bool ForVirtualBase = false; + + switch (E->getConstructionKind()) { + case CXXConstructExpr::CK_Delegating: // We should be emitting a constructor; GlobalDecl will assert this Type = CurGD.getCtorType(); - } else { - Type = (E->getConstructionKind() == CXXConstructExpr::CK_Complete) - ? Ctor_Complete : Ctor_Base; - } + break; + + case CXXConstructExpr::CK_Complete: + Type = Ctor_Complete; + break; + + case CXXConstructExpr::CK_VirtualBase: + ForVirtualBase = true; + // fall-through - bool ForVirtualBase = - E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase; + case CXXConstructExpr::CK_NonVirtualBase: + Type = Ctor_Base; + } // Call the constructor. EmitCXXConstructorCall(CD, Type, ForVirtualBase, Dest.getAddr(), @@ -447,204 +444,256 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtor(llvm::Value *Dest, E->arg_begin(), E->arg_end()); } -/// Check whether the given operator new[] is the global placement -/// operator new[]. -static bool IsPlacementOperatorNewArray(ASTContext &Ctx, - const FunctionDecl *Fn) { - // Must be in global scope. Note that allocation functions can't be - // declared in namespaces. - if (!Fn->getDeclContext()->getRedeclContext()->isFileContext()) - return false; - - // Signature must be void *operator new[](size_t, void*). - // The size_t is common to all operator new[]s. - if (Fn->getNumParams() != 2) - return false; - - CanQualType ParamType = Ctx.getCanonicalType(Fn->getParamDecl(1)->getType()); - return (ParamType == Ctx.VoidPtrTy); -} - static CharUnits CalculateCookiePadding(CodeGenFunction &CGF, const CXXNewExpr *E) { if (!E->isArray()) return CharUnits::Zero(); - // No cookie is required if the new operator being used is - // ::operator new[](size_t, void*). - const FunctionDecl *OperatorNew = E->getOperatorNew(); - if (IsPlacementOperatorNewArray(CGF.getContext(), OperatorNew)) + // No cookie is required if the operator new[] being used is the + // reserved placement operator new[]. + if (E->getOperatorNew()->isReservedGlobalPlacementOperator()) return CharUnits::Zero(); return CGF.CGM.getCXXABI().GetArrayCookieSize(E); } -static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context, - CodeGenFunction &CGF, - const CXXNewExpr *E, - llvm::Value *&NumElements, - llvm::Value *&SizeWithoutCookie) { - QualType ElemType = E->getAllocatedType(); - - const llvm::IntegerType *SizeTy = - cast<llvm::IntegerType>(CGF.ConvertType(CGF.getContext().getSizeType())); - - CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(ElemType); - - if (!E->isArray()) { - SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity()); - return SizeWithoutCookie; +static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF, + const CXXNewExpr *e, + llvm::Value *&numElements, + llvm::Value *&sizeWithoutCookie) { + QualType type = e->getAllocatedType(); + + if (!e->isArray()) { + CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type); + sizeWithoutCookie + = llvm::ConstantInt::get(CGF.SizeTy, typeSize.getQuantity()); + return sizeWithoutCookie; } + // The width of size_t. + unsigned sizeWidth = CGF.SizeTy->getBitWidth(); + // Figure out the cookie size. - CharUnits CookieSize = CalculateCookiePadding(CGF, E); + llvm::APInt cookieSize(sizeWidth, + CalculateCookiePadding(CGF, e).getQuantity()); // Emit the array size expression. // We multiply the size of all dimensions for NumElements. // e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6. - NumElements = CGF.EmitScalarExpr(E->getArraySize()); - assert(NumElements->getType() == SizeTy && "element count not a size_t"); - - uint64_t ArraySizeMultiplier = 1; + numElements = CGF.EmitScalarExpr(e->getArraySize()); + assert(isa<llvm::IntegerType>(numElements->getType())); + + // The number of elements can be have an arbitrary integer type; + // essentially, we need to multiply it by a constant factor, add a + // cookie size, and verify that the result is representable as a + // size_t. That's just a gloss, though, and it's wrong in one + // important way: if the count is negative, it's an error even if + // the cookie size would bring the total size >= 0. + bool isSigned + = e->getArraySize()->getType()->isSignedIntegerOrEnumerationType(); + const llvm::IntegerType *numElementsType + = cast<llvm::IntegerType>(numElements->getType()); + unsigned numElementsWidth = numElementsType->getBitWidth(); + + // Compute the constant factor. + llvm::APInt arraySizeMultiplier(sizeWidth, 1); while (const ConstantArrayType *CAT - = CGF.getContext().getAsConstantArrayType(ElemType)) { - ElemType = CAT->getElementType(); - ArraySizeMultiplier *= CAT->getSize().getZExtValue(); + = CGF.getContext().getAsConstantArrayType(type)) { + type = CAT->getElementType(); + arraySizeMultiplier *= CAT->getSize(); } - llvm::Value *Size; + CharUnits typeSize = CGF.getContext().getTypeSizeInChars(type); + llvm::APInt typeSizeMultiplier(sizeWidth, typeSize.getQuantity()); + typeSizeMultiplier *= arraySizeMultiplier; + + // This will be a size_t. + llvm::Value *size; // If someone is doing 'new int[42]' there is no need to do a dynamic check. // Don't bloat the -O0 code. - if (llvm::ConstantInt *NumElementsC = - dyn_cast<llvm::ConstantInt>(NumElements)) { - llvm::APInt NEC = NumElementsC->getValue(); - unsigned SizeWidth = NEC.getBitWidth(); - - // Determine if there is an overflow here by doing an extended multiply. - NEC = NEC.zext(SizeWidth*2); - llvm::APInt SC(SizeWidth*2, TypeSize.getQuantity()); - SC *= NEC; - - if (!CookieSize.isZero()) { - // Save the current size without a cookie. We don't care if an - // overflow's already happened because SizeWithoutCookie isn't - // used if the allocator returns null or throws, as it should - // always do on an overflow. - llvm::APInt SWC = SC.trunc(SizeWidth); - SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, SWC); - - // Add the cookie size. - SC += llvm::APInt(SizeWidth*2, CookieSize.getQuantity()); + if (llvm::ConstantInt *numElementsC = + dyn_cast<llvm::ConstantInt>(numElements)) { + const llvm::APInt &count = numElementsC->getValue(); + + bool hasAnyOverflow = false; + + // If 'count' was a negative number, it's an overflow. + if (isSigned && count.isNegative()) + hasAnyOverflow = true; + + // We want to do all this arithmetic in size_t. If numElements is + // wider than that, check whether it's already too big, and if so, + // overflow. + else if (numElementsWidth > sizeWidth && + numElementsWidth - sizeWidth > count.countLeadingZeros()) + hasAnyOverflow = true; + + // Okay, compute a count at the right width. + llvm::APInt adjustedCount = count.zextOrTrunc(sizeWidth); + + // Scale numElements by that. This might overflow, but we don't + // care because it only overflows if allocationSize does, too, and + // if that overflows then we shouldn't use this. + numElements = llvm::ConstantInt::get(CGF.SizeTy, + adjustedCount * arraySizeMultiplier); + + // Compute the size before cookie, and track whether it overflowed. + bool overflow; + llvm::APInt allocationSize + = adjustedCount.umul_ov(typeSizeMultiplier, overflow); + hasAnyOverflow |= overflow; + + // Add in the cookie, and check whether it's overflowed. + if (cookieSize != 0) { + // Save the current size without a cookie. This shouldn't be + // used if there was overflow. + sizeWithoutCookie = llvm::ConstantInt::get(CGF.SizeTy, allocationSize); + + allocationSize = allocationSize.uadd_ov(cookieSize, overflow); + hasAnyOverflow |= overflow; } - - if (SC.countLeadingZeros() >= SizeWidth) { - SC = SC.trunc(SizeWidth); - Size = llvm::ConstantInt::get(SizeTy, SC); + + // On overflow, produce a -1 so operator new will fail. + if (hasAnyOverflow) { + size = llvm::Constant::getAllOnesValue(CGF.SizeTy); } else { - // On overflow, produce a -1 so operator new throws. - Size = llvm::Constant::getAllOnesValue(SizeTy); + size = llvm::ConstantInt::get(CGF.SizeTy, allocationSize); } - // Scale NumElements while we're at it. - uint64_t N = NEC.getZExtValue() * ArraySizeMultiplier; - NumElements = llvm::ConstantInt::get(SizeTy, N); - - // Otherwise, we don't need to do an overflow-checked multiplication if - // we're multiplying by one. - } else if (TypeSize.isOne()) { - assert(ArraySizeMultiplier == 1); - - Size = NumElements; - - // If we need a cookie, add its size in with an overflow check. - // This is maybe a little paranoid. - if (!CookieSize.isZero()) { - SizeWithoutCookie = Size; + // Otherwise, we might need to use the overflow intrinsics. + } else { + // There are up to four conditions we need to test for: + // 1) if isSigned, we need to check whether numElements is negative; + // 2) if numElementsWidth > sizeWidth, we need to check whether + // numElements is larger than something representable in size_t; + // 3) we need to compute + // sizeWithoutCookie := numElements * typeSizeMultiplier + // and check whether it overflows; and + // 4) if we need a cookie, we need to compute + // size := sizeWithoutCookie + cookieSize + // and check whether it overflows. + + llvm::Value *hasOverflow = 0; + + // If numElementsWidth > sizeWidth, then one way or another, we're + // going to have to do a comparison for (2), and this happens to + // take care of (1), too. + if (numElementsWidth > sizeWidth) { + llvm::APInt threshold(numElementsWidth, 1); + threshold <<= sizeWidth; + + llvm::Value *thresholdV + = llvm::ConstantInt::get(numElementsType, threshold); + + hasOverflow = CGF.Builder.CreateICmpUGE(numElements, thresholdV); + numElements = CGF.Builder.CreateTrunc(numElements, CGF.SizeTy); + + // Otherwise, if we're signed, we want to sext up to size_t. + } else if (isSigned) { + if (numElementsWidth < sizeWidth) + numElements = CGF.Builder.CreateSExt(numElements, CGF.SizeTy); + + // If there's a non-1 type size multiplier, then we can do the + // signedness check at the same time as we do the multiply + // because a negative number times anything will cause an + // unsigned overflow. Otherwise, we have to do it here. + if (typeSizeMultiplier == 1) + hasOverflow = CGF.Builder.CreateICmpSLT(numElements, + llvm::ConstantInt::get(CGF.SizeTy, 0)); + + // Otherwise, zext up to size_t if necessary. + } else if (numElementsWidth < sizeWidth) { + numElements = CGF.Builder.CreateZExt(numElements, CGF.SizeTy); + } - llvm::Value *CookieSizeV - = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity()); + assert(numElements->getType() == CGF.SizeTy); - const llvm::Type *Types[] = { SizeTy }; - llvm::Value *UAddF - = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, Types, 1); - llvm::Value *AddRes - = CGF.Builder.CreateCall2(UAddF, Size, CookieSizeV); + size = numElements; - Size = CGF.Builder.CreateExtractValue(AddRes, 0); - llvm::Value *DidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1); - Size = CGF.Builder.CreateSelect(DidOverflow, - llvm::ConstantInt::get(SizeTy, -1), - Size); + // Multiply by the type size if necessary. This multiplier + // includes all the factors for nested arrays. + // + // This step also causes numElements to be scaled up by the + // nested-array factor if necessary. Overflow on this computation + // can be ignored because the result shouldn't be used if + // allocation fails. + if (typeSizeMultiplier != 1) { + const llvm::Type *intrinsicTypes[] = { CGF.SizeTy }; + llvm::Value *umul_with_overflow + = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, + intrinsicTypes, 1); + + llvm::Value *tsmV = + llvm::ConstantInt::get(CGF.SizeTy, typeSizeMultiplier); + llvm::Value *result = + CGF.Builder.CreateCall2(umul_with_overflow, size, tsmV); + + llvm::Value *overflowed = CGF.Builder.CreateExtractValue(result, 1); + if (hasOverflow) + hasOverflow = CGF.Builder.CreateOr(hasOverflow, overflowed); + else + hasOverflow = overflowed; + + size = CGF.Builder.CreateExtractValue(result, 0); + + // Also scale up numElements by the array size multiplier. + if (arraySizeMultiplier != 1) { + // If the base element type size is 1, then we can re-use the + // multiply we just did. + if (typeSize.isOne()) { + assert(arraySizeMultiplier == typeSizeMultiplier); + numElements = size; + + // Otherwise we need a separate multiply. + } else { + llvm::Value *asmV = + llvm::ConstantInt::get(CGF.SizeTy, arraySizeMultiplier); + numElements = CGF.Builder.CreateMul(numElements, asmV); + } + } + } else { + // numElements doesn't need to be scaled. + assert(arraySizeMultiplier == 1); } + + // Add in the cookie size if necessary. + if (cookieSize != 0) { + sizeWithoutCookie = size; + + const llvm::Type *intrinsicTypes[] = { CGF.SizeTy }; + llvm::Value *uadd_with_overflow + = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, + intrinsicTypes, 1); + + llvm::Value *cookieSizeV = llvm::ConstantInt::get(CGF.SizeTy, cookieSize); + llvm::Value *result = + CGF.Builder.CreateCall2(uadd_with_overflow, size, cookieSizeV); + + llvm::Value *overflowed = CGF.Builder.CreateExtractValue(result, 1); + if (hasOverflow) + hasOverflow = CGF.Builder.CreateOr(hasOverflow, overflowed); + else + hasOverflow = overflowed; - // Otherwise use the int.umul.with.overflow intrinsic. - } else { - llvm::Value *OutermostElementSize - = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity()); - - llvm::Value *NumOutermostElements = NumElements; - - // Scale NumElements by the array size multiplier. This might - // overflow, but only if the multiplication below also overflows, - // in which case this multiplication isn't used. - if (ArraySizeMultiplier != 1) - NumElements = CGF.Builder.CreateMul(NumElements, - llvm::ConstantInt::get(SizeTy, ArraySizeMultiplier)); - - // The requested size of the outermost array is non-constant. - // Multiply that by the static size of the elements of that array; - // on unsigned overflow, set the size to -1 to trigger an - // exception from the allocation routine. This is sufficient to - // prevent buffer overruns from the allocator returning a - // seemingly valid pointer to insufficient space. This idea comes - // originally from MSVC, and GCC has an open bug requesting - // similar behavior: - // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19351 - // - // This will not be sufficient for C++0x, which requires a - // specific exception class (std::bad_array_new_length). - // That will require ABI support that has not yet been specified. - const llvm::Type *Types[] = { SizeTy }; - llvm::Value *UMulF - = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, Types, 1); - llvm::Value *MulRes = CGF.Builder.CreateCall2(UMulF, NumOutermostElements, - OutermostElementSize); - - // The overflow bit. - llvm::Value *DidOverflow = CGF.Builder.CreateExtractValue(MulRes, 1); - - // The result of the multiplication. - Size = CGF.Builder.CreateExtractValue(MulRes, 0); - - // If we have a cookie, we need to add that size in, too. - if (!CookieSize.isZero()) { - SizeWithoutCookie = Size; - - llvm::Value *CookieSizeV - = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity()); - llvm::Value *UAddF - = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, Types, 1); - llvm::Value *AddRes - = CGF.Builder.CreateCall2(UAddF, SizeWithoutCookie, CookieSizeV); - - Size = CGF.Builder.CreateExtractValue(AddRes, 0); - - llvm::Value *AddDidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1); - DidOverflow = CGF.Builder.CreateOr(DidOverflow, AddDidOverflow); + size = CGF.Builder.CreateExtractValue(result, 0); } - Size = CGF.Builder.CreateSelect(DidOverflow, - llvm::ConstantInt::get(SizeTy, -1), - Size); + // If we had any possibility of dynamic overflow, make a select to + // overwrite 'size' with an all-ones value, which should cause + // operator new to throw. + if (hasOverflow) + size = CGF.Builder.CreateSelect(hasOverflow, + llvm::Constant::getAllOnesValue(CGF.SizeTy), + size); } - if (CookieSize.isZero()) - SizeWithoutCookie = Size; + if (cookieSize == 0) + sizeWithoutCookie = size; else - assert(SizeWithoutCookie && "didn't set SizeWithoutCookie?"); + assert(sizeWithoutCookie && "didn't set sizeWithoutCookie?"); - return Size; + return size; } static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E, @@ -741,7 +790,7 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, if (E->isArray()) { if (CXXConstructorDecl *Ctor = E->getConstructor()) { bool RequiresZeroInitialization = false; - if (Ctor->getParent()->hasTrivialConstructor()) { + if (Ctor->getParent()->hasTrivialDefaultConstructor()) { // If new expression did not specify value-initialization, then there // is no initialization. if (!E->hasInitializer() || Ctor->getParent()->isEmpty()) @@ -972,8 +1021,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { llvm::Value *numElements = 0; llvm::Value *allocSizeWithoutCookie = 0; llvm::Value *allocSize = - EmitCXXNewAllocSize(getContext(), *this, E, numElements, - allocSizeWithoutCookie); + EmitCXXNewAllocSize(*this, E, numElements, allocSizeWithoutCookie); allocatorArgs.add(RValue::get(allocSize), sizeType); @@ -1007,11 +1055,19 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { EmitCallArg(allocatorArgs, *placementArg, placementArg->getType()); } - // Emit the allocation call. - RValue RV = - EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType), - CGM.GetAddrOfFunction(allocator), ReturnValueSlot(), - allocatorArgs, allocator); + // Emit the allocation call. If the allocator is a global placement + // operator, just "inline" it directly. + RValue RV; + if (allocator->isReservedGlobalPlacementOperator()) { + assert(allocatorArgs.size() == 2); + RV = allocatorArgs[1].RV; + // TODO: kill any unnecessary computations done for the size + // argument. + } else { + RV = EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType), + CGM.GetAddrOfFunction(allocator), ReturnValueSlot(), + allocatorArgs, allocator); + } // Emit a null check on the allocation result if the allocation // function is allowed to return null (because it has a non-throwing @@ -1056,7 +1112,8 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // If there's an operator delete, enter a cleanup to call it if an // exception is thrown. EHScopeStack::stable_iterator operatorDeleteCleanup; - if (E->getOperatorDelete()) { + if (E->getOperatorDelete() && + !E->getOperatorDelete()->isReservedGlobalPlacementOperator()) { EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocatorArgs); operatorDeleteCleanup = EHStack.stable_begin(); } |