summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Analysis/Loads.cpp82
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp21
2 files changed, 82 insertions, 21 deletions
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index 7d3fd5951eb..128f2b82ffa 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -300,8 +300,9 @@ llvm::DefMaxInstsToScan("available-load-scan-limit", cl::init(6), cl::Hidden,
"to scan backward from a given instruction, when searching for "
"available loaded value"));
-/// \brief Scan the ScanBB block backwards to see if we have the value at the
-/// memory address *Ptr locally available within a small number of instructions.
+/// Scan the ScanBB block backwards checking to see if we have the value at
+/// the memory address \p Ptr of type \p AccessTy locally available within a
+/// small number of instructions. If the value is available, return it.
///
/// The scan starts from \c ScanFrom. \c MaxInstsToScan specifies the maximum
/// instructions to scan in the block. If it is set to \c 0, it will scan the whole
@@ -318,26 +319,25 @@ llvm::DefMaxInstsToScan("available-load-scan-limit", cl::init(6), cl::Hidden,
///
/// If \c AATags is non-null and a load or store is found, the AA tags from the
/// load or store are recorded there. If there are no AA tags or if no access is
-/// found, it is left unmodified.
-Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB,
+/// is found, it is left unmodified.
+///
+/// IsAtomicMemOp specifies the atomicity of the memory operation that accesses
+/// \p *Ptr. We verify atomicity constraints are satisfied when value forwarding
+/// from another memory operation that has value \p *Ptr available.
+///
+/// Note that we assume the \p *Ptr is accessed through a non-volatile but
+/// potentially atomic load. Any other constraints should be verified at the
+/// caller.
+Value *llvm::FindAvailableLoadedValue(Value *Ptr, Type *AccessTy, bool IsAtomicMemOp,
+ BasicBlock *ScanBB,
BasicBlock::iterator &ScanFrom,
unsigned MaxInstsToScan,
AliasAnalysis *AA, AAMDNodes *AATags,
bool *IsLoadCSE) {
+
if (MaxInstsToScan == 0)
MaxInstsToScan = ~0U;
- Value *Ptr = Load->getPointerOperand();
- Type *AccessTy = Load->getType();
-
- // We can never remove a volatile load
- if (Load->isVolatile())
- return nullptr;
-
- // Anything stronger than unordered is currently unimplemented.
- if (!Load->isUnordered())
- return nullptr;
-
const DataLayout &DL = ScanBB->getModule()->getDataLayout();
// Try to get the store size for the type.
@@ -363,14 +363,14 @@ Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB,
// If this is a load of Ptr, the loaded value is available.
// (This is true even if the load is volatile or atomic, although
// those cases are unlikely.)
- if (LoadInst *LI = dyn_cast<LoadInst>(Inst))
- if (AreEquivalentAddressValues(
- LI->getPointerOperand()->stripPointerCasts(), StrippedPtr) &&
+ if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
+ Value *LoadPtr = LI->getPointerOperand()->stripPointerCasts();
+ if (AreEquivalentAddressValues(LoadPtr, StrippedPtr) &&
CastInst::isBitOrNoopPointerCastable(LI->getType(), AccessTy, DL)) {
// We can value forward from an atomic to a non-atomic, but not the
// other way around.
- if (LI->isAtomic() < Load->isAtomic())
+ if (LI->isAtomic() < IsAtomicMemOp)
return nullptr;
if (AATags)
@@ -380,6 +380,8 @@ Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB,
return LI;
}
+ }
+
if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
Value *StorePtr = SI->getPointerOperand()->stripPointerCasts();
// If this is a store through Ptr, the value is available!
@@ -391,7 +393,7 @@ Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB,
// We can value forward from an atomic to a non-atomic, but not the
// other way around.
- if (SI->isAtomic() < Load->isAtomic())
+ if (SI->isAtomic() < IsAtomicMemOp)
return nullptr;
if (AATags)
@@ -434,4 +436,44 @@ Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB,
// Got to the start of the block, we didn't find it, but are done for this
// block.
return nullptr;
+
+}
+
+/// \brief Scan the ScanBB block backwards to see if we have the value at the
+/// memory address *Ptr locally available within a small number of instructions.
+///
+/// The scan starts from \c ScanFrom. \c MaxInstsToScan specifies the maximum
+/// instructions to scan in the block. If it is set to \c 0, it will scan the whole
+/// block.
+///
+/// If the value is available, this function returns it. If not, it returns the
+/// iterator for the last validated instruction that the value would be live
+/// through. If we scanned the entire block and didn't find something that
+/// invalidates \c *Ptr or provides it, \c ScanFrom is left at the last
+/// instruction processed and this returns null.
+///
+/// You can also optionally specify an alias analysis implementation, which
+/// makes this more precise.
+///
+/// If \c AATags is non-null and a load or store is found, the AA tags from the
+/// load or store are recorded there. If there are no AA tags or if no access is
+/// is found, it is left unmodified.
+Value *llvm::FindAvailableLoadedValue(LoadInst *Load, BasicBlock *ScanBB,
+ BasicBlock::iterator &ScanFrom,
+ unsigned MaxInstsToScan,
+ AliasAnalysis *AA, AAMDNodes *AATags,
+ bool *IsLoadCSE) {
+
+ // We can never remove a volatile load
+ if (Load->isVolatile())
+ return nullptr;
+
+ // Anything stronger than unordered is currently unimplemented.
+ if (!Load->isUnordered())
+ return nullptr;
+
+ // Return the full value of the load if available.
+ return FindAvailableLoadedValue(Load->getPointerOperand(), Load->getType(),
+ Load->isAtomic(), ScanBB, ScanFrom,
+ MaxInstsToScan, AA, AATags, IsLoadCSE);
}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index dddcd0183b3..2aaf600c84b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -14,9 +14,10 @@
#include "InstCombineInternal.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/Analysis/ConstantFolding.h"
+#include "llvm/Analysis/Loads.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/PatternMatch.h"
-#include "llvm/Analysis/TargetLibraryInfo.h"
using namespace llvm;
using namespace PatternMatch;
@@ -576,6 +577,24 @@ Instruction *InstCombiner::visitTrunc(TruncInst &CI) {
if (Instruction *I = foldVecTruncToExtElt(CI, *this, DL))
return I;
+ // When trunc operand is a widened load, see if we can get the value from a
+ // previous store/load
+ if (auto *LI = dyn_cast<LoadInst>(Src)) {
+ BasicBlock::iterator BBI(*LI);
+
+ // Scan a few instructions up from LI and if we find a partial load/store
+ // of Type DestTy that feeds into LI, we can replace all uses of the trunc
+ // with the load/store value.
+ // This replacement can be done only in the case of non-volatile loads. If
+ // the load is atomic, its only use should be the trunc instruction. We
+ // don't want to allow other users of LI to see a value that is out of sync
+ // with the value we're folding the trunc to (in case of a race).
+ if (!LI->isVolatile() && (!LI->isAtomic() || LI->hasOneUse()))
+ if (Value *AvailableVal = FindAvailableLoadedValue(
+ LI->getPointerOperand(), DestTy, LI->isAtomic(), LI->getParent(),
+ BBI, DefMaxInstsToScan))
+ return replaceInstUsesWith(CI, AvailableVal);
+ }
return nullptr;
}
OpenPOWER on IntegriCloud