Fix pointer addressing and array subscripting of Objective-C interface

types.
 - I broke this in the switch to representing interfaces with opaque
   types.

 - <rdar://problem/6822660> clang crashes on subscript of interface in
   32-bit mode

llvm-svn: 70009
This commit is contained in:
Daniel Dunbar 2009-04-25 05:08:32 +00:00
parent e75de95408
commit ef2ffbc390
3 changed files with 82 additions and 5 deletions

View File

@ -809,8 +809,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
Idx = Builder.CreateIntCast(Idx, llvm::IntegerType::get(LLVMPointerWidth), Idx = Builder.CreateIntCast(Idx, llvm::IntegerType::get(LLVMPointerWidth),
IdxSigned, "idxprom"); IdxSigned, "idxprom");
// We know that the pointer points to a type of the correct size, unless the // We know that the pointer points to a type of the correct size,
// size is a VLA. // unless the size is a VLA or Objective-C interface.
llvm::Value *Address = 0;
if (const VariableArrayType *VAT = if (const VariableArrayType *VAT =
getContext().getAsVariableArrayType(E->getType())) { getContext().getAsVariableArrayType(E->getType())) {
llvm::Value *VLASize = VLASizeMap[VAT]; llvm::Value *VLASize = VLASizeMap[VAT];
@ -823,10 +824,25 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
Idx = Builder.CreateUDiv(Idx, Idx = Builder.CreateUDiv(Idx,
llvm::ConstantInt::get(Idx->getType(), llvm::ConstantInt::get(Idx->getType(),
BaseTypeSize)); BaseTypeSize));
Address = Builder.CreateGEP(Base, Idx, "arrayidx");
} else if (const ObjCInterfaceType *OIT =
dyn_cast<ObjCInterfaceType>(E->getType())) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
getContext().getTypeSize(OIT) / 8);
Idx = Builder.CreateMul(Idx, InterfaceSize);
llvm::Type *i8PTy = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
Address = Builder.CreateGEP(Builder.CreateBitCast(Base, i8PTy),
Idx, "arrayidx");
Address = Builder.CreateBitCast(Address, Base->getType());
} else {
Address = Builder.CreateGEP(Base, Idx, "arrayidx");
} }
QualType T = E->getBase()->getType()->getAsPointerType()->getPointeeType(); QualType T = E->getBase()->getType()->getAsPointerType()->getPointeeType();
LValue LV = LValue::MakeAddr(Builder.CreateGEP(Base, Idx, "arrayidx"), LValue LV = LValue::MakeAddr(Address,
T.getCVRQualifiers(), T.getCVRQualifiers(),
getContext().getObjCGCAttrKind(T)); getContext().getObjCGCAttrKind(T));
if (getContext().getLangOptions().ObjC1 && if (getContext().getLangOptions().ObjC1 &&

View File

@ -968,14 +968,27 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext"); Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
} }
const QualType ElementType = PT->getPointeeType();
// Handle interface types, which are not represented with a concrete
// type.
if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
CGF.getContext().getTypeSize(OIT) / 8);
Idx = Builder.CreateMul(Idx, InterfaceSize);
const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
Value *Casted = Builder.CreateBitCast(Ptr, i8Ty);
Value *Res = Builder.CreateGEP(Casted, Idx, "add.ptr");
return Builder.CreateBitCast(Res, Ptr->getType());
}
// Explicitly handle GNU void* and function pointer arithmetic // Explicitly handle GNU void* and function pointer arithmetic
// extensions. The GNU void* casts amount to no-ops since our void* // extensions. The GNU void* casts amount to no-ops since our void*
// type is i8*, but this is future proof. // type is i8*, but this is future proof.
const QualType ElementType = PT->getPointeeType();
if (ElementType->isVoidType() || ElementType->isFunctionType()) { if (ElementType->isVoidType() || ElementType->isFunctionType()) {
const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
Value *Casted = Builder.CreateBitCast(Ptr, i8Ty); Value *Casted = Builder.CreateBitCast(Ptr, i8Ty);
Value *Res = Builder.CreateGEP(Casted, Idx, "sub.ptr"); Value *Res = Builder.CreateGEP(Casted, Idx, "add.ptr");
return Builder.CreateBitCast(Res, Ptr->getType()); return Builder.CreateBitCast(Res, Ptr->getType());
} }
@ -1015,6 +1028,20 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
} }
Idx = Builder.CreateNeg(Idx, "sub.ptr.neg"); Idx = Builder.CreateNeg(Idx, "sub.ptr.neg");
// Handle interface types, which are not represented with a concrete
// type.
if (const ObjCInterfaceType *OIT =
dyn_cast<ObjCInterfaceType>(LHSElementType)) {
llvm::Value *InterfaceSize =
llvm::ConstantInt::get(Idx->getType(),
CGF.getContext().getTypeSize(OIT) / 8);
Idx = Builder.CreateMul(Idx, InterfaceSize);
const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty);
Value *Res = Builder.CreateGEP(LHSCasted, Idx, "add.ptr");
return Builder.CreateBitCast(Res, Ops.LHS->getType());
}
// Explicitly handle GNU void* and function pointer arithmetic // Explicitly handle GNU void* and function pointer arithmetic
// extensions. The GNU void* casts amount to no-ops since our // extensions. The GNU void* casts amount to no-ops since our
// void* type is i8*, but this is future proof. // void* type is i8*, but this is future proof.

View File

@ -0,0 +1,34 @@
// RUN: clang-cc -triple i386-apple-darwin9 -O3 -emit-llvm -o %t %s &&
// RUN: grep 'ret i32 385' %t
void *alloca();
@interface I0 {
@public
int iv0;
int iv1;
int iv2;
}
@end
static int f0(I0 *a0) {
return (*(a0 + 2)).iv0;
}
static int f1(I0 *a0) {
return a0[2].iv1;
}
static int f2(I0 *a0) {
return (*(a0 - 1)).iv2;
}
int g0(void) {
I0 *a = alloca(sizeof(*a) * 4);
a[2].iv0 = 5;
a[2].iv1 = 7;
a[2].iv2 = 11;
return f0(a) * f1(a) * f2(&a[3]);
}