diff options
-rw-r--r-- | lib/AST/ExprConstant.cpp | 27 | ||||
-rw-r--r-- | test/CodeGen/const-arithmetic.c | 8 |
2 files changed, 25 insertions, 10 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index e03669246e..eeeeb5c836 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -406,27 +406,34 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (!EvaluatePointer(PExp, ResultLValue, Info)) return APValue(); - llvm::APSInt AdditionalOffset(32); + llvm::APSInt AdditionalOffset; if (!EvaluateInteger(IExp, AdditionalOffset, Info)) return APValue(); - QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType(); - CharUnits SizeOfPointee; + // Compute the new offset in the appropriate width. + + QualType PointeeType = + PExp->getType()->getAs<PointerType>()->getPointeeType(); + llvm::APSInt SizeOfPointee(AdditionalOffset); // Explicitly handle GNU void* and function pointer arithmetic extensions. if (PointeeType->isVoidType() || PointeeType->isFunctionType()) - SizeOfPointee = CharUnits::One(); + SizeOfPointee = 1; else - SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType); - - CharUnits Offset = ResultLValue.getLValueOffset(); + SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType).getQuantity(); + llvm::APSInt Offset(AdditionalOffset); + Offset = ResultLValue.getLValueOffset().getQuantity(); if (E->getOpcode() == BinaryOperator::Add) - Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee; + Offset += AdditionalOffset * SizeOfPointee; else - Offset -= AdditionalOffset.getLimitedValue() * SizeOfPointee; + Offset -= AdditionalOffset * SizeOfPointee; - return APValue(ResultLValue.getLValueBase(), Offset); + // Sign extend prior to converting back to a char unit. + if (Offset.getBitWidth() < 64) + Offset.extend(64); + return APValue(ResultLValue.getLValueBase(), + CharUnits::fromQuantity(Offset.getLimitedValue())); } APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { diff --git a/test/CodeGen/const-arithmetic.c b/test/CodeGen/const-arithmetic.c new file mode 100644 index 0000000000..e12b4f6d92 --- /dev/null +++ b/test/CodeGen/const-arithmetic.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s + +// CHECK: @g1 = global [2 x i8*] [i8* getelementptr (i8* getelementptr inbounds ([0 x %struct.anon]* @g0, i32 0, i32 0, i32 0), i64 -2), i8* getelementptr (i8* getelementptr inbounds ([0 x %struct.anon]* @g0, i32 0, i32 0, i32 0), i64 -46)], align 8 ; <[2 x i8*]*> [#uses=0] +// CHECK: @g2 = global [2 x i8*] [i8* getelementptr (i8* getelementptr inbounds ([0 x %struct.anon]* @g0, i32 0, i32 0, i32 0), i64 -2), i8* getelementptr (i8* getelementptr inbounds ([0 x %struct.anon]* @g0, i32 0, i32 0, i32 0), i64 -46)], align 8 ; <[2 x i8*]*> [#uses=0] + +extern struct { unsigned char a, b; } g0[]; +void *g1[] = {g0 + -1, g0 + -23 }; +void *g2[] = {g0 - 1, g0 - 23 }; |