summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2009-01-23 18:51:09 +0000
committerDaniel Dunbar <daniel@zuster.org>2009-01-23 18:51:09 +0000
commit42a8cd37b23e6482f7a6f4c5264d0d39d680142e (patch)
tree125fdcb823ef13547797cb48798a9ca760adea1a /clang/lib/CodeGen
parent1f6c7fe6a87583eecb49b00b02fbb529f45bac90 (diff)
downloadbcm5719-llvm-42a8cd37b23e6482f7a6f4c5264d0d39d680142e.tar.gz
bcm5719-llvm-42a8cd37b23e6482f7a6f4c5264d0d39d680142e.zip
Handle pointer arithmetic on function pointers.
- <rdar://problem/6518844> Clang-generated bitcode crashes LLVM while compiling function pointer addition expression llvm-svn: 62857
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp33
1 files changed, 28 insertions, 5 deletions
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index f21373a5383..fc87726a211 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -872,11 +872,14 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
// FIXME: What about a pointer to a VLA?
Value *Ptr, *Idx;
Expr *IdxExp;
- if (isa<llvm::PointerType>(Ops.LHS->getType())) { // pointer + int
+ const PointerType *PT;
+ if ((PT = Ops.E->getLHS()->getType()->getAsPointerType())) {
Ptr = Ops.LHS;
Idx = Ops.RHS;
IdxExp = Ops.E->getRHS();
} else { // int + pointer
+ PT = Ops.E->getRHS()->getType()->getAsPointerType();
+ assert(PT && "Invalid add expr");
Ptr = Ops.RHS;
Idx = Ops.LHS;
IdxExp = Ops.E->getLHS();
@@ -892,6 +895,17 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
else
Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
}
+
+ // 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");
+ return Builder.CreateBitCast(Res, Ptr->getType());
+ }
return Builder.CreateGEP(Ptr, Idx, "add.ptr");
}
@@ -900,6 +914,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
if (!isa<llvm::PointerType>(Ops.LHS->getType()))
return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
+ const QualType LHSType = Ops.E->getLHS()->getType();
+ const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType();
if (!isa<llvm::PointerType>(Ops.RHS->getType())) {
// pointer - int
Value *Idx = Ops.RHS;
@@ -916,16 +932,23 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
Idx = Builder.CreateNeg(Idx, "sub.ptr.neg");
// FIXME: The pointer could point to a VLA.
- // The GNU void* - int case is automatically handled here because
- // our LLVM type for void* is i8*.
+
+ // 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.
+ if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) {
+ const llvm::Type *i8Ty = llvm::PointerType::getUnqual(llvm::Type::Int8Ty);
+ Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty);
+ Value *Res = Builder.CreateGEP(LHSCasted, Idx, "sub.ptr");
+ return Builder.CreateBitCast(Res, Ops.LHS->getType());
+ }
+
return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr");
} else {
// pointer - pointer
Value *LHS = Ops.LHS;
Value *RHS = Ops.RHS;
- const QualType LHSType = Ops.E->getLHS()->getType();
- const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType();
uint64_t ElementSize;
// Handle GCC extension for pointer arithmetic on void* types.
OpenPOWER on IntegriCloud