diff options
Diffstat (limited to 'llvm/lib/Analysis/MemoryLocation.cpp')
| -rw-r--r-- | llvm/lib/Analysis/MemoryLocation.cpp | 211 | 
1 files changed, 211 insertions, 0 deletions
diff --git a/llvm/lib/Analysis/MemoryLocation.cpp b/llvm/lib/Analysis/MemoryLocation.cpp new file mode 100644 index 000000000000..163830eee797 --- /dev/null +++ b/llvm/lib/Analysis/MemoryLocation.cpp @@ -0,0 +1,211 @@ +//===- MemoryLocation.cpp - Memory location descriptions -------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/MemoryLocation.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +using namespace llvm; + +void LocationSize::print(raw_ostream &OS) const { +  OS << "LocationSize::"; +  if (*this == unknown()) +    OS << "unknown"; +  else if (*this == mapEmpty()) +    OS << "mapEmpty"; +  else if (*this == mapTombstone()) +    OS << "mapTombstone"; +  else if (isPrecise()) +    OS << "precise(" << getValue() << ')'; +  else +    OS << "upperBound(" << getValue() << ')'; +} + +MemoryLocation MemoryLocation::get(const LoadInst *LI) { +  AAMDNodes AATags; +  LI->getAAMetadata(AATags); +  const auto &DL = LI->getModule()->getDataLayout(); + +  return MemoryLocation( +      LI->getPointerOperand(), +      LocationSize::precise(DL.getTypeStoreSize(LI->getType())), AATags); +} + +MemoryLocation MemoryLocation::get(const StoreInst *SI) { +  AAMDNodes AATags; +  SI->getAAMetadata(AATags); +  const auto &DL = SI->getModule()->getDataLayout(); + +  return MemoryLocation(SI->getPointerOperand(), +                        LocationSize::precise(DL.getTypeStoreSize( +                            SI->getValueOperand()->getType())), +                        AATags); +} + +MemoryLocation MemoryLocation::get(const VAArgInst *VI) { +  AAMDNodes AATags; +  VI->getAAMetadata(AATags); + +  return MemoryLocation(VI->getPointerOperand(), LocationSize::unknown(), +                        AATags); +} + +MemoryLocation MemoryLocation::get(const AtomicCmpXchgInst *CXI) { +  AAMDNodes AATags; +  CXI->getAAMetadata(AATags); +  const auto &DL = CXI->getModule()->getDataLayout(); + +  return MemoryLocation(CXI->getPointerOperand(), +                        LocationSize::precise(DL.getTypeStoreSize( +                            CXI->getCompareOperand()->getType())), +                        AATags); +} + +MemoryLocation MemoryLocation::get(const AtomicRMWInst *RMWI) { +  AAMDNodes AATags; +  RMWI->getAAMetadata(AATags); +  const auto &DL = RMWI->getModule()->getDataLayout(); + +  return MemoryLocation(RMWI->getPointerOperand(), +                        LocationSize::precise(DL.getTypeStoreSize( +                            RMWI->getValOperand()->getType())), +                        AATags); +} + +MemoryLocation MemoryLocation::getForSource(const MemTransferInst *MTI) { +  return getForSource(cast<AnyMemTransferInst>(MTI)); +} + +MemoryLocation MemoryLocation::getForSource(const AtomicMemTransferInst *MTI) { +  return getForSource(cast<AnyMemTransferInst>(MTI)); +} + +MemoryLocation MemoryLocation::getForSource(const AnyMemTransferInst *MTI) { +  auto Size = LocationSize::unknown(); +  if (ConstantInt *C = dyn_cast<ConstantInt>(MTI->getLength())) +    Size = LocationSize::precise(C->getValue().getZExtValue()); + +  // memcpy/memmove can have AA tags. For memcpy, they apply +  // to both the source and the destination. +  AAMDNodes AATags; +  MTI->getAAMetadata(AATags); + +  return MemoryLocation(MTI->getRawSource(), Size, AATags); +} + +MemoryLocation MemoryLocation::getForDest(const MemIntrinsic *MI) { +  return getForDest(cast<AnyMemIntrinsic>(MI)); +} + +MemoryLocation MemoryLocation::getForDest(const AtomicMemIntrinsic *MI) { +  return getForDest(cast<AnyMemIntrinsic>(MI)); +} + +MemoryLocation MemoryLocation::getForDest(const AnyMemIntrinsic *MI) { +  auto Size = LocationSize::unknown(); +  if (ConstantInt *C = dyn_cast<ConstantInt>(MI->getLength())) +    Size = LocationSize::precise(C->getValue().getZExtValue()); + +  // memcpy/memmove can have AA tags. For memcpy, they apply +  // to both the source and the destination. +  AAMDNodes AATags; +  MI->getAAMetadata(AATags); + +  return MemoryLocation(MI->getRawDest(), Size, AATags); +} + +MemoryLocation MemoryLocation::getForArgument(const CallBase *Call, +                                              unsigned ArgIdx, +                                              const TargetLibraryInfo *TLI) { +  AAMDNodes AATags; +  Call->getAAMetadata(AATags); +  const Value *Arg = Call->getArgOperand(ArgIdx); + +  // We may be able to produce an exact size for known intrinsics. +  if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(Call)) { +    const DataLayout &DL = II->getModule()->getDataLayout(); + +    switch (II->getIntrinsicID()) { +    default: +      break; +    case Intrinsic::memset: +    case Intrinsic::memcpy: +    case Intrinsic::memmove: +      assert((ArgIdx == 0 || ArgIdx == 1) && +             "Invalid argument index for memory intrinsic"); +      if (ConstantInt *LenCI = dyn_cast<ConstantInt>(II->getArgOperand(2))) +        return MemoryLocation(Arg, LocationSize::precise(LenCI->getZExtValue()), +                              AATags); +      break; + +    case Intrinsic::lifetime_start: +    case Intrinsic::lifetime_end: +    case Intrinsic::invariant_start: +      assert(ArgIdx == 1 && "Invalid argument index"); +      return MemoryLocation( +          Arg, +          LocationSize::precise( +              cast<ConstantInt>(II->getArgOperand(0))->getZExtValue()), +          AATags); + +    case Intrinsic::invariant_end: +      // The first argument to an invariant.end is a "descriptor" type (e.g. a +      // pointer to a empty struct) which is never actually dereferenced. +      if (ArgIdx == 0) +        return MemoryLocation(Arg, LocationSize::precise(0), AATags); +      assert(ArgIdx == 2 && "Invalid argument index"); +      return MemoryLocation( +          Arg, +          LocationSize::precise( +              cast<ConstantInt>(II->getArgOperand(1))->getZExtValue()), +          AATags); + +    case Intrinsic::arm_neon_vld1: +      assert(ArgIdx == 0 && "Invalid argument index"); +      // LLVM's vld1 and vst1 intrinsics currently only support a single +      // vector register. +      return MemoryLocation( +          Arg, LocationSize::precise(DL.getTypeStoreSize(II->getType())), +          AATags); + +    case Intrinsic::arm_neon_vst1: +      assert(ArgIdx == 0 && "Invalid argument index"); +      return MemoryLocation(Arg, +                            LocationSize::precise(DL.getTypeStoreSize( +                                II->getArgOperand(1)->getType())), +                            AATags); +    } +  } + +  // We can bound the aliasing properties of memset_pattern16 just as we can +  // for memcpy/memset.  This is particularly important because the +  // LoopIdiomRecognizer likes to turn loops into calls to memset_pattern16 +  // whenever possible. +  LibFunc F; +  if (TLI && Call->getCalledFunction() && +      TLI->getLibFunc(*Call->getCalledFunction(), F) && +      F == LibFunc_memset_pattern16 && TLI->has(F)) { +    assert((ArgIdx == 0 || ArgIdx == 1) && +           "Invalid argument index for memset_pattern16"); +    if (ArgIdx == 1) +      return MemoryLocation(Arg, LocationSize::precise(16), AATags); +    if (const ConstantInt *LenCI = +            dyn_cast<ConstantInt>(Call->getArgOperand(2))) +      return MemoryLocation(Arg, LocationSize::precise(LenCI->getZExtValue()), +                            AATags); +  } +  // FIXME: Handle memset_pattern4 and memset_pattern8 also. + +  return MemoryLocation(Call->getArgOperand(ArgIdx), LocationSize::unknown(), +                        AATags); +}  | 
