[llvm-commits] [llvm] r152555 - in /llvm/trunk: lib/Analysis/InstructionSimplify.cpp test/Transforms/InstSimplify/ptr_diff.ll

Duncan Sands baldrick at free.fr
Mon Mar 12 13:28:15 PDT 2012


Hi Chandler,

> --- llvm/trunk/lib/Analysis/InstructionSimplify.cpp (original)
> +++ llvm/trunk/lib/Analysis/InstructionSimplify.cpp Mon Mar 12 06:19:31 2012
> @@ -18,6 +18,7 @@
>   //===----------------------------------------------------------------------===//
>
>   #define DEBUG_TYPE "instsimplify"
> +#include "llvm/GlobalAlias.h"
>   #include "llvm/Operator.h"
>   #include "llvm/ADT/Statistic.h"
>   #include "llvm/Analysis/InstructionSimplify.h"
> @@ -26,6 +27,7 @@
>   #include "llvm/Analysis/Dominators.h"
>   #include "llvm/Analysis/ValueTracking.h"
>   #include "llvm/Support/ConstantRange.h"
> +#include "llvm/Support/GetElementPtrTypeIterator.h"
>   #include "llvm/Support/PatternMatch.h"
>   #include "llvm/Support/ValueHandle.h"
>   #include "llvm/Target/TargetData.h"
> @@ -665,6 +667,112 @@
>     return ::SimplifyAddInst(Op0, Op1, isNSW, isNUW, TD, TLI, DT, RecursionLimit);
>   }
>
> +/// \brief Compute the constant integer offset a GEP represents.
> +///
> +/// Given a getelementptr instruction/constantexpr, form a constant expression
> +/// which computes the offset from the base pointer (without adding in the base
> +/// pointer).
> +static Constant *computeGEPOffset(const TargetData&TD, GEPOperator *GEP) {
> +  Type *IntPtrTy = TD.getIntPtrType(GEP->getContext());
> +  Constant *Result = Constant::getNullValue(IntPtrTy);

why do you do all your arithmetic using ConstantExpr?  After all, you only
consider GEPs where the indices are numbers, so you could just do the arithmetic
in a int64_t, which is way more efficient.  In fact, rather than returning a
Constant* this should probably just return an int64_t (plus some way of knowing
if it succeeded or not).

> +
> +  // If the GEP is inbounds, we know that none of the addressing operations will
> +  // overflow in an unsigned sense.
> +  bool IsInBounds = GEP->isInBounds();
> +
> +  // Build a mask for high order bits.
> +  unsigned IntPtrWidth = TD.getPointerSizeInBits();
> +  uint64_t PtrSizeMask = ~0ULL>>  (64-IntPtrWidth);
> +
> +  gep_type_iterator GTI = gep_type_begin(GEP);
> +  for (User::op_iterator I = GEP->op_begin() + 1, E = GEP->op_end(); I != E;
> +       ++I, ++GTI) {
> +    ConstantInt *OpC = dyn_cast<ConstantInt>(*I);
> +    if (!OpC) return 0;
> +    if (OpC->isZero()) continue;
> +
> +    uint64_t Size = TD.getTypeAllocSize(GTI.getIndexedType())&  PtrSizeMask;
> +
> +    // Handle a struct index, which adds its field offset to the pointer.
> +    if (StructType *STy = dyn_cast<StructType>(*GTI)) {
> +      Size = TD.getStructLayout(STy)->getElementOffset(OpC->getZExtValue());
> +
> +      if (Size)
> +        Result = ConstantExpr::getAdd(Result, ConstantInt::get(IntPtrTy, Size));
> +      continue;
> +    }
> +
> +    Constant *Scale = ConstantInt::get(IntPtrTy, Size);
> +    Constant *OC = ConstantExpr::getIntegerCast(OpC, IntPtrTy, true /*SExt*/);
> +    Scale = ConstantExpr::getMul(OC, Scale, IsInBounds/*NUW*/);
> +    Result = ConstantExpr::getAdd(Result, Scale);
> +  }
> +  return Result;
> +}
> +
> +/// \brief Compute the base pointer and cumulative constant offsets for V.
> +///
> +/// This strips all constant offsets off of V, leaving it the base pointer, and
> +/// accumulates the total constant offset applied in the returned constant. It
> +/// returns 0 if V is not a pointer, and returns the constant '0' if there are
> +/// no constant offsets applied.
> +static Constant *stripAndComputeConstantOffsets(const TargetData&TD,
> +                                                Value *&V) {
> +  if (!V->getType()->isPointerTy())
> +    return 0;
> +
> +  Type *IntPtrTy = TD.getIntPtrType(V->getContext());
> +  Constant *Result = Constant::getNullValue(IntPtrTy);

Likewise, you are just computing a number, so why not just do all the
computations and accumulate the result in an int64_t?

> +
> +  // Even though we don't look through PHI nodes, we could be called on an
> +  // instruction in an unreachable block, which may be on a cycle.
> +  SmallPtrSet<Value *, 4>  Visited;
> +  Visited.insert(V);
> +  do {
> +    if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
> +      Constant *Offset = computeGEPOffset(TD, GEP);
> +      if (!Offset)
> +        break;
> +      Result = ConstantExpr::getAdd(Result, Offset);
> +      V = GEP->getPointerOperand();
> +    } else if (Operator::getOpcode(V) == Instruction::BitCast) {
> +      V = cast<Operator>(V)->getOperand(0);
> +    } else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
> +      if (GA->mayBeOverridden())
> +        break;
> +      V = GA->getAliasee();
> +    } else {
> +      break;
> +    }
> +    assert(V->getType()->isPointerTy()&&  "Unexpected operand type!");
> +  } while (Visited.insert(V));
> +
> +  return Result;
> +}
> +
> +/// \brief Compute the constant difference between two pointer values.
> +/// If the difference is not a constant, returns zero.
> +static Constant *computePointerDifference(const TargetData&TD,
> +                                          Value *LHS, Value *RHS) {
> +  Constant *LHSOffset = stripAndComputeConstantOffsets(TD, LHS);
> +  if (!LHSOffset)
> +    return 0;
> +  Constant *RHSOffset = stripAndComputeConstantOffsets(TD, RHS);
> +  if (!RHSOffset)
> +    return 0;
> +
> +  // If LHS and RHS are not related via constant offsets to the same base
> +  // value, there is nothing we can do here.
> +  if (LHS != RHS)
> +    return 0;
> +
> +  // Otherwise, the difference of LHS - RHS can be computed as:
> +  //    LHS - RHS
> +  //  = (LHSOffset + Base) - (RHSOffset + Base)
> +  //  = LHSOffset - RHSOffset
> +  return ConstantExpr::getSub(LHSOffset, RHSOffset);
> +}
> +
>   /// SimplifySubInst - Given operands for a Sub, see if we can
>   /// fold the result.  If not, this returns null.
>   static Value *SimplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
> @@ -699,6 +807,20 @@
>         match(Op0, m_Shl(m_Specific(Op1), m_One())))
>       return Op1;
>
> +  if (TD) {
> +    Value *LHSOp, *RHSOp;
> +    if (match(Op0, m_PtrToInt(m_Value(LHSOp)))&&
> +        match(Op1, m_PtrToInt(m_Value(RHSOp))))
> +      if (Constant *Result = computePointerDifference(*TD, LHSOp, RHSOp))
> +        return ConstantExpr::getIntegerCast(Result, Op0->getType(), true);
> +
> +    // trunc(p)-trunc(q) ->  trunc(p-q)

This trunc transform is not specific to this context, it could be generalized as
follows: if you see trunc(p) - trunc(q), then recursively try to simplify p - q.
If it simplifies to a constant, then return trunc of the constant.

> +    if (match(Op0, m_Trunc(m_PtrToInt(m_Value(LHSOp))))&&
> +        match(Op1, m_Trunc(m_PtrToInt(m_Value(RHSOp)))))
> +      if (Constant *Result = computePointerDifference(*TD, LHSOp, RHSOp))
> +        return ConstantExpr::getIntegerCast(Result, Op0->getType(), true);
> +  }
> +
>     // (X + Y) - Z ->  X + (Y - Z) or Y + (X - Z) if everything simplifies.
>     // For example, (X + Y) - Y ->  X; (Y + X) - Y ->  X
>     Value *Y = 0, *Z = Op1;

Ciao, Duncan.



More information about the llvm-commits mailing list