[cfe-commits] r54392 - in /cfe/trunk: lib/CodeGen/CGExprScalar.cpp test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
Daniel Dunbar
daniel at zuster.org
Tue Aug 5 19:00:41 PDT 2008
Author: ddunbar
Date: Tue Aug 5 21:00:38 2008
New Revision: 54392
URL: http://llvm.org/viewvc/llvm-project?rev=54392&view=rev
Log:
Fix CodeGen of pointer arithmetic in compound assignment statements.
- Changed EmitSub to work on all cases (arithmetic, ptr - int, ptr -
ptr) so that implementation matches that of other operators.
- Modify EmitCompoundAssign to compute and perform the appropriate
casts of left, right, and result types for the assorted pointer
arithmetic cases.
- Fix EmitSub (ptr - int) case to negate the rhs *after*
extension. This is critical when the rhs is unsigned (and needs
extension).
- This fixes cfrac.
- <rdr://6115726>
Added:
cfe/trunk/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
Modified:
cfe/trunk/lib/CodeGen/CGExprScalar.cpp
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=54392&r1=54391&r2=54392&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Aug 5 21:00:38 2008
@@ -264,18 +264,14 @@
HANDLEBINOP(Div);
HANDLEBINOP(Rem);
HANDLEBINOP(Add);
- // (Sub) - Sub is handled specially below for ptr-ptr subtract.
+ HANDLEBINOP(Sub);
HANDLEBINOP(Shl);
HANDLEBINOP(Shr);
HANDLEBINOP(And);
HANDLEBINOP(Xor);
HANDLEBINOP(Or);
#undef HANDLEBINOP
- Value *VisitBinSub(const BinaryOperator *E);
- Value *VisitBinSubAssign(const CompoundAssignOperator *E) {
- return EmitCompoundAssign(E, &ScalarExprEmitter::EmitSub);
- }
-
+
// Comparisons.
Value *EmitCompare(const BinaryOperator *E, unsigned UICmpOpc,
unsigned SICmpOpc, unsigned FCmpOpc);
@@ -751,26 +747,56 @@
OpInfo.RHS = Visit(E->getRHS());
}
- // Convert the LHS/RHS values to the computation type.
- OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, ComputeType);
-
- // Do not merge types for -= or += where the LHS is a pointer.
- if (!(E->getOpcode() == BinaryOperator::SubAssign ||
- E->getOpcode() == BinaryOperator::AddAssign) ||
- !E->getLHS()->getType()->isPointerType()) {
- OpInfo.RHS = EmitScalarConversion(OpInfo.RHS, RHSTy, ComputeType);
+ QualType LComputeTy, RComputeTy, ResultTy;
+
+ // Compound assignment does not contain enough information about all
+ // the types involved for pointer arithmetic cases. Figure it out
+ // here for now.
+ if (E->getLHS()->getType()->isPointerType()) {
+ // Pointer arithmetic cases: ptr +=,-= int and ptr -= ptr,
+ assert((E->getOpcode() == BinaryOperator::AddAssign ||
+ E->getOpcode() == BinaryOperator::SubAssign) &&
+ "Invalid compound assignment operator on pointer type.");
+ LComputeTy = E->getLHS()->getType();
+
+ if (E->getRHS()->getType()->isPointerType()) {
+ // Degenerate case of (ptr -= ptr) allowed by GCC implicit cast
+ // extension, the conversion from the pointer difference back to
+ // the LHS type is handled at the end.
+ assert(E->getOpcode() == BinaryOperator::SubAssign &&
+ "Invalid compound assignment operator on pointer type.");
+ RComputeTy = E->getLHS()->getType();
+ ResultTy = CGF.getContext().getPointerDiffType();
+ } else {
+ RComputeTy = E->getRHS()->getType();
+ ResultTy = LComputeTy;
+ }
+ } else if (E->getRHS()->getType()->isPointerType()) {
+ // Degenerate case of (int += ptr) allowed by GCC implicit cast
+ // extension.
+ assert(E->getOpcode() == BinaryOperator::AddAssign &&
+ "Invalid compound assignment operator on pointer type.");
+ LComputeTy = E->getLHS()->getType();
+ RComputeTy = E->getRHS()->getType();
+ ResultTy = RComputeTy;
+ } else {
+ LComputeTy = RComputeTy = ResultTy = ComputeType;
}
- OpInfo.Ty = ComputeType;
+
+ // Convert the LHS/RHS values to the computation type.
+ OpInfo.LHS = EmitScalarConversion(OpInfo.LHS, LHSTy, LComputeTy);
+ OpInfo.RHS = EmitScalarConversion(OpInfo.RHS, RHSTy, RComputeTy);
+ OpInfo.Ty = ResultTy;
OpInfo.E = E;
// Expand the binary operator.
Value *Result = (this->*Func)(OpInfo);
- // Truncate the result back to the LHS type.
- Result = EmitScalarConversion(Result, ComputeType, LHSTy);
+ // Convert the result back to the LHS type.
+ Result = EmitScalarConversion(Result, ResultTy, LHSTy);
// Store the result value into the LHS lvalue.
- CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, E->getType());
+ CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy);
// For bitfields, we need the value in the bitfield
// FIXME: This adds an extra bitfield load
@@ -833,70 +859,62 @@
Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
if (!isa<llvm::PointerType>(Ops.LHS->getType()))
return Builder.CreateSub(Ops.LHS, Ops.RHS, "sub");
-
- // pointer - int
- assert(!isa<llvm::PointerType>(Ops.RHS->getType()) &&
- "ptr-ptr shouldn't get here");
- // FIXME: The pointer could point to a VLA.
- Value *Idx = Builder.CreateNeg(Ops.RHS, "sub.ptr.neg");
-
- unsigned Width = cast<llvm::IntegerType>(Idx->getType())->getBitWidth();
- if (Width < CGF.LLVMPointerWidth) {
- // Zero or sign extend the pointer value based on whether the index is
- // signed or not.
- const llvm::Type *IdxType = llvm::IntegerType::get(CGF.LLVMPointerWidth);
- if (Ops.E->getRHS()->getType()->isSignedIntegerType())
- Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
- else
- Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
- }
-
- // The GNU void* - int case is automatically handled here because
- // our LLVM type for void* is i8*.
- return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr");
-}
-Value *ScalarExprEmitter::VisitBinSub(const BinaryOperator *E) {
- // "X - Y" is different from "X -= Y" in one case: when Y is a pointer. In
- // the compound assignment case it is invalid, so just handle it here.
- if (!E->getRHS()->getType()->isPointerType())
- return EmitSub(EmitBinOps(E));
-
- // pointer - pointer
- Value *LHS = Visit(E->getLHS());
- Value *RHS = Visit(E->getRHS());
-
- const QualType LHSType = E->getLHS()->getType();
- const QualType LHSElementType = LHSType->getAsPointerType()->getPointeeType();
- uint64_t ElementSize;
-
- // Handle GCC extension for pointer arithmetic on void* types.
- if (LHSElementType->isVoidType()) {
- ElementSize = 1;
+ if (!isa<llvm::PointerType>(Ops.RHS->getType())) {
+ // pointer - int
+ Value *Idx = Ops.RHS;
+ unsigned Width = cast<llvm::IntegerType>(Idx->getType())->getBitWidth();
+ if (Width < CGF.LLVMPointerWidth) {
+ // Zero or sign extend the pointer value based on whether the index is
+ // signed or not.
+ const llvm::Type *IdxType = llvm::IntegerType::get(CGF.LLVMPointerWidth);
+ if (Ops.E->getRHS()->getType()->isSignedIntegerType())
+ Idx = Builder.CreateSExt(Idx, IdxType, "idx.ext");
+ else
+ Idx = Builder.CreateZExt(Idx, IdxType, "idx.ext");
+ }
+ 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*.
+ return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr");
} else {
- ElementSize = CGF.getContext().getTypeSize(LHSElementType) / 8;
+ // 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.
+ if (LHSElementType->isVoidType()) {
+ ElementSize = 1;
+ } else {
+ ElementSize = CGF.getContext().getTypeSize(LHSElementType) / 8;
+ }
+
+ const llvm::Type *ResultType = ConvertType(Ops.Ty);
+ LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast");
+ RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
+ Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
+
+ // HACK: LLVM doesn't have an divide instruction that 'knows' there is no
+ // remainder. As such, we handle common power-of-two cases here to generate
+ // better code. See PR2247.
+ if (llvm::isPowerOf2_64(ElementSize)) {
+ Value *ShAmt =
+ llvm::ConstantInt::get(ResultType, llvm::Log2_64(ElementSize));
+ return Builder.CreateAShr(BytesBetween, ShAmt, "sub.ptr.shr");
+ }
+
+ // Otherwise, do a full sdiv.
+ Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize);
+ return Builder.CreateSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
}
-
- const llvm::Type *ResultType = ConvertType(E->getType());
- LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast");
- RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast");
- Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
-
- // HACK: LLVM doesn't have an divide instruction that 'knows' there is no
- // remainder. As such, we handle common power-of-two cases here to generate
- // better code.
- if (llvm::isPowerOf2_64(ElementSize)) {
- Value *ShAmt =
- llvm::ConstantInt::get(ResultType, llvm::Log2_64(ElementSize));
- return Builder.CreateAShr(BytesBetween, ShAmt, "sub.ptr.shr");
- }
-
- // Otherwise, do a full sdiv.
- Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize);
- return Builder.CreateSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
}
-
Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) {
// LLVM requires the LHS and RHS to be the same type: promote or truncate the
// RHS to the same size as the LHS.
Added: cfe/trunk/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c?rev=54392&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c (added)
+++ cfe/trunk/test/CodeGen/2008-07-31-promotion-of-compound-pointer-arithmetic.c Tue Aug 5 21:00:38 2008
@@ -0,0 +1,25 @@
+// RUN: clang -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis | grep "ret i32 1" | count 3
+// <rdr://6115726>
+
+int f0() {
+ int x;
+ unsigned short n = 1;
+ int *a = &x;
+ int *b = &x;
+ a = a - n;
+ b -= n;
+ return a == b;
+}
+
+int f1(int *a) {
+ int b = a - (int*) 1;
+ a -= (int*) 1;
+ return b == (int) a;
+}
+
+int f2(int n) {
+ int *b = n + (int*) 1;
+ n += (int*) 1;
+ return b == (int*) n;
+}
+
More information about the cfe-commits
mailing list