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:
parent
e75de95408
commit
ef2ffbc390
|
@ -809,8 +809,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
|
|||
Idx = Builder.CreateIntCast(Idx, llvm::IntegerType::get(LLVMPointerWidth),
|
||||
IdxSigned, "idxprom");
|
||||
|
||||
// We know that the pointer points to a type of the correct size, unless the
|
||||
// size is a VLA.
|
||||
// We know that the pointer points to a type of the correct size,
|
||||
// unless the size is a VLA or Objective-C interface.
|
||||
llvm::Value *Address = 0;
|
||||
if (const VariableArrayType *VAT =
|
||||
getContext().getAsVariableArrayType(E->getType())) {
|
||||
llvm::Value *VLASize = VLASizeMap[VAT];
|
||||
|
@ -823,10 +824,25 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
|
|||
Idx = Builder.CreateUDiv(Idx,
|
||||
llvm::ConstantInt::get(Idx->getType(),
|
||||
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();
|
||||
LValue LV = LValue::MakeAddr(Builder.CreateGEP(Base, Idx, "arrayidx"),
|
||||
LValue LV = LValue::MakeAddr(Address,
|
||||
T.getCVRQualifiers(),
|
||||
getContext().getObjCGCAttrKind(T));
|
||||
if (getContext().getLangOptions().ObjC1 &&
|
||||
|
|
|
@ -968,14 +968,27 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
|
|||
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
|
||||
// extensions. The GNU void* casts amount to no-ops since our void*
|
||||
// type is i8*, but this is future proof.
|
||||
const QualType ElementType = PT->getPointeeType();
|
||||
if (ElementType->isVoidType() || ElementType->isFunctionType()) {
|
||||
const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -1015,6 +1028,20 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
|
|||
}
|
||||
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
|
||||
// extensions. The GNU void* casts amount to no-ops since our
|
||||
// void* type is i8*, but this is future proof.
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue