From 23c29fea92a130313bd389f23a696165eae4a36b Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 24 Jun 2011 21:55:10 +0000 Subject: [PATCH] Change the IR-generation of VLAs so that we capture bounds, not sizes; so that we use well-typed allocas; and so that we properly recurse through the full set of variably-modified types. llvm-svn: 133827 --- clang/lib/CodeGen/CGDecl.cpp | 28 +++-- clang/lib/CodeGen/CGExpr.cpp | 15 +-- clang/lib/CodeGen/CGExprScalar.cpp | 38 ++++--- clang/lib/CodeGen/CGObjC.cpp | 25 ++-- clang/lib/CodeGen/CodeGenFunction.cpp | 157 ++++++++++++++++++-------- clang/lib/CodeGen/CodeGenFunction.h | 16 +-- clang/lib/CodeGen/CodeGenModule.cpp | 4 + clang/lib/CodeGen/CodeGenModule.h | 4 + clang/test/CodeGen/vla.c | 20 ++-- clang/test/CodeGenCXX/vla.cpp | 43 +++++++ clang/test/CodeGenObjC/arc.m | 37 +++--- 11 files changed, 259 insertions(+), 128 deletions(-) create mode 100644 clang/test/CodeGenCXX/vla.cpp diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index a12365e8e4fe..b6ad130a4039 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -98,7 +98,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { QualType Ty = TD.getUnderlyingType(); if (Ty->isVariablyModifiedType()) - EmitVLASize(Ty); + EmitVariablyModifiedType(Ty); } } } @@ -258,7 +258,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, // even though that doesn't really make any sense. // Make sure to evaluate VLA bounds now so that we have them for later. if (D.getType()->isVariablyModifiedType()) - EmitVLASize(D.getType()); + EmitVariablyModifiedType(D.getType()); // Local static block variables must be treated as globals as they may be // referenced in their RHS initializer block-literal expresion. @@ -699,6 +699,10 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { CharUnits alignment = getContext().getDeclAlign(&D); emission.Alignment = alignment; + // If the type is variably-modified, emit all the VLA sizes for it. + if (Ty->isVariablyModifiedType()) + EmitVariablyModifiedType(Ty); + llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { if (!Target.useGlobalsForAutomaticVariables()) { @@ -778,10 +782,6 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { DeclPtr = CreateStaticVarDecl(D, Class, llvm::GlobalValue::InternalLinkage); } - - // FIXME: Can this happen? - if (Ty->isVariablyModifiedType()) - EmitVLASize(Ty); } else { EnsureInsertPoint(); @@ -801,19 +801,17 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { EHStack.pushCleanup(NormalCleanup, Stack); } - // Get the element type. - const llvm::Type *LElemTy = ConvertTypeForMem(Ty); - const llvm::Type *LElemPtrTy = - LElemTy->getPointerTo(CGM.getContext().getTargetAddressSpace(Ty)); + llvm::Value *elementCount; + QualType elementType; + llvm::tie(elementCount, elementType) = getVLASize(Ty); - llvm::Value *VLASize = EmitVLASize(Ty); + const llvm::Type *llvmTy = ConvertTypeForMem(elementType); // Allocate memory for the array. - llvm::AllocaInst *VLA = - Builder.CreateAlloca(llvm::Type::getInt8Ty(getLLVMContext()), VLASize, "vla"); - VLA->setAlignment(alignment.getQuantity()); + llvm::AllocaInst *vla = Builder.CreateAlloca(llvmTy, elementCount, "vla"); + vla->setAlignment(alignment.getQuantity()); - DeclPtr = Builder.CreateBitCast(VLA, LElemPtrTy, "tmp"); + DeclPtr = vla; } llvm::Value *&DMEntry = LocalDeclMap[&D]; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index af0af7fbefd1..e8d156ea64d2 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1579,21 +1579,22 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { // size is a VLA or Objective-C interface. llvm::Value *Address = 0; unsigned ArrayAlignment = 0; - if (const VariableArrayType *VAT = + if (const VariableArrayType *vla = getContext().getAsVariableArrayType(E->getType())) { - llvm::Value *VLASize = GetVLASize(VAT); + // The base must be a pointer, which is not an aggregate. Emit + // it. It needs to be emitted first in case it's what captures + // the VLA bounds. + Address = EmitScalarExpr(E->getBase()); - Idx = Builder.CreateMul(Idx, VLASize); + // The element count here is the total number of non-VLA elements. + llvm::Value *numElements = getVLASize(vla).first; - // The base must be a pointer, which is not an aggregate. Emit it. - llvm::Value *Base = EmitScalarExpr(E->getBase()); + Idx = Builder.CreateMul(Idx, numElements); - Address = EmitCastToVoidPtr(Base); if (getContext().getLangOptions().isSignedOverflowDefined()) Address = Builder.CreateGEP(Address, Idx, "arrayidx"); else Address = Builder.CreateInBoundsGEP(Address, Idx, "arrayidx"); - Address = Builder.CreateBitCast(Address, Base->getType()); } else if (const ObjCObjectType *OIT = E->getType()->getAs()){ // Indexing over an interface, as in "NSString *P; P[4];" llvm::Value *InterfaceSize = diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 6e42da8e01a9..7b4aecceb900 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -269,14 +269,12 @@ public: Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { return CGF.CGM.EmitNullConstant(E->getType()); } - Value *VisitCastExpr(CastExpr *E) { - // Make sure to evaluate VLA bounds now so that we have them for later. + Value *VisitExplicitCastExpr(ExplicitCastExpr *E) { if (E->getType()->isVariablyModifiedType()) - CGF.EmitVLASize(E->getType()); - - return EmitCastExpr(E); + CGF.EmitVariablyModifiedType(E->getType()); + return VisitCastExpr(E); } - Value *EmitCastExpr(CastExpr *E); + Value *VisitCastExpr(CastExpr *E); Value *VisitCallExpr(const CallExpr *E) { if (E->getCallReturnType()->isReferenceType()) @@ -1001,7 +999,7 @@ static bool ShouldNullCheckClassCastValue(const CastExpr *CE) { // VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts // have to handle a more broad range of conversions than explicit casts, as they // handle things like function to ptr-to-function decay etc. -Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { +Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { Expr *E = CE->getSubExpr(); QualType DestTy = CE->getType(); CastKind Kind = CE->getCastKind(); @@ -1298,15 +1296,12 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, // VLA types don't have constant size. if (type->isVariableArrayType()) { - llvm::Value *vlaSize = - CGF.GetVLASize(CGF.getContext().getAsVariableArrayType(type)); - value = CGF.EmitCastToVoidPtr(value); - if (!isInc) vlaSize = Builder.CreateNSWNeg(vlaSize, "vla.negsize"); + llvm::Value *numElts = CGF.getVLASize(type).first; + if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize"); if (CGF.getContext().getLangOptions().isSignedOverflowDefined()) - value = Builder.CreateGEP(value, vlaSize, "vla.inc"); + value = Builder.CreateGEP(value, numElts, "vla.inc"); else - value = Builder.CreateInBoundsGEP(value, vlaSize, "vla.inc"); - value = Builder.CreateBitCast(value, input->getType()); + value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc"); // Arithmetic on function pointers (!) is just +-1. } else if (type->isFunctionType()) { @@ -1526,14 +1521,25 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr( CGF.getContext().getAsVariableArrayType(TypeToSize)) { if (E->isArgumentType()) { // sizeof(type) - make sure to emit the VLA size. - CGF.EmitVLASize(TypeToSize); + CGF.EmitVariablyModifiedType(TypeToSize); } else { // C99 6.5.3.4p2: If the argument is an expression of type // VLA, it is evaluated. CGF.EmitIgnoredExpr(E->getArgumentExpr()); } - return CGF.GetVLASize(VAT); + QualType eltType; + llvm::Value *numElts; + llvm::tie(numElts, eltType) = CGF.getVLASize(VAT); + + llvm::Value *size = numElts; + + // Scale the number of non-VLA elements by the non-VLA element size. + CharUnits eltSize = CGF.getContext().getTypeSizeInChars(eltType); + if (!eltSize.isOne()) + size = CGF.Builder.CreateNUWMul(CGF.CGM.getSize(eltSize), numElts); + + return size; } } diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 50e8d320dd51..9107e9859e5f 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1894,9 +1894,10 @@ namespace { // If it's a VLA, we have to load the stored size. Note that // this is the size of the VLA in bytes, not its size in elements. - llvm::Value *vlaSizeInBytes = 0; + llvm::Value *numVLAElements = 0; if (isa(arrayType)) { - vlaSizeInBytes = CGF.GetVLASize(cast(arrayType)); + numVLAElements = + CGF.getVLASize(cast(arrayType)).first; // Walk into all VLAs. This doesn't require changes to addr, // which has type T* where T is the first non-VLA element type. @@ -1907,7 +1908,7 @@ namespace { // If we only have VLA components, 'addr' requires no adjustment. if (!arrayType) { baseType = elementType; - return divideVLASizeByBaseType(CGF, vlaSizeInBytes, baseType); + return numVLAElements; } } while (isa(arrayType)); @@ -1947,22 +1948,20 @@ namespace { assert(arrayType && "LLVM and Clang types are out-of-synch"); } + baseType = arrayType->getElementType(); + // Create the actual GEP. addr = CGF.Builder.CreateInBoundsGEP(addr, gepIndices.begin(), gepIndices.end(), "array.begin"); - baseType = arrayType->getElementType(); + llvm::Value *numElements + = llvm::ConstantInt::get(CGF.IntPtrTy, countFromCLAs); - // If we had an VLA dimensions, we need to use the captured size. - if (vlaSizeInBytes) - return divideVLASizeByBaseType(CGF, vlaSizeInBytes, baseType); + // If we had any VLA dimensions, factor them in. + if (numVLAElements) + numElements = CGF.Builder.CreateNUWMul(numVLAElements, numElements); - // Otherwise, use countFromCLAs. - assert(countFromCLAs == (uint64_t) - (Ctx.getTypeSizeInChars(origArrayType).getQuantity() / - Ctx.getTypeSizeInChars(baseType).getQuantity())); - - return llvm::ConstantInt::get(CGF.IntPtrTy, countFromCLAs); + return numElements; } static llvm::Value *divideVLASizeByBaseType(CodeGenFunction &CGF, diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 6ab4b76e75d0..43e07e24fc61 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -343,7 +343,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, QualType Ty = (*i)->getType(); if (Ty->isVariablyModifiedType()) - EmitVLASize(Ty); + EmitVariablyModifiedType(Ty); } } @@ -709,13 +709,20 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { if (const VariableArrayType *vlaType = dyn_cast_or_null( getContext().getAsArrayType(Ty))) { - SizeVal = GetVLASize(vlaType); + QualType eltType; + llvm::Value *numElts; + llvm::tie(numElts, eltType) = getVLASize(vlaType); + + SizeVal = numElts; + CharUnits eltSize = getContext().getTypeSizeInChars(eltType); + if (!eltSize.isOne()) + SizeVal = Builder.CreateNUWMul(SizeVal, CGM.getSize(eltSize)); vla = vlaType; } else { return; } } else { - SizeVal = llvm::ConstantInt::get(IntPtrTy, Size.getQuantity()); + SizeVal = CGM.getSize(Size); vla = 0; } @@ -778,60 +785,120 @@ llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { return IndirectBranch->getParent(); } -llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) { - llvm::Value *&SizeEntry = VLASizeMap[VAT->getSizeExpr()]; - - assert(SizeEntry && "Did not emit size for type"); - return SizeEntry; +std::pair +CodeGenFunction::getVLASize(QualType type) { + const VariableArrayType *vla = getContext().getAsVariableArrayType(type); + assert(vla && "type was not a variable array type!"); + return getVLASize(vla); } -llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty) { - assert(Ty->isVariablyModifiedType() && +std::pair +CodeGenFunction::getVLASize(const VariableArrayType *type) { + // The number of elements so far; always size_t. + llvm::Value *numElements = 0; + + QualType elementType; + do { + elementType = type->getElementType(); + llvm::Value *vlaSize = VLASizeMap[type->getSizeExpr()]; + assert(vlaSize && "no size for VLA!"); + assert(vlaSize->getType() == SizeTy); + + if (!numElements) { + numElements = vlaSize; + } else { + // It's undefined behavior if this wraps around, so mark it that way. + numElements = Builder.CreateNUWMul(numElements, vlaSize); + } + } while ((type = getContext().getAsVariableArrayType(elementType))); + + return std::pair(numElements, elementType); +} + +void CodeGenFunction::EmitVariablyModifiedType(QualType type) { + assert(type->isVariablyModifiedType() && "Must pass variably modified type to EmitVLASizes!"); EnsureInsertPoint(); - if (const VariableArrayType *VAT = getContext().getAsVariableArrayType(Ty)) { - // unknown size indication requires no size computation. - if (!VAT->getSizeExpr()) - return 0; - llvm::Value *&SizeEntry = VLASizeMap[VAT->getSizeExpr()]; + // We're going to walk down into the type and look for VLA + // expressions. + type = type.getCanonicalType(); + do { + assert(type->isVariablyModifiedType()); - if (!SizeEntry) { - const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); + const Type *ty = type.getTypePtr(); + switch (ty->getTypeClass()) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("unexpected dependent or non-canonical type!"); - // Get the element size; - QualType ElemTy = VAT->getElementType(); - llvm::Value *ElemSize; - if (ElemTy->isVariableArrayType()) - ElemSize = EmitVLASize(ElemTy); - else - ElemSize = llvm::ConstantInt::get(SizeTy, - getContext().getTypeSizeInChars(ElemTy).getQuantity()); + // These types are never variably-modified. + case Type::Builtin: + case Type::Complex: + case Type::Vector: + case Type::ExtVector: + case Type::Record: + case Type::Enum: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + llvm_unreachable("type class is never variably-modified!"); - llvm::Value *NumElements = EmitScalarExpr(VAT->getSizeExpr()); - NumElements = Builder.CreateIntCast(NumElements, SizeTy, false, "tmp"); + case Type::Pointer: + type = cast(ty)->getPointeeType(); + break; - SizeEntry = Builder.CreateMul(ElemSize, NumElements); + case Type::BlockPointer: + type = cast(ty)->getPointeeType(); + break; + + case Type::LValueReference: + case Type::RValueReference: + type = cast(ty)->getPointeeType(); + break; + + case Type::MemberPointer: + type = cast(ty)->getPointeeType(); + break; + + case Type::ConstantArray: + case Type::IncompleteArray: + // Losing element qualification here is fine. + type = cast(ty)->getElementType(); + break; + + case Type::VariableArray: { + // Losing element qualification here is fine. + const VariableArrayType *vat = cast(ty); + + // Unknown size indication requires no size computation. + // Otherwise, evaluate and record it. + if (const Expr *size = vat->getSizeExpr()) { + // It's possible that we might have emitted this already, + // e.g. with a typedef and a pointer to it. + llvm::Value *&entry = VLASizeMap[size]; + if (!entry) { + // Always zexting here would be wrong if it weren't + // undefined behavior to have a negative bound. + entry = Builder.CreateIntCast(EmitScalarExpr(size), SizeTy, + /*signed*/ false); + } + } + type = vat->getElementType(); + break; } - return SizeEntry; - } - - if (const ArrayType *AT = dyn_cast(Ty)) { - EmitVLASize(AT->getElementType()); - return 0; - } - - if (const ParenType *PT = dyn_cast(Ty)) { - EmitVLASize(PT->getInnerType()); - return 0; - } - - const PointerType *PT = Ty->getAs(); - assert(PT && "unknown VM type!"); - EmitVLASize(PT->getPointeeType()); - return 0; + case Type::FunctionProto: + case Type::FunctionNoProto: + type = cast(ty)->getResultType(); + break; + } + } while (type->isVariablyModifiedType()); } llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 0b2452502952..fea2e6111a38 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1526,16 +1526,18 @@ public: // instruction in LLVM instead once it works well enough. llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty); - /// EmitVLASize - Generate code for any VLA size expressions that might occur - /// in a variably modified type. If Ty is a VLA, will return the value that - /// corresponds to the size in bytes of the VLA type. Will return 0 otherwise. + /// EmitVLASize - Capture all the sizes for the VLA expressions in + /// the given variably-modified type and store them in the VLASizeMap. /// /// This function can be called with a null (unreachable) insert point. - llvm::Value *EmitVLASize(QualType Ty); + void EmitVariablyModifiedType(QualType Ty); - // GetVLASize - Returns an LLVM value that corresponds to the size in bytes - // of a variable length array type. - llvm::Value *GetVLASize(const VariableArrayType *); + /// getVLASize - Returns an LLVM value that corresponds to the size, + /// in non-variably-sized elements, of a variable length array type, + /// plus that largest non-variably-sized element type. Assumes that + /// the type has already been emitted with EmitVariablyModifiedType. + std::pair getVLASize(const VariableArrayType *vla); + std::pair getVLASize(QualType vla); /// LoadCXXThis - Load the value of 'this'. This function is only valid while /// generating code for an C++ member function. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index af29990da68a..ddef39726f70 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -196,6 +196,10 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type, getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg; } +llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) { + return llvm::ConstantInt::get(SizeTy, size.getQuantity()); +} + void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const { // Internal definitions always have default visibility. diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 7321ac45f44f..3cca76a171eb 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -33,6 +33,7 @@ namespace llvm { class Module; class Constant; + class ConstantInt; class Function; class GlobalValue; class TargetData; @@ -382,6 +383,9 @@ public: static void DecorateInstruction(llvm::Instruction *Inst, llvm::MDNode *TBAAInfo); + /// getSize - Emit the given number of characters as a value of type size_t. + llvm::ConstantInt *getSize(CharUnits numChars); + /// setGlobalVisibility - Set the visibility for the given LLVM /// GlobalValue. void setGlobalVisibility(llvm::GlobalValue *GV, const NamedDecl *D) const; diff --git a/clang/test/CodeGen/vla.c b/clang/test/CodeGen/vla.c index e5114a5b0db9..f7cba25d9346 100644 --- a/clang/test/CodeGen/vla.c +++ b/clang/test/CodeGen/vla.c @@ -88,13 +88,17 @@ int test2(int n) // http://llvm.org/PR8567 // CHECK: define double @test_PR8567 double test_PR8567(int n, double (*p)[n][5]) { - // CHECK: store [[vla_type:.*]] %p, - // CHECK: load i32* - // CHECK-NEXT: mul i32 40 - // CHECK-NEXT: [[byte_idx:%.*]] = mul i32 1 - // CHECK-NEXT: [[tmp_1:%.*]] = load [[vla_type]]* - // CHECK-NEXT: [[tmp_2:%.*]] = bitcast [[vla_type]] [[tmp_1]] to i8* - // CHECK-NEXT: [[idx:%.*]] = getelementptr inbounds i8* [[tmp_2]], i32 [[byte_idx]] - // CHECK-NEXT: bitcast i8* [[idx]] to [[vla_type]] + // CHECK: [[NV:%.*]] = alloca i32, align 4 + // CHECK-NEXT: [[PV:%.*]] = alloca [5 x double]*, align 4 + // CHECK-NEXT: store + // CHECK-NEXT: store + // CHECK-NEXT: [[N:%.*]] = load i32* [[NV]], align 4 + // CHECK-NEXT: [[P:%.*]] = load [5 x double]** [[PV]], align 4 + // CHECK-NEXT: [[T0:%.*]] = mul i32 1, [[N]] + // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [5 x double]* [[P]], i32 [[T0]] + // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [5 x double]* [[T1]], i32 2 + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [5 x double]* [[T2]], i32 0, i32 3 + // CHECK-NEXT: [[T4:%.*]] = load double* [[T3]] + // CHECK-NEXT: ret double [[T4]] return p[1][2][3]; } diff --git a/clang/test/CodeGenCXX/vla.cpp b/clang/test/CodeGenCXX/vla.cpp new file mode 100644 index 000000000000..cee00f277136 --- /dev/null +++ b/clang/test/CodeGenCXX/vla.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s + +// rdar://problem/9506377 +void test0(void *array, int n) { + // CHECK: define void @_Z5test0Pvi( + // CHECK: [[ARRAY:%.*]] = alloca i8*, align 8 + // CHECK-NEXT: [[N:%.*]] = alloca i32, align 4 + // CHECK-NEXT: [[REF:%.*]] = alloca i16*, align 8 + // CHECK-NEXT: [[S:%.*]] = alloca i16, align 2 + // CHECK-NEXT: store i8* + // CHECK-NEXT: store i32 + + // Capture the bounds. + // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4 + // CHECK-NEXT: [[DIM0:%.*]] = zext i32 [[T0]] to i64 + // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4 + // CHECK-NEXT: [[T1:%.*]] = add nsw i32 [[T0]], 1 + // CHECK-NEXT: [[DIM1:%.*]] = zext i32 [[T1]] to i64 + typedef short array_t[n][n+1]; + + // CHECK-NEXT: [[T0:%.*]] = load i8** [[ARRAY]], align 8 + // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i16* + // CHECK-NEXT: store i16* [[T1]], i16** [[REF]], align 8 + array_t &ref = *(array_t*) array; + + // CHECK-NEXT: [[T0:%.*]] = load i16** [[REF]] + // CHECK-NEXT: [[T1:%.*]] = mul i64 1, [[DIM1]] + // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i16* [[T0]], i64 [[T1]] + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i16* [[T2]], i64 2 + // CHECK-NEXT: store i16 3, i16* [[T3]] + ref[1][2] = 3; + + // CHECK-NEXT: [[T0:%.*]] = load i16** [[REF]] + // CHECK-NEXT: [[T1:%.*]] = mul i64 4, [[DIM1]] + // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i16* [[T0]], i64 [[T1]] + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i16* [[T2]], i64 5 + // CHECK-NEXT: [[T4:%.*]] = load i16* [[T3]] + // CHECK-NEXT: store i16 [[T4]], i16* [[S]], align 2 + short s = ref[4][5]; + + // CHECK-NEXT: ret void +} + diff --git a/clang/test/CodeGenObjC/arc.m b/clang/test/CodeGenObjC/arc.m index 1d5b4f42205e..2a51454e758c 100644 --- a/clang/test/CodeGenObjC/arc.m +++ b/clang/test/CodeGenObjC/arc.m @@ -487,23 +487,23 @@ void test20(unsigned n) { id x[n]; // Capture the VLA size. + // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4 + // CHECK-NEXT: [[DIM:%.*]] = zext i32 [[T0]] to i64 + + // Save the stack pointer. // CHECK-NEXT: [[T0:%.*]] = call i8* @llvm.stacksave() // CHECK-NEXT: store i8* [[T0]], i8** [[SAVED_STACK]] - // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4 - // CHECK-NEXT: [[T1:%.*]] = zext i32 [[T0]] to i64 - // CHECK-NEXT: [[VLA_SIZE:%.*]] = mul i64 8, [[T1]] // Allocate the VLA. - // CHECK-NEXT: [[T0:%.*]] = alloca i8, i64 [[VLA_SIZE]], align 16 - // CHECK-NEXT: [[VLA:%.*]] = bitcast i8* [[T0]] to i8** + // CHECK-NEXT: [[VLA:%.*]] = alloca i8*, i64 [[DIM]], align 16 // Zero-initialize. // CHECK-NEXT: [[T0:%.*]] = bitcast i8** [[VLA]] to i8* - // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 [[VLA_SIZE]], i32 8, i1 false) + // CHECK-NEXT: [[T1:%.*]] = mul nuw i64 [[DIM]], 8 + // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 [[T1]], i32 8, i1 false) // Destroy. - // CHECK-NEXT: [[VLA_COUNT:%.*]] = udiv i64 [[VLA_SIZE]], 8 - // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[VLA]], i64 [[VLA_COUNT]] + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[VLA]], i64 [[DIM]] // CHECK-NEXT: br label // CHECK: [[CUR:%.*]] = phi i8** @@ -529,25 +529,28 @@ void test21(unsigned n) { id x[2][n][3]; // Capture the VLA size. + // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4 + // CHECK-NEXT: [[DIM:%.*]] = zext i32 [[T0]] to i64 + // CHECK-NEXT: [[T0:%.*]] = call i8* @llvm.stacksave() // CHECK-NEXT: store i8* [[T0]], i8** [[SAVED_STACK]] - // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4 - // CHECK-NEXT: [[T1:%.*]] = zext i32 [[T0]] to i64 - // CHECK-NEXT: [[T2:%.*]] = mul i64 24, [[T1]] - // CHECK-NEXT: [[VLA_SIZE:%.*]] = mul i64 [[T2]], 2 + // Allocate the VLA. - // CHECK-NEXT: [[T0:%.*]] = alloca i8, i64 [[VLA_SIZE]], align 16 - // CHECK-NEXT: [[VLA:%.*]] = bitcast i8* [[T0]] to [3 x i8*]* + // CHECK-NEXT: [[T0:%.*]] = mul nuw i64 2, [[DIM]] + // CHECK-NEXT: [[VLA:%.*]] = alloca [3 x i8*], i64 [[T0]], align 16 // Zero-initialize. // CHECK-NEXT: [[T0:%.*]] = bitcast [3 x i8*]* [[VLA]] to i8* - // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 [[VLA_SIZE]], i32 8, i1 false) + // CHECK-NEXT: [[T1:%.*]] = mul nuw i64 2, [[DIM]] + // CHECK-NEXT: [[T2:%.*]] = mul nuw i64 [[T1]], 24 + // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 [[T2]], i32 8, i1 false) // Destroy. + // CHECK-NEXT: [[T0:%.*]] = mul nuw i64 2, [[DIM]] // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [3 x i8*]* [[VLA]], i32 0, i32 0 - // CHECK-NEXT: [[VLA_COUNT:%.*]] = udiv i64 [[VLA_SIZE]], 8 - // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 [[VLA_COUNT]] + // CHECK-NEXT: [[T1:%.*]] = mul nuw i64 [[T0]], 3 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 [[T1]] // CHECK-NEXT: br label // CHECK: [[CUR:%.*]] = phi i8**