[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