forked from OSchip/llvm-project
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
This commit is contained in:
parent
932e5b5d52
commit
23c29fea92
|
@ -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<CallStackRestore>(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];
|
||||
|
|
|
@ -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<ObjCObjectType>()){
|
||||
// Indexing over an interface, as in "NSString *P; P[4];"
|
||||
llvm::Value *InterfaceSize =
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<VariableArrayType>(arrayType)) {
|
||||
vlaSizeInBytes = CGF.GetVLASize(cast<VariableArrayType>(arrayType));
|
||||
numVLAElements =
|
||||
CGF.getVLASize(cast<VariableArrayType>(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<VariableArrayType>(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,
|
||||
|
|
|
@ -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<VariableArrayType>(
|
||||
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<llvm::Value*, QualType>
|
||||
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<llvm::Value*, QualType>
|
||||
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<llvm::Value*,QualType>(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<PointerType>(ty)->getPointeeType();
|
||||
break;
|
||||
|
||||
SizeEntry = Builder.CreateMul(ElemSize, NumElements);
|
||||
case Type::BlockPointer:
|
||||
type = cast<BlockPointerType>(ty)->getPointeeType();
|
||||
break;
|
||||
|
||||
case Type::LValueReference:
|
||||
case Type::RValueReference:
|
||||
type = cast<ReferenceType>(ty)->getPointeeType();
|
||||
break;
|
||||
|
||||
case Type::MemberPointer:
|
||||
type = cast<MemberPointerType>(ty)->getPointeeType();
|
||||
break;
|
||||
|
||||
case Type::ConstantArray:
|
||||
case Type::IncompleteArray:
|
||||
// Losing element qualification here is fine.
|
||||
type = cast<ArrayType>(ty)->getElementType();
|
||||
break;
|
||||
|
||||
case Type::VariableArray: {
|
||||
// Losing element qualification here is fine.
|
||||
const VariableArrayType *vat = cast<VariableArrayType>(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<ArrayType>(Ty)) {
|
||||
EmitVLASize(AT->getElementType());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
|
||||
EmitVLASize(PT->getInnerType());
|
||||
return 0;
|
||||
}
|
||||
|
||||
const PointerType *PT = Ty->getAs<PointerType>();
|
||||
assert(PT && "unknown VM type!");
|
||||
EmitVLASize(PT->getPointeeType());
|
||||
return 0;
|
||||
case Type::FunctionProto:
|
||||
case Type::FunctionNoProto:
|
||||
type = cast<FunctionType>(ty)->getResultType();
|
||||
break;
|
||||
}
|
||||
} while (type->isVariablyModifiedType());
|
||||
}
|
||||
|
||||
llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
|
||||
|
|
|
@ -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<llvm::Value*,QualType> getVLASize(const VariableArrayType *vla);
|
||||
std::pair<llvm::Value*,QualType> getVLASize(QualType vla);
|
||||
|
||||
/// LoadCXXThis - Load the value of 'this'. This function is only valid while
|
||||
/// generating code for an C++ member function.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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**
|
||||
|
|
Loading…
Reference in New Issue