diff options
| author | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-23 14:19:52 +0000 | 
|---|---|---|
| committer | Roman Divacky <rdivacky@FreeBSD.org> | 2009-10-23 14:19:52 +0000 | 
| commit | 4a142eb28942073eb27a112b5ca1cca3f01beb9c (patch) | |
| tree | 22cc59e4b240d84c3a5a60531119c4eca914a256 /lib/Analysis/ConstantFolding.cpp | |
| parent | 5cd822fa9bbb9622241e3bf4d7674ed49ccde5b9 (diff) | |
Notes
Diffstat (limited to 'lib/Analysis/ConstantFolding.cpp')
| -rw-r--r-- | lib/Analysis/ConstantFolding.cpp | 273 | 
1 files changed, 268 insertions, 5 deletions
diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp index 0ce1c24bed67b..214caeb92a0e4 100644 --- a/lib/Analysis/ConstantFolding.cpp +++ b/lib/Analysis/ConstantFolding.cpp @@ -24,9 +24,10 @@  #include "llvm/Instructions.h"  #include "llvm/Intrinsics.h"  #include "llvm/LLVMContext.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/Target/TargetData.h"  #include "llvm/ADT/SmallVector.h"  #include "llvm/ADT/StringMap.h" -#include "llvm/Target/TargetData.h"  #include "llvm/Support/ErrorHandling.h"  #include "llvm/Support/GetElementPtrTypeIterator.h"  #include "llvm/Support/MathExtras.h" @@ -92,6 +93,265 @@ static bool IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV,    return false;  } +/// ReadDataFromGlobal - Recursive helper to read bits out of global.  C is the +/// constant being copied out of. ByteOffset is an offset into C.  CurPtr is the +/// pointer to copy results into and BytesLeft is the number of bytes left in +/// the CurPtr buffer.  TD is the target data. +static bool ReadDataFromGlobal(Constant *C, uint64_t ByteOffset, +                               unsigned char *CurPtr, unsigned BytesLeft, +                               const TargetData &TD) { +  assert(ByteOffset <= TD.getTypeAllocSize(C->getType()) && +         "Out of range access"); +   +  if (isa<ConstantAggregateZero>(C) || isa<UndefValue>(C)) +    return true; +   +  if (ConstantInt *CI = dyn_cast<ConstantInt>(C)) { +    if (CI->getBitWidth() > 64 || +        (CI->getBitWidth() & 7) != 0) +      return false; +     +    uint64_t Val = CI->getZExtValue(); +    unsigned IntBytes = unsigned(CI->getBitWidth()/8); +     +    for (unsigned i = 0; i != BytesLeft && ByteOffset != IntBytes; ++i) { +      CurPtr[i] = (unsigned char)(Val >> ByteOffset * 8); +      ++ByteOffset; +    } +    return true; +  } +   +  if (ConstantFP *CFP = dyn_cast<ConstantFP>(C)) { +    if (CFP->getType()->isDoubleTy()) { +      C = ConstantExpr::getBitCast(C, Type::getInt64Ty(C->getContext())); +      return ReadDataFromGlobal(C, ByteOffset, CurPtr, BytesLeft, TD); +    } +    if (CFP->getType()->isFloatTy()){ +      C = ConstantExpr::getBitCast(C, Type::getInt32Ty(C->getContext())); +      return ReadDataFromGlobal(C, ByteOffset, CurPtr, BytesLeft, TD); +    } +  } + +  if (ConstantStruct *CS = dyn_cast<ConstantStruct>(C)) { +    const StructLayout *SL = TD.getStructLayout(CS->getType()); +    unsigned Index = SL->getElementContainingOffset(ByteOffset); +    uint64_t CurEltOffset = SL->getElementOffset(Index); +    ByteOffset -= CurEltOffset; +     +    while (1) { +      // If the element access is to the element itself and not to tail padding, +      // read the bytes from the element. +      uint64_t EltSize = TD.getTypeAllocSize(CS->getOperand(Index)->getType()); + +      if (ByteOffset < EltSize && +          !ReadDataFromGlobal(CS->getOperand(Index), ByteOffset, CurPtr, +                              BytesLeft, TD)) +        return false; +       +      ++Index; +       +      // Check to see if we read from the last struct element, if so we're done. +      if (Index == CS->getType()->getNumElements()) +        return true; + +      // If we read all of the bytes we needed from this element we're done. +      uint64_t NextEltOffset = SL->getElementOffset(Index); + +      if (BytesLeft <= NextEltOffset-CurEltOffset-ByteOffset) +        return true; + +      // Move to the next element of the struct. +      BytesLeft -= NextEltOffset-CurEltOffset-ByteOffset; +      ByteOffset = 0; +      CurEltOffset = NextEltOffset; +    } +    // not reached. +  } + +  if (ConstantArray *CA = dyn_cast<ConstantArray>(C)) { +    uint64_t EltSize = TD.getTypeAllocSize(CA->getType()->getElementType()); +    uint64_t Index = ByteOffset / EltSize; +    uint64_t Offset = ByteOffset - Index * EltSize; +    for (; Index != CA->getType()->getNumElements(); ++Index) { +      if (!ReadDataFromGlobal(CA->getOperand(Index), Offset, CurPtr, +                              BytesLeft, TD)) +        return false; +      if (EltSize >= BytesLeft) +        return true; +       +      Offset = 0; +      BytesLeft -= EltSize; +      CurPtr += EltSize; +    } +    return true; +  } +   +  if (ConstantVector *CV = dyn_cast<ConstantVector>(C)) { +    uint64_t EltSize = TD.getTypeAllocSize(CV->getType()->getElementType()); +    uint64_t Index = ByteOffset / EltSize; +    uint64_t Offset = ByteOffset - Index * EltSize; +    for (; Index != CV->getType()->getNumElements(); ++Index) { +      if (!ReadDataFromGlobal(CV->getOperand(Index), Offset, CurPtr, +                              BytesLeft, TD)) +        return false; +      if (EltSize >= BytesLeft) +        return true; +       +      Offset = 0; +      BytesLeft -= EltSize; +      CurPtr += EltSize; +    } +    return true; +  } +   +  // Otherwise, unknown initializer type. +  return false; +} + +static Constant *FoldReinterpretLoadFromConstPtr(Constant *C, +                                                 const TargetData &TD) { +  const Type *LoadTy = cast<PointerType>(C->getType())->getElementType(); +  const IntegerType *IntType = dyn_cast<IntegerType>(LoadTy); +   +  // If this isn't an integer load we can't fold it directly. +  if (!IntType) { +    // If this is a float/double load, we can try folding it as an int32/64 load +    // and then bitcast the result.  This can be useful for union cases.  Note +    // that address spaces don't matter here since we're not going to result in +    // an actual new load. +    const Type *MapTy; +    if (LoadTy->isFloatTy()) +      MapTy = Type::getInt32PtrTy(C->getContext()); +    else if (LoadTy->isDoubleTy()) +      MapTy = Type::getInt64PtrTy(C->getContext()); +    else if (isa<VectorType>(LoadTy)) { +      MapTy = IntegerType::get(C->getContext(), +                               TD.getTypeAllocSizeInBits(LoadTy)); +      MapTy = PointerType::getUnqual(MapTy); +    } else +      return 0; + +    C = ConstantExpr::getBitCast(C, MapTy); +    if (Constant *Res = FoldReinterpretLoadFromConstPtr(C, TD)) +      return ConstantExpr::getBitCast(Res, LoadTy); +    return 0; +  } +   +  unsigned BytesLoaded = (IntType->getBitWidth() + 7) / 8; +  if (BytesLoaded > 32 || BytesLoaded == 0) return 0; +   +  GlobalValue *GVal; +  int64_t Offset; +  if (!IsConstantOffsetFromGlobal(C, GVal, Offset, TD)) +    return 0; +   +  GlobalVariable *GV = dyn_cast<GlobalVariable>(GVal); +  if (!GV || !GV->isConstant() || !GV->hasInitializer() || +      !GV->hasDefinitiveInitializer() || +      !GV->getInitializer()->getType()->isSized()) +    return 0; + +  // If we're loading off the beginning of the global, some bytes may be valid, +  // but we don't try to handle this. +  if (Offset < 0) return 0; +   +  // If we're not accessing anything in this constant, the result is undefined. +  if (uint64_t(Offset) >= TD.getTypeAllocSize(GV->getInitializer()->getType())) +    return UndefValue::get(IntType); +   +  unsigned char RawBytes[32] = {0}; +  if (!ReadDataFromGlobal(GV->getInitializer(), Offset, RawBytes, +                          BytesLoaded, TD)) +    return 0; + +  APInt ResultVal(IntType->getBitWidth(), 0); +  for (unsigned i = 0; i != BytesLoaded; ++i) { +    ResultVal <<= 8; +    ResultVal |= APInt(IntType->getBitWidth(), RawBytes[BytesLoaded-1-i]); +  } + +  return ConstantInt::get(IntType->getContext(), ResultVal); +} + +/// ConstantFoldLoadFromConstPtr - Return the value that a load from C would +/// produce if it is constant and determinable.  If this is not determinable, +/// return null. +Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, +                                             const TargetData *TD) { +  // First, try the easy cases: +  if (GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) +    if (GV->isConstant() && GV->hasDefinitiveInitializer()) +      return GV->getInitializer(); + +  // If the loaded value isn't a constant expr, we can't handle it. +  ConstantExpr *CE = dyn_cast<ConstantExpr>(C); +  if (!CE) return 0; +   +  if (CE->getOpcode() == Instruction::GetElementPtr) { +    if (GlobalVariable *GV = dyn_cast<GlobalVariable>(CE->getOperand(0))) +      if (GV->isConstant() && GV->hasDefinitiveInitializer()) +        if (Constant *V =  +             ConstantFoldLoadThroughGEPConstantExpr(GV->getInitializer(), CE)) +          return V; +  } +   +  // Instead of loading constant c string, use corresponding integer value +  // directly if string length is small enough. +  std::string Str; +  if (TD && GetConstantStringInfo(CE->getOperand(0), Str) && !Str.empty()) { +    unsigned StrLen = Str.length(); +    const Type *Ty = cast<PointerType>(CE->getType())->getElementType(); +    unsigned NumBits = Ty->getPrimitiveSizeInBits(); +    // Replace LI with immediate integer store. +    if ((NumBits >> 3) == StrLen + 1) { +      APInt StrVal(NumBits, 0); +      APInt SingleChar(NumBits, 0); +      if (TD->isLittleEndian()) { +        for (signed i = StrLen-1; i >= 0; i--) { +          SingleChar = (uint64_t) Str[i] & UCHAR_MAX; +          StrVal = (StrVal << 8) | SingleChar; +        } +      } else { +        for (unsigned i = 0; i < StrLen; i++) { +          SingleChar = (uint64_t) Str[i] & UCHAR_MAX; +          StrVal = (StrVal << 8) | SingleChar; +        } +        // Append NULL at the end. +        SingleChar = 0; +        StrVal = (StrVal << 8) | SingleChar; +      } +      return ConstantInt::get(CE->getContext(), StrVal); +    } +  } +   +  // If this load comes from anywhere in a constant global, and if the global +  // is all undef or zero, we know what it loads. +  if (GlobalVariable *GV = dyn_cast<GlobalVariable>(CE->getUnderlyingObject())){ +    if (GV->isConstant() && GV->hasDefinitiveInitializer()) { +      const Type *ResTy = cast<PointerType>(C->getType())->getElementType(); +      if (GV->getInitializer()->isNullValue()) +        return Constant::getNullValue(ResTy); +      if (isa<UndefValue>(GV->getInitializer())) +        return UndefValue::get(ResTy); +    } +  } +   +  // Try hard to fold loads from bitcasted strange and non-type-safe things.  We +  // currently don't do any of this for big endian systems.  It can be +  // generalized in the future if someone is interested. +  if (TD && TD->isLittleEndian()) +    return FoldReinterpretLoadFromConstPtr(CE, *TD); +  return 0; +} + +static Constant *ConstantFoldLoadInst(const LoadInst *LI, const TargetData *TD){ +  if (LI->isVolatile()) return 0; +   +  if (Constant *C = dyn_cast<Constant>(LI->getOperand(0))) +    return ConstantFoldLoadFromConstPtr(C, TD); + +  return 0; +}  /// SymbolicallyEvaluateBinop - One of Op0/Op1 is a constant expression.  /// Attempt to symbolically evaluate the result of a binary operator merging @@ -380,6 +640,9 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, LLVMContext &Context,                                             Ops.data(), Ops.size(),                                              Context, TD); +  if (const LoadInst *LI = dyn_cast<LoadInst>(I)) +    return ConstantFoldLoadInst(LI, TD); +      return ConstantFoldInstOperands(I->getOpcode(), I->getType(),                                    Ops.data(), Ops.size(), Context, TD);  } @@ -640,15 +903,15 @@ Constant *llvm::ConstantFoldLoadThroughGEPConstantExpr(Constant *C,            C = UndefValue::get(ATy->getElementType());          else            return 0; -      } else if (const VectorType *PTy = dyn_cast<VectorType>(*I)) { -        if (CI->getZExtValue() >= PTy->getNumElements()) +      } else if (const VectorType *VTy = dyn_cast<VectorType>(*I)) { +        if (CI->getZExtValue() >= VTy->getNumElements())            return 0;          if (ConstantVector *CP = dyn_cast<ConstantVector>(C))            C = CP->getOperand(CI->getZExtValue());          else if (isa<ConstantAggregateZero>(C)) -          C = Constant::getNullValue(PTy->getElementType()); +          C = Constant::getNullValue(VTy->getElementType());          else if (isa<UndefValue>(C)) -          C = UndefValue::get(PTy->getElementType()); +          C = UndefValue::get(VTy->getElementType());          else            return 0;        } else {  | 
