diff options
| author | Eric Christopher <echristo@apple.com> | 2010-03-05 06:58:57 +0000 | 
|---|---|---|
| committer | Eric Christopher <echristo@apple.com> | 2010-03-05 06:58:57 +0000 | 
| commit | 4899cbc77d9e496e0db497660f71b00e8b7652d3 (patch) | |
| tree | 0ed5ac1f2fb724d547dd67812d55eaf475df3dbb /llvm/lib/Analysis | |
| parent | 5c92f933b33ee7e3a5f1a9e944bfd84a6aa935dc (diff) | |
| download | bcm5719-llvm-4899cbc77d9e496e0db497660f71b00e8b7652d3.tar.gz bcm5719-llvm-4899cbc77d9e496e0db497660f71b00e8b7652d3.zip | |
Move GetStringLength and helper from SimplifyLibCalls to ValueTracking.
No functionality change.
llvm-svn: 97793
Diffstat (limited to 'llvm/lib/Analysis')
| -rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 129 | 
1 files changed, 129 insertions, 0 deletions
| diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 09344a32b86..92cbb7c95c0 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -23,6 +23,7 @@  #include "llvm/Target/TargetData.h"  #include "llvm/Support/GetElementPtrTypeIterator.h"  #include "llvm/Support/MathExtras.h" +#include "llvm/ADT/SmallPtrSet.h"  #include <cstring>  using namespace llvm; @@ -1436,3 +1437,131 @@ bool llvm::GetConstantStringInfo(Value *V, std::string &Str, uint64_t Offset,    // The array isn't null terminated, but maybe this is a memcpy, not a strcpy.    return true;  } + +// These next two are very similar to the above, but also look through PHI +// nodes. +// TODO: See if we can integrate these two together. + +/// GetStringLengthH - If we can compute the length of the string pointed to by +/// the specified pointer, return 'len+1'.  If we can't, return 0. +static uint64_t GetStringLengthH(Value *V, SmallPtrSet<PHINode*, 32> &PHIs) { +  // Look through noop bitcast instructions. +  if (BitCastInst *BCI = dyn_cast<BitCastInst>(V)) +    return GetStringLengthH(BCI->getOperand(0), PHIs); + +  // If this is a PHI node, there are two cases: either we have already seen it +  // or we haven't. +  if (PHINode *PN = dyn_cast<PHINode>(V)) { +    if (!PHIs.insert(PN)) +      return ~0ULL;  // already in the set. + +    // If it was new, see if all the input strings are the same length. +    uint64_t LenSoFar = ~0ULL; +    for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { +      uint64_t Len = GetStringLengthH(PN->getIncomingValue(i), PHIs); +      if (Len == 0) return 0; // Unknown length -> unknown. + +      if (Len == ~0ULL) continue; + +      if (Len != LenSoFar && LenSoFar != ~0ULL) +        return 0;    // Disagree -> unknown. +      LenSoFar = Len; +    } + +    // Success, all agree. +    return LenSoFar; +  } + +  // strlen(select(c,x,y)) -> strlen(x) ^ strlen(y) +  if (SelectInst *SI = dyn_cast<SelectInst>(V)) { +    uint64_t Len1 = GetStringLengthH(SI->getTrueValue(), PHIs); +    if (Len1 == 0) return 0; +    uint64_t Len2 = GetStringLengthH(SI->getFalseValue(), PHIs); +    if (Len2 == 0) return 0; +    if (Len1 == ~0ULL) return Len2; +    if (Len2 == ~0ULL) return Len1; +    if (Len1 != Len2) return 0; +    return Len1; +  } + +  // If the value is not a GEP instruction nor a constant expression with a +  // GEP instruction, then return unknown. +  User *GEP = 0; +  if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(V)) { +    GEP = GEPI; +  } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) { +    if (CE->getOpcode() != Instruction::GetElementPtr) +      return 0; +    GEP = CE; +  } else { +    return 0; +  } + +  // Make sure the GEP has exactly three arguments. +  if (GEP->getNumOperands() != 3) +    return 0; + +  // Check to make sure that the first operand of the GEP is an integer and +  // has value 0 so that we are sure we're indexing into the initializer. +  if (ConstantInt *Idx = dyn_cast<ConstantInt>(GEP->getOperand(1))) { +    if (!Idx->isZero()) +      return 0; +  } else +    return 0; + +  // If the second index isn't a ConstantInt, then this is a variable index +  // into the array.  If this occurs, we can't say anything meaningful about +  // the string. +  uint64_t StartIdx = 0; +  if (ConstantInt *CI = dyn_cast<ConstantInt>(GEP->getOperand(2))) +    StartIdx = CI->getZExtValue(); +  else +    return 0; + +  // The GEP instruction, constant or instruction, must reference a global +  // variable that is a constant and is initialized. The referenced constant +  // initializer is the array that we'll use for optimization. +  GlobalVariable* GV = dyn_cast<GlobalVariable>(GEP->getOperand(0)); +  if (!GV || !GV->isConstant() || !GV->hasInitializer() || +      GV->mayBeOverridden()) +    return 0; +  Constant *GlobalInit = GV->getInitializer(); + +  // Handle the ConstantAggregateZero case, which is a degenerate case. The +  // initializer is constant zero so the length of the string must be zero. +  if (isa<ConstantAggregateZero>(GlobalInit)) +    return 1;  // Len = 0 offset by 1. + +  // Must be a Constant Array +  ConstantArray *Array = dyn_cast<ConstantArray>(GlobalInit); +  if (!Array || !Array->getType()->getElementType()->isIntegerTy(8)) +    return false; + +  // Get the number of elements in the array +  uint64_t NumElts = Array->getType()->getNumElements(); + +  // Traverse the constant array from StartIdx (derived above) which is +  // the place the GEP refers to in the array. +  for (unsigned i = StartIdx; i != NumElts; ++i) { +    Constant *Elt = Array->getOperand(i); +    ConstantInt *CI = dyn_cast<ConstantInt>(Elt); +    if (!CI) // This array isn't suitable, non-int initializer. +      return 0; +    if (CI->isZero()) +      return i-StartIdx+1; // We found end of string, success! +  } + +  return 0; // The array isn't null terminated, conservatively return 'unknown'. +} + +/// GetStringLength - If we can compute the length of the string pointed to by +/// the specified pointer, return 'len+1'.  If we can't, return 0. +uint64_t llvm::GetStringLength(Value *V) { +  if (!V->getType()->isPointerTy()) return 0; + +  SmallPtrSet<PHINode*, 32> PHIs; +  uint64_t Len = GetStringLengthH(V, PHIs); +  // If Len is ~0ULL, we had an infinite phi cycle: this is dead code, so return +  // an empty string as a length. +  return Len == ~0ULL ? 1 : Len; +} | 

