summaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Scalar
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
commit344a3780b2e33f6ca763666c380202b18aab72a3 (patch)
treef0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/Transforms/Scalar
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
Diffstat (limited to 'llvm/lib/Transforms/Scalar')
-rw-r--r--llvm/lib/Transforms/Scalar/ADCE.cpp13
-rw-r--r--llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp11
-rw-r--r--llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp51
-rw-r--r--llvm/lib/Transforms/Scalar/BDCE.cpp1
-rw-r--r--llvm/lib/Transforms/Scalar/ConstantHoisting.cpp29
-rw-r--r--llvm/lib/Transforms/Scalar/ConstraintElimination.cpp249
-rw-r--r--llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp135
-rw-r--r--llvm/lib/Transforms/Scalar/DCE.cpp9
-rw-r--r--llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp1286
-rw-r--r--llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp1311
-rw-r--r--llvm/lib/Transforms/Scalar/DivRemPairs.cpp49
-rw-r--r--llvm/lib/Transforms/Scalar/EarlyCSE.cpp58
-rw-r--r--llvm/lib/Transforms/Scalar/Float2Int.cpp6
-rw-r--r--llvm/lib/Transforms/Scalar/GVN.cpp560
-rw-r--r--llvm/lib/Transforms/Scalar/GVNHoist.cpp1
-rw-r--r--llvm/lib/Transforms/Scalar/GVNSink.cpp5
-rw-r--r--llvm/lib/Transforms/Scalar/IndVarSimplify.cpp12
-rw-r--r--llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp16
-rw-r--r--llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp27
-rw-r--r--llvm/lib/Transforms/Scalar/JumpThreading.cpp63
-rw-r--r--llvm/lib/Transforms/Scalar/LICM.cpp313
-rw-r--r--llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp439
-rw-r--r--llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp4
-rw-r--r--llvm/lib/Transforms/Scalar/LoopDeletion.cpp267
-rw-r--r--llvm/lib/Transforms/Scalar/LoopDistribute.cpp1
-rw-r--r--llvm/lib/Transforms/Scalar/LoopFlatten.cpp245
-rw-r--r--llvm/lib/Transforms/Scalar/LoopFuse.cpp14
-rw-r--r--llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp708
-rw-r--r--llvm/lib/Transforms/Scalar/LoopInterchange.cpp208
-rw-r--r--llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp10
-rw-r--r--llvm/lib/Transforms/Scalar/LoopPassManager.cpp37
-rw-r--r--llvm/lib/Transforms/Scalar/LoopRerollPass.cpp13
-rw-r--r--llvm/lib/Transforms/Scalar/LoopRotation.cpp6
-rw-r--r--llvm/lib/Transforms/Scalar/LoopSink.cpp11
-rw-r--r--llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp642
-rw-r--r--llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp87
-rw-r--r--llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp171
-rw-r--r--llvm/lib/Transforms/Scalar/LoopUnswitch.cpp230
-rw-r--r--llvm/lib/Transforms/Scalar/LowerAtomic.cpp4
-rw-r--r--llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp46
-rw-r--r--llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp13
-rw-r--r--llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp441
-rw-r--r--llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp235
-rw-r--r--llvm/lib/Transforms/Scalar/MergeICmps.cpp196
-rw-r--r--llvm/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp1
-rw-r--r--llvm/lib/Transforms/Scalar/NaryReassociate.cpp131
-rw-r--r--llvm/lib/Transforms/Scalar/NewGVN.cpp273
-rw-r--r--llvm/lib/Transforms/Scalar/PartiallyInlineLibCalls.cpp69
-rw-r--r--llvm/lib/Transforms/Scalar/Reassociate.cpp14
-rw-r--r--llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp539
-rw-r--r--llvm/lib/Transforms/Scalar/SCCP.cpp1585
-rw-r--r--llvm/lib/Transforms/Scalar/SROA.cpp98
-rw-r--r--llvm/lib/Transforms/Scalar/Scalar.cpp1
-rw-r--r--llvm/lib/Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp226
-rw-r--r--llvm/lib/Transforms/Scalar/Scalarizer.cpp11
-rw-r--r--llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp402
-rw-r--r--llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp196
-rw-r--r--llvm/lib/Transforms/Scalar/Sink.cpp2
-rw-r--r--llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp830
-rw-r--r--llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp26
-rw-r--r--llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp8
-rw-r--r--llvm/lib/Transforms/Scalar/StructurizeCFG.cpp20
-rw-r--r--llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp168
63 files changed, 7245 insertions, 5588 deletions
diff --git a/llvm/lib/Transforms/Scalar/ADCE.cpp b/llvm/lib/Transforms/Scalar/ADCE.cpp
index 2b649732a799..6f3fdb88eda5 100644
--- a/llvm/lib/Transforms/Scalar/ADCE.cpp
+++ b/llvm/lib/Transforms/Scalar/ADCE.cpp
@@ -50,6 +50,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/Local.h"
#include <cassert>
#include <cstddef>
#include <utility>
@@ -521,10 +522,14 @@ bool AggressiveDeadCodeElimination::removeDeadInstructions() {
// If intrinsic is pointing at a live SSA value, there may be an
// earlier optimization bug: if we know the location of the variable,
// why isn't the scope of the location alive?
- if (Value *V = DII->getVariableLocation())
- if (Instruction *II = dyn_cast<Instruction>(V))
- if (isLive(II))
+ for (Value *V : DII->location_ops()) {
+ if (Instruction *II = dyn_cast<Instruction>(V)) {
+ if (isLive(II)) {
dbgs() << "Dropping debug info for " << *DII << "\n";
+ break;
+ }
+ }
+ }
}
}
});
@@ -548,6 +553,7 @@ bool AggressiveDeadCodeElimination::removeDeadInstructions() {
// Prepare to delete.
Worklist.push_back(&I);
+ salvageDebugInfo(I);
I.dropAllReferences();
}
@@ -696,7 +702,6 @@ PreservedAnalyses ADCEPass::run(Function &F, FunctionAnalysisManager &FAM) {
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<PostDominatorTreeAnalysis>();
}
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp b/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp
index bccf94fc217f..be21db9087d2 100644
--- a/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp
+++ b/llvm/lib/Transforms/Scalar/AlignmentFromAssumptions.cpp
@@ -17,8 +17,6 @@
#include "llvm/IR/Instructions.h"
#include "llvm/InitializePasses.h"
-#define AA_NAME "alignment-from-assumptions"
-#define DEBUG_TYPE AA_NAME
#include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
@@ -37,6 +35,9 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
+
+#define AA_NAME "alignment-from-assumptions"
+#define DEBUG_TYPE AA_NAME
using namespace llvm;
STATISTIC(NumLoadAlignChanged,
@@ -134,6 +135,8 @@ static Align getNewAlignment(const SCEV *AASCEV, const SCEV *AlignSCEV,
PtrSCEV = SE->getTruncateOrZeroExtend(
PtrSCEV, SE->getEffectiveSCEVType(AASCEV->getType()));
const SCEV *DiffSCEV = SE->getMinusSCEV(PtrSCEV, AASCEV);
+ if (isa<SCEVCouldNotCompute>(DiffSCEV))
+ return Align(1);
// On 32-bit platforms, DiffSCEV might now have type i32 -- we've always
// sign-extended OffSCEV to i64, so make sure they agree again.
@@ -141,7 +144,7 @@ static Align getNewAlignment(const SCEV *AASCEV, const SCEV *AlignSCEV,
// What we really want to know is the overall offset to the aligned
// address. This address is displaced by the provided offset.
- DiffSCEV = SE->getMinusSCEV(DiffSCEV, OffSCEV);
+ DiffSCEV = SE->getAddExpr(DiffSCEV, OffSCEV);
LLVM_DEBUG(dbgs() << "AFI: alignment of " << *Ptr << " relative to "
<< *AlignSCEV << " and offset " << *OffSCEV
@@ -352,8 +355,6 @@ AlignmentFromAssumptionsPass::run(Function &F, FunctionAnalysisManager &AM) {
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
- PA.preserve<AAManager>();
PA.preserve<ScalarEvolutionAnalysis>();
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp b/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp
index a02d88fe066f..a5e65ffc45fe 100644
--- a/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp
+++ b/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp
@@ -16,10 +16,13 @@
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/MemoryOpRemark.h"
using namespace llvm;
using namespace llvm::ore;
@@ -27,16 +30,37 @@ using namespace llvm::ore;
#define DEBUG_TYPE "annotation-remarks"
#define REMARK_PASS DEBUG_TYPE
-static void runImpl(Function &F) {
+static void tryEmitAutoInitRemark(ArrayRef<Instruction *> Instructions,
+ OptimizationRemarkEmitter &ORE,
+ const TargetLibraryInfo &TLI) {
+ // For every auto-init annotation generate a separate remark.
+ for (Instruction *I : Instructions) {
+ if (!AutoInitRemark::canHandle(I))
+ continue;
+
+ Function &F = *I->getParent()->getParent();
+ const DataLayout &DL = F.getParent()->getDataLayout();
+ AutoInitRemark Remark(ORE, REMARK_PASS, DL, TLI);
+ Remark.visit(I);
+ }
+}
+
+static void runImpl(Function &F, const TargetLibraryInfo &TLI) {
if (!OptimizationRemarkEmitter::allowExtraAnalysis(F, REMARK_PASS))
return;
+ // Track all annotated instructions aggregated based on their debug location.
+ DenseMap<MDNode *, SmallVector<Instruction *, 4>> DebugLoc2Annotated;
+
OptimizationRemarkEmitter ORE(&F);
- // For now, just generate a summary of the annotated instructions.
+ // First, generate a summary of the annotated instructions.
MapVector<StringRef, unsigned> Mapping;
for (Instruction &I : instructions(F)) {
if (!I.hasMetadata(LLVMContext::MD_annotation))
continue;
+ auto Iter = DebugLoc2Annotated.insert({I.getDebugLoc().getAsMDNode(), {}});
+ Iter.first->second.push_back(&I);
+
for (const MDOperand &Op :
I.getMetadata(LLVMContext::MD_annotation)->operands()) {
auto Iter = Mapping.insert({cast<MDString>(Op.get())->getString(), 0});
@@ -44,11 +68,21 @@ static void runImpl(Function &F) {
}
}
- Instruction *IP = &*F.begin()->begin();
for (const auto &KV : Mapping)
- ORE.emit(OptimizationRemarkAnalysis(REMARK_PASS, "AnnotationSummary", IP)
+ ORE.emit(OptimizationRemarkAnalysis(REMARK_PASS, "AnnotationSummary",
+ F.getSubprogram(), &F.front())
<< "Annotated " << NV("count", KV.second) << " instructions with "
<< NV("type", KV.first));
+
+ // For each debug location, look for all the instructions with annotations and
+ // generate more detailed remarks to be displayed at that location.
+ for (auto &KV : DebugLoc2Annotated) {
+ // Don't generate remarks with no debug location.
+ if (!KV.first)
+ continue;
+
+ tryEmitAutoInitRemark(KV.second, ORE, TLI);
+ }
}
namespace {
@@ -61,12 +95,15 @@ struct AnnotationRemarksLegacy : public FunctionPass {
}
bool runOnFunction(Function &F) override {
- runImpl(F);
+ const TargetLibraryInfo &TLI =
+ getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
+ runImpl(F, TLI);
return false;
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
+ AU.addRequired<TargetLibraryInfoWrapperPass>();
}
};
@@ -76,6 +113,7 @@ char AnnotationRemarksLegacy::ID = 0;
INITIALIZE_PASS_BEGIN(AnnotationRemarksLegacy, "annotation-remarks",
"Annotation Remarks", false, false)
+INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(AnnotationRemarksLegacy, "annotation-remarks",
"Annotation Remarks", false, false)
@@ -85,6 +123,7 @@ FunctionPass *llvm::createAnnotationRemarksLegacyPass() {
PreservedAnalyses AnnotationRemarksPass::run(Function &F,
FunctionAnalysisManager &AM) {
- runImpl(F);
+ auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
+ runImpl(F, TLI);
return PreservedAnalyses::all();
}
diff --git a/llvm/lib/Transforms/Scalar/BDCE.cpp b/llvm/lib/Transforms/Scalar/BDCE.cpp
index 767c7656dcfa..c06125788f37 100644
--- a/llvm/lib/Transforms/Scalar/BDCE.cpp
+++ b/llvm/lib/Transforms/Scalar/BDCE.cpp
@@ -170,7 +170,6 @@ PreservedAnalyses BDCEPass::run(Function &F, FunctionAnalysisManager &AM) {
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp
index fdab74fc94c5..535f50d4f904 100644
--- a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp
@@ -185,13 +185,20 @@ Instruction *ConstantHoistingPass::findMatInsertPt(Instruction *Inst,
// We can't insert directly before a phi node or an eh pad. Insert before
// the terminator of the incoming or dominating block.
assert(Entry != Inst->getParent() && "PHI or landing pad in entry block!");
- if (Idx != ~0U && isa<PHINode>(Inst))
- return cast<PHINode>(Inst)->getIncomingBlock(Idx)->getTerminator();
+ BasicBlock *InsertionBlock = nullptr;
+ if (Idx != ~0U && isa<PHINode>(Inst)) {
+ InsertionBlock = cast<PHINode>(Inst)->getIncomingBlock(Idx);
+ if (!InsertionBlock->isEHPad()) {
+ return InsertionBlock->getTerminator();
+ }
+ } else {
+ InsertionBlock = Inst->getParent();
+ }
// This must be an EH pad. Iterate over immediate dominators until we find a
// non-EH pad. We need to skip over catchswitch blocks, which are both EH pads
// and terminators.
- auto IDom = DT->getNode(Inst->getParent())->getIDom();
+ auto *IDom = DT->getNode(InsertionBlock)->getIDom();
while (IDom->getBlock()->isEHPad()) {
assert(Entry != IDom->getBlock() && "eh pad in entry block");
IDom = IDom->getIDom();
@@ -358,7 +365,7 @@ SetVector<Instruction *> ConstantHoistingPass::findConstantInsertionPoint(
void ConstantHoistingPass::collectConstantCandidates(
ConstCandMapType &ConstCandMap, Instruction *Inst, unsigned Idx,
ConstantInt *ConstInt) {
- unsigned Cost;
+ InstructionCost Cost;
// Ask the target about the cost of materializing the constant for the given
// instruction and operand index.
if (auto IntrInst = dyn_cast<IntrinsicInst>(Inst))
@@ -380,7 +387,7 @@ void ConstantHoistingPass::collectConstantCandidates(
ConstIntCandVec.push_back(ConstantCandidate(ConstInt));
Itr->second = ConstIntCandVec.size() - 1;
}
- ConstIntCandVec[Itr->second].addUser(Inst, Idx, Cost);
+ ConstIntCandVec[Itr->second].addUser(Inst, Idx, *Cost.getValue());
LLVM_DEBUG(if (isa<ConstantInt>(Inst->getOperand(Idx))) dbgs()
<< "Collect constant " << *ConstInt << " from " << *Inst
<< " with cost " << Cost << '\n';
@@ -418,7 +425,7 @@ void ConstantHoistingPass::collectConstantCandidates(
// usually lowered to a load from constant pool. Such operation is unlikely
// to be cheaper than compute it by <Base + Offset>, which can be lowered to
// an ADD instruction or folded into Load/Store instruction.
- int Cost =
+ InstructionCost Cost =
TTI->getIntImmCostInst(Instruction::Add, 1, Offset, PtrIntTy,
TargetTransformInfo::TCK_SizeAndLatency, Inst);
ConstCandVecType &ExprCandVec = ConstGEPCandMap[BaseGV];
@@ -432,7 +439,7 @@ void ConstantHoistingPass::collectConstantCandidates(
ConstExpr));
Itr->second = ExprCandVec.size() - 1;
}
- ExprCandVec[Itr->second].addUser(Inst, Idx, Cost);
+ ExprCandVec[Itr->second].addUser(Inst, Idx, *Cost.getValue());
}
/// Check the operand for instruction Inst at index Idx.
@@ -574,11 +581,11 @@ ConstantHoistingPass::maximizeConstantsInRange(ConstCandVecType::iterator S,
}
LLVM_DEBUG(dbgs() << "== Maximize constants in range ==\n");
- int MaxCost = -1;
+ InstructionCost MaxCost = -1;
for (auto ConstCand = S; ConstCand != E; ++ConstCand) {
auto Value = ConstCand->ConstInt->getValue();
Type *Ty = ConstCand->ConstInt->getType();
- int Cost = 0;
+ InstructionCost Cost = 0;
NumUses += ConstCand->Uses.size();
LLVM_DEBUG(dbgs() << "= Constant: " << ConstCand->ConstInt->getValue()
<< "\n");
@@ -595,8 +602,8 @@ ConstantHoistingPass::maximizeConstantsInRange(ConstCandVecType::iterator S,
C2->ConstInt->getValue(),
ConstCand->ConstInt->getValue());
if (Diff) {
- const int ImmCosts =
- TTI->getIntImmCodeSizeCost(Opcode, OpndIdx, Diff.getValue(), Ty);
+ const InstructionCost ImmCosts =
+ TTI->getIntImmCodeSizeCost(Opcode, OpndIdx, Diff.getValue(), Ty);
Cost -= ImmCosts;
LLVM_DEBUG(dbgs() << "Offset " << Diff.getValue() << " "
<< "has penalty: " << ImmCosts << "\n"
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 3b8af6f21ce5..efd1c025d0cd 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -13,6 +13,7 @@
#include "llvm/Transforms/Scalar/ConstraintElimination.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/ConstraintSystem.h"
@@ -28,6 +29,8 @@
#include "llvm/Support/DebugCounter.h"
#include "llvm/Transforms/Scalar.h"
+#include <string>
+
using namespace llvm;
using namespace PatternMatch;
@@ -50,32 +53,50 @@ static SmallVector<std::pair<int64_t, Value *>, 4> decompose(Value *V) {
return {{CI->getSExtValue(), nullptr}};
}
auto *GEP = dyn_cast<GetElementPtrInst>(V);
- if (GEP && GEP->getNumOperands() == 2) {
- if (isa<ConstantInt>(GEP->getOperand(GEP->getNumOperands() - 1))) {
- return {{cast<ConstantInt>(GEP->getOperand(GEP->getNumOperands() - 1))
- ->getSExtValue(),
- nullptr},
- {1, GEP->getPointerOperand()}};
- }
- Value *Op0;
+ if (GEP && GEP->getNumOperands() == 2 && GEP->isInBounds()) {
+ Value *Op0, *Op1;
ConstantInt *CI;
+
+ // If the index is zero-extended, it is guaranteed to be positive.
if (match(GEP->getOperand(GEP->getNumOperands() - 1),
- m_NUWShl(m_Value(Op0), m_ConstantInt(CI))))
- return {{0, nullptr},
- {1, GEP->getPointerOperand()},
- {std::pow(int64_t(2), CI->getSExtValue()), Op0}};
- if (match(GEP->getOperand(GEP->getNumOperands() - 1),
- m_ZExt(m_NUWShl(m_Value(Op0), m_ConstantInt(CI)))))
- return {{0, nullptr},
- {1, GEP->getPointerOperand()},
- {std::pow(int64_t(2), CI->getSExtValue()), Op0}};
+ m_ZExt(m_Value(Op0)))) {
+ if (match(Op0, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))))
+ return {{0, nullptr},
+ {1, GEP->getPointerOperand()},
+ {std::pow(int64_t(2), CI->getSExtValue()), Op1}};
+ if (match(Op0, m_NSWAdd(m_Value(Op1), m_ConstantInt(CI))))
+ return {{CI->getSExtValue(), nullptr},
+ {1, GEP->getPointerOperand()},
+ {1, Op1}};
+ return {{0, nullptr}, {1, GEP->getPointerOperand()}, {1, Op0}};
+ }
+
+ if (match(GEP->getOperand(GEP->getNumOperands() - 1), m_ConstantInt(CI)) &&
+ !CI->isNegative())
+ return {{CI->getSExtValue(), nullptr}, {1, GEP->getPointerOperand()}};
- return {{0, nullptr},
- {1, GEP->getPointerOperand()},
- {1, GEP->getOperand(GEP->getNumOperands() - 1)}};
+ SmallVector<std::pair<int64_t, Value *>, 4> Result;
+ if (match(GEP->getOperand(GEP->getNumOperands() - 1),
+ m_NUWShl(m_Value(Op0), m_ConstantInt(CI))))
+ Result = {{0, nullptr},
+ {1, GEP->getPointerOperand()},
+ {std::pow(int64_t(2), CI->getSExtValue()), Op0}};
+ else if (match(GEP->getOperand(GEP->getNumOperands() - 1),
+ m_NSWAdd(m_Value(Op0), m_ConstantInt(CI))))
+ Result = {{CI->getSExtValue(), nullptr},
+ {1, GEP->getPointerOperand()},
+ {1, Op0}};
+ else {
+ Op0 = GEP->getOperand(GEP->getNumOperands() - 1);
+ Result = {{0, nullptr}, {1, GEP->getPointerOperand()}, {1, Op0}};
+ }
+ return Result;
}
Value *Op0;
+ if (match(V, m_ZExt(m_Value(Op0))))
+ V = Op0;
+
Value *Op1;
ConstantInt *CI;
if (match(V, m_NUWAdd(m_Value(Op0), m_ConstantInt(CI))))
@@ -91,37 +112,62 @@ static SmallVector<std::pair<int64_t, Value *>, 4> decompose(Value *V) {
return {{0, nullptr}, {1, V}};
}
-/// Turn a condition \p CmpI into a constraint vector, using indices from \p
-/// Value2Index. If \p ShouldAdd is true, new indices are added for values not
-/// yet in \p Value2Index.
-static SmallVector<int64_t, 8>
+struct ConstraintTy {
+ SmallVector<int64_t, 8> Coefficients;
+
+ ConstraintTy(SmallVector<int64_t, 8> Coefficients)
+ : Coefficients(Coefficients) {}
+
+ unsigned size() const { return Coefficients.size(); }
+};
+
+/// Turn a condition \p CmpI into a vector of constraints, using indices from \p
+/// Value2Index. Additional indices for newly discovered values are added to \p
+/// NewIndices.
+static SmallVector<ConstraintTy, 4>
getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
- DenseMap<Value *, unsigned> &Value2Index, bool ShouldAdd) {
+ const DenseMap<Value *, unsigned> &Value2Index,
+ DenseMap<Value *, unsigned> &NewIndices) {
int64_t Offset1 = 0;
int64_t Offset2 = 0;
- auto TryToGetIndex = [ShouldAdd,
- &Value2Index](Value *V) -> Optional<unsigned> {
- if (ShouldAdd) {
- Value2Index.insert({V, Value2Index.size() + 1});
- return Value2Index[V];
- }
- auto I = Value2Index.find(V);
- if (I == Value2Index.end())
- return None;
- return I->second;
+ // First try to look up \p V in Value2Index and NewIndices. Otherwise add a
+ // new entry to NewIndices.
+ auto GetOrAddIndex = [&Value2Index, &NewIndices](Value *V) -> unsigned {
+ auto V2I = Value2Index.find(V);
+ if (V2I != Value2Index.end())
+ return V2I->second;
+ auto NewI = NewIndices.find(V);
+ if (NewI != NewIndices.end())
+ return NewI->second;
+ auto Insert =
+ NewIndices.insert({V, Value2Index.size() + NewIndices.size() + 1});
+ return Insert.first->second;
};
if (Pred == CmpInst::ICMP_UGT || Pred == CmpInst::ICMP_UGE)
return getConstraint(CmpInst::getSwappedPredicate(Pred), Op1, Op0,
- Value2Index, ShouldAdd);
+ Value2Index, NewIndices);
+
+ if (Pred == CmpInst::ICMP_EQ) {
+ auto A =
+ getConstraint(CmpInst::ICMP_UGE, Op0, Op1, Value2Index, NewIndices);
+ auto B =
+ getConstraint(CmpInst::ICMP_ULE, Op0, Op1, Value2Index, NewIndices);
+ append_range(A, B);
+ return A;
+ }
+
+ if (Pred == CmpInst::ICMP_NE && match(Op1, m_Zero())) {
+ return getConstraint(CmpInst::ICMP_UGT, Op0, Op1, Value2Index, NewIndices);
+ }
// Only ULE and ULT predicates are supported at the moment.
if (Pred != CmpInst::ICMP_ULE && Pred != CmpInst::ICMP_ULT)
return {};
- auto ADec = decompose(Op0);
- auto BDec = decompose(Op1);
+ auto ADec = decompose(Op0->stripPointerCastsSameRepresentation());
+ auto BDec = decompose(Op1->stripPointerCastsSameRepresentation());
// Skip if decomposing either of the values failed.
if (ADec.empty() || BDec.empty())
return {};
@@ -135,34 +181,32 @@ getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
Offset1 *= -1;
// Create iterator ranges that skip the constant-factor.
- auto VariablesA = make_range(std::next(ADec.begin()), ADec.end());
- auto VariablesB = make_range(std::next(BDec.begin()), BDec.end());
+ auto VariablesA = llvm::drop_begin(ADec);
+ auto VariablesB = llvm::drop_begin(BDec);
- // Check if each referenced value in the constraint is already in the system
- // or can be added (if ShouldAdd is true).
+ // Make sure all variables have entries in Value2Index or NewIndices.
for (const auto &KV :
concat<std::pair<int64_t, Value *>>(VariablesA, VariablesB))
- if (!TryToGetIndex(KV.second))
- return {};
+ GetOrAddIndex(KV.second);
// Build result constraint, by first adding all coefficients from A and then
// subtracting all coefficients from B.
- SmallVector<int64_t, 8> R(Value2Index.size() + 1, 0);
+ SmallVector<int64_t, 8> R(Value2Index.size() + NewIndices.size() + 1, 0);
for (const auto &KV : VariablesA)
- R[Value2Index[KV.second]] += KV.first;
+ R[GetOrAddIndex(KV.second)] += KV.first;
for (const auto &KV : VariablesB)
- R[Value2Index[KV.second]] -= KV.first;
+ R[GetOrAddIndex(KV.second)] -= KV.first;
R[0] = Offset1 + Offset2 + (Pred == CmpInst::ICMP_ULT ? -1 : 0);
- return R;
+ return {R};
}
-static SmallVector<int64_t, 8>
-getConstraint(CmpInst *Cmp, DenseMap<Value *, unsigned> &Value2Index,
- bool ShouldAdd) {
+static SmallVector<ConstraintTy, 4>
+getConstraint(CmpInst *Cmp, const DenseMap<Value *, unsigned> &Value2Index,
+ DenseMap<Value *, unsigned> &NewIndices) {
return getConstraint(Cmp->getPredicate(), Cmp->getOperand(0),
- Cmp->getOperand(1), Value2Index, ShouldAdd);
+ Cmp->getOperand(1), Value2Index, NewIndices);
}
namespace {
@@ -197,6 +241,19 @@ struct StackEntry {
};
} // namespace
+#ifndef NDEBUG
+static void dumpWithNames(ConstraintTy &C,
+ DenseMap<Value *, unsigned> &Value2Index) {
+ SmallVector<std::string> Names(Value2Index.size(), "");
+ for (auto &KV : Value2Index) {
+ Names[KV.second - 1] = std::string("%") + KV.first->getName().str();
+ }
+ ConstraintSystem CS;
+ CS.addVariableRowFill(C.Coefficients);
+ CS.dump(Names);
+}
+#endif
+
static bool eliminateConstraints(Function &F, DominatorTree &DT) {
bool Changed = false;
DT.updateDFSNumbers();
@@ -215,6 +272,15 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
if (!Br || !Br->isConditional())
continue;
+ // Returns true if we can add a known condition from BB to its successor
+ // block Succ. Each predecessor of Succ can either be BB or be dominated by
+ // Succ (e.g. the case when adding a condition from a pre-header to a loop
+ // header).
+ auto CanAdd = [&BB, &DT](BasicBlock *Succ) {
+ return all_of(predecessors(Succ), [&BB, &DT, Succ](BasicBlock *Pred) {
+ return Pred == &BB || DT.dominates(Succ, Pred);
+ });
+ };
// If the condition is an OR of 2 compares and the false successor only has
// the current block as predecessor, queue both negated conditions for the
// false successor.
@@ -222,7 +288,7 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
if (match(Br->getCondition(), m_LogicalOr(m_Value(Op0), m_Value(Op1))) &&
match(Op0, m_Cmp()) && match(Op1, m_Cmp())) {
BasicBlock *FalseSuccessor = Br->getSuccessor(1);
- if (FalseSuccessor->getSinglePredecessor()) {
+ if (CanAdd(FalseSuccessor)) {
WorkList.emplace_back(DT.getNode(FalseSuccessor), cast<CmpInst>(Op0),
true);
WorkList.emplace_back(DT.getNode(FalseSuccessor), cast<CmpInst>(Op1),
@@ -237,7 +303,7 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
if (match(Br->getCondition(), m_LogicalAnd(m_Value(Op0), m_Value(Op1))) &&
match(Op0, m_Cmp()) && match(Op1, m_Cmp())) {
BasicBlock *TrueSuccessor = Br->getSuccessor(0);
- if (TrueSuccessor->getSinglePredecessor()) {
+ if (CanAdd(TrueSuccessor)) {
WorkList.emplace_back(DT.getNode(TrueSuccessor), cast<CmpInst>(Op0),
false);
WorkList.emplace_back(DT.getNode(TrueSuccessor), cast<CmpInst>(Op1),
@@ -249,9 +315,9 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
auto *CmpI = dyn_cast<CmpInst>(Br->getCondition());
if (!CmpI)
continue;
- if (Br->getSuccessor(0)->getSinglePredecessor())
+ if (CanAdd(Br->getSuccessor(0)))
WorkList.emplace_back(DT.getNode(Br->getSuccessor(0)), CmpI, false);
- if (Br->getSuccessor(1)->getSinglePredecessor())
+ if (CanAdd(Br->getSuccessor(1)))
WorkList.emplace_back(DT.getNode(Br->getSuccessor(1)), CmpI, true);
}
@@ -299,10 +365,27 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
auto *Cmp = dyn_cast<CmpInst>(&I);
if (!Cmp)
continue;
- auto R = getConstraint(Cmp, Value2Index, false);
- if (R.empty() || R.size() == 1)
+
+ DenseMap<Value *, unsigned> NewIndices;
+ auto R = getConstraint(Cmp, Value2Index, NewIndices);
+ if (R.size() != 1)
continue;
- if (CS.isConditionImplied(R)) {
+
+ // Check if all coefficients of new indices are 0 after building the
+ // constraint. Skip if any of the new indices has a non-null
+ // coefficient.
+ bool HasNewIndex = false;
+ for (unsigned I = 0; I < NewIndices.size(); ++I) {
+ int64_t Last = R[0].Coefficients.pop_back_val();
+ if (Last != 0) {
+ HasNewIndex = true;
+ break;
+ }
+ }
+ if (HasNewIndex || R[0].size() == 1)
+ continue;
+
+ if (CS.isConditionImplied(R[0].Coefficients)) {
if (!DebugCounter::shouldExecute(EliminatedCounter))
continue;
@@ -317,7 +400,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
NumCondsRemoved++;
Changed = true;
}
- if (CS.isConditionImplied(ConstraintSystem::negate(R))) {
+ if (CS.isConditionImplied(
+ ConstraintSystem::negate(R[0].Coefficients))) {
if (!DebugCounter::shouldExecute(EliminatedCounter))
continue;
@@ -336,22 +420,50 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
continue;
}
+ // Set up a function to restore the predicate at the end of the scope if it
+ // has been negated. Negate the predicate in-place, if required.
+ auto *CI = dyn_cast<CmpInst>(CB.Condition);
+ auto PredicateRestorer = make_scope_exit([CI, &CB]() {
+ if (CB.Not && CI)
+ CI->setPredicate(CI->getInversePredicate());
+ });
+ if (CB.Not) {
+ if (CI) {
+ CI->setPredicate(CI->getInversePredicate());
+ } else {
+ LLVM_DEBUG(dbgs() << "Can only negate compares so far.\n");
+ continue;
+ }
+ }
+
// Otherwise, add the condition to the system and stack, if we can transform
// it into a constraint.
- auto R = getConstraint(CB.Condition, Value2Index, true);
+ DenseMap<Value *, unsigned> NewIndices;
+ auto R = getConstraint(CB.Condition, Value2Index, NewIndices);
if (R.empty())
continue;
- LLVM_DEBUG(dbgs() << "Adding " << *CB.Condition << " " << CB.Not << "\n");
- if (CB.Not)
- R = ConstraintSystem::negate(R);
+ for (auto &KV : NewIndices)
+ Value2Index.insert(KV);
- // If R has been added to the system, queue it for removal once it goes
- // out-of-scope.
- if (CS.addVariableRowFill(R))
- DFSInStack.emplace_back(CB.NumIn, CB.NumOut, CB.Condition, CB.Not);
+ LLVM_DEBUG(dbgs() << "Adding " << *CB.Condition << " " << CB.Not << "\n");
+ bool Added = false;
+ for (auto &C : R) {
+ auto Coeffs = C.Coefficients;
+ LLVM_DEBUG({
+ dbgs() << " constraint: ";
+ dumpWithNames(C, Value2Index);
+ });
+ Added |= CS.addVariableRowFill(Coeffs);
+ // If R has been added to the system, queue it for removal once it goes
+ // out-of-scope.
+ if (Added)
+ DFSInStack.emplace_back(CB.NumIn, CB.NumOut, CB.Condition, CB.Not);
+ }
}
+ assert(CS.size() == DFSInStack.size() &&
+ "updates to CS and DFSInStack are out of sync");
return Changed;
}
@@ -363,7 +475,6 @@ PreservedAnalyses ConstraintEliminationPass::run(Function &F,
PreservedAnalyses PA;
PA.preserve<DominatorTreeAnalysis>();
- PA.preserve<GlobalsAA>();
PA.preserveSet<CFGAnalyses>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index b671d68031a8..36cbd42a5fdd 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -19,6 +19,7 @@
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LazyValueInfo.h"
+#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
@@ -82,11 +83,12 @@ STATISTIC(NumMulNUW, "Number of no-unsigned-wrap deductions for mul");
STATISTIC(NumShlNW, "Number of no-wrap deductions for shl");
STATISTIC(NumShlNSW, "Number of no-signed-wrap deductions for shl");
STATISTIC(NumShlNUW, "Number of no-unsigned-wrap deductions for shl");
+STATISTIC(NumAbs, "Number of llvm.abs intrinsics removed");
STATISTIC(NumOverflows, "Number of overflow checks removed");
STATISTIC(NumSaturating,
"Number of saturating arithmetics converted to normal arithmetics");
-
-static cl::opt<bool> DontAddNoWrapFlags("cvp-dont-add-nowrap-flags", cl::init(false));
+STATISTIC(NumNonNull, "Number of function pointer arguments marked non-null");
+STATISTIC(NumMinMax, "Number of llvm.[us]{min,max} intrinsics removed");
namespace {
@@ -192,15 +194,14 @@ static bool simplifyCommonValuePhi(PHINode *P, LazyValueInfo *LVI,
return false;
}
+ // LVI only guarantees that the value matches a certain constant if the value
+ // is not poison. Make sure we don't replace a well-defined value with poison.
+ // This is usually satisfied due to a prior branch on the value.
+ if (!isGuaranteedNotToBePoison(CommonValue, nullptr, P, DT))
+ return false;
+
// All constant incoming values map to the same variable along the incoming
- // edges of the phi. The phi is unnecessary. However, we must drop all
- // poison-generating flags to ensure that no poison is propagated to the phi
- // location by performing this substitution.
- // Warning: If the underlying analysis changes, this may not be enough to
- // guarantee that poison is not propagated.
- // TODO: We may be able to re-infer flags by re-analyzing the instruction.
- if (auto *CommonInst = dyn_cast<Instruction>(CommonValue))
- CommonInst->dropPoisonGeneratingFlags();
+ // edges of the phi. The phi is unnecessary.
P->replaceAllUsesWith(CommonValue);
P->eraseFromParent();
++NumPhiCommon;
@@ -444,8 +445,81 @@ static void setDeducedOverflowingFlags(Value *V, Instruction::BinaryOps Opcode,
static bool processBinOp(BinaryOperator *BinOp, LazyValueInfo *LVI);
+// See if @llvm.abs argument is alays positive/negative, and simplify.
+// Notably, INT_MIN can belong to either range, regardless of the NSW,
+// because it is negation-invariant.
+static bool processAbsIntrinsic(IntrinsicInst *II, LazyValueInfo *LVI) {
+ Value *X = II->getArgOperand(0);
+ bool IsIntMinPoison = cast<ConstantInt>(II->getArgOperand(1))->isOne();
+
+ Type *Ty = X->getType();
+ Constant *IntMin =
+ ConstantInt::get(Ty, APInt::getSignedMinValue(Ty->getScalarSizeInBits()));
+ LazyValueInfo::Tristate Result;
+
+ // Is X in [0, IntMin]? NOTE: INT_MIN is fine!
+ Result = LVI->getPredicateAt(CmpInst::Predicate::ICMP_ULE, X, IntMin, II,
+ /*UseBlockValue=*/true);
+ if (Result == LazyValueInfo::True) {
+ ++NumAbs;
+ II->replaceAllUsesWith(X);
+ II->eraseFromParent();
+ return true;
+ }
+
+ // Is X in [IntMin, 0]? NOTE: INT_MIN is fine!
+ Constant *Zero = ConstantInt::getNullValue(Ty);
+ Result = LVI->getPredicateAt(CmpInst::Predicate::ICMP_SLE, X, Zero, II,
+ /*UseBlockValue=*/true);
+ assert(Result != LazyValueInfo::False && "Should have been handled already.");
+
+ if (Result == LazyValueInfo::Unknown) {
+ // Argument's range crosses zero.
+ bool Changed = false;
+ if (!IsIntMinPoison) {
+ // Can we at least tell that the argument is never INT_MIN?
+ Result = LVI->getPredicateAt(CmpInst::Predicate::ICMP_NE, X, IntMin, II,
+ /*UseBlockValue=*/true);
+ if (Result == LazyValueInfo::True) {
+ ++NumNSW;
+ ++NumSubNSW;
+ II->setArgOperand(1, ConstantInt::getTrue(II->getContext()));
+ Changed = true;
+ }
+ }
+ return Changed;
+ }
+
+ IRBuilder<> B(II);
+ Value *NegX = B.CreateNeg(X, II->getName(), /*HasNUW=*/false,
+ /*HasNSW=*/IsIntMinPoison);
+ ++NumAbs;
+ II->replaceAllUsesWith(NegX);
+ II->eraseFromParent();
+
+ // See if we can infer some no-wrap flags.
+ if (auto *BO = dyn_cast<BinaryOperator>(NegX))
+ processBinOp(BO, LVI);
+
+ return true;
+}
+
+// See if this min/max intrinsic always picks it's one specific operand.
+static bool processMinMaxIntrinsic(MinMaxIntrinsic *MM, LazyValueInfo *LVI) {
+ CmpInst::Predicate Pred = CmpInst::getNonStrictPredicate(MM->getPredicate());
+ LazyValueInfo::Tristate Result = LVI->getPredicateAt(
+ Pred, MM->getLHS(), MM->getRHS(), MM, /*UseBlockValue=*/true);
+ if (Result == LazyValueInfo::Unknown)
+ return false;
+
+ ++NumMinMax;
+ MM->replaceAllUsesWith(MM->getOperand(!Result));
+ MM->eraseFromParent();
+ return true;
+}
+
// Rewrite this with.overflow intrinsic as non-overflowing.
-static void processOverflowIntrinsic(WithOverflowInst *WO, LazyValueInfo *LVI) {
+static bool processOverflowIntrinsic(WithOverflowInst *WO, LazyValueInfo *LVI) {
IRBuilder<> B(WO);
Instruction::BinaryOps Opcode = WO->getBinaryOp();
bool NSW = WO->isSigned();
@@ -467,9 +541,11 @@ static void processOverflowIntrinsic(WithOverflowInst *WO, LazyValueInfo *LVI) {
// See if we can infer the other no-wrap too.
if (auto *BO = dyn_cast<BinaryOperator>(NewOp))
processBinOp(BO, LVI);
+
+ return true;
}
-static void processSaturatingInst(SaturatingInst *SI, LazyValueInfo *LVI) {
+static bool processSaturatingInst(SaturatingInst *SI, LazyValueInfo *LVI) {
Instruction::BinaryOps Opcode = SI->getBinaryOp();
bool NSW = SI->isSigned();
bool NUW = !SI->isSigned();
@@ -485,22 +561,30 @@ static void processSaturatingInst(SaturatingInst *SI, LazyValueInfo *LVI) {
// See if we can infer the other no-wrap too.
if (auto *BO = dyn_cast<BinaryOperator>(BinOp))
processBinOp(BO, LVI);
+
+ return true;
}
/// Infer nonnull attributes for the arguments at the specified callsite.
static bool processCallSite(CallBase &CB, LazyValueInfo *LVI) {
+ if (CB.getIntrinsicID() == Intrinsic::abs) {
+ return processAbsIntrinsic(&cast<IntrinsicInst>(CB), LVI);
+ }
+
+ if (auto *MM = dyn_cast<MinMaxIntrinsic>(&CB)) {
+ return processMinMaxIntrinsic(MM, LVI);
+ }
+
if (auto *WO = dyn_cast<WithOverflowInst>(&CB)) {
if (WO->getLHS()->getType()->isIntegerTy() && willNotOverflow(WO, LVI)) {
- processOverflowIntrinsic(WO, LVI);
- return true;
+ return processOverflowIntrinsic(WO, LVI);
}
}
if (auto *SI = dyn_cast<SaturatingInst>(&CB)) {
if (SI->getType()->isIntegerTy() && willNotOverflow(SI, LVI)) {
- processSaturatingInst(SI, LVI);
- return true;
+ return processSaturatingInst(SI, LVI);
}
}
@@ -538,8 +622,8 @@ static bool processCallSite(CallBase &CB, LazyValueInfo *LVI) {
if (Type && !CB.paramHasAttr(ArgNo, Attribute::NonNull) &&
!isa<Constant>(V) &&
LVI->getPredicateAt(ICmpInst::ICMP_EQ, V,
- ConstantPointerNull::get(Type),
- &CB) == LazyValueInfo::False)
+ ConstantPointerNull::get(Type), &CB,
+ /*UseBlockValue=*/false) == LazyValueInfo::False)
ArgNos.push_back(ArgNo);
ArgNo++;
}
@@ -549,6 +633,7 @@ static bool processCallSite(CallBase &CB, LazyValueInfo *LVI) {
if (ArgNos.empty())
return Changed;
+ NumNonNull += ArgNos.size();
AttributeList AS = CB.getAttributes();
LLVMContext &Ctx = CB.getContext();
AS = AS.addParamAttribute(Ctx, ArgNos,
@@ -560,13 +645,15 @@ static bool processCallSite(CallBase &CB, LazyValueInfo *LVI) {
static bool isNonNegative(Value *V, LazyValueInfo *LVI, Instruction *CxtI) {
Constant *Zero = ConstantInt::get(V->getType(), 0);
- auto Result = LVI->getPredicateAt(ICmpInst::ICMP_SGE, V, Zero, CxtI);
+ auto Result = LVI->getPredicateAt(ICmpInst::ICMP_SGE, V, Zero, CxtI,
+ /*UseBlockValue=*/true);
return Result == LazyValueInfo::True;
}
static bool isNonPositive(Value *V, LazyValueInfo *LVI, Instruction *CxtI) {
Constant *Zero = ConstantInt::get(V->getType(), 0);
- auto Result = LVI->getPredicateAt(ICmpInst::ICMP_SLE, V, Zero, CxtI);
+ auto Result = LVI->getPredicateAt(ICmpInst::ICMP_SLE, V, Zero, CxtI,
+ /*UseBlockValue=*/true);
return Result == LazyValueInfo::True;
}
@@ -843,9 +930,6 @@ static bool processSExt(SExtInst *SDI, LazyValueInfo *LVI) {
static bool processBinOp(BinaryOperator *BinOp, LazyValueInfo *LVI) {
using OBO = OverflowingBinaryOperator;
- if (DontAddNoWrapFlags)
- return false;
-
if (BinOp->getType()->isVectorTy())
return false;
@@ -919,8 +1003,8 @@ static Constant *getConstantAt(Value *V, Instruction *At, LazyValueInfo *LVI) {
Constant *Op1 = dyn_cast<Constant>(C->getOperand(1));
if (!Op1) return nullptr;
- LazyValueInfo::Tristate Result =
- LVI->getPredicateAt(C->getPredicate(), Op0, Op1, At);
+ LazyValueInfo::Tristate Result = LVI->getPredicateAt(
+ C->getPredicate(), Op0, Op1, At, /*UseBlockValue=*/false);
if (Result == LazyValueInfo::Unknown)
return nullptr;
@@ -1034,7 +1118,6 @@ CorrelatedValuePropagationPass::run(Function &F, FunctionAnalysisManager &AM) {
if (!Changed) {
PA = PreservedAnalyses::all();
} else {
- PA.preserve<GlobalsAA>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LazyValueAnalysis>();
}
diff --git a/llvm/lib/Transforms/Scalar/DCE.cpp b/llvm/lib/Transforms/Scalar/DCE.cpp
index d55adf7c2d12..d309799d95f0 100644
--- a/llvm/lib/Transforms/Scalar/DCE.cpp
+++ b/llvm/lib/Transforms/Scalar/DCE.cpp
@@ -125,14 +125,11 @@ static bool eliminateDeadCode(Function &F, TargetLibraryInfo *TLI) {
// Iterate over the original function, only adding insts to the worklist
// if they actually need to be revisited. This avoids having to pre-init
// the worklist with the entire function's worth of instructions.
- for (inst_iterator FI = inst_begin(F), FE = inst_end(F); FI != FE;) {
- Instruction *I = &*FI;
- ++FI;
-
+ for (Instruction &I : llvm::make_early_inc_range(instructions(F))) {
// We're visiting this instruction now, so make sure it's not in the
// worklist from an earlier visit.
- if (!WorkList.count(I))
- MadeChange |= DCEInstruction(I, WorkList, TLI);
+ if (!WorkList.count(&I))
+ MadeChange |= DCEInstruction(&I, WorkList, TLI);
}
while (!WorkList.empty()) {
diff --git a/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp b/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
new file mode 100644
index 000000000000..90679bcac4b7
--- /dev/null
+++ b/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
@@ -0,0 +1,1286 @@
+//===- DFAJumpThreading.cpp - Threads a switch statement inside a loop ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Transform each threading path to effectively jump thread the DFA. For
+// example, the CFG below could be transformed as follows, where the cloned
+// blocks unconditionally branch to the next correct case based on what is
+// identified in the analysis.
+//
+// sw.bb sw.bb
+// / | \ / | \
+// case1 case2 case3 case1 case2 case3
+// \ | / | | |
+// determinator det.2 det.3 det.1
+// br sw.bb / | \
+// sw.bb.2 sw.bb.3 sw.bb.1
+// br case2 br case3 br case1§
+//
+// Definitions and Terminology:
+//
+// * Threading path:
+// a list of basic blocks, the exit state, and the block that determines
+// the next state, for which the following notation will be used:
+// < path of BBs that form a cycle > [ state, determinator ]
+//
+// * Predictable switch:
+// The switch variable is always a known constant so that all conditional
+// jumps based on switch variable can be converted to unconditional jump.
+//
+// * Determinator:
+// The basic block that determines the next state of the DFA.
+//
+// Representing the optimization in C-like pseudocode: the code pattern on the
+// left could functionally be transformed to the right pattern if the switch
+// condition is predictable.
+//
+// X = A goto A
+// for (...) A:
+// switch (X) ...
+// case A goto B
+// X = B B:
+// case B ...
+// X = C goto C
+//
+// The pass first checks that switch variable X is decided by the control flow
+// path taken in the loop; for example, in case B, the next value of X is
+// decided to be C. It then enumerates through all paths in the loop and labels
+// the basic blocks where the next state is decided.
+//
+// Using this information it creates new paths that unconditionally branch to
+// the next case. This involves cloning code, so it only gets triggered if the
+// amount of code duplicated is below a threshold.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/DFAJumpThreading.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/AssumptionCache.h"
+#include "llvm/Analysis/CodeMetrics.h"
+#include "llvm/Analysis/LoopIterator.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/Transforms/Utils/SSAUpdaterBulk.h"
+#include "llvm/Transforms/Utils/ValueMapper.h"
+#include <algorithm>
+#include <deque>
+#include <unordered_map>
+#include <unordered_set>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "dfa-jump-threading"
+
+STATISTIC(NumTransforms, "Number of transformations done");
+STATISTIC(NumCloned, "Number of blocks cloned");
+STATISTIC(NumPaths, "Number of individual paths threaded");
+
+static cl::opt<bool>
+ ClViewCfgBefore("dfa-jump-view-cfg-before",
+ cl::desc("View the CFG before DFA Jump Threading"),
+ cl::Hidden, cl::init(false));
+
+static cl::opt<unsigned> MaxPathLength(
+ "dfa-max-path-length",
+ cl::desc("Max number of blocks searched to find a threading path"),
+ cl::Hidden, cl::init(20));
+
+static cl::opt<unsigned>
+ CostThreshold("dfa-cost-threshold",
+ cl::desc("Maximum cost accepted for the transformation"),
+ cl::Hidden, cl::init(50));
+
+namespace {
+
+class SelectInstToUnfold {
+ SelectInst *SI;
+ PHINode *SIUse;
+
+public:
+ SelectInstToUnfold(SelectInst *SI, PHINode *SIUse) : SI(SI), SIUse(SIUse) {}
+
+ SelectInst *getInst() { return SI; }
+ PHINode *getUse() { return SIUse; }
+
+ explicit operator bool() const { return SI && SIUse; }
+};
+
+void unfold(DomTreeUpdater *DTU, SelectInstToUnfold SIToUnfold,
+ std::vector<SelectInstToUnfold> *NewSIsToUnfold,
+ std::vector<BasicBlock *> *NewBBs);
+
+class DFAJumpThreading {
+public:
+ DFAJumpThreading(AssumptionCache *AC, DominatorTree *DT,
+ TargetTransformInfo *TTI, OptimizationRemarkEmitter *ORE)
+ : AC(AC), DT(DT), TTI(TTI), ORE(ORE) {}
+
+ bool run(Function &F);
+
+private:
+ void
+ unfoldSelectInstrs(DominatorTree *DT,
+ const SmallVector<SelectInstToUnfold, 4> &SelectInsts) {
+ DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
+ SmallVector<SelectInstToUnfold, 4> Stack;
+ for (SelectInstToUnfold SIToUnfold : SelectInsts)
+ Stack.push_back(SIToUnfold);
+
+ while (!Stack.empty()) {
+ SelectInstToUnfold SIToUnfold = Stack.back();
+ Stack.pop_back();
+
+ std::vector<SelectInstToUnfold> NewSIsToUnfold;
+ std::vector<BasicBlock *> NewBBs;
+ unfold(&DTU, SIToUnfold, &NewSIsToUnfold, &NewBBs);
+
+ // Put newly discovered select instructions into the work list.
+ for (const SelectInstToUnfold &NewSIToUnfold : NewSIsToUnfold)
+ Stack.push_back(NewSIToUnfold);
+ }
+ }
+
+ AssumptionCache *AC;
+ DominatorTree *DT;
+ TargetTransformInfo *TTI;
+ OptimizationRemarkEmitter *ORE;
+};
+
+class DFAJumpThreadingLegacyPass : public FunctionPass {
+public:
+ static char ID; // Pass identification
+ DFAJumpThreadingLegacyPass() : FunctionPass(ID) {}
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addRequired<AssumptionCacheTracker>();
+ AU.addRequired<DominatorTreeWrapperPass>();
+ AU.addRequired<TargetTransformInfoWrapperPass>();
+ AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
+ }
+
+ bool runOnFunction(Function &F) override {
+ if (skipFunction(F))
+ return false;
+
+ AssumptionCache *AC =
+ &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
+ DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+ TargetTransformInfo *TTI =
+ &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
+ OptimizationRemarkEmitter *ORE =
+ &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
+
+ return DFAJumpThreading(AC, DT, TTI, ORE).run(F);
+ }
+};
+} // end anonymous namespace
+
+char DFAJumpThreadingLegacyPass::ID = 0;
+INITIALIZE_PASS_BEGIN(DFAJumpThreadingLegacyPass, "dfa-jump-threading",
+ "DFA Jump Threading", false, false)
+INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass)
+INITIALIZE_PASS_END(DFAJumpThreadingLegacyPass, "dfa-jump-threading",
+ "DFA Jump Threading", false, false)
+
+// Public interface to the DFA Jump Threading pass
+FunctionPass *llvm::createDFAJumpThreadingPass() {
+ return new DFAJumpThreadingLegacyPass();
+}
+
+namespace {
+
+/// Create a new basic block and sink \p SIToSink into it.
+void createBasicBlockAndSinkSelectInst(
+ DomTreeUpdater *DTU, SelectInst *SI, PHINode *SIUse, SelectInst *SIToSink,
+ BasicBlock *EndBlock, StringRef NewBBName, BasicBlock **NewBlock,
+ BranchInst **NewBranch, std::vector<SelectInstToUnfold> *NewSIsToUnfold,
+ std::vector<BasicBlock *> *NewBBs) {
+ assert(SIToSink->hasOneUse());
+ assert(NewBlock);
+ assert(NewBranch);
+ *NewBlock = BasicBlock::Create(SI->getContext(), NewBBName,
+ EndBlock->getParent(), EndBlock);
+ NewBBs->push_back(*NewBlock);
+ *NewBranch = BranchInst::Create(EndBlock, *NewBlock);
+ SIToSink->moveBefore(*NewBranch);
+ NewSIsToUnfold->push_back(SelectInstToUnfold(SIToSink, SIUse));
+ DTU->applyUpdates({{DominatorTree::Insert, *NewBlock, EndBlock}});
+}
+
+/// Unfold the select instruction held in \p SIToUnfold by replacing it with
+/// control flow.
+///
+/// Put newly discovered select instructions into \p NewSIsToUnfold. Put newly
+/// created basic blocks into \p NewBBs.
+///
+/// TODO: merge it with CodeGenPrepare::optimizeSelectInst() if possible.
+void unfold(DomTreeUpdater *DTU, SelectInstToUnfold SIToUnfold,
+ std::vector<SelectInstToUnfold> *NewSIsToUnfold,
+ std::vector<BasicBlock *> *NewBBs) {
+ SelectInst *SI = SIToUnfold.getInst();
+ PHINode *SIUse = SIToUnfold.getUse();
+ BasicBlock *StartBlock = SI->getParent();
+ BasicBlock *EndBlock = SIUse->getParent();
+ BranchInst *StartBlockTerm =
+ dyn_cast<BranchInst>(StartBlock->getTerminator());
+
+ assert(StartBlockTerm && StartBlockTerm->isUnconditional());
+ assert(SI->hasOneUse());
+
+ // These are the new basic blocks for the conditional branch.
+ // At least one will become an actual new basic block.
+ BasicBlock *TrueBlock = nullptr;
+ BasicBlock *FalseBlock = nullptr;
+ BranchInst *TrueBranch = nullptr;
+ BranchInst *FalseBranch = nullptr;
+
+ // Sink select instructions to be able to unfold them later.
+ if (SelectInst *SIOp = dyn_cast<SelectInst>(SI->getTrueValue())) {
+ createBasicBlockAndSinkSelectInst(DTU, SI, SIUse, SIOp, EndBlock,
+ "si.unfold.true", &TrueBlock, &TrueBranch,
+ NewSIsToUnfold, NewBBs);
+ }
+ if (SelectInst *SIOp = dyn_cast<SelectInst>(SI->getFalseValue())) {
+ createBasicBlockAndSinkSelectInst(DTU, SI, SIUse, SIOp, EndBlock,
+ "si.unfold.false", &FalseBlock,
+ &FalseBranch, NewSIsToUnfold, NewBBs);
+ }
+
+ // If there was nothing to sink, then arbitrarily choose the 'false' side
+ // for a new input value to the PHI.
+ if (!TrueBlock && !FalseBlock) {
+ FalseBlock = BasicBlock::Create(SI->getContext(), "si.unfold.false",
+ EndBlock->getParent(), EndBlock);
+ NewBBs->push_back(FalseBlock);
+ BranchInst::Create(EndBlock, FalseBlock);
+ DTU->applyUpdates({{DominatorTree::Insert, FalseBlock, EndBlock}});
+ }
+
+ // Insert the real conditional branch based on the original condition.
+ // If we did not create a new block for one of the 'true' or 'false' paths
+ // of the condition, it means that side of the branch goes to the end block
+ // directly and the path originates from the start block from the point of
+ // view of the new PHI.
+ BasicBlock *TT = EndBlock;
+ BasicBlock *FT = EndBlock;
+ if (TrueBlock && FalseBlock) {
+ // A diamond.
+ TT = TrueBlock;
+ FT = FalseBlock;
+
+ // Update the phi node of SI.
+ SIUse->removeIncomingValue(StartBlock, /* DeletePHIIfEmpty = */ false);
+ SIUse->addIncoming(SI->getTrueValue(), TrueBlock);
+ SIUse->addIncoming(SI->getFalseValue(), FalseBlock);
+
+ // Update any other PHI nodes in EndBlock.
+ for (PHINode &Phi : EndBlock->phis()) {
+ if (&Phi != SIUse) {
+ Phi.addIncoming(Phi.getIncomingValueForBlock(StartBlock), TrueBlock);
+ Phi.addIncoming(Phi.getIncomingValueForBlock(StartBlock), FalseBlock);
+ }
+ }
+ } else {
+ BasicBlock *NewBlock = nullptr;
+ Value *SIOp1 = SI->getTrueValue();
+ Value *SIOp2 = SI->getFalseValue();
+
+ // A triangle pointing right.
+ if (!TrueBlock) {
+ NewBlock = FalseBlock;
+ FT = FalseBlock;
+ }
+ // A triangle pointing left.
+ else {
+ NewBlock = TrueBlock;
+ TT = TrueBlock;
+ std::swap(SIOp1, SIOp2);
+ }
+
+ // Update the phi node of SI.
+ for (unsigned Idx = 0; Idx < SIUse->getNumIncomingValues(); ++Idx) {
+ if (SIUse->getIncomingBlock(Idx) == StartBlock)
+ SIUse->setIncomingValue(Idx, SIOp1);
+ }
+ SIUse->addIncoming(SIOp2, NewBlock);
+
+ // Update any other PHI nodes in EndBlock.
+ for (auto II = EndBlock->begin(); PHINode *Phi = dyn_cast<PHINode>(II);
+ ++II) {
+ if (Phi != SIUse)
+ Phi->addIncoming(Phi->getIncomingValueForBlock(StartBlock), NewBlock);
+ }
+ }
+ StartBlockTerm->eraseFromParent();
+ BranchInst::Create(TT, FT, SI->getCondition(), StartBlock);
+ DTU->applyUpdates({{DominatorTree::Insert, StartBlock, TT},
+ {DominatorTree::Insert, StartBlock, FT}});
+
+ // The select is now dead.
+ SI->eraseFromParent();
+}
+
+struct ClonedBlock {
+ BasicBlock *BB;
+ uint64_t State; ///< \p State corresponds to the next value of a switch stmnt.
+};
+
+typedef std::deque<BasicBlock *> PathType;
+typedef std::vector<PathType> PathsType;
+typedef std::set<const BasicBlock *> VisitedBlocks;
+typedef std::vector<ClonedBlock> CloneList;
+
+// This data structure keeps track of all blocks that have been cloned. If two
+// different ThreadingPaths clone the same block for a certain state it should
+// be reused, and it can be looked up in this map.
+typedef DenseMap<BasicBlock *, CloneList> DuplicateBlockMap;
+
+// This map keeps track of all the new definitions for an instruction. This
+// information is needed when restoring SSA form after cloning blocks.
+typedef DenseMap<Instruction *, std::vector<Instruction *>> DefMap;
+
+inline raw_ostream &operator<<(raw_ostream &OS, const PathType &Path) {
+ OS << "< ";
+ for (const BasicBlock *BB : Path) {
+ std::string BBName;
+ if (BB->hasName())
+ raw_string_ostream(BBName) << BB->getName();
+ else
+ raw_string_ostream(BBName) << BB;
+ OS << BBName << " ";
+ }
+ OS << ">";
+ return OS;
+}
+
+/// ThreadingPath is a path in the control flow of a loop that can be threaded
+/// by cloning necessary basic blocks and replacing conditional branches with
+/// unconditional ones. A threading path includes a list of basic blocks, the
+/// exit state, and the block that determines the next state.
+struct ThreadingPath {
+ /// Exit value is DFA's exit state for the given path.
+ uint64_t getExitValue() const { return ExitVal; }
+ void setExitValue(const ConstantInt *V) {
+ ExitVal = V->getZExtValue();
+ IsExitValSet = true;
+ }
+ bool isExitValueSet() const { return IsExitValSet; }
+
+ /// Determinator is the basic block that determines the next state of the DFA.
+ const BasicBlock *getDeterminatorBB() const { return DBB; }
+ void setDeterminator(const BasicBlock *BB) { DBB = BB; }
+
+ /// Path is a list of basic blocks.
+ const PathType &getPath() const { return Path; }
+ void setPath(const PathType &NewPath) { Path = NewPath; }
+
+ void print(raw_ostream &OS) const {
+ OS << Path << " [ " << ExitVal << ", " << DBB->getName() << " ]";
+ }
+
+private:
+ PathType Path;
+ uint64_t ExitVal;
+ const BasicBlock *DBB = nullptr;
+ bool IsExitValSet = false;
+};
+
+#ifndef NDEBUG
+inline raw_ostream &operator<<(raw_ostream &OS, const ThreadingPath &TPath) {
+ TPath.print(OS);
+ return OS;
+}
+#endif
+
+struct MainSwitch {
+ MainSwitch(SwitchInst *SI, OptimizationRemarkEmitter *ORE) {
+ if (isPredictable(SI)) {
+ Instr = SI;
+ } else {
+ ORE->emit([&]() {
+ return OptimizationRemarkMissed(DEBUG_TYPE, "SwitchNotPredictable", SI)
+ << "Switch instruction is not predictable.";
+ });
+ }
+ }
+
+ virtual ~MainSwitch() = default;
+
+ SwitchInst *getInstr() const { return Instr; }
+ const SmallVector<SelectInstToUnfold, 4> getSelectInsts() {
+ return SelectInsts;
+ }
+
+private:
+ /// Do a use-def chain traversal. Make sure the value of the switch variable
+ /// is always a known constant. This means that all conditional jumps based on
+ /// switch variable can be converted to unconditional jumps.
+ bool isPredictable(const SwitchInst *SI) {
+ std::deque<Instruction *> Q;
+ SmallSet<Value *, 16> SeenValues;
+ SelectInsts.clear();
+
+ Value *FirstDef = SI->getOperand(0);
+ auto *Inst = dyn_cast<Instruction>(FirstDef);
+
+ // If this is a function argument or another non-instruction, then give up.
+ // We are interested in loop local variables.
+ if (!Inst)
+ return false;
+
+ // Require the first definition to be a PHINode
+ if (!isa<PHINode>(Inst))
+ return false;
+
+ LLVM_DEBUG(dbgs() << "\tisPredictable() FirstDef: " << *Inst << "\n");
+
+ Q.push_back(Inst);
+ SeenValues.insert(FirstDef);
+
+ while (!Q.empty()) {
+ Instruction *Current = Q.front();
+ Q.pop_front();
+
+ if (auto *Phi = dyn_cast<PHINode>(Current)) {
+ for (Value *Incoming : Phi->incoming_values()) {
+ if (!isPredictableValue(Incoming, SeenValues))
+ return false;
+ addInstToQueue(Incoming, Q, SeenValues);
+ }
+ LLVM_DEBUG(dbgs() << "\tisPredictable() phi: " << *Phi << "\n");
+ } else if (SelectInst *SelI = dyn_cast<SelectInst>(Current)) {
+ if (!isValidSelectInst(SelI))
+ return false;
+ if (!isPredictableValue(SelI->getTrueValue(), SeenValues) ||
+ !isPredictableValue(SelI->getFalseValue(), SeenValues)) {
+ return false;
+ }
+ addInstToQueue(SelI->getTrueValue(), Q, SeenValues);
+ addInstToQueue(SelI->getFalseValue(), Q, SeenValues);
+ LLVM_DEBUG(dbgs() << "\tisPredictable() select: " << *SelI << "\n");
+ if (auto *SelIUse = dyn_cast<PHINode>(SelI->user_back()))
+ SelectInsts.push_back(SelectInstToUnfold(SelI, SelIUse));
+ } else {
+ // If it is neither a phi nor a select, then we give up.
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool isPredictableValue(Value *InpVal, SmallSet<Value *, 16> &SeenValues) {
+ if (SeenValues.find(InpVal) != SeenValues.end())
+ return true;
+
+ if (isa<ConstantInt>(InpVal))
+ return true;
+
+ // If this is a function argument or another non-instruction, then give up.
+ if (!isa<Instruction>(InpVal))
+ return false;
+
+ return true;
+ }
+
+ void addInstToQueue(Value *Val, std::deque<Instruction *> &Q,
+ SmallSet<Value *, 16> &SeenValues) {
+ if (SeenValues.find(Val) != SeenValues.end())
+ return;
+ if (Instruction *I = dyn_cast<Instruction>(Val))
+ Q.push_back(I);
+ SeenValues.insert(Val);
+ }
+
+ bool isValidSelectInst(SelectInst *SI) {
+ if (!SI->hasOneUse())
+ return false;
+
+ Instruction *SIUse = dyn_cast<Instruction>(SI->user_back());
+ // The use of the select inst should be either a phi or another select.
+ if (!SIUse && !(isa<PHINode>(SIUse) || isa<SelectInst>(SIUse)))
+ return false;
+
+ BasicBlock *SIBB = SI->getParent();
+
+ // Currently, we can only expand select instructions in basic blocks with
+ // one successor.
+ BranchInst *SITerm = dyn_cast<BranchInst>(SIBB->getTerminator());
+ if (!SITerm || !SITerm->isUnconditional())
+ return false;
+
+ if (isa<PHINode>(SIUse) &&
+ SIBB->getSingleSuccessor() != dyn_cast<Instruction>(SIUse)->getParent())
+ return false;
+
+ // If select will not be sunk during unfolding, and it is in the same basic
+ // block as another state defining select, then cannot unfold both.
+ for (SelectInstToUnfold SIToUnfold : SelectInsts) {
+ SelectInst *PrevSI = SIToUnfold.getInst();
+ if (PrevSI->getTrueValue() != SI && PrevSI->getFalseValue() != SI &&
+ PrevSI->getParent() == SI->getParent())
+ return false;
+ }
+
+ return true;
+ }
+
+ SwitchInst *Instr = nullptr;
+ SmallVector<SelectInstToUnfold, 4> SelectInsts;
+};
+
+struct AllSwitchPaths {
+ AllSwitchPaths(const MainSwitch *MSwitch, OptimizationRemarkEmitter *ORE)
+ : Switch(MSwitch->getInstr()), SwitchBlock(Switch->getParent()),
+ ORE(ORE) {}
+
+ std::vector<ThreadingPath> &getThreadingPaths() { return TPaths; }
+ unsigned getNumThreadingPaths() { return TPaths.size(); }
+ SwitchInst *getSwitchInst() { return Switch; }
+ BasicBlock *getSwitchBlock() { return SwitchBlock; }
+
+ void run() {
+ VisitedBlocks Visited;
+ PathsType LoopPaths = paths(SwitchBlock, Visited, /* PathDepth = */ 1);
+ StateDefMap StateDef = getStateDefMap();
+
+ for (PathType Path : LoopPaths) {
+ ThreadingPath TPath;
+
+ const BasicBlock *PrevBB = Path.back();
+ for (const BasicBlock *BB : Path) {
+ if (StateDef.count(BB) != 0) {
+ const PHINode *Phi = dyn_cast<PHINode>(StateDef[BB]);
+ assert(Phi && "Expected a state-defining instr to be a phi node.");
+
+ const Value *V = Phi->getIncomingValueForBlock(PrevBB);
+ if (const ConstantInt *C = dyn_cast<const ConstantInt>(V)) {
+ TPath.setExitValue(C);
+ TPath.setDeterminator(BB);
+ TPath.setPath(Path);
+ }
+ }
+
+ // Switch block is the determinator, this is the final exit value.
+ if (TPath.isExitValueSet() && BB == Path.front())
+ break;
+
+ PrevBB = BB;
+ }
+
+ if (TPath.isExitValueSet())
+ TPaths.push_back(TPath);
+ }
+ }
+
+private:
+ // Value: an instruction that defines a switch state;
+ // Key: the parent basic block of that instruction.
+ typedef DenseMap<const BasicBlock *, const PHINode *> StateDefMap;
+
+ PathsType paths(BasicBlock *BB, VisitedBlocks &Visited,
+ unsigned PathDepth) const {
+ PathsType Res;
+
+ // Stop exploring paths after visiting MaxPathLength blocks
+ if (PathDepth > MaxPathLength) {
+ ORE->emit([&]() {
+ return OptimizationRemarkAnalysis(DEBUG_TYPE, "MaxPathLengthReached",
+ Switch)
+ << "Exploration stopped after visiting MaxPathLength="
+ << ore::NV("MaxPathLength", MaxPathLength) << " blocks.";
+ });
+ return Res;
+ }
+
+ Visited.insert(BB);
+
+ // Some blocks have multiple edges to the same successor, and this set
+ // is used to prevent a duplicate path from being generated
+ SmallSet<BasicBlock *, 4> Successors;
+
+ for (succ_iterator SI = succ_begin(BB), E = succ_end(BB); SI != E; ++SI) {
+ BasicBlock *Succ = *SI;
+
+ if (Successors.find(Succ) != Successors.end())
+ continue;
+ Successors.insert(Succ);
+
+ // Found a cycle through the SwitchBlock
+ if (Succ == SwitchBlock) {
+ Res.push_back({BB});
+ continue;
+ }
+
+ // We have encountered a cycle, do not get caught in it
+ if (Visited.find(Succ) != Visited.end())
+ continue;
+
+ PathsType SuccPaths = paths(Succ, Visited, PathDepth + 1);
+ for (PathType Path : SuccPaths) {
+ PathType NewPath(Path);
+ NewPath.push_front(BB);
+ Res.push_back(NewPath);
+ }
+ }
+ // This block could now be visited again from a different predecessor. Note
+ // that this will result in exponential runtime. Subpaths could possibly be
+ // cached but it takes a lot of memory to store them.
+ Visited.erase(BB);
+ return Res;
+ }
+
+ /// Walk the use-def chain and collect all the state-defining instructions.
+ StateDefMap getStateDefMap() const {
+ StateDefMap Res;
+
+ Value *FirstDef = Switch->getOperand(0);
+
+ assert(isa<PHINode>(FirstDef) && "After select unfolding, all state "
+ "definitions are expected to be phi "
+ "nodes.");
+
+ SmallVector<PHINode *, 8> Stack;
+ Stack.push_back(dyn_cast<PHINode>(FirstDef));
+ SmallSet<Value *, 16> SeenValues;
+
+ while (!Stack.empty()) {
+ PHINode *CurPhi = Stack.back();
+ Stack.pop_back();
+
+ Res[CurPhi->getParent()] = CurPhi;
+ SeenValues.insert(CurPhi);
+
+ for (Value *Incoming : CurPhi->incoming_values()) {
+ if (Incoming == FirstDef || isa<ConstantInt>(Incoming) ||
+ SeenValues.find(Incoming) != SeenValues.end()) {
+ continue;
+ }
+
+ assert(isa<PHINode>(Incoming) && "After select unfolding, all state "
+ "definitions are expected to be phi "
+ "nodes.");
+
+ Stack.push_back(cast<PHINode>(Incoming));
+ }
+ }
+
+ return Res;
+ }
+
+ SwitchInst *Switch;
+ BasicBlock *SwitchBlock;
+ OptimizationRemarkEmitter *ORE;
+ std::vector<ThreadingPath> TPaths;
+};
+
+struct TransformDFA {
+ TransformDFA(AllSwitchPaths *SwitchPaths, DominatorTree *DT,
+ AssumptionCache *AC, TargetTransformInfo *TTI,
+ OptimizationRemarkEmitter *ORE,
+ SmallPtrSet<const Value *, 32> EphValues)
+ : SwitchPaths(SwitchPaths), DT(DT), AC(AC), TTI(TTI), ORE(ORE),
+ EphValues(EphValues) {}
+
+ void run() {
+ if (isLegalAndProfitableToTransform()) {
+ createAllExitPaths();
+ NumTransforms++;
+ }
+ }
+
+private:
+ /// This function performs both a legality check and profitability check at
+ /// the same time since it is convenient to do so. It iterates through all
+ /// blocks that will be cloned, and keeps track of the duplication cost. It
+ /// also returns false if it is illegal to clone some required block.
+ bool isLegalAndProfitableToTransform() {
+ CodeMetrics Metrics;
+ SwitchInst *Switch = SwitchPaths->getSwitchInst();
+
+ // Note that DuplicateBlockMap is not being used as intended here. It is
+ // just being used to ensure (BB, State) pairs are only counted once.
+ DuplicateBlockMap DuplicateMap;
+
+ for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) {
+ PathType PathBBs = TPath.getPath();
+ uint64_t NextState = TPath.getExitValue();
+ const BasicBlock *Determinator = TPath.getDeterminatorBB();
+
+ // Update Metrics for the Switch block, this is always cloned
+ BasicBlock *BB = SwitchPaths->getSwitchBlock();
+ BasicBlock *VisitedBB = getClonedBB(BB, NextState, DuplicateMap);
+ if (!VisitedBB) {
+ Metrics.analyzeBasicBlock(BB, *TTI, EphValues);
+ DuplicateMap[BB].push_back({BB, NextState});
+ }
+
+ // If the Switch block is the Determinator, then we can continue since
+ // this is the only block that is cloned and we already counted for it.
+ if (PathBBs.front() == Determinator)
+ continue;
+
+ // Otherwise update Metrics for all blocks that will be cloned. If any
+ // block is already cloned and would be reused, don't double count it.
+ auto DetIt = std::find(PathBBs.begin(), PathBBs.end(), Determinator);
+ for (auto BBIt = DetIt; BBIt != PathBBs.end(); BBIt++) {
+ BB = *BBIt;
+ VisitedBB = getClonedBB(BB, NextState, DuplicateMap);
+ if (VisitedBB)
+ continue;
+ Metrics.analyzeBasicBlock(BB, *TTI, EphValues);
+ DuplicateMap[BB].push_back({BB, NextState});
+ }
+
+ if (Metrics.notDuplicatable) {
+ LLVM_DEBUG(dbgs() << "DFA Jump Threading: Not jump threading, contains "
+ << "non-duplicatable instructions.\n");
+ ORE->emit([&]() {
+ return OptimizationRemarkMissed(DEBUG_TYPE, "NonDuplicatableInst",
+ Switch)
+ << "Contains non-duplicatable instructions.";
+ });
+ return false;
+ }
+
+ if (Metrics.convergent) {
+ LLVM_DEBUG(dbgs() << "DFA Jump Threading: Not jump threading, contains "
+ << "convergent instructions.\n");
+ ORE->emit([&]() {
+ return OptimizationRemarkMissed(DEBUG_TYPE, "ConvergentInst", Switch)
+ << "Contains convergent instructions.";
+ });
+ return false;
+ }
+ }
+
+ unsigned DuplicationCost = 0;
+
+ unsigned JumpTableSize = 0;
+ TTI->getEstimatedNumberOfCaseClusters(*Switch, JumpTableSize, nullptr,
+ nullptr);
+ if (JumpTableSize == 0) {
+ // Factor in the number of conditional branches reduced from jump
+ // threading. Assume that lowering the switch block is implemented by
+ // using binary search, hence the LogBase2().
+ unsigned CondBranches =
+ APInt(32, Switch->getNumSuccessors()).ceilLogBase2();
+ DuplicationCost = Metrics.NumInsts / CondBranches;
+ } else {
+ // Compared with jump tables, the DFA optimizer removes an indirect branch
+ // on each loop iteration, thus making branch prediction more precise. The
+ // more branch targets there are, the more likely it is for the branch
+ // predictor to make a mistake, and the more benefit there is in the DFA
+ // optimizer. Thus, the more branch targets there are, the lower is the
+ // cost of the DFA opt.
+ DuplicationCost = Metrics.NumInsts / JumpTableSize;
+ }
+
+ LLVM_DEBUG(dbgs() << "\nDFA Jump Threading: Cost to jump thread block "
+ << SwitchPaths->getSwitchBlock()->getName()
+ << " is: " << DuplicationCost << "\n\n");
+
+ if (DuplicationCost > CostThreshold) {
+ LLVM_DEBUG(dbgs() << "Not jump threading, duplication cost exceeds the "
+ << "cost threshold.\n");
+ ORE->emit([&]() {
+ return OptimizationRemarkMissed(DEBUG_TYPE, "NotProfitable", Switch)
+ << "Duplication cost exceeds the cost threshold (cost="
+ << ore::NV("Cost", DuplicationCost)
+ << ", threshold=" << ore::NV("Threshold", CostThreshold) << ").";
+ });
+ return false;
+ }
+
+ ORE->emit([&]() {
+ return OptimizationRemark(DEBUG_TYPE, "JumpThreaded", Switch)
+ << "Switch statement jump-threaded.";
+ });
+
+ return true;
+ }
+
+ /// Transform each threading path to effectively jump thread the DFA.
+ void createAllExitPaths() {
+ DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Eager);
+
+ // Move the switch block to the end of the path, since it will be duplicated
+ BasicBlock *SwitchBlock = SwitchPaths->getSwitchBlock();
+ for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) {
+ LLVM_DEBUG(dbgs() << TPath << "\n");
+ PathType NewPath(TPath.getPath());
+ NewPath.push_back(SwitchBlock);
+ TPath.setPath(NewPath);
+ }
+
+ // Transform the ThreadingPaths and keep track of the cloned values
+ DuplicateBlockMap DuplicateMap;
+ DefMap NewDefs;
+
+ SmallSet<BasicBlock *, 16> BlocksToClean;
+ for (BasicBlock *BB : successors(SwitchBlock))
+ BlocksToClean.insert(BB);
+
+ for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths()) {
+ createExitPath(NewDefs, TPath, DuplicateMap, BlocksToClean, &DTU);
+ NumPaths++;
+ }
+
+ // After all paths are cloned, now update the last successor of the cloned
+ // path so it skips over the switch statement
+ for (ThreadingPath &TPath : SwitchPaths->getThreadingPaths())
+ updateLastSuccessor(TPath, DuplicateMap, &DTU);
+
+ // For each instruction that was cloned and used outside, update its uses
+ updateSSA(NewDefs);
+
+ // Clean PHI Nodes for the newly created blocks
+ for (BasicBlock *BB : BlocksToClean)
+ cleanPhiNodes(BB);
+ }
+
+ /// For a specific ThreadingPath \p Path, create an exit path starting from
+ /// the determinator block.
+ ///
+ /// To remember the correct destination, we have to duplicate blocks
+ /// corresponding to each state. Also update the terminating instruction of
+ /// the predecessors, and phis in the successor blocks.
+ void createExitPath(DefMap &NewDefs, ThreadingPath &Path,
+ DuplicateBlockMap &DuplicateMap,
+ SmallSet<BasicBlock *, 16> &BlocksToClean,
+ DomTreeUpdater *DTU) {
+ uint64_t NextState = Path.getExitValue();
+ const BasicBlock *Determinator = Path.getDeterminatorBB();
+ PathType PathBBs = Path.getPath();
+
+ // Don't select the placeholder block in front
+ if (PathBBs.front() == Determinator)
+ PathBBs.pop_front();
+
+ auto DetIt = std::find(PathBBs.begin(), PathBBs.end(), Determinator);
+ auto Prev = std::prev(DetIt);
+ BasicBlock *PrevBB = *Prev;
+ for (auto BBIt = DetIt; BBIt != PathBBs.end(); BBIt++) {
+ BasicBlock *BB = *BBIt;
+ BlocksToClean.insert(BB);
+
+ // We already cloned BB for this NextState, now just update the branch
+ // and continue.
+ BasicBlock *NextBB = getClonedBB(BB, NextState, DuplicateMap);
+ if (NextBB) {
+ updatePredecessor(PrevBB, BB, NextBB, DTU);
+ PrevBB = NextBB;
+ continue;
+ }
+
+ // Clone the BB and update the successor of Prev to jump to the new block
+ BasicBlock *NewBB = cloneBlockAndUpdatePredecessor(
+ BB, PrevBB, NextState, DuplicateMap, NewDefs, DTU);
+ DuplicateMap[BB].push_back({NewBB, NextState});
+ BlocksToClean.insert(NewBB);
+ PrevBB = NewBB;
+ }
+ }
+
+ /// Restore SSA form after cloning blocks.
+ ///
+ /// Each cloned block creates new defs for a variable, and the uses need to be
+ /// updated to reflect this. The uses may be replaced with a cloned value, or
+ /// some derived phi instruction. Note that all uses of a value defined in the
+ /// same block were already remapped when cloning the block.
+ void updateSSA(DefMap &NewDefs) {
+ SSAUpdaterBulk SSAUpdate;
+ SmallVector<Use *, 16> UsesToRename;
+
+ for (auto KV : NewDefs) {
+ Instruction *I = KV.first;
+ BasicBlock *BB = I->getParent();
+ std::vector<Instruction *> Cloned = KV.second;
+
+ // Scan all uses of this instruction to see if it is used outside of its
+ // block, and if so, record them in UsesToRename.
+ for (Use &U : I->uses()) {
+ Instruction *User = cast<Instruction>(U.getUser());
+ if (PHINode *UserPN = dyn_cast<PHINode>(User)) {
+ if (UserPN->getIncomingBlock(U) == BB)
+ continue;
+ } else if (User->getParent() == BB) {
+ continue;
+ }
+
+ UsesToRename.push_back(&U);
+ }
+
+ // If there are no uses outside the block, we're done with this
+ // instruction.
+ if (UsesToRename.empty())
+ continue;
+ LLVM_DEBUG(dbgs() << "DFA-JT: Renaming non-local uses of: " << *I
+ << "\n");
+
+ // We found a use of I outside of BB. Rename all uses of I that are
+ // outside its block to be uses of the appropriate PHI node etc. See
+ // ValuesInBlocks with the values we know.
+ unsigned VarNum = SSAUpdate.AddVariable(I->getName(), I->getType());
+ SSAUpdate.AddAvailableValue(VarNum, BB, I);
+ for (Instruction *New : Cloned)
+ SSAUpdate.AddAvailableValue(VarNum, New->getParent(), New);
+
+ while (!UsesToRename.empty())
+ SSAUpdate.AddUse(VarNum, UsesToRename.pop_back_val());
+
+ LLVM_DEBUG(dbgs() << "\n");
+ }
+ // SSAUpdater handles phi placement and renaming uses with the appropriate
+ // value.
+ SSAUpdate.RewriteAllUses(DT);
+ }
+
+ /// Clones a basic block, and adds it to the CFG.
+ ///
+ /// This function also includes updating phi nodes in the successors of the
+ /// BB, and remapping uses that were defined locally in the cloned BB.
+ BasicBlock *cloneBlockAndUpdatePredecessor(BasicBlock *BB, BasicBlock *PrevBB,
+ uint64_t NextState,
+ DuplicateBlockMap &DuplicateMap,
+ DefMap &NewDefs,
+ DomTreeUpdater *DTU) {
+ ValueToValueMapTy VMap;
+ BasicBlock *NewBB = CloneBasicBlock(
+ BB, VMap, ".jt" + std::to_string(NextState), BB->getParent());
+ NewBB->moveAfter(BB);
+ NumCloned++;
+
+ for (Instruction &I : *NewBB) {
+ // Do not remap operands of PHINode in case a definition in BB is an
+ // incoming value to a phi in the same block. This incoming value will
+ // be renamed later while restoring SSA.
+ if (isa<PHINode>(&I))
+ continue;
+ RemapInstruction(&I, VMap,
+ RF_IgnoreMissingLocals | RF_NoModuleLevelChanges);
+ if (AssumeInst *II = dyn_cast<AssumeInst>(&I))
+ AC->registerAssumption(II);
+ }
+
+ updateSuccessorPhis(BB, NewBB, NextState, VMap, DuplicateMap);
+ updatePredecessor(PrevBB, BB, NewBB, DTU);
+ updateDefMap(NewDefs, VMap);
+
+ // Add all successors to the DominatorTree
+ SmallPtrSet<BasicBlock *, 4> SuccSet;
+ for (auto *SuccBB : successors(NewBB)) {
+ if (SuccSet.insert(SuccBB).second)
+ DTU->applyUpdates({{DominatorTree::Insert, NewBB, SuccBB}});
+ }
+ SuccSet.clear();
+ return NewBB;
+ }
+
+ /// Update the phi nodes in BB's successors.
+ ///
+ /// This means creating a new incoming value from NewBB with the new
+ /// instruction wherever there is an incoming value from BB.
+ void updateSuccessorPhis(BasicBlock *BB, BasicBlock *ClonedBB,
+ uint64_t NextState, ValueToValueMapTy &VMap,
+ DuplicateBlockMap &DuplicateMap) {
+ std::vector<BasicBlock *> BlocksToUpdate;
+
+ // If BB is the last block in the path, we can simply update the one case
+ // successor that will be reached.
+ if (BB == SwitchPaths->getSwitchBlock()) {
+ SwitchInst *Switch = SwitchPaths->getSwitchInst();
+ BasicBlock *NextCase = getNextCaseSuccessor(Switch, NextState);
+ BlocksToUpdate.push_back(NextCase);
+ BasicBlock *ClonedSucc = getClonedBB(NextCase, NextState, DuplicateMap);
+ if (ClonedSucc)
+ BlocksToUpdate.push_back(ClonedSucc);
+ }
+ // Otherwise update phis in all successors.
+ else {
+ for (BasicBlock *Succ : successors(BB)) {
+ BlocksToUpdate.push_back(Succ);
+
+ // Check if a successor has already been cloned for the particular exit
+ // value. In this case if a successor was already cloned, the phi nodes
+ // in the cloned block should be updated directly.
+ BasicBlock *ClonedSucc = getClonedBB(Succ, NextState, DuplicateMap);
+ if (ClonedSucc)
+ BlocksToUpdate.push_back(ClonedSucc);
+ }
+ }
+
+ // If there is a phi with an incoming value from BB, create a new incoming
+ // value for the new predecessor ClonedBB. The value will either be the same
+ // value from BB or a cloned value.
+ for (BasicBlock *Succ : BlocksToUpdate) {
+ for (auto II = Succ->begin(); PHINode *Phi = dyn_cast<PHINode>(II);
+ ++II) {
+ Value *Incoming = Phi->getIncomingValueForBlock(BB);
+ if (Incoming) {
+ if (isa<Constant>(Incoming)) {
+ Phi->addIncoming(Incoming, ClonedBB);
+ continue;
+ }
+ Value *ClonedVal = VMap[Incoming];
+ if (ClonedVal)
+ Phi->addIncoming(ClonedVal, ClonedBB);
+ else
+ Phi->addIncoming(Incoming, ClonedBB);
+ }
+ }
+ }
+ }
+
+ /// Sets the successor of PrevBB to be NewBB instead of OldBB. Note that all
+ /// other successors are kept as well.
+ void updatePredecessor(BasicBlock *PrevBB, BasicBlock *OldBB,
+ BasicBlock *NewBB, DomTreeUpdater *DTU) {
+ // When a path is reused, there is a chance that predecessors were already
+ // updated before. Check if the predecessor needs to be updated first.
+ if (!isPredecessor(OldBB, PrevBB))
+ return;
+
+ Instruction *PrevTerm = PrevBB->getTerminator();
+ for (unsigned Idx = 0; Idx < PrevTerm->getNumSuccessors(); Idx++) {
+ if (PrevTerm->getSuccessor(Idx) == OldBB) {
+ OldBB->removePredecessor(PrevBB, /* KeepOneInputPHIs = */ true);
+ PrevTerm->setSuccessor(Idx, NewBB);
+ }
+ }
+ DTU->applyUpdates({{DominatorTree::Delete, PrevBB, OldBB},
+ {DominatorTree::Insert, PrevBB, NewBB}});
+ }
+
+ /// Add new value mappings to the DefMap to keep track of all new definitions
+ /// for a particular instruction. These will be used while updating SSA form.
+ void updateDefMap(DefMap &NewDefs, ValueToValueMapTy &VMap) {
+ for (auto Entry : VMap) {
+ Instruction *Inst =
+ dyn_cast<Instruction>(const_cast<Value *>(Entry.first));
+ if (!Inst || !Entry.second || isa<BranchInst>(Inst) ||
+ isa<SwitchInst>(Inst)) {
+ continue;
+ }
+
+ Instruction *Cloned = dyn_cast<Instruction>(Entry.second);
+ if (!Cloned)
+ continue;
+
+ if (NewDefs.find(Inst) == NewDefs.end())
+ NewDefs[Inst] = {Cloned};
+ else
+ NewDefs[Inst].push_back(Cloned);
+ }
+ }
+
+ /// Update the last branch of a particular cloned path to point to the correct
+ /// case successor.
+ ///
+ /// Note that this is an optional step and would have been done in later
+ /// optimizations, but it makes the CFG significantly easier to work with.
+ void updateLastSuccessor(ThreadingPath &TPath,
+ DuplicateBlockMap &DuplicateMap,
+ DomTreeUpdater *DTU) {
+ uint64_t NextState = TPath.getExitValue();
+ BasicBlock *BB = TPath.getPath().back();
+ BasicBlock *LastBlock = getClonedBB(BB, NextState, DuplicateMap);
+
+ // Note multiple paths can end at the same block so check that it is not
+ // updated yet
+ if (!isa<SwitchInst>(LastBlock->getTerminator()))
+ return;
+ SwitchInst *Switch = cast<SwitchInst>(LastBlock->getTerminator());
+ BasicBlock *NextCase = getNextCaseSuccessor(Switch, NextState);
+
+ std::vector<DominatorTree::UpdateType> DTUpdates;
+ SmallPtrSet<BasicBlock *, 4> SuccSet;
+ for (BasicBlock *Succ : successors(LastBlock)) {
+ if (Succ != NextCase && SuccSet.insert(Succ).second)
+ DTUpdates.push_back({DominatorTree::Delete, LastBlock, Succ});
+ }
+
+ Switch->eraseFromParent();
+ BranchInst::Create(NextCase, LastBlock);
+
+ DTU->applyUpdates(DTUpdates);
+ }
+
+ /// After cloning blocks, some of the phi nodes have extra incoming values
+ /// that are no longer used. This function removes them.
+ void cleanPhiNodes(BasicBlock *BB) {
+ // If BB is no longer reachable, remove any remaining phi nodes
+ if (pred_empty(BB)) {
+ std::vector<PHINode *> PhiToRemove;
+ for (auto II = BB->begin(); PHINode *Phi = dyn_cast<PHINode>(II); ++II) {
+ PhiToRemove.push_back(Phi);
+ }
+ for (PHINode *PN : PhiToRemove) {
+ PN->replaceAllUsesWith(UndefValue::get(PN->getType()));
+ PN->eraseFromParent();
+ }
+ return;
+ }
+
+ // Remove any incoming values that come from an invalid predecessor
+ for (auto II = BB->begin(); PHINode *Phi = dyn_cast<PHINode>(II); ++II) {
+ std::vector<BasicBlock *> BlocksToRemove;
+ for (BasicBlock *IncomingBB : Phi->blocks()) {
+ if (!isPredecessor(BB, IncomingBB))
+ BlocksToRemove.push_back(IncomingBB);
+ }
+ for (BasicBlock *BB : BlocksToRemove)
+ Phi->removeIncomingValue(BB);
+ }
+ }
+
+ /// Checks if BB was already cloned for a particular next state value. If it
+ /// was then it returns this cloned block, and otherwise null.
+ BasicBlock *getClonedBB(BasicBlock *BB, uint64_t NextState,
+ DuplicateBlockMap &DuplicateMap) {
+ CloneList ClonedBBs = DuplicateMap[BB];
+
+ // Find an entry in the CloneList with this NextState. If it exists then
+ // return the corresponding BB
+ auto It = llvm::find_if(ClonedBBs, [NextState](const ClonedBlock &C) {
+ return C.State == NextState;
+ });
+ return It != ClonedBBs.end() ? (*It).BB : nullptr;
+ }
+
+ /// Helper to get the successor corresponding to a particular case value for
+ /// a switch statement.
+ BasicBlock *getNextCaseSuccessor(SwitchInst *Switch, uint64_t NextState) {
+ BasicBlock *NextCase = nullptr;
+ for (auto Case : Switch->cases()) {
+ if (Case.getCaseValue()->getZExtValue() == NextState) {
+ NextCase = Case.getCaseSuccessor();
+ break;
+ }
+ }
+ if (!NextCase)
+ NextCase = Switch->getDefaultDest();
+ return NextCase;
+ }
+
+ /// Returns true if IncomingBB is a predecessor of BB.
+ bool isPredecessor(BasicBlock *BB, BasicBlock *IncomingBB) {
+ return llvm::find(predecessors(BB), IncomingBB) != pred_end(BB);
+ }
+
+ AllSwitchPaths *SwitchPaths;
+ DominatorTree *DT;
+ AssumptionCache *AC;
+ TargetTransformInfo *TTI;
+ OptimizationRemarkEmitter *ORE;
+ SmallPtrSet<const Value *, 32> EphValues;
+ std::vector<ThreadingPath> TPaths;
+};
+
+bool DFAJumpThreading::run(Function &F) {
+ LLVM_DEBUG(dbgs() << "\nDFA Jump threading: " << F.getName() << "\n");
+
+ if (F.hasOptSize()) {
+ LLVM_DEBUG(dbgs() << "Skipping due to the 'minsize' attribute\n");
+ return false;
+ }
+
+ if (ClViewCfgBefore)
+ F.viewCFG();
+
+ SmallVector<AllSwitchPaths, 2> ThreadableLoops;
+ bool MadeChanges = false;
+
+ for (BasicBlock &BB : F) {
+ auto *SI = dyn_cast<SwitchInst>(BB.getTerminator());
+ if (!SI)
+ continue;
+
+ LLVM_DEBUG(dbgs() << "\nCheck if SwitchInst in BB " << BB.getName()
+ << " is predictable\n");
+ MainSwitch Switch(SI, ORE);
+
+ if (!Switch.getInstr())
+ continue;
+
+ LLVM_DEBUG(dbgs() << "\nSwitchInst in BB " << BB.getName() << " is a "
+ << "candidate for jump threading\n");
+ LLVM_DEBUG(SI->dump());
+
+ unfoldSelectInstrs(DT, Switch.getSelectInsts());
+ if (!Switch.getSelectInsts().empty())
+ MadeChanges = true;
+
+ AllSwitchPaths SwitchPaths(&Switch, ORE);
+ SwitchPaths.run();
+
+ if (SwitchPaths.getNumThreadingPaths() > 0) {
+ ThreadableLoops.push_back(SwitchPaths);
+
+ // For the time being limit this optimization to occurring once in a
+ // function since it can change the CFG significantly. This is not a
+ // strict requirement but it can cause buggy behavior if there is an
+ // overlap of blocks in different opportunities. There is a lot of room to
+ // experiment with catching more opportunities here.
+ break;
+ }
+ }
+
+ SmallPtrSet<const Value *, 32> EphValues;
+ if (ThreadableLoops.size() > 0)
+ CodeMetrics::collectEphemeralValues(&F, AC, EphValues);
+
+ for (AllSwitchPaths SwitchPaths : ThreadableLoops) {
+ TransformDFA Transform(&SwitchPaths, DT, AC, TTI, ORE, EphValues);
+ Transform.run();
+ MadeChanges = true;
+ }
+
+#ifdef EXPENSIVE_CHECKS
+ assert(DT->verify(DominatorTree::VerificationLevel::Full));
+ verifyFunction(F, &dbgs());
+#endif
+
+ return MadeChanges;
+}
+
+} // end anonymous namespace
+
+/// Integrate with the new Pass Manager
+PreservedAnalyses DFAJumpThreadingPass::run(Function &F,
+ FunctionAnalysisManager &AM) {
+ AssumptionCache &AC = AM.getResult<AssumptionAnalysis>(F);
+ DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F);
+ TargetTransformInfo &TTI = AM.getResult<TargetIRAnalysis>(F);
+ OptimizationRemarkEmitter ORE(&F);
+
+ if (!DFAJumpThreading(&AC, &DT, &TTI, &ORE).run(F))
+ return PreservedAnalyses::all();
+
+ PreservedAnalyses PA;
+ PA.preserve<DominatorTreeAnalysis>();
+ return PA;
+}
diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
index 2979225c6016..d22b3f409585 100644
--- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
@@ -1,4 +1,4 @@
-//===- DeadStoreElimination.cpp - Fast Dead Store Elimination -------------===//
+//===- DeadStoreElimination.cpp - MemorySSA Backed Dead Store Elimination -===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,11 +6,24 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements a trivial dead store elimination that only considers
-// basic-block local redundant stores.
+// The code below implements dead store elimination using MemorySSA. It uses
+// the following general approach: given a MemoryDef, walk upwards to find
+// clobbering MemoryDefs that may be killed by the starting def. Then check
+// that there are no uses that may read the location of the original MemoryDef
+// in between both MemoryDefs. A bit more concretely:
//
-// FIXME: This should eventually be extended to be a post-dominator tree
-// traversal. Doing so would be pretty trivial.
+// For all MemoryDefs StartDef:
+// 1. Get the next dominating clobbering MemoryDef (EarlierAccess) by walking
+// upwards.
+// 2. Check that there are no reads between EarlierAccess and the StartDef by
+// checking all uses starting at EarlierAccess and walking until we see
+// StartDef.
+// 3. For each found CurrentDef, check that:
+// 1. There are no barrier instructions between CurrentDef and StartDef (like
+// throws or stores with ordering constraints).
+// 2. StartDef is executed whenever CurrentDef is executed.
+// 3. StartDef completely overwrites CurrentDef.
+// 4. Erase CurrentDef from the function and MemorySSA.
//
//===----------------------------------------------------------------------===//
@@ -27,11 +40,12 @@
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h"
-#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
+#include "llvm/Analysis/MustExecute.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
@@ -105,10 +119,6 @@ EnablePartialStoreMerging("enable-dse-partial-store-merging",
cl::init(true), cl::Hidden,
cl::desc("Enable partial store merging in DSE"));
-static cl::opt<bool>
- EnableMemorySSA("enable-dse-memoryssa", cl::init(true), cl::Hidden,
- cl::desc("Use the new MemorySSA-backed DSE."));
-
static cl::opt<unsigned>
MemorySSAScanLimit("dse-memoryssa-scanlimit", cl::init(150), cl::Hidden,
cl::desc("The number of memory instructions to scan for "
@@ -153,69 +163,6 @@ static cl::opt<unsigned> MemorySSAPathCheckLimit(
using OverlapIntervalsTy = std::map<int64_t, int64_t>;
using InstOverlapIntervalsTy = DenseMap<Instruction *, OverlapIntervalsTy>;
-/// Delete this instruction. Before we do, go through and zero out all the
-/// operands of this instruction. If any of them become dead, delete them and
-/// the computation tree that feeds them.
-/// If ValueSet is non-null, remove any deleted instructions from it as well.
-static void
-deleteDeadInstruction(Instruction *I, BasicBlock::iterator *BBI,
- MemoryDependenceResults &MD, const TargetLibraryInfo &TLI,
- InstOverlapIntervalsTy &IOL,
- MapVector<Instruction *, bool> &ThrowableInst,
- SmallSetVector<const Value *, 16> *ValueSet = nullptr) {
- SmallVector<Instruction*, 32> NowDeadInsts;
-
- NowDeadInsts.push_back(I);
- --NumFastOther;
-
- // Keeping the iterator straight is a pain, so we let this routine tell the
- // caller what the next instruction is after we're done mucking about.
- BasicBlock::iterator NewIter = *BBI;
-
- // Before we touch this instruction, remove it from memdep!
- do {
- Instruction *DeadInst = NowDeadInsts.pop_back_val();
- // Mark the DeadInst as dead in the list of throwable instructions.
- auto It = ThrowableInst.find(DeadInst);
- if (It != ThrowableInst.end())
- ThrowableInst[It->first] = false;
- ++NumFastOther;
-
- // Try to preserve debug information attached to the dead instruction.
- salvageDebugInfo(*DeadInst);
- salvageKnowledge(DeadInst);
-
- // This instruction is dead, zap it, in stages. Start by removing it from
- // MemDep, which needs to know the operands and needs it to be in the
- // function.
- MD.removeInstruction(DeadInst);
-
- for (unsigned op = 0, e = DeadInst->getNumOperands(); op != e; ++op) {
- Value *Op = DeadInst->getOperand(op);
- DeadInst->setOperand(op, nullptr);
-
- // If this operand just became dead, add it to the NowDeadInsts list.
- if (!Op->use_empty()) continue;
-
- if (Instruction *OpI = dyn_cast<Instruction>(Op))
- if (isInstructionTriviallyDead(OpI, &TLI))
- NowDeadInsts.push_back(OpI);
- }
-
- if (ValueSet) ValueSet->remove(DeadInst);
- IOL.erase(DeadInst);
-
- if (NewIter == DeadInst->getIterator())
- NewIter = DeadInst->eraseFromParent();
- else
- DeadInst->eraseFromParent();
- } while (!NowDeadInsts.empty());
- *BBI = NewIter;
- // Pop dead entries from back of ThrowableInst till we find an alive entry.
- while (!ThrowableInst.empty() && !ThrowableInst.back().second)
- ThrowableInst.pop_back();
-}
-
/// Does this instruction write some memory? This only returns true for things
/// that we can analyze with other helpers below.
static bool hasAnalyzableMemoryWrite(Instruction *I,
@@ -289,19 +236,6 @@ static MemoryLocation getLocForWrite(Instruction *Inst,
return MemoryLocation();
}
-/// Return the location read by the specified "hasAnalyzableMemoryWrite"
-/// instruction if any.
-static MemoryLocation getLocForRead(Instruction *Inst,
- const TargetLibraryInfo &TLI) {
- assert(hasAnalyzableMemoryWrite(Inst, TLI) && "Unknown instruction case");
-
- // The only instructions that both read and write are the mem transfer
- // instructions (memcpy/memmove).
- if (auto *MTI = dyn_cast<AnyMemTransferInst>(Inst))
- return MemoryLocation::getForSource(MTI);
- return MemoryLocation();
-}
-
/// If the value of this instruction and the memory it writes to is unused, may
/// we delete this instruction?
static bool isRemovable(Instruction *I) {
@@ -373,17 +307,6 @@ static bool isShortenableAtTheBeginning(Instruction *I) {
return isa<AnyMemSetInst>(I);
}
-/// Return the pointer that is being written to.
-static Value *getStoredPointerOperand(Instruction *I,
- const TargetLibraryInfo &TLI) {
- //TODO: factor this to reuse getLocForWrite
- MemoryLocation Loc = getLocForWrite(I, TLI);
- assert(Loc.Ptr &&
- "unable to find pointer written for analyzable instruction?");
- // TODO: most APIs don't expect const Value *
- return const_cast<Value*>(Loc.Ptr);
-}
-
static uint64_t getPointerSize(const Value *V, const DataLayout &DL,
const TargetLibraryInfo &TLI,
const Function *F) {
@@ -412,10 +335,9 @@ enum OverwriteResult {
/// Check if two instruction are masked stores that completely
/// overwrite one another. More specifically, \p Later has to
/// overwrite \p Earlier.
-template <typename AATy>
static OverwriteResult isMaskedStoreOverwrite(const Instruction *Later,
const Instruction *Earlier,
- AATy &AA) {
+ BatchAAResults &AA) {
const auto *IIL = dyn_cast<IntrinsicInst>(Later);
const auto *IIE = dyn_cast<IntrinsicInst>(Earlier);
if (IIL == nullptr || IIE == nullptr)
@@ -435,106 +357,6 @@ static OverwriteResult isMaskedStoreOverwrite(const Instruction *Later,
return OW_Complete;
}
-/// Return 'OW_Complete' if a store to the 'Later' location (by \p LaterI
-/// instruction) completely overwrites a store to the 'Earlier' location.
-/// (by \p EarlierI instruction).
-/// Return OW_MaybePartial if \p Later does not completely overwrite
-/// \p Earlier, but they both write to the same underlying object. In that
-/// case, use isPartialOverwrite to check if \p Later partially overwrites
-/// \p Earlier. Returns 'OW_Unknown' if nothing can be determined.
-template <typename AATy>
-static OverwriteResult
-isOverwrite(const Instruction *LaterI, const Instruction *EarlierI,
- const MemoryLocation &Later, const MemoryLocation &Earlier,
- const DataLayout &DL, const TargetLibraryInfo &TLI,
- int64_t &EarlierOff, int64_t &LaterOff, AATy &AA,
- const Function *F) {
- // FIXME: Vet that this works for size upper-bounds. Seems unlikely that we'll
- // get imprecise values here, though (except for unknown sizes).
- if (!Later.Size.isPrecise() || !Earlier.Size.isPrecise()) {
- // Masked stores have imprecise locations, but we can reason about them
- // to some extent.
- return isMaskedStoreOverwrite(LaterI, EarlierI, AA);
- }
-
- const uint64_t LaterSize = Later.Size.getValue();
- const uint64_t EarlierSize = Earlier.Size.getValue();
-
- const Value *P1 = Earlier.Ptr->stripPointerCasts();
- const Value *P2 = Later.Ptr->stripPointerCasts();
-
- // If the start pointers are the same, we just have to compare sizes to see if
- // the later store was larger than the earlier store.
- if (P1 == P2 || AA.isMustAlias(P1, P2)) {
- // Make sure that the Later size is >= the Earlier size.
- if (LaterSize >= EarlierSize)
- return OW_Complete;
- }
-
- // Check to see if the later store is to the entire object (either a global,
- // an alloca, or a byval/inalloca argument). If so, then it clearly
- // overwrites any other store to the same object.
- const Value *UO1 = getUnderlyingObject(P1), *UO2 = getUnderlyingObject(P2);
-
- // If we can't resolve the same pointers to the same object, then we can't
- // analyze them at all.
- if (UO1 != UO2)
- return OW_Unknown;
-
- // If the "Later" store is to a recognizable object, get its size.
- uint64_t ObjectSize = getPointerSize(UO2, DL, TLI, F);
- if (ObjectSize != MemoryLocation::UnknownSize)
- if (ObjectSize == LaterSize && ObjectSize >= EarlierSize)
- return OW_Complete;
-
- // Okay, we have stores to two completely different pointers. Try to
- // decompose the pointer into a "base + constant_offset" form. If the base
- // pointers are equal, then we can reason about the two stores.
- EarlierOff = 0;
- LaterOff = 0;
- const Value *BP1 = GetPointerBaseWithConstantOffset(P1, EarlierOff, DL);
- const Value *BP2 = GetPointerBaseWithConstantOffset(P2, LaterOff, DL);
-
- // If the base pointers still differ, we have two completely different stores.
- if (BP1 != BP2)
- return OW_Unknown;
-
- // The later access completely overlaps the earlier store if and only if
- // both start and end of the earlier one is "inside" the later one:
- // |<->|--earlier--|<->|
- // |-------later-------|
- // Accesses may overlap if and only if start of one of them is "inside"
- // another one:
- // |<->|--earlier--|<----->|
- // |-------later-------|
- // OR
- // |----- earlier -----|
- // |<->|---later---|<----->|
- //
- // We have to be careful here as *Off is signed while *.Size is unsigned.
-
- // Check if the earlier access starts "not before" the later one.
- if (EarlierOff >= LaterOff) {
- // If the earlier access ends "not after" the later access then the earlier
- // one is completely overwritten by the later one.
- if (uint64_t(EarlierOff - LaterOff) + EarlierSize <= LaterSize)
- return OW_Complete;
- // If start of the earlier access is "before" end of the later access then
- // accesses overlap.
- else if ((uint64_t)(EarlierOff - LaterOff) < LaterSize)
- return OW_MaybePartial;
- }
- // If start of the later access is "before" end of the earlier access then
- // accesses overlap.
- else if ((uint64_t)(LaterOff - EarlierOff) < EarlierSize) {
- return OW_MaybePartial;
- }
-
- // Can reach here only if accesses are known not to overlap. There is no
- // dedicated code to indicate no overlap so signal "unknown".
- return OW_Unknown;
-}
-
/// Return 'OW_Complete' if a store to the 'Later' location completely
/// overwrites a store to the 'Earlier' location, 'OW_End' if the end of the
/// 'Earlier' location is completely overwritten by 'Later', 'OW_Begin' if the
@@ -659,69 +481,14 @@ static OverwriteResult isPartialOverwrite(const MemoryLocation &Later,
return OW_Unknown;
}
-/// If 'Inst' might be a self read (i.e. a noop copy of a
-/// memory region into an identical pointer) then it doesn't actually make its
-/// input dead in the traditional sense. Consider this case:
-///
-/// memmove(A <- B)
-/// memmove(A <- A)
-///
-/// In this case, the second store to A does not make the first store to A dead.
-/// The usual situation isn't an explicit A<-A store like this (which can be
-/// trivially removed) but a case where two pointers may alias.
-///
-/// This function detects when it is unsafe to remove a dependent instruction
-/// because the DSE inducing instruction may be a self-read.
-static bool isPossibleSelfRead(Instruction *Inst,
- const MemoryLocation &InstStoreLoc,
- Instruction *DepWrite,
- const TargetLibraryInfo &TLI,
- AliasAnalysis &AA) {
- // Self reads can only happen for instructions that read memory. Get the
- // location read.
- MemoryLocation InstReadLoc = getLocForRead(Inst, TLI);
- if (!InstReadLoc.Ptr)
- return false; // Not a reading instruction.
-
- // If the read and written loc obviously don't alias, it isn't a read.
- if (AA.isNoAlias(InstReadLoc, InstStoreLoc))
- return false;
-
- if (isa<AnyMemCpyInst>(Inst)) {
- // LLVM's memcpy overlap semantics are not fully fleshed out (see PR11763)
- // but in practice memcpy(A <- B) either means that A and B are disjoint or
- // are equal (i.e. there are not partial overlaps). Given that, if we have:
- //
- // memcpy/memmove(A <- B) // DepWrite
- // memcpy(A <- B) // Inst
- //
- // with Inst reading/writing a >= size than DepWrite, we can reason as
- // follows:
- //
- // - If A == B then both the copies are no-ops, so the DepWrite can be
- // removed.
- // - If A != B then A and B are disjoint locations in Inst. Since
- // Inst.size >= DepWrite.size A and B are disjoint in DepWrite too.
- // Therefore DepWrite can be removed.
- MemoryLocation DepReadLoc = getLocForRead(DepWrite, TLI);
-
- if (DepReadLoc.Ptr && AA.isMustAlias(InstReadLoc.Ptr, DepReadLoc.Ptr))
- return false;
- }
-
- // If DepWrite doesn't read memory or if we can't prove it is a must alias,
- // then it can't be considered dead.
- return true;
-}
-
/// Returns true if the memory which is accessed by the second instruction is not
/// modified between the first and the second instruction.
/// Precondition: Second instruction must be dominated by the first
/// instruction.
-template <typename AATy>
static bool
-memoryIsNotModifiedBetween(Instruction *FirstI, Instruction *SecondI, AATy &AA,
- const DataLayout &DL, DominatorTree *DT) {
+memoryIsNotModifiedBetween(Instruction *FirstI, Instruction *SecondI,
+ BatchAAResults &AA, const DataLayout &DL,
+ DominatorTree *DT) {
// Do a backwards scan through the CFG from SecondI to FirstI. Look for
// instructions which can modify the memory location accessed by SecondI.
//
@@ -776,16 +543,16 @@ memoryIsNotModifiedBetween(Instruction *FirstI, Instruction *SecondI, AATy &AA,
if (B != FirstBB) {
assert(B != &FirstBB->getParent()->getEntryBlock() &&
"Should not hit the entry block because SI must be dominated by LI");
- for (auto PredI = pred_begin(B), PE = pred_end(B); PredI != PE; ++PredI) {
+ for (BasicBlock *Pred : predecessors(B)) {
PHITransAddr PredAddr = Addr;
if (PredAddr.NeedsPHITranslationFromBlock(B)) {
if (!PredAddr.IsPotentiallyPHITranslatable())
return false;
- if (PredAddr.PHITranslateValue(B, *PredI, DT, false))
+ if (PredAddr.PHITranslateValue(B, Pred, DT, false))
return false;
}
Value *TranslatedPtr = PredAddr.getAddr();
- auto Inserted = Visited.insert(std::make_pair(*PredI, TranslatedPtr));
+ auto Inserted = Visited.insert(std::make_pair(Pred, TranslatedPtr));
if (!Inserted.second) {
// We already visited this block before. If it was with a different
// address - bail out!
@@ -794,332 +561,111 @@ memoryIsNotModifiedBetween(Instruction *FirstI, Instruction *SecondI, AATy &AA,
// ... otherwise just skip it.
continue;
}
- WorkList.push_back(std::make_pair(*PredI, PredAddr));
+ WorkList.push_back(std::make_pair(Pred, PredAddr));
}
}
}
return true;
}
-/// Find all blocks that will unconditionally lead to the block BB and append
-/// them to F.
-static void findUnconditionalPreds(SmallVectorImpl<BasicBlock *> &Blocks,
- BasicBlock *BB, DominatorTree *DT) {
- for (pred_iterator I = pred_begin(BB), E = pred_end(BB); I != E; ++I) {
- BasicBlock *Pred = *I;
- if (Pred == BB) continue;
- Instruction *PredTI = Pred->getTerminator();
- if (PredTI->getNumSuccessors() != 1)
- continue;
-
- if (DT->isReachableFromEntry(Pred))
- Blocks.push_back(Pred);
- }
-}
-
-/// Handle frees of entire structures whose dependency is a store
-/// to a field of that structure.
-static bool handleFree(CallInst *F, AliasAnalysis *AA,
- MemoryDependenceResults *MD, DominatorTree *DT,
- const TargetLibraryInfo *TLI,
- InstOverlapIntervalsTy &IOL,
- MapVector<Instruction *, bool> &ThrowableInst) {
- bool MadeChange = false;
-
- MemoryLocation Loc = MemoryLocation::getAfter(F->getOperand(0));
- SmallVector<BasicBlock *, 16> Blocks;
- Blocks.push_back(F->getParent());
-
- while (!Blocks.empty()) {
- BasicBlock *BB = Blocks.pop_back_val();
- Instruction *InstPt = BB->getTerminator();
- if (BB == F->getParent()) InstPt = F;
-
- MemDepResult Dep =
- MD->getPointerDependencyFrom(Loc, false, InstPt->getIterator(), BB);
- while (Dep.isDef() || Dep.isClobber()) {
- Instruction *Dependency = Dep.getInst();
- if (!hasAnalyzableMemoryWrite(Dependency, *TLI) ||
- !isRemovable(Dependency))
- break;
-
- Value *DepPointer =
- getUnderlyingObject(getStoredPointerOperand(Dependency, *TLI));
-
- // Check for aliasing.
- if (!AA->isMustAlias(F->getArgOperand(0), DepPointer))
- break;
-
- LLVM_DEBUG(
- dbgs() << "DSE: Dead Store to soon to be freed memory:\n DEAD: "
- << *Dependency << '\n');
-
- // DCE instructions only used to calculate that store.
- BasicBlock::iterator BBI(Dependency);
- deleteDeadInstruction(Dependency, &BBI, *MD, *TLI, IOL,
- ThrowableInst);
- ++NumFastStores;
- MadeChange = true;
-
- // Inst's old Dependency is now deleted. Compute the next dependency,
- // which may also be dead, as in
- // s[0] = 0;
- // s[1] = 0; // This has just been deleted.
- // free(s);
- Dep = MD->getPointerDependencyFrom(Loc, false, BBI, BB);
- }
-
- if (Dep.isNonLocal())
- findUnconditionalPreds(Blocks, BB, DT);
- }
-
- return MadeChange;
-}
-
-/// Check to see if the specified location may alias any of the stack objects in
-/// the DeadStackObjects set. If so, they become live because the location is
-/// being loaded.
-static void removeAccessedObjects(const MemoryLocation &LoadedLoc,
- SmallSetVector<const Value *, 16> &DeadStackObjects,
- const DataLayout &DL, AliasAnalysis *AA,
- const TargetLibraryInfo *TLI,
- const Function *F) {
- const Value *UnderlyingPointer = getUnderlyingObject(LoadedLoc.Ptr);
-
- // A constant can't be in the dead pointer set.
- if (isa<Constant>(UnderlyingPointer))
- return;
-
- // If the kill pointer can be easily reduced to an alloca, don't bother doing
- // extraneous AA queries.
- if (isa<AllocaInst>(UnderlyingPointer) || isa<Argument>(UnderlyingPointer)) {
- DeadStackObjects.remove(UnderlyingPointer);
- return;
- }
-
- // Remove objects that could alias LoadedLoc.
- DeadStackObjects.remove_if([&](const Value *I) {
- // See if the loaded location could alias the stack location.
- MemoryLocation StackLoc(I, getPointerSize(I, DL, *TLI, F));
- return !AA->isNoAlias(StackLoc, LoadedLoc);
- });
-}
-
-/// Remove dead stores to stack-allocated locations in the function end block.
-/// Ex:
-/// %A = alloca i32
-/// ...
-/// store i32 1, i32* %A
-/// ret void
-static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA,
- MemoryDependenceResults *MD,
- const TargetLibraryInfo *TLI,
- InstOverlapIntervalsTy &IOL,
- MapVector<Instruction *, bool> &ThrowableInst) {
- bool MadeChange = false;
-
- // Keep track of all of the stack objects that are dead at the end of the
- // function.
- SmallSetVector<const Value*, 16> DeadStackObjects;
-
- // Find all of the alloca'd pointers in the entry block.
- BasicBlock &Entry = BB.getParent()->front();
- for (Instruction &I : Entry) {
- if (isa<AllocaInst>(&I))
- DeadStackObjects.insert(&I);
-
- // Okay, so these are dead heap objects, but if the pointer never escapes
- // then it's leaked by this function anyways.
- else if (isAllocLikeFn(&I, TLI) && !PointerMayBeCaptured(&I, true, true))
- DeadStackObjects.insert(&I);
- }
-
- // Treat byval or inalloca arguments the same, stores to them are dead at the
- // end of the function.
- for (Argument &AI : BB.getParent()->args())
- if (AI.hasPassPointeeByValueCopyAttr())
- DeadStackObjects.insert(&AI);
-
- const DataLayout &DL = BB.getModule()->getDataLayout();
-
- // Scan the basic block backwards
- for (BasicBlock::iterator BBI = BB.end(); BBI != BB.begin(); ){
- --BBI;
-
- // If we find a store, check to see if it points into a dead stack value.
- if (hasAnalyzableMemoryWrite(&*BBI, *TLI) && isRemovable(&*BBI)) {
- // See through pointer-to-pointer bitcasts
- SmallVector<const Value *, 4> Pointers;
- getUnderlyingObjects(getStoredPointerOperand(&*BBI, *TLI), Pointers);
-
- // Stores to stack values are valid candidates for removal.
- bool AllDead = true;
- for (const Value *Pointer : Pointers)
- if (!DeadStackObjects.count(Pointer)) {
- AllDead = false;
- break;
- }
-
- if (AllDead) {
- Instruction *Dead = &*BBI;
-
- LLVM_DEBUG(dbgs() << "DSE: Dead Store at End of Block:\n DEAD: "
- << *Dead << "\n Objects: ";
- for (SmallVectorImpl<const Value *>::iterator I =
- Pointers.begin(),
- E = Pointers.end();
- I != E; ++I) {
- dbgs() << **I;
- if (std::next(I) != E)
- dbgs() << ", ";
- } dbgs()
- << '\n');
-
- // DCE instructions only used to calculate that store.
- deleteDeadInstruction(Dead, &BBI, *MD, *TLI, IOL, ThrowableInst,
- &DeadStackObjects);
- ++NumFastStores;
- MadeChange = true;
- continue;
- }
- }
-
- // Remove any dead non-memory-mutating instructions.
- if (isInstructionTriviallyDead(&*BBI, TLI)) {
- LLVM_DEBUG(dbgs() << "DSE: Removing trivially dead instruction:\n DEAD: "
- << *&*BBI << '\n');
- deleteDeadInstruction(&*BBI, &BBI, *MD, *TLI, IOL, ThrowableInst,
- &DeadStackObjects);
- ++NumFastOther;
- MadeChange = true;
- continue;
- }
-
- if (isa<AllocaInst>(BBI)) {
- // Remove allocas from the list of dead stack objects; there can't be
- // any references before the definition.
- DeadStackObjects.remove(&*BBI);
- continue;
- }
-
- if (auto *Call = dyn_cast<CallBase>(&*BBI)) {
- // Remove allocation function calls from the list of dead stack objects;
- // there can't be any references before the definition.
- if (isAllocLikeFn(&*BBI, TLI))
- DeadStackObjects.remove(&*BBI);
-
- // If this call does not access memory, it can't be loading any of our
- // pointers.
- if (AA->doesNotAccessMemory(Call))
- continue;
-
- // If the call might load from any of our allocas, then any store above
- // the call is live.
- DeadStackObjects.remove_if([&](const Value *I) {
- // See if the call site touches the value.
- return isRefSet(AA->getModRefInfo(
- Call, I, getPointerSize(I, DL, *TLI, BB.getParent())));
- });
-
- // If all of the allocas were clobbered by the call then we're not going
- // to find anything else to process.
- if (DeadStackObjects.empty())
- break;
+static bool tryToShorten(Instruction *EarlierWrite, int64_t &EarlierStart,
+ uint64_t &EarlierSize, int64_t LaterStart,
+ uint64_t LaterSize, bool IsOverwriteEnd) {
+ auto *EarlierIntrinsic = cast<AnyMemIntrinsic>(EarlierWrite);
+ Align PrefAlign = EarlierIntrinsic->getDestAlign().valueOrOne();
- continue;
- }
+ // We assume that memet/memcpy operates in chunks of the "largest" native
+ // type size and aligned on the same value. That means optimal start and size
+ // of memset/memcpy should be modulo of preferred alignment of that type. That
+ // is it there is no any sense in trying to reduce store size any further
+ // since any "extra" stores comes for free anyway.
+ // On the other hand, maximum alignment we can achieve is limited by alignment
+ // of initial store.
- // We can remove the dead stores, irrespective of the fence and its ordering
- // (release/acquire/seq_cst). Fences only constraints the ordering of
- // already visible stores, it does not make a store visible to other
- // threads. So, skipping over a fence does not change a store from being
- // dead.
- if (isa<FenceInst>(*BBI))
- continue;
+ // TODO: Limit maximum alignment by preferred (or abi?) alignment of the
+ // "largest" native type.
+ // Note: What is the proper way to get that value?
+ // Should TargetTransformInfo::getRegisterBitWidth be used or anything else?
+ // PrefAlign = std::min(DL.getPrefTypeAlign(LargestType), PrefAlign);
- MemoryLocation LoadedLoc;
-
- // If we encounter a use of the pointer, it is no longer considered dead
- if (LoadInst *L = dyn_cast<LoadInst>(BBI)) {
- if (!L->isUnordered()) // Be conservative with atomic/volatile load
- break;
- LoadedLoc = MemoryLocation::get(L);
- } else if (VAArgInst *V = dyn_cast<VAArgInst>(BBI)) {
- LoadedLoc = MemoryLocation::get(V);
- } else if (!BBI->mayReadFromMemory()) {
- // Instruction doesn't read memory. Note that stores that weren't removed
- // above will hit this case.
- continue;
- } else {
- // Unknown inst; assume it clobbers everything.
- break;
+ int64_t ToRemoveStart = 0;
+ uint64_t ToRemoveSize = 0;
+ // Compute start and size of the region to remove. Make sure 'PrefAlign' is
+ // maintained on the remaining store.
+ if (IsOverwriteEnd) {
+ // Calculate required adjustment for 'LaterStart'in order to keep remaining
+ // store size aligned on 'PerfAlign'.
+ uint64_t Off =
+ offsetToAlignment(uint64_t(LaterStart - EarlierStart), PrefAlign);
+ ToRemoveStart = LaterStart + Off;
+ if (EarlierSize <= uint64_t(ToRemoveStart - EarlierStart))
+ return false;
+ ToRemoveSize = EarlierSize - uint64_t(ToRemoveStart - EarlierStart);
+ } else {
+ ToRemoveStart = EarlierStart;
+ assert(LaterSize >= uint64_t(EarlierStart - LaterStart) &&
+ "Not overlapping accesses?");
+ ToRemoveSize = LaterSize - uint64_t(EarlierStart - LaterStart);
+ // Calculate required adjustment for 'ToRemoveSize'in order to keep
+ // start of the remaining store aligned on 'PerfAlign'.
+ uint64_t Off = offsetToAlignment(ToRemoveSize, PrefAlign);
+ if (Off != 0) {
+ if (ToRemoveSize <= (PrefAlign.value() - Off))
+ return false;
+ ToRemoveSize -= PrefAlign.value() - Off;
}
-
- // Remove any allocas from the DeadPointer set that are loaded, as this
- // makes any stores above the access live.
- removeAccessedObjects(LoadedLoc, DeadStackObjects, DL, AA, TLI, BB.getParent());
-
- // If all of the allocas were clobbered by the access then we're not going
- // to find anything else to process.
- if (DeadStackObjects.empty())
- break;
+ assert(isAligned(PrefAlign, ToRemoveSize) &&
+ "Should preserve selected alignment");
}
- return MadeChange;
-}
-
-static bool tryToShorten(Instruction *EarlierWrite, int64_t &EarlierOffset,
- uint64_t &EarlierSize, int64_t LaterOffset,
- uint64_t LaterSize, bool IsOverwriteEnd) {
- // TODO: base this on the target vector size so that if the earlier
- // store was too small to get vector writes anyway then its likely
- // a good idea to shorten it
- // Power of 2 vector writes are probably always a bad idea to optimize
- // as any store/memset/memcpy is likely using vector instructions so
- // shortening it to not vector size is likely to be slower
- auto *EarlierIntrinsic = cast<AnyMemIntrinsic>(EarlierWrite);
- unsigned EarlierWriteAlign = EarlierIntrinsic->getDestAlignment();
- if (!IsOverwriteEnd)
- LaterOffset = int64_t(LaterOffset + LaterSize);
-
- if (!(isPowerOf2_64(LaterOffset) && EarlierWriteAlign <= LaterOffset) &&
- !((EarlierWriteAlign != 0) && LaterOffset % EarlierWriteAlign == 0))
- return false;
-
- int64_t NewLength = IsOverwriteEnd
- ? LaterOffset - EarlierOffset
- : EarlierSize - (LaterOffset - EarlierOffset);
+ assert(ToRemoveSize > 0 && "Shouldn't reach here if nothing to remove");
+ assert(EarlierSize > ToRemoveSize && "Can't remove more than original size");
+ uint64_t NewSize = EarlierSize - ToRemoveSize;
if (auto *AMI = dyn_cast<AtomicMemIntrinsic>(EarlierWrite)) {
// When shortening an atomic memory intrinsic, the newly shortened
// length must remain an integer multiple of the element size.
const uint32_t ElementSize = AMI->getElementSizeInBytes();
- if (0 != NewLength % ElementSize)
+ if (0 != NewSize % ElementSize)
return false;
}
LLVM_DEBUG(dbgs() << "DSE: Remove Dead Store:\n OW "
<< (IsOverwriteEnd ? "END" : "BEGIN") << ": "
- << *EarlierWrite << "\n KILLER (offset " << LaterOffset
- << ", " << EarlierSize << ")\n");
+ << *EarlierWrite << "\n KILLER [" << ToRemoveStart << ", "
+ << int64_t(ToRemoveStart + ToRemoveSize) << ")\n");
Value *EarlierWriteLength = EarlierIntrinsic->getLength();
Value *TrimmedLength =
- ConstantInt::get(EarlierWriteLength->getType(), NewLength);
+ ConstantInt::get(EarlierWriteLength->getType(), NewSize);
EarlierIntrinsic->setLength(TrimmedLength);
+ EarlierIntrinsic->setDestAlignment(PrefAlign);
- EarlierSize = NewLength;
if (!IsOverwriteEnd) {
- int64_t OffsetMoved = (LaterOffset - EarlierOffset);
+ Value *OrigDest = EarlierIntrinsic->getRawDest();
+ Type *Int8PtrTy =
+ Type::getInt8PtrTy(EarlierIntrinsic->getContext(),
+ OrigDest->getType()->getPointerAddressSpace());
+ Value *Dest = OrigDest;
+ if (OrigDest->getType() != Int8PtrTy)
+ Dest = CastInst::CreatePointerCast(OrigDest, Int8PtrTy, "", EarlierWrite);
Value *Indices[1] = {
- ConstantInt::get(EarlierWriteLength->getType(), OffsetMoved)};
- GetElementPtrInst *NewDestGEP = GetElementPtrInst::CreateInBounds(
- EarlierIntrinsic->getRawDest()->getType()->getPointerElementType(),
- EarlierIntrinsic->getRawDest(), Indices, "", EarlierWrite);
+ ConstantInt::get(EarlierWriteLength->getType(), ToRemoveSize)};
+ Instruction *NewDestGEP = GetElementPtrInst::CreateInBounds(
+ Type::getInt8Ty(EarlierIntrinsic->getContext()),
+ Dest, Indices, "", EarlierWrite);
NewDestGEP->setDebugLoc(EarlierIntrinsic->getDebugLoc());
+ if (NewDestGEP->getType() != OrigDest->getType())
+ NewDestGEP = CastInst::CreatePointerCast(NewDestGEP, OrigDest->getType(),
+ "", EarlierWrite);
EarlierIntrinsic->setDest(NewDestGEP);
- EarlierOffset = EarlierOffset + OffsetMoved;
}
+
+ // Finally update start and size of earlier access.
+ if (!IsOverwriteEnd)
+ EarlierStart += ToRemoveSize;
+ EarlierSize = NewSize;
+
return true;
}
@@ -1204,59 +750,10 @@ static bool removePartiallyOverlappedStores(const DataLayout &DL,
return Changed;
}
-static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI,
- AliasAnalysis *AA, MemoryDependenceResults *MD,
- const DataLayout &DL,
- const TargetLibraryInfo *TLI,
- InstOverlapIntervalsTy &IOL,
- MapVector<Instruction *, bool> &ThrowableInst,
- DominatorTree *DT) {
- // Must be a store instruction.
- StoreInst *SI = dyn_cast<StoreInst>(Inst);
- if (!SI)
- return false;
-
- // If we're storing the same value back to a pointer that we just loaded from,
- // then the store can be removed.
- if (LoadInst *DepLoad = dyn_cast<LoadInst>(SI->getValueOperand())) {
- if (SI->getPointerOperand() == DepLoad->getPointerOperand() &&
- isRemovable(SI) &&
- memoryIsNotModifiedBetween(DepLoad, SI, *AA, DL, DT)) {
-
- LLVM_DEBUG(
- dbgs() << "DSE: Remove Store Of Load from same pointer:\n LOAD: "
- << *DepLoad << "\n STORE: " << *SI << '\n');
-
- deleteDeadInstruction(SI, &BBI, *MD, *TLI, IOL, ThrowableInst);
- ++NumRedundantStores;
- return true;
- }
- }
-
- // Remove null stores into the calloc'ed objects
- Constant *StoredConstant = dyn_cast<Constant>(SI->getValueOperand());
- if (StoredConstant && StoredConstant->isNullValue() && isRemovable(SI)) {
- Instruction *UnderlyingPointer =
- dyn_cast<Instruction>(getUnderlyingObject(SI->getPointerOperand()));
-
- if (UnderlyingPointer && isCallocLikeFn(UnderlyingPointer, TLI) &&
- memoryIsNotModifiedBetween(UnderlyingPointer, SI, *AA, DL, DT)) {
- LLVM_DEBUG(
- dbgs() << "DSE: Remove null store to the calloc'ed object:\n DEAD: "
- << *Inst << "\n OBJECT: " << *UnderlyingPointer << '\n');
-
- deleteDeadInstruction(SI, &BBI, *MD, *TLI, IOL, ThrowableInst);
- ++NumRedundantStores;
- return true;
- }
- }
- return false;
-}
-
-template <typename AATy>
static Constant *tryToMergePartialOverlappingStores(
StoreInst *Earlier, StoreInst *Later, int64_t InstWriteOffset,
- int64_t DepWriteOffset, const DataLayout &DL, AATy &AA, DominatorTree *DT) {
+ int64_t DepWriteOffset, const DataLayout &DL, BatchAAResults &AA,
+ DominatorTree *DT) {
if (Earlier && isa<ConstantInt>(Earlier->getValueOperand()) &&
DL.typeSizeEqualsStoreSize(Earlier->getValueOperand()->getType()) &&
@@ -1298,251 +795,7 @@ static Constant *tryToMergePartialOverlappingStores(
return nullptr;
}
-static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA,
- MemoryDependenceResults *MD, DominatorTree *DT,
- const TargetLibraryInfo *TLI) {
- const DataLayout &DL = BB.getModule()->getDataLayout();
- bool MadeChange = false;
-
- MapVector<Instruction *, bool> ThrowableInst;
-
- // A map of interval maps representing partially-overwritten value parts.
- InstOverlapIntervalsTy IOL;
-
- // Do a top-down walk on the BB.
- for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; ) {
- // Handle 'free' calls specially.
- if (CallInst *F = isFreeCall(&*BBI, TLI)) {
- MadeChange |= handleFree(F, AA, MD, DT, TLI, IOL, ThrowableInst);
- // Increment BBI after handleFree has potentially deleted instructions.
- // This ensures we maintain a valid iterator.
- ++BBI;
- continue;
- }
-
- Instruction *Inst = &*BBI++;
-
- if (Inst->mayThrow()) {
- ThrowableInst[Inst] = true;
- continue;
- }
-
- // Check to see if Inst writes to memory. If not, continue.
- if (!hasAnalyzableMemoryWrite(Inst, *TLI))
- continue;
-
- // eliminateNoopStore will update in iterator, if necessary.
- if (eliminateNoopStore(Inst, BBI, AA, MD, DL, TLI, IOL,
- ThrowableInst, DT)) {
- MadeChange = true;
- continue;
- }
-
- // If we find something that writes memory, get its memory dependence.
- MemDepResult InstDep = MD->getDependency(Inst);
-
- // Ignore any store where we can't find a local dependence.
- // FIXME: cross-block DSE would be fun. :)
- if (!InstDep.isDef() && !InstDep.isClobber())
- continue;
-
- // Figure out what location is being stored to.
- MemoryLocation Loc = getLocForWrite(Inst, *TLI);
-
- // If we didn't get a useful location, fail.
- if (!Loc.Ptr)
- continue;
-
- // Loop until we find a store we can eliminate or a load that
- // invalidates the analysis. Without an upper bound on the number of
- // instructions examined, this analysis can become very time-consuming.
- // However, the potential gain diminishes as we process more instructions
- // without eliminating any of them. Therefore, we limit the number of
- // instructions we look at.
- auto Limit = MD->getDefaultBlockScanLimit();
- while (InstDep.isDef() || InstDep.isClobber()) {
- // Get the memory clobbered by the instruction we depend on. MemDep will
- // skip any instructions that 'Loc' clearly doesn't interact with. If we
- // end up depending on a may- or must-aliased load, then we can't optimize
- // away the store and we bail out. However, if we depend on something
- // that overwrites the memory location we *can* potentially optimize it.
- //
- // Find out what memory location the dependent instruction stores.
- Instruction *DepWrite = InstDep.getInst();
- if (!hasAnalyzableMemoryWrite(DepWrite, *TLI))
- break;
- MemoryLocation DepLoc = getLocForWrite(DepWrite, *TLI);
- // If we didn't get a useful location, or if it isn't a size, bail out.
- if (!DepLoc.Ptr)
- break;
-
- // Find the last throwable instruction not removed by call to
- // deleteDeadInstruction.
- Instruction *LastThrowing = nullptr;
- if (!ThrowableInst.empty())
- LastThrowing = ThrowableInst.back().first;
-
- // Make sure we don't look past a call which might throw. This is an
- // issue because MemoryDependenceAnalysis works in the wrong direction:
- // it finds instructions which dominate the current instruction, rather than
- // instructions which are post-dominated by the current instruction.
- //
- // If the underlying object is a non-escaping memory allocation, any store
- // to it is dead along the unwind edge. Otherwise, we need to preserve
- // the store.
- if (LastThrowing && DepWrite->comesBefore(LastThrowing)) {
- const Value *Underlying = getUnderlyingObject(DepLoc.Ptr);
- bool IsStoreDeadOnUnwind = isa<AllocaInst>(Underlying);
- if (!IsStoreDeadOnUnwind) {
- // We're looking for a call to an allocation function
- // where the allocation doesn't escape before the last
- // throwing instruction; PointerMayBeCaptured
- // reasonably fast approximation.
- IsStoreDeadOnUnwind = isAllocLikeFn(Underlying, TLI) &&
- !PointerMayBeCaptured(Underlying, false, true);
- }
- if (!IsStoreDeadOnUnwind)
- break;
- }
-
- // If we find a write that is a) removable (i.e., non-volatile), b) is
- // completely obliterated by the store to 'Loc', and c) which we know that
- // 'Inst' doesn't load from, then we can remove it.
- // Also try to merge two stores if a later one only touches memory written
- // to by the earlier one.
- if (isRemovable(DepWrite) &&
- !isPossibleSelfRead(Inst, Loc, DepWrite, *TLI, *AA)) {
- int64_t InstWriteOffset, DepWriteOffset;
- OverwriteResult OR = isOverwrite(Inst, DepWrite, Loc, DepLoc, DL, *TLI,
- DepWriteOffset, InstWriteOffset, *AA,
- BB.getParent());
- if (OR == OW_MaybePartial)
- OR = isPartialOverwrite(Loc, DepLoc, DepWriteOffset, InstWriteOffset,
- DepWrite, IOL);
-
- if (OR == OW_Complete) {
- LLVM_DEBUG(dbgs() << "DSE: Remove Dead Store:\n DEAD: " << *DepWrite
- << "\n KILLER: " << *Inst << '\n');
-
- // Delete the store and now-dead instructions that feed it.
- deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL,
- ThrowableInst);
- ++NumFastStores;
- MadeChange = true;
-
- // We erased DepWrite; start over.
- InstDep = MD->getDependency(Inst);
- continue;
- } else if ((OR == OW_End && isShortenableAtTheEnd(DepWrite)) ||
- ((OR == OW_Begin &&
- isShortenableAtTheBeginning(DepWrite)))) {
- assert(!EnablePartialOverwriteTracking && "Do not expect to perform "
- "when partial-overwrite "
- "tracking is enabled");
- // The overwrite result is known, so these must be known, too.
- uint64_t EarlierSize = DepLoc.Size.getValue();
- uint64_t LaterSize = Loc.Size.getValue();
- bool IsOverwriteEnd = (OR == OW_End);
- MadeChange |= tryToShorten(DepWrite, DepWriteOffset, EarlierSize,
- InstWriteOffset, LaterSize, IsOverwriteEnd);
- } else if (EnablePartialStoreMerging &&
- OR == OW_PartialEarlierWithFullLater) {
- auto *Earlier = dyn_cast<StoreInst>(DepWrite);
- auto *Later = dyn_cast<StoreInst>(Inst);
- if (Constant *C = tryToMergePartialOverlappingStores(
- Earlier, Later, InstWriteOffset, DepWriteOffset, DL, *AA,
- DT)) {
- auto *SI = new StoreInst(
- C, Earlier->getPointerOperand(), false, Earlier->getAlign(),
- Earlier->getOrdering(), Earlier->getSyncScopeID(), DepWrite);
-
- unsigned MDToKeep[] = {LLVMContext::MD_dbg, LLVMContext::MD_tbaa,
- LLVMContext::MD_alias_scope,
- LLVMContext::MD_noalias,
- LLVMContext::MD_nontemporal};
- SI->copyMetadata(*DepWrite, MDToKeep);
- ++NumModifiedStores;
-
- // Delete the old stores and now-dead instructions that feed them.
- deleteDeadInstruction(Inst, &BBI, *MD, *TLI, IOL,
- ThrowableInst);
- deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL,
- ThrowableInst);
- MadeChange = true;
-
- // We erased DepWrite and Inst (Loc); start over.
- break;
- }
- }
- }
-
- // If this is a may-aliased store that is clobbering the store value, we
- // can keep searching past it for another must-aliased pointer that stores
- // to the same location. For example, in:
- // store -> P
- // store -> Q
- // store -> P
- // we can remove the first store to P even though we don't know if P and Q
- // alias.
- if (DepWrite == &BB.front()) break;
-
- // Can't look past this instruction if it might read 'Loc'.
- if (isRefSet(AA->getModRefInfo(DepWrite, Loc)))
- break;
-
- InstDep = MD->getPointerDependencyFrom(Loc, /*isLoad=*/ false,
- DepWrite->getIterator(), &BB,
- /*QueryInst=*/ nullptr, &Limit);
- }
- }
-
- if (EnablePartialOverwriteTracking)
- MadeChange |= removePartiallyOverlappedStores(DL, IOL, *TLI);
-
- // If this block ends in a return, unwind, or unreachable, all allocas are
- // dead at its end, which means stores to them are also dead.
- if (BB.getTerminator()->getNumSuccessors() == 0)
- MadeChange |= handleEndBlock(BB, AA, MD, TLI, IOL, ThrowableInst);
-
- return MadeChange;
-}
-
-static bool eliminateDeadStores(Function &F, AliasAnalysis *AA,
- MemoryDependenceResults *MD, DominatorTree *DT,
- const TargetLibraryInfo *TLI) {
- bool MadeChange = false;
- for (BasicBlock &BB : F)
- // Only check non-dead blocks. Dead blocks may have strange pointer
- // cycles that will confuse alias analysis.
- if (DT->isReachableFromEntry(&BB))
- MadeChange |= eliminateDeadStores(BB, AA, MD, DT, TLI);
-
- return MadeChange;
-}
-
namespace {
-//=============================================================================
-// MemorySSA backed dead store elimination.
-//
-// The code below implements dead store elimination using MemorySSA. It uses
-// the following general approach: given a MemoryDef, walk upwards to find
-// clobbering MemoryDefs that may be killed by the starting def. Then check
-// that there are no uses that may read the location of the original MemoryDef
-// in between both MemoryDefs. A bit more concretely:
-//
-// For all MemoryDefs StartDef:
-// 1. Get the next dominating clobbering MemoryDef (EarlierAccess) by walking
-// upwards.
-// 2. Check that there are no reads between EarlierAccess and the StartDef by
-// checking all uses starting at EarlierAccess and walking until we see
-// StartDef.
-// 3. For each found CurrentDef, check that:
-// 1. There are no barrier instructions between CurrentDef and StartDef (like
-// throws or stores with ordering constraints).
-// 2. StartDef is executed whenever CurrentDef is executed.
-// 3. StartDef completely overwrites CurrentDef.
-// 4. Erase CurrentDef from the function and MemorySSA.
-
// Returns true if \p I is an intrisnic that does not read or write memory.
bool isNoopIntrinsic(Instruction *I) {
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
@@ -1612,6 +865,11 @@ struct DSEState {
PostDominatorTree &PDT;
const TargetLibraryInfo &TLI;
const DataLayout &DL;
+ const LoopInfo &LI;
+
+ // Whether the function contains any irreducible control flow, useful for
+ // being accurately able to detect loops.
+ bool ContainsIrreducibleLoops;
// All MemoryDefs that potentially could kill other MemDefs.
SmallVector<MemoryDef *, 64> MemDefs;
@@ -1635,14 +893,15 @@ struct DSEState {
DenseMap<BasicBlock *, InstOverlapIntervalsTy> IOLs;
DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT,
- PostDominatorTree &PDT, const TargetLibraryInfo &TLI)
+ PostDominatorTree &PDT, const TargetLibraryInfo &TLI,
+ const LoopInfo &LI)
: F(F), AA(AA), BatchAA(AA), MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI),
- DL(F.getParent()->getDataLayout()) {}
+ DL(F.getParent()->getDataLayout()), LI(LI) {}
static DSEState get(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
DominatorTree &DT, PostDominatorTree &PDT,
- const TargetLibraryInfo &TLI) {
- DSEState State(F, AA, MSSA, DT, PDT, TLI);
+ const TargetLibraryInfo &TLI, const LoopInfo &LI) {
+ DSEState State(F, AA, MSSA, DT, PDT, TLI, LI);
// Collect blocks with throwing instructions not modeled in MemorySSA and
// alloc-like objects.
unsigned PO = 0;
@@ -1670,9 +929,135 @@ struct DSEState {
State.InvisibleToCallerAfterRet.insert({&AI, true});
}
+ // Collect whether there is any irreducible control flow in the function.
+ State.ContainsIrreducibleLoops = mayContainIrreducibleControl(F, &LI);
+
return State;
}
+ /// Return 'OW_Complete' if a store to the 'Later' location (by \p LaterI
+ /// instruction) completely overwrites a store to the 'Earlier' location.
+ /// (by \p EarlierI instruction).
+ /// Return OW_MaybePartial if \p Later does not completely overwrite
+ /// \p Earlier, but they both write to the same underlying object. In that
+ /// case, use isPartialOverwrite to check if \p Later partially overwrites
+ /// \p Earlier. Returns 'OW_Unknown' if nothing can be determined.
+ OverwriteResult
+ isOverwrite(const Instruction *LaterI, const Instruction *EarlierI,
+ const MemoryLocation &Later, const MemoryLocation &Earlier,
+ int64_t &EarlierOff, int64_t &LaterOff) {
+ // AliasAnalysis does not always account for loops. Limit overwrite checks
+ // to dependencies for which we can guarantee they are independant of any
+ // loops they are in.
+ if (!isGuaranteedLoopIndependent(EarlierI, LaterI, Earlier))
+ return OW_Unknown;
+
+ // FIXME: Vet that this works for size upper-bounds. Seems unlikely that we'll
+ // get imprecise values here, though (except for unknown sizes).
+ if (!Later.Size.isPrecise() || !Earlier.Size.isPrecise()) {
+ // In case no constant size is known, try to an IR values for the number
+ // of bytes written and check if they match.
+ const auto *LaterMemI = dyn_cast<MemIntrinsic>(LaterI);
+ const auto *EarlierMemI = dyn_cast<MemIntrinsic>(EarlierI);
+ if (LaterMemI && EarlierMemI) {
+ const Value *LaterV = LaterMemI->getLength();
+ const Value *EarlierV = EarlierMemI->getLength();
+ if (LaterV == EarlierV && BatchAA.isMustAlias(Earlier, Later))
+ return OW_Complete;
+ }
+
+ // Masked stores have imprecise locations, but we can reason about them
+ // to some extent.
+ return isMaskedStoreOverwrite(LaterI, EarlierI, BatchAA);
+ }
+
+ const uint64_t LaterSize = Later.Size.getValue();
+ const uint64_t EarlierSize = Earlier.Size.getValue();
+
+ // Query the alias information
+ AliasResult AAR = BatchAA.alias(Later, Earlier);
+
+ // If the start pointers are the same, we just have to compare sizes to see if
+ // the later store was larger than the earlier store.
+ if (AAR == AliasResult::MustAlias) {
+ // Make sure that the Later size is >= the Earlier size.
+ if (LaterSize >= EarlierSize)
+ return OW_Complete;
+ }
+
+ // If we hit a partial alias we may have a full overwrite
+ if (AAR == AliasResult::PartialAlias && AAR.hasOffset()) {
+ int32_t Off = AAR.getOffset();
+ if (Off >= 0 && (uint64_t)Off + EarlierSize <= LaterSize)
+ return OW_Complete;
+ }
+
+ // Check to see if the later store is to the entire object (either a global,
+ // an alloca, or a byval/inalloca argument). If so, then it clearly
+ // overwrites any other store to the same object.
+ const Value *P1 = Earlier.Ptr->stripPointerCasts();
+ const Value *P2 = Later.Ptr->stripPointerCasts();
+ const Value *UO1 = getUnderlyingObject(P1), *UO2 = getUnderlyingObject(P2);
+
+ // If we can't resolve the same pointers to the same object, then we can't
+ // analyze them at all.
+ if (UO1 != UO2)
+ return OW_Unknown;
+
+ // If the "Later" store is to a recognizable object, get its size.
+ uint64_t ObjectSize = getPointerSize(UO2, DL, TLI, &F);
+ if (ObjectSize != MemoryLocation::UnknownSize)
+ if (ObjectSize == LaterSize && ObjectSize >= EarlierSize)
+ return OW_Complete;
+
+ // Okay, we have stores to two completely different pointers. Try to
+ // decompose the pointer into a "base + constant_offset" form. If the base
+ // pointers are equal, then we can reason about the two stores.
+ EarlierOff = 0;
+ LaterOff = 0;
+ const Value *BP1 = GetPointerBaseWithConstantOffset(P1, EarlierOff, DL);
+ const Value *BP2 = GetPointerBaseWithConstantOffset(P2, LaterOff, DL);
+
+ // If the base pointers still differ, we have two completely different stores.
+ if (BP1 != BP2)
+ return OW_Unknown;
+
+ // The later access completely overlaps the earlier store if and only if
+ // both start and end of the earlier one is "inside" the later one:
+ // |<->|--earlier--|<->|
+ // |-------later-------|
+ // Accesses may overlap if and only if start of one of them is "inside"
+ // another one:
+ // |<->|--earlier--|<----->|
+ // |-------later-------|
+ // OR
+ // |----- earlier -----|
+ // |<->|---later---|<----->|
+ //
+ // We have to be careful here as *Off is signed while *.Size is unsigned.
+
+ // Check if the earlier access starts "not before" the later one.
+ if (EarlierOff >= LaterOff) {
+ // If the earlier access ends "not after" the later access then the earlier
+ // one is completely overwritten by the later one.
+ if (uint64_t(EarlierOff - LaterOff) + EarlierSize <= LaterSize)
+ return OW_Complete;
+ // If start of the earlier access is "before" end of the later access then
+ // accesses overlap.
+ else if ((uint64_t)(EarlierOff - LaterOff) < LaterSize)
+ return OW_MaybePartial;
+ }
+ // If start of the later access is "before" end of the earlier access then
+ // accesses overlap.
+ else if ((uint64_t)(LaterOff - EarlierOff) < EarlierSize) {
+ return OW_MaybePartial;
+ }
+
+ // Can reach here only if accesses are known not to overlap. There is no
+ // dedicated code to indicate no overlap so signal "unknown".
+ return OW_Unknown;
+ }
+
bool isInvisibleToCallerAfterRet(const Value *V) {
if (isa<AllocaInst>(V))
return true;
@@ -1760,8 +1145,8 @@ struct DSEState {
int64_t InstWriteOffset, DepWriteOffset;
if (auto CC = getLocForWriteEx(UseInst))
- return isOverwrite(UseInst, DefInst, *CC, DefLoc, DL, TLI, DepWriteOffset,
- InstWriteOffset, BatchAA, &F) == OW_Complete;
+ return isOverwrite(UseInst, DefInst, *CC, DefLoc, DepWriteOffset,
+ InstWriteOffset) == OW_Complete;
return false;
}
@@ -1864,9 +1249,8 @@ struct DSEState {
return BatchAA.isMustAlias(TermLoc.Ptr, LocUO);
}
int64_t InstWriteOffset, DepWriteOffset;
- return isOverwrite(MaybeTerm, AccessI, TermLoc, Loc, DL, TLI,
- DepWriteOffset, InstWriteOffset, BatchAA,
- &F) == OW_Complete;
+ return isOverwrite(MaybeTerm, AccessI, TermLoc, Loc, DepWriteOffset,
+ InstWriteOffset) == OW_Complete;
}
// Returns true if \p Use may read from \p DefLoc.
@@ -1893,11 +1277,33 @@ struct DSEState {
return isRefSet(BatchAA.getModRefInfo(UseInst, DefLoc));
}
+ /// Returns true if a dependency between \p Current and \p KillingDef is
+ /// guaranteed to be loop invariant for the loops that they are in. Either
+ /// because they are known to be in the same block, in the same loop level or
+ /// by guaranteeing that \p CurrentLoc only references a single MemoryLocation
+ /// during execution of the containing function.
+ bool isGuaranteedLoopIndependent(const Instruction *Current,
+ const Instruction *KillingDef,
+ const MemoryLocation &CurrentLoc) {
+ // If the dependency is within the same block or loop level (being careful
+ // of irreducible loops), we know that AA will return a valid result for the
+ // memory dependency. (Both at the function level, outside of any loop,
+ // would also be valid but we currently disable that to limit compile time).
+ if (Current->getParent() == KillingDef->getParent())
+ return true;
+ const Loop *CurrentLI = LI.getLoopFor(Current->getParent());
+ if (!ContainsIrreducibleLoops && CurrentLI &&
+ CurrentLI == LI.getLoopFor(KillingDef->getParent()))
+ return true;
+ // Otherwise check the memory location is invariant to any loops.
+ return isGuaranteedLoopInvariant(CurrentLoc.Ptr);
+ }
+
/// Returns true if \p Ptr is guaranteed to be loop invariant for any possible
/// loop. In particular, this guarantees that it only references a single
/// MemoryLocation during execution of the containing function.
- bool IsGuaranteedLoopInvariant(Value *Ptr) {
- auto IsGuaranteedLoopInvariantBase = [this](Value *Ptr) {
+ bool isGuaranteedLoopInvariant(const Value *Ptr) {
+ auto IsGuaranteedLoopInvariantBase = [this](const Value *Ptr) {
Ptr = Ptr->stripPointerCasts();
if (auto *I = dyn_cast<Instruction>(Ptr)) {
if (isa<AllocaInst>(Ptr))
@@ -1912,6 +1318,10 @@ struct DSEState {
};
Ptr = Ptr->stripPointerCasts();
+ if (auto *I = dyn_cast<Instruction>(Ptr)) {
+ if (I->getParent()->isEntryBlock())
+ return true;
+ }
if (auto *GEP = dyn_cast<GEPOperator>(Ptr)) {
return IsGuaranteedLoopInvariantBase(GEP->getPointerOperand()) &&
GEP->hasAllConstantIndices();
@@ -1937,13 +1347,11 @@ struct DSEState {
MemoryAccess *Current = StartAccess;
Instruction *KillingI = KillingDef->getMemoryInst();
- bool StepAgain;
LLVM_DEBUG(dbgs() << " trying to get dominating access\n");
// Find the next clobbering Mod access for DefLoc, starting at StartAccess.
Optional<MemoryLocation> CurrentLoc;
- do {
- StepAgain = false;
+ for (;; Current = cast<MemoryDef>(Current)->getDefiningAccess()) {
LLVM_DEBUG({
dbgs() << " visiting " << *Current;
if (!MSSA.isLiveOnEntryDef(Current) && isa<MemoryUseOrDef>(Current))
@@ -1981,11 +1389,8 @@ struct DSEState {
MemoryDef *CurrentDef = cast<MemoryDef>(Current);
Instruction *CurrentI = CurrentDef->getMemoryInst();
- if (canSkipDef(CurrentDef, !isInvisibleToCallerBeforeRet(DefUO))) {
- StepAgain = true;
- Current = CurrentDef->getDefiningAccess();
+ if (canSkipDef(CurrentDef, !isInvisibleToCallerBeforeRet(DefUO)))
continue;
- }
// Before we try to remove anything, check for any extra throwing
// instructions that block us from DSEing
@@ -2021,27 +1426,19 @@ struct DSEState {
// If Current cannot be analyzed or is not removable, check the next
// candidate.
- if (!hasAnalyzableMemoryWrite(CurrentI, TLI) || !isRemovable(CurrentI)) {
- StepAgain = true;
- Current = CurrentDef->getDefiningAccess();
+ if (!hasAnalyzableMemoryWrite(CurrentI, TLI) || !isRemovable(CurrentI))
continue;
- }
// If Current does not have an analyzable write location, skip it
CurrentLoc = getLocForWriteEx(CurrentI);
- if (!CurrentLoc) {
- StepAgain = true;
- Current = CurrentDef->getDefiningAccess();
+ if (!CurrentLoc)
continue;
- }
// AliasAnalysis does not account for loops. Limit elimination to
// candidates for which we can guarantee they always store to the same
- // memory location and not multiple locations in a loop.
- if (Current->getBlock() != KillingDef->getBlock() &&
- !IsGuaranteedLoopInvariant(const_cast<Value *>(CurrentLoc->Ptr))) {
- StepAgain = true;
- Current = CurrentDef->getDefiningAccess();
+ // memory location and not located in different loops.
+ if (!isGuaranteedLoopIndependent(CurrentI, KillingI, *CurrentLoc)) {
+ LLVM_DEBUG(dbgs() << " ... not guaranteed loop independent\n");
WalkerStepLimit -= 1;
continue;
}
@@ -2050,35 +1447,30 @@ struct DSEState {
// If the killing def is a memory terminator (e.g. lifetime.end), check
// the next candidate if the current Current does not write the same
// underlying object as the terminator.
- if (!isMemTerminator(*CurrentLoc, CurrentI, KillingI)) {
- StepAgain = true;
- Current = CurrentDef->getDefiningAccess();
- }
- continue;
+ if (!isMemTerminator(*CurrentLoc, CurrentI, KillingI))
+ continue;
} else {
int64_t InstWriteOffset, DepWriteOffset;
- auto OR = isOverwrite(KillingI, CurrentI, DefLoc, *CurrentLoc, DL, TLI,
- DepWriteOffset, InstWriteOffset, BatchAA, &F);
+ auto OR = isOverwrite(KillingI, CurrentI, DefLoc, *CurrentLoc,
+ DepWriteOffset, InstWriteOffset);
// If Current does not write to the same object as KillingDef, check
// the next candidate.
- if (OR == OW_Unknown) {
- StepAgain = true;
- Current = CurrentDef->getDefiningAccess();
- } else if (OR == OW_MaybePartial) {
+ if (OR == OW_Unknown)
+ continue;
+ else if (OR == OW_MaybePartial) {
// If KillingDef only partially overwrites Current, check the next
// candidate if the partial step limit is exceeded. This aggressively
// limits the number of candidates for partial store elimination,
// which are less likely to be removable in the end.
if (PartialLimit <= 1) {
- StepAgain = true;
- Current = CurrentDef->getDefiningAccess();
WalkerStepLimit -= 1;
continue;
}
PartialLimit -= 1;
}
}
- } while (StepAgain);
+ break;
+ };
// Accesses to objects accessible after the function returns can only be
// eliminated if the access is killed along all paths to the exit. Collect
@@ -2168,8 +1560,16 @@ struct DSEState {
return None;
}
- // For the KillingDef and EarlierAccess we only have to check if it reads
- // the memory location.
+ // If this worklist walks back to the original memory access (and the
+ // pointer is not guarenteed loop invariant) then we cannot assume that a
+ // store kills itself.
+ if (EarlierAccess == UseAccess &&
+ !isGuaranteedLoopInvariant(CurrentLoc->Ptr)) {
+ LLVM_DEBUG(dbgs() << " ... found not loop invariant self access\n");
+ return None;
+ }
+ // Otherwise, for the KillingDef and EarlierAccess we only have to check
+ // if it reads the memory location.
// TODO: It would probably be better to check for self-reads before
// calling the function.
if (KillingDef == UseAccess || EarlierAccess == UseAccess) {
@@ -2189,16 +1589,18 @@ struct DSEState {
// stores [0,1]
if (MemoryDef *UseDef = dyn_cast<MemoryDef>(UseAccess)) {
if (isCompleteOverwrite(*CurrentLoc, EarlierMemInst, UseInst)) {
- if (!isInvisibleToCallerAfterRet(DefUO) &&
- UseAccess != EarlierAccess) {
- BasicBlock *MaybeKillingBlock = UseInst->getParent();
- if (PostOrderNumbers.find(MaybeKillingBlock)->second <
- PostOrderNumbers.find(EarlierAccess->getBlock())->second) {
-
+ BasicBlock *MaybeKillingBlock = UseInst->getParent();
+ if (PostOrderNumbers.find(MaybeKillingBlock)->second <
+ PostOrderNumbers.find(EarlierAccess->getBlock())->second) {
+ if (!isInvisibleToCallerAfterRet(DefUO)) {
LLVM_DEBUG(dbgs()
<< " ... found killing def " << *UseInst << "\n");
KillingDefs.insert(UseInst);
}
+ } else {
+ LLVM_DEBUG(dbgs()
+ << " ... found preceeding def " << *UseInst << "\n");
+ return None;
}
} else
PushMemUses(UseDef);
@@ -2405,6 +1807,25 @@ struct DSEState {
bool storeIsNoop(MemoryDef *Def, const MemoryLocation &DefLoc,
const Value *DefUO) {
StoreInst *Store = dyn_cast<StoreInst>(Def->getMemoryInst());
+ MemSetInst *MemSet = dyn_cast<MemSetInst>(Def->getMemoryInst());
+ Constant *StoredConstant = nullptr;
+ if (Store)
+ StoredConstant = dyn_cast<Constant>(Store->getOperand(0));
+ if (MemSet)
+ StoredConstant = dyn_cast<Constant>(MemSet->getValue());
+
+ if (StoredConstant && StoredConstant->isNullValue()) {
+ auto *DefUOInst = dyn_cast<Instruction>(DefUO);
+ if (DefUOInst && isCallocLikeFn(DefUOInst, &TLI)) {
+ auto *UnderlyingDef = cast<MemoryDef>(MSSA.getMemoryAccess(DefUOInst));
+ // If UnderlyingDef is the clobbering access of Def, no instructions
+ // between them can modify the memory location.
+ auto *ClobberDef =
+ MSSA.getSkipSelfWalker()->getClobberingMemoryAccess(Def);
+ return UnderlyingDef == ClobberDef;
+ }
+ }
+
if (!Store)
return false;
@@ -2452,29 +1873,17 @@ struct DSEState {
}
}
- Constant *StoredConstant = dyn_cast<Constant>(Store->getOperand(0));
- if (StoredConstant && StoredConstant->isNullValue()) {
- auto *DefUOInst = dyn_cast<Instruction>(DefUO);
- if (DefUOInst && isCallocLikeFn(DefUOInst, &TLI)) {
- auto *UnderlyingDef = cast<MemoryDef>(MSSA.getMemoryAccess(DefUOInst));
- // If UnderlyingDef is the clobbering access of Def, no instructions
- // between them can modify the memory location.
- auto *ClobberDef =
- MSSA.getSkipSelfWalker()->getClobberingMemoryAccess(Def);
- return UnderlyingDef == ClobberDef;
- }
- }
return false;
}
};
-bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA,
- MemorySSA &MSSA, DominatorTree &DT,
- PostDominatorTree &PDT,
- const TargetLibraryInfo &TLI) {
+static bool eliminateDeadStores(Function &F, AliasAnalysis &AA, MemorySSA &MSSA,
+ DominatorTree &DT, PostDominatorTree &PDT,
+ const TargetLibraryInfo &TLI,
+ const LoopInfo &LI) {
bool MadeChange = false;
- DSEState State = DSEState::get(F, AA, MSSA, DT, PDT, TLI);
+ DSEState State = DSEState::get(F, AA, MSSA, DT, PDT, TLI, LI);
// For each store:
for (unsigned I = 0; I < State.MemDefs.size(); I++) {
MemoryDef *KillingDef = State.MemDefs[I];
@@ -2500,7 +1909,7 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA,
MemoryAccess *Current = KillingDef;
LLVM_DEBUG(dbgs() << "Trying to eliminate MemoryDefs killed by "
- << *KillingDef << " (" << *SI << ")\n");
+ << *Current << " (" << *SI << ")\n");
unsigned ScanLimit = MemorySSAScanLimit;
unsigned WalkerStepLimit = MemorySSAUpwardsStepLimit;
@@ -2569,9 +1978,8 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA,
} else {
// Check if NI overwrites SI.
int64_t InstWriteOffset, DepWriteOffset;
- OverwriteResult OR =
- isOverwrite(SI, NI, SILoc, NILoc, State.DL, TLI, DepWriteOffset,
- InstWriteOffset, State.BatchAA, &F);
+ OverwriteResult OR = State.isOverwrite(SI, NI, SILoc, NILoc,
+ DepWriteOffset, InstWriteOffset);
if (OR == OW_MaybePartial) {
auto Iter = State.IOLs.insert(
std::make_pair<BasicBlock *, InstOverlapIntervalsTy>(
@@ -2646,18 +2054,11 @@ PreservedAnalyses DSEPass::run(Function &F, FunctionAnalysisManager &AM) {
AliasAnalysis &AA = AM.getResult<AAManager>(F);
const TargetLibraryInfo &TLI = AM.getResult<TargetLibraryAnalysis>(F);
DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F);
+ MemorySSA &MSSA = AM.getResult<MemorySSAAnalysis>(F).getMSSA();
+ PostDominatorTree &PDT = AM.getResult<PostDominatorTreeAnalysis>(F);
+ LoopInfo &LI = AM.getResult<LoopAnalysis>(F);
- bool Changed = false;
- if (EnableMemorySSA) {
- MemorySSA &MSSA = AM.getResult<MemorySSAAnalysis>(F).getMSSA();
- PostDominatorTree &PDT = AM.getResult<PostDominatorTreeAnalysis>(F);
-
- Changed = eliminateDeadStoresMemorySSA(F, AA, MSSA, DT, PDT, TLI);
- } else {
- MemoryDependenceResults &MD = AM.getResult<MemoryDependenceAnalysis>(F);
-
- Changed = eliminateDeadStores(F, &AA, &MD, &DT, &TLI);
- }
+ bool Changed = eliminateDeadStores(F, AA, MSSA, DT, PDT, TLI, LI);
#ifdef LLVM_ENABLE_STATS
if (AreStatisticsEnabled())
@@ -2670,11 +2071,8 @@ PreservedAnalyses DSEPass::run(Function &F, FunctionAnalysisManager &AM) {
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
- PA.preserve<GlobalsAA>();
- if (EnableMemorySSA)
- PA.preserve<MemorySSAAnalysis>();
- else
- PA.preserve<MemoryDependenceAnalysis>();
+ PA.preserve<MemorySSAAnalysis>();
+ PA.preserve<LoopAnalysis>();
return PA;
}
@@ -2697,20 +2095,12 @@ public:
DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
const TargetLibraryInfo &TLI =
getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
+ MemorySSA &MSSA = getAnalysis<MemorySSAWrapperPass>().getMSSA();
+ PostDominatorTree &PDT =
+ getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
+ LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
- bool Changed = false;
- if (EnableMemorySSA) {
- MemorySSA &MSSA = getAnalysis<MemorySSAWrapperPass>().getMSSA();
- PostDominatorTree &PDT =
- getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
-
- Changed = eliminateDeadStoresMemorySSA(F, AA, MSSA, DT, PDT, TLI);
- } else {
- MemoryDependenceResults &MD =
- getAnalysis<MemoryDependenceWrapperPass>().getMemDep();
-
- Changed = eliminateDeadStores(F, &AA, &MD, &DT, &TLI);
- }
+ bool Changed = eliminateDeadStores(F, AA, MSSA, DT, PDT, TLI, LI);
#ifdef LLVM_ENABLE_STATS
if (AreStatisticsEnabled())
@@ -2728,16 +2118,12 @@ public:
AU.addPreserved<GlobalsAAWrapperPass>();
AU.addRequired<DominatorTreeWrapperPass>();
AU.addPreserved<DominatorTreeWrapperPass>();
-
- if (EnableMemorySSA) {
- AU.addRequired<PostDominatorTreeWrapperPass>();
- AU.addRequired<MemorySSAWrapperPass>();
- AU.addPreserved<PostDominatorTreeWrapperPass>();
- AU.addPreserved<MemorySSAWrapperPass>();
- } else {
- AU.addRequired<MemoryDependenceWrapperPass>();
- AU.addPreserved<MemoryDependenceWrapperPass>();
- }
+ AU.addRequired<PostDominatorTreeWrapperPass>();
+ AU.addRequired<MemorySSAWrapperPass>();
+ AU.addPreserved<PostDominatorTreeWrapperPass>();
+ AU.addPreserved<MemorySSAWrapperPass>();
+ AU.addRequired<LoopInfoWrapperPass>();
+ AU.addPreserved<LoopInfoWrapperPass>();
}
};
@@ -2754,6 +2140,7 @@ INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass)
INITIALIZE_PASS_DEPENDENCY(MemoryDependenceWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
INITIALIZE_PASS_END(DSELegacyPass, "dse", "Dead Store Elimination", false,
false)
diff --git a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp
index 3c6c444d6649..c77769368ede 100644
--- a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp
+++ b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp
@@ -238,8 +238,52 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI,
if (!DivDominates && !DT.dominates(RemInst, DivInst)) {
// We have matching div-rem pair, but they are in two different blocks,
// neither of which dominates one another.
- // FIXME: We could hoist both ops to the common predecessor block?
- continue;
+
+ BasicBlock *PredBB = nullptr;
+ BasicBlock *DivBB = DivInst->getParent();
+ BasicBlock *RemBB = RemInst->getParent();
+
+ // It's only safe to hoist if every instruction before the Div/Rem in the
+ // basic block is guaranteed to transfer execution.
+ auto IsSafeToHoist = [](Instruction *DivOrRem, BasicBlock *ParentBB) {
+ for (auto I = ParentBB->begin(), E = DivOrRem->getIterator(); I != E;
+ ++I)
+ if (!isGuaranteedToTransferExecutionToSuccessor(&*I))
+ return false;
+
+ return true;
+ };
+
+ // Look for something like this
+ // PredBB
+ // | \
+ // | Rem
+ // | /
+ // Div
+ //
+ // If the Rem block has a single predecessor and successor, and all paths
+ // from PredBB go to either RemBB or DivBB, and execution of RemBB and
+ // DivBB will always reach the Div/Rem, we can hoist Div to PredBB. If
+ // we have a DivRem operation we can also hoist Rem. Otherwise we'll leave
+ // Rem where it is and rewrite it to mul/sub.
+ // FIXME: We could handle more hoisting cases.
+ if (RemBB->getSingleSuccessor() == DivBB)
+ PredBB = RemBB->getUniquePredecessor();
+
+ if (PredBB && IsSafeToHoist(RemInst, RemBB) &&
+ IsSafeToHoist(DivInst, DivBB) &&
+ llvm::all_of(successors(PredBB), [&](BasicBlock *BB) {
+ return BB == DivBB || BB == RemBB;
+ })) {
+ DivDominates = true;
+ DivInst->moveBefore(PredBB->getTerminator());
+ Changed = true;
+ if (HasDivRemOp) {
+ RemInst->moveBefore(PredBB->getTerminator());
+ continue;
+ }
+ } else
+ continue;
}
// The target does not have a single div/rem operation,
@@ -394,6 +438,5 @@ PreservedAnalyses DivRemPairsPass::run(Function &F,
// TODO: This pass just hoists/replaces math ops - all analyses are preserved?
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
index 180a82917fa9..978c6a77b8dc 100644
--- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -41,7 +41,6 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/PatternMatch.h"
-#include "llvm/IR/Statepoint.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/Value.h"
@@ -109,8 +108,29 @@ struct SimpleValue {
static bool canHandle(Instruction *Inst) {
// This can only handle non-void readnone functions.
- if (CallInst *CI = dyn_cast<CallInst>(Inst))
+ // Also handled are constrained intrinsic that look like the types
+ // of instruction handled below (UnaryOperator, etc.).
+ if (CallInst *CI = dyn_cast<CallInst>(Inst)) {
+ if (Function *F = CI->getCalledFunction()) {
+ switch ((Intrinsic::ID)F->getIntrinsicID()) {
+ case Intrinsic::experimental_constrained_fadd:
+ case Intrinsic::experimental_constrained_fsub:
+ case Intrinsic::experimental_constrained_fmul:
+ case Intrinsic::experimental_constrained_fdiv:
+ case Intrinsic::experimental_constrained_frem:
+ case Intrinsic::experimental_constrained_fptosi:
+ case Intrinsic::experimental_constrained_sitofp:
+ case Intrinsic::experimental_constrained_fptoui:
+ case Intrinsic::experimental_constrained_uitofp:
+ case Intrinsic::experimental_constrained_fcmp:
+ case Intrinsic::experimental_constrained_fcmps: {
+ auto *CFP = cast<ConstrainedFPIntrinsic>(CI);
+ return CFP->isDefaultFPEnvironment();
+ }
+ }
+ }
return CI->doesNotAccessMemory() && !CI->getType()->isVoidTy();
+ }
return isa<CastInst>(Inst) || isa<UnaryOperator>(Inst) ||
isa<BinaryOperator>(Inst) || isa<GetElementPtrInst>(Inst) ||
isa<CmpInst>(Inst) || isa<SelectInst>(Inst) ||
@@ -280,6 +300,13 @@ static unsigned getHashValueImpl(SimpleValue Val) {
return hash_combine(II->getOpcode(), LHS, RHS);
}
+ // gc.relocate is 'special' call: its second and third operands are
+ // not real values, but indices into statepoint's argument list.
+ // Get values they point to.
+ if (const GCRelocateInst *GCR = dyn_cast<GCRelocateInst>(Inst))
+ return hash_combine(GCR->getOpcode(), GCR->getOperand(0),
+ GCR->getBasePtr(), GCR->getDerivedPtr());
+
// Mix in the opcode.
return hash_combine(
Inst->getOpcode(),
@@ -341,6 +368,13 @@ static bool isEqualImpl(SimpleValue LHS, SimpleValue RHS) {
LII->getArgOperand(1) == RII->getArgOperand(0);
}
+ // See comment above in `getHashValue()`.
+ if (const GCRelocateInst *GCR1 = dyn_cast<GCRelocateInst>(LHSI))
+ if (const GCRelocateInst *GCR2 = dyn_cast<GCRelocateInst>(RHSI))
+ return GCR1->getOperand(0) == GCR2->getOperand(0) &&
+ GCR1->getBasePtr() == GCR2->getBasePtr() &&
+ GCR1->getDerivedPtr() == GCR2->getDerivedPtr();
+
// Min/max can occur with commuted operands, non-canonical predicates,
// and/or non-canonical operands.
// Selects can be non-trivially equivalent via inverted conditions and swaps.
@@ -454,13 +488,6 @@ template <> struct DenseMapInfo<CallValue> {
unsigned DenseMapInfo<CallValue>::getHashValue(CallValue Val) {
Instruction *Inst = Val.Inst;
- // gc.relocate is 'special' call: its second and third operands are
- // not real values, but indices into statepoint's argument list.
- // Get values they point to.
- if (const GCRelocateInst *GCR = dyn_cast<GCRelocateInst>(Inst))
- return hash_combine(GCR->getOpcode(), GCR->getOperand(0),
- GCR->getBasePtr(), GCR->getDerivedPtr());
-
// Hash all of the operands as pointers and mix in the opcode.
return hash_combine(
Inst->getOpcode(),
@@ -472,13 +499,6 @@ bool DenseMapInfo<CallValue>::isEqual(CallValue LHS, CallValue RHS) {
if (LHS.isSentinel() || RHS.isSentinel())
return LHSI == RHSI;
- // See comment above in `getHashValue()`.
- if (const GCRelocateInst *GCR1 = dyn_cast<GCRelocateInst>(LHSI))
- if (const GCRelocateInst *GCR2 = dyn_cast<GCRelocateInst>(RHSI))
- return GCR1->getOperand(0) == GCR2->getOperand(0) &&
- GCR1->getBasePtr() == GCR2->getBasePtr() &&
- GCR1->getDerivedPtr() == GCR2->getDerivedPtr();
-
return LHSI->isIdenticalTo(RHSI);
}
@@ -1220,9 +1240,8 @@ bool EarlyCSE::processNode(DomTreeNode *Node) {
// they're marked as such to ensure preservation of control dependencies),
// and this pass will not bother with its removal. However, we should mark
// its condition as true for all dominated blocks.
- if (match(&Inst, m_Intrinsic<Intrinsic::assume>())) {
- auto *CondI =
- dyn_cast<Instruction>(cast<CallInst>(Inst).getArgOperand(0));
+ if (auto *Assume = dyn_cast<AssumeInst>(&Inst)) {
+ auto *CondI = dyn_cast<Instruction>(Assume->getArgOperand(0));
if (CondI && SimpleValue::canHandle(CondI)) {
LLVM_DEBUG(dbgs() << "EarlyCSE considering assumption: " << Inst
<< '\n');
@@ -1618,7 +1637,6 @@ PreservedAnalyses EarlyCSEPass::run(Function &F,
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
- PA.preserve<GlobalsAA>();
if (UseMemorySSA)
PA.preserve<MemorySSAAnalysis>();
return PA;
diff --git a/llvm/lib/Transforms/Scalar/Float2Int.cpp b/llvm/lib/Transforms/Scalar/Float2Int.cpp
index b6d82685e884..8a5d4f568774 100644
--- a/llvm/lib/Transforms/Scalar/Float2Int.cpp
+++ b/llvm/lib/Transforms/Scalar/Float2Int.cpp
@@ -13,8 +13,6 @@
#include "llvm/InitializePasses.h"
#include "llvm/Support/CommandLine.h"
-#define DEBUG_TYPE "float2int"
-
#include "llvm/Transforms/Scalar/Float2Int.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
@@ -31,6 +29,9 @@
#include "llvm/Transforms/Scalar.h"
#include <deque>
#include <functional> // For std::function
+
+#define DEBUG_TYPE "float2int"
+
using namespace llvm;
// The algorithm is simple. Start at instructions that convert from the
@@ -544,7 +545,6 @@ PreservedAnalyses Float2IntPass::run(Function &F, FunctionAnalysisManager &AM) {
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
- PA.preserve<GlobalsAA>();
return PA;
}
} // End namespace llvm
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index c6b6d75aefe8..16368aec7c3f 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -82,7 +82,6 @@
#include <cassert>
#include <cstdint>
#include <utility>
-#include <vector>
using namespace llvm;
using namespace llvm::gvn;
@@ -91,13 +90,14 @@ using namespace PatternMatch;
#define DEBUG_TYPE "gvn"
-STATISTIC(NumGVNInstr, "Number of instructions deleted");
-STATISTIC(NumGVNLoad, "Number of loads deleted");
-STATISTIC(NumGVNPRE, "Number of instructions PRE'd");
+STATISTIC(NumGVNInstr, "Number of instructions deleted");
+STATISTIC(NumGVNLoad, "Number of loads deleted");
+STATISTIC(NumGVNPRE, "Number of instructions PRE'd");
STATISTIC(NumGVNBlocks, "Number of blocks merged");
-STATISTIC(NumGVNSimpl, "Number of instructions simplified");
+STATISTIC(NumGVNSimpl, "Number of instructions simplified");
STATISTIC(NumGVNEqProp, "Number of equalities propagated");
-STATISTIC(NumPRELoad, "Number of loads PRE'd");
+STATISTIC(NumPRELoad, "Number of loads PRE'd");
+STATISTIC(NumPRELoopLoad, "Number of loop loads PRE'd");
STATISTIC(IsValueFullyAvailableInBlockNumSpeculationsMax,
"Number of blocks speculated as available in "
@@ -207,9 +207,9 @@ struct llvm::gvn::AvailableValue {
return Res;
}
- static AvailableValue getLoad(LoadInst *LI, unsigned Offset = 0) {
+ static AvailableValue getLoad(LoadInst *Load, unsigned Offset = 0) {
AvailableValue Res;
- Res.Val.setPointer(LI);
+ Res.Val.setPointer(Load);
Res.Val.setInt(LoadVal);
Res.Offset = Offset;
return Res;
@@ -245,7 +245,7 @@ struct llvm::gvn::AvailableValue {
/// Emit code at the specified insertion point to adjust the value defined
/// here to the specified type. This handles various coercion cases.
- Value *MaterializeAdjustedValue(LoadInst *LI, Instruction *InsertPt,
+ Value *MaterializeAdjustedValue(LoadInst *Load, Instruction *InsertPt,
GVN &gvn) const;
};
@@ -276,8 +276,8 @@ struct llvm::gvn::AvailableValueInBlock {
/// Emit code at the end of this block to adjust the value defined here to
/// the specified type. This handles various coercion cases.
- Value *MaterializeAdjustedValue(LoadInst *LI, GVN &gvn) const {
- return AV.MaterializeAdjustedValue(LI, BB->getTerminator(), gvn);
+ Value *MaterializeAdjustedValue(LoadInst *Load, GVN &gvn) const {
+ return AV.MaterializeAdjustedValue(Load, BB->getTerminator(), gvn);
}
};
@@ -289,9 +289,17 @@ GVN::Expression GVN::ValueTable::createExpr(Instruction *I) {
Expression e;
e.type = I->getType();
e.opcode = I->getOpcode();
- for (Instruction::op_iterator OI = I->op_begin(), OE = I->op_end();
- OI != OE; ++OI)
- e.varargs.push_back(lookupOrAdd(*OI));
+ if (const GCRelocateInst *GCR = dyn_cast<GCRelocateInst>(I)) {
+ // gc.relocate is 'special' call: its second and third operands are
+ // not real values, but indices into statepoint's argument list.
+ // Use the refered to values for purposes of identity.
+ e.varargs.push_back(lookupOrAdd(GCR->getOperand(0)));
+ e.varargs.push_back(lookupOrAdd(GCR->getBasePtr()));
+ e.varargs.push_back(lookupOrAdd(GCR->getDerivedPtr()));
+ } else {
+ for (Use &Op : I->operands())
+ e.varargs.push_back(lookupOrAdd(Op));
+ }
if (I->isCommutative()) {
// Ensure that commutative instructions that only differ by a permutation
// of their operands get the same value number by sorting the operand value
@@ -362,9 +370,8 @@ GVN::Expression GVN::ValueTable::createExtractvalueExpr(ExtractValueInst *EI) {
// Not a recognised intrinsic. Fall back to producing an extract value
// expression.
e.opcode = EI->getOpcode();
- for (Instruction::op_iterator OI = EI->op_begin(), OE = EI->op_end();
- OI != OE; ++OI)
- e.varargs.push_back(lookupOrAdd(*OI));
+ for (Use &Op : EI->operands())
+ e.varargs.push_back(lookupOrAdd(Op));
append_range(e.varargs, EI->indices());
@@ -669,7 +676,6 @@ PreservedAnalyses GVN::run(Function &F, FunctionAnalysisManager &AM) {
return PreservedAnalyses::all();
PreservedAnalyses PA;
PA.preserve<DominatorTreeAnalysis>();
- PA.preserve<GlobalsAA>();
PA.preserve<TargetLibraryAnalysis>();
if (MSSA)
PA.preserve<MemorySSAAnalysis>();
@@ -681,10 +687,9 @@ PreservedAnalyses GVN::run(Function &F, FunctionAnalysisManager &AM) {
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void GVN::dump(DenseMap<uint32_t, Value*>& d) const {
errs() << "{\n";
- for (DenseMap<uint32_t, Value*>::iterator I = d.begin(),
- E = d.end(); I != E; ++I) {
- errs() << I->first << "\n";
- I->second->dump();
+ for (auto &I : d) {
+ errs() << I.first << "\n";
+ I.second->dump();
}
errs() << "}\n";
}
@@ -727,7 +732,7 @@ static bool IsValueFullyAvailableInBlock(
Worklist.emplace_back(BB);
while (!Worklist.empty()) {
- BasicBlock *CurrBB = Worklist.pop_back_val(); // LIFO - depth-first!
+ BasicBlock *CurrBB = Worklist.pop_back_val(); // LoadFO - depth-first!
// Optimistically assume that the block is Speculatively Available and check
// to see if we already know about this block in one lookup.
std::pair<DenseMap<BasicBlock *, AvailabilityState>::iterator, bool> IV =
@@ -825,29 +830,33 @@ static bool IsValueFullyAvailableInBlock(
}
/// Given a set of loads specified by ValuesPerBlock,
-/// construct SSA form, allowing us to eliminate LI. This returns the value
-/// that should be used at LI's definition site.
-static Value *ConstructSSAForLoadSet(LoadInst *LI,
- SmallVectorImpl<AvailableValueInBlock> &ValuesPerBlock,
- GVN &gvn) {
+/// construct SSA form, allowing us to eliminate Load. This returns the value
+/// that should be used at Load's definition site.
+static Value *
+ConstructSSAForLoadSet(LoadInst *Load,
+ SmallVectorImpl<AvailableValueInBlock> &ValuesPerBlock,
+ GVN &gvn) {
// Check for the fully redundant, dominating load case. In this case, we can
// just use the dominating value directly.
if (ValuesPerBlock.size() == 1 &&
gvn.getDominatorTree().properlyDominates(ValuesPerBlock[0].BB,
- LI->getParent())) {
+ Load->getParent())) {
assert(!ValuesPerBlock[0].AV.isUndefValue() &&
"Dead BB dominate this block");
- return ValuesPerBlock[0].MaterializeAdjustedValue(LI, gvn);
+ return ValuesPerBlock[0].MaterializeAdjustedValue(Load, gvn);
}
// Otherwise, we have to construct SSA form.
SmallVector<PHINode*, 8> NewPHIs;
SSAUpdater SSAUpdate(&NewPHIs);
- SSAUpdate.Initialize(LI->getType(), LI->getName());
+ SSAUpdate.Initialize(Load->getType(), Load->getName());
for (const AvailableValueInBlock &AV : ValuesPerBlock) {
BasicBlock *BB = AV.BB;
+ if (AV.AV.isUndefValue())
+ continue;
+
if (SSAUpdate.HasValueForBlock(BB))
continue;
@@ -855,24 +864,24 @@ static Value *ConstructSSAForLoadSet(LoadInst *LI,
// available in is the block that the load is in, then don't add it as
// SSAUpdater will resolve the value to the relevant phi which may let it
// avoid phi construction entirely if there's actually only one value.
- if (BB == LI->getParent() &&
- ((AV.AV.isSimpleValue() && AV.AV.getSimpleValue() == LI) ||
- (AV.AV.isCoercedLoadValue() && AV.AV.getCoercedLoadValue() == LI)))
+ if (BB == Load->getParent() &&
+ ((AV.AV.isSimpleValue() && AV.AV.getSimpleValue() == Load) ||
+ (AV.AV.isCoercedLoadValue() && AV.AV.getCoercedLoadValue() == Load)))
continue;
- SSAUpdate.AddAvailableValue(BB, AV.MaterializeAdjustedValue(LI, gvn));
+ SSAUpdate.AddAvailableValue(BB, AV.MaterializeAdjustedValue(Load, gvn));
}
// Perform PHI construction.
- return SSAUpdate.GetValueInMiddleOfBlock(LI->getParent());
+ return SSAUpdate.GetValueInMiddleOfBlock(Load->getParent());
}
-Value *AvailableValue::MaterializeAdjustedValue(LoadInst *LI,
+Value *AvailableValue::MaterializeAdjustedValue(LoadInst *Load,
Instruction *InsertPt,
GVN &gvn) const {
Value *Res;
- Type *LoadTy = LI->getType();
- const DataLayout &DL = LI->getModule()->getDataLayout();
+ Type *LoadTy = Load->getType();
+ const DataLayout &DL = Load->getModule()->getDataLayout();
if (isSimpleValue()) {
Res = getSimpleValue();
if (Res->getType() != LoadTy) {
@@ -884,17 +893,17 @@ Value *AvailableValue::MaterializeAdjustedValue(LoadInst *LI,
<< "\n\n\n");
}
} else if (isCoercedLoadValue()) {
- LoadInst *Load = getCoercedLoadValue();
- if (Load->getType() == LoadTy && Offset == 0) {
- Res = Load;
+ LoadInst *CoercedLoad = getCoercedLoadValue();
+ if (CoercedLoad->getType() == LoadTy && Offset == 0) {
+ Res = CoercedLoad;
} else {
- Res = getLoadValueForLoad(Load, Offset, LoadTy, InsertPt, DL);
+ Res = getLoadValueForLoad(CoercedLoad, Offset, LoadTy, InsertPt, DL);
// We would like to use gvn.markInstructionForDeletion here, but we can't
// because the load is already memoized into the leader map table that GVN
// tracks. It is potentially possible to remove the load from the table,
// but then there all of the operations based on it would need to be
// rehashed. Just leave the dead load around.
- gvn.getMemDep().removeInstruction(Load);
+ gvn.getMemDep().removeInstruction(CoercedLoad);
LLVM_DEBUG(dbgs() << "GVN COERCED NONLOCAL LOAD:\nOffset: " << Offset
<< " " << *getCoercedLoadValue() << '\n'
<< *Res << '\n'
@@ -908,9 +917,7 @@ Value *AvailableValue::MaterializeAdjustedValue(LoadInst *LI,
<< *Res << '\n'
<< "\n\n\n");
} else {
- assert(isUndefValue() && "Should be UndefVal");
- LLVM_DEBUG(dbgs() << "GVN COERCED NONLOCAL Undef:\n";);
- return UndefValue::get(LoadTy);
+ llvm_unreachable("Should not materialize value from dead block");
}
assert(Res && "failed to materialize?");
return Res;
@@ -922,30 +929,70 @@ static bool isLifetimeStart(const Instruction *Inst) {
return false;
}
+/// Assuming To can be reached from both From and Between, does Between lie on
+/// every path from From to To?
+static bool liesBetween(const Instruction *From, Instruction *Between,
+ const Instruction *To, DominatorTree *DT) {
+ if (From->getParent() == Between->getParent())
+ return DT->dominates(From, Between);
+ SmallSet<BasicBlock *, 1> Exclusion;
+ Exclusion.insert(Between->getParent());
+ return !isPotentiallyReachable(From, To, &Exclusion, DT);
+}
+
/// Try to locate the three instruction involved in a missed
/// load-elimination case that is due to an intervening store.
-static void reportMayClobberedLoad(LoadInst *LI, MemDepResult DepInfo,
+static void reportMayClobberedLoad(LoadInst *Load, MemDepResult DepInfo,
DominatorTree *DT,
OptimizationRemarkEmitter *ORE) {
using namespace ore;
User *OtherAccess = nullptr;
- OptimizationRemarkMissed R(DEBUG_TYPE, "LoadClobbered", LI);
- R << "load of type " << NV("Type", LI->getType()) << " not eliminated"
+ OptimizationRemarkMissed R(DEBUG_TYPE, "LoadClobbered", Load);
+ R << "load of type " << NV("Type", Load->getType()) << " not eliminated"
<< setExtraArgs();
- for (auto *U : LI->getPointerOperand()->users())
- if (U != LI && (isa<LoadInst>(U) || isa<StoreInst>(U)) &&
- DT->dominates(cast<Instruction>(U), LI)) {
- // FIXME: for now give up if there are multiple memory accesses that
- // dominate the load. We need further analysis to decide which one is
- // that we're forwarding from.
- if (OtherAccess)
- OtherAccess = nullptr;
- else
+ for (auto *U : Load->getPointerOperand()->users()) {
+ if (U != Load && (isa<LoadInst>(U) || isa<StoreInst>(U)) &&
+ cast<Instruction>(U)->getFunction() == Load->getFunction() &&
+ DT->dominates(cast<Instruction>(U), Load)) {
+ // Use the most immediately dominating value
+ if (OtherAccess) {
+ if (DT->dominates(cast<Instruction>(OtherAccess), cast<Instruction>(U)))
+ OtherAccess = U;
+ else
+ assert(DT->dominates(cast<Instruction>(U),
+ cast<Instruction>(OtherAccess)));
+ } else
OtherAccess = U;
}
+ }
+
+ if (!OtherAccess) {
+ // There is no dominating use, check if we can find a closest non-dominating
+ // use that lies between any other potentially available use and Load.
+ for (auto *U : Load->getPointerOperand()->users()) {
+ if (U != Load && (isa<LoadInst>(U) || isa<StoreInst>(U)) &&
+ cast<Instruction>(U)->getFunction() == Load->getFunction() &&
+ isPotentiallyReachable(cast<Instruction>(U), Load, nullptr, DT)) {
+ if (OtherAccess) {
+ if (liesBetween(cast<Instruction>(OtherAccess), cast<Instruction>(U),
+ Load, DT)) {
+ OtherAccess = U;
+ } else if (!liesBetween(cast<Instruction>(U),
+ cast<Instruction>(OtherAccess), Load, DT)) {
+ // These uses are both partially available at Load were it not for
+ // the clobber, but neither lies strictly after the other.
+ OtherAccess = nullptr;
+ break;
+ } // else: keep current OtherAccess since it lies between U and Load
+ } else {
+ OtherAccess = U;
+ }
+ }
+ }
+ }
if (OtherAccess)
R << " in favor of " << NV("OtherAccess", OtherAccess);
@@ -955,13 +1002,13 @@ static void reportMayClobberedLoad(LoadInst *LI, MemDepResult DepInfo,
ORE->emit(R);
}
-bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
+bool GVN::AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo,
Value *Address, AvailableValue &Res) {
assert((DepInfo.isDef() || DepInfo.isClobber()) &&
"expected a local dependence");
- assert(LI->isUnordered() && "rules below are incorrect for ordered access");
+ assert(Load->isUnordered() && "rules below are incorrect for ordered access");
- const DataLayout &DL = LI->getModule()->getDataLayout();
+ const DataLayout &DL = Load->getModule()->getDataLayout();
Instruction *DepInst = DepInfo.getInst();
if (DepInfo.isClobber()) {
@@ -970,9 +1017,9 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// stored value.
if (StoreInst *DepSI = dyn_cast<StoreInst>(DepInst)) {
// Can't forward from non-atomic to atomic without violating memory model.
- if (Address && LI->isAtomic() <= DepSI->isAtomic()) {
+ if (Address && Load->isAtomic() <= DepSI->isAtomic()) {
int Offset =
- analyzeLoadFromClobberingStore(LI->getType(), Address, DepSI, DL);
+ analyzeLoadFromClobberingStore(Load->getType(), Address, DepSI, DL);
if (Offset != -1) {
Res = AvailableValue::get(DepSI->getValueOperand(), Offset);
return true;
@@ -984,16 +1031,29 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// load i32* P
// load i8* (P+1)
// if we have this, replace the later with an extraction from the former.
- if (LoadInst *DepLI = dyn_cast<LoadInst>(DepInst)) {
+ if (LoadInst *DepLoad = dyn_cast<LoadInst>(DepInst)) {
// If this is a clobber and L is the first instruction in its block, then
// we have the first instruction in the entry block.
// Can't forward from non-atomic to atomic without violating memory model.
- if (DepLI != LI && Address && LI->isAtomic() <= DepLI->isAtomic()) {
- int Offset =
- analyzeLoadFromClobberingLoad(LI->getType(), Address, DepLI, DL);
+ if (DepLoad != Load && Address &&
+ Load->isAtomic() <= DepLoad->isAtomic()) {
+ Type *LoadType = Load->getType();
+ int Offset = -1;
+ // If MD reported clobber, check it was nested.
+ if (DepInfo.isClobber() &&
+ canCoerceMustAliasedValueToLoad(DepLoad, LoadType, DL)) {
+ const auto ClobberOff = MD->getClobberOffset(DepLoad);
+ // GVN has no deal with a negative offset.
+ Offset = (ClobberOff == None || ClobberOff.getValue() < 0)
+ ? -1
+ : ClobberOff.getValue();
+ }
+ if (Offset == -1)
+ Offset =
+ analyzeLoadFromClobberingLoad(LoadType, Address, DepLoad, DL);
if (Offset != -1) {
- Res = AvailableValue::getLoad(DepLI, Offset);
+ Res = AvailableValue::getLoad(DepLoad, Offset);
return true;
}
}
@@ -1002,8 +1062,8 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// If the clobbering value is a memset/memcpy/memmove, see if we can
// forward a value on from it.
if (MemIntrinsic *DepMI = dyn_cast<MemIntrinsic>(DepInst)) {
- if (Address && !LI->isAtomic()) {
- int Offset = analyzeLoadFromClobberingMemInst(LI->getType(), Address,
+ if (Address && !Load->isAtomic()) {
+ int Offset = analyzeLoadFromClobberingMemInst(Load->getType(), Address,
DepMI, DL);
if (Offset != -1) {
Res = AvailableValue::getMI(DepMI, Offset);
@@ -1014,10 +1074,10 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// Nothing known about this clobber, have to be conservative
LLVM_DEBUG(
// fast print dep, using operator<< on instruction is too slow.
- dbgs() << "GVN: load "; LI->printAsOperand(dbgs());
+ dbgs() << "GVN: load "; Load->printAsOperand(dbgs());
dbgs() << " is clobbered by " << *DepInst << '\n';);
if (ORE->allowExtraAnalysis(DEBUG_TYPE))
- reportMayClobberedLoad(LI, DepInfo, DT, ORE);
+ reportMayClobberedLoad(Load, DepInfo, DT, ORE);
return false;
}
@@ -1028,13 +1088,13 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
isAlignedAllocLikeFn(DepInst, TLI) ||
// Loading immediately after lifetime begin -> undef.
isLifetimeStart(DepInst)) {
- Res = AvailableValue::get(UndefValue::get(LI->getType()));
+ Res = AvailableValue::get(UndefValue::get(Load->getType()));
return true;
}
// Loading from calloc (which zero initializes memory) -> zero
if (isCallocLikeFn(DepInst, TLI)) {
- Res = AvailableValue::get(Constant::getNullValue(LI->getType()));
+ Res = AvailableValue::get(Constant::getNullValue(Load->getType()));
return true;
}
@@ -1042,12 +1102,12 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// Reject loads and stores that are to the same address but are of
// different types if we have to. If the stored value is convertable to
// the loaded value, we can reuse it.
- if (!canCoerceMustAliasedValueToLoad(S->getValueOperand(), LI->getType(),
+ if (!canCoerceMustAliasedValueToLoad(S->getValueOperand(), Load->getType(),
DL))
return false;
// Can't forward from non-atomic to atomic without violating memory model.
- if (S->isAtomic() < LI->isAtomic())
+ if (S->isAtomic() < Load->isAtomic())
return false;
Res = AvailableValue::get(S->getValueOperand());
@@ -1058,11 +1118,11 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// If the types mismatch and we can't handle it, reject reuse of the load.
// If the stored value is larger or equal to the loaded value, we can reuse
// it.
- if (!canCoerceMustAliasedValueToLoad(LD, LI->getType(), DL))
+ if (!canCoerceMustAliasedValueToLoad(LD, Load->getType(), DL))
return false;
// Can't forward from non-atomic to atomic without violating memory model.
- if (LD->isAtomic() < LI->isAtomic())
+ if (LD->isAtomic() < Load->isAtomic())
return false;
Res = AvailableValue::getLoad(LD);
@@ -1072,12 +1132,12 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo,
// Unknown def - must be conservative
LLVM_DEBUG(
// fast print dep, using operator<< on instruction is too slow.
- dbgs() << "GVN: load "; LI->printAsOperand(dbgs());
+ dbgs() << "GVN: load "; Load->printAsOperand(dbgs());
dbgs() << " has unknown def " << *DepInst << '\n';);
return false;
}
-void GVN::AnalyzeLoadAvailability(LoadInst *LI, LoadDepVect &Deps,
+void GVN::AnalyzeLoadAvailability(LoadInst *Load, LoadDepVect &Deps,
AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks) {
// Filter out useless results (non-locals, etc). Keep track of the blocks
@@ -1107,7 +1167,7 @@ void GVN::AnalyzeLoadAvailability(LoadInst *LI, LoadDepVect &Deps,
Value *Address = Deps[i].getAddress();
AvailableValue AV;
- if (AnalyzeLoadAvailability(LI, DepInfo, Address, AV)) {
+ if (AnalyzeLoadAvailability(Load, DepInfo, Address, AV)) {
// subtlety: because we know this was a non-local dependency, we know
// it's safe to materialize anywhere between the instruction within
// DepInfo and the end of it's block.
@@ -1122,7 +1182,82 @@ void GVN::AnalyzeLoadAvailability(LoadInst *LI, LoadDepVect &Deps,
"post condition violation");
}
-bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
+void GVN::eliminatePartiallyRedundantLoad(
+ LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
+ MapVector<BasicBlock *, Value *> &AvailableLoads) {
+ for (const auto &AvailableLoad : AvailableLoads) {
+ BasicBlock *UnavailableBlock = AvailableLoad.first;
+ Value *LoadPtr = AvailableLoad.second;
+
+ auto *NewLoad =
+ new LoadInst(Load->getType(), LoadPtr, Load->getName() + ".pre",
+ Load->isVolatile(), Load->getAlign(), Load->getOrdering(),
+ Load->getSyncScopeID(), UnavailableBlock->getTerminator());
+ NewLoad->setDebugLoc(Load->getDebugLoc());
+ if (MSSAU) {
+ auto *MSSA = MSSAU->getMemorySSA();
+ // Get the defining access of the original load or use the load if it is a
+ // MemoryDef (e.g. because it is volatile). The inserted loads are
+ // guaranteed to load from the same definition.
+ auto *LoadAcc = MSSA->getMemoryAccess(Load);
+ auto *DefiningAcc =
+ isa<MemoryDef>(LoadAcc) ? LoadAcc : LoadAcc->getDefiningAccess();
+ auto *NewAccess = MSSAU->createMemoryAccessInBB(
+ NewLoad, DefiningAcc, NewLoad->getParent(),
+ MemorySSA::BeforeTerminator);
+ if (auto *NewDef = dyn_cast<MemoryDef>(NewAccess))
+ MSSAU->insertDef(NewDef, /*RenameUses=*/true);
+ else
+ MSSAU->insertUse(cast<MemoryUse>(NewAccess), /*RenameUses=*/true);
+ }
+
+ // Transfer the old load's AA tags to the new load.
+ AAMDNodes Tags;
+ Load->getAAMetadata(Tags);
+ if (Tags)
+ NewLoad->setAAMetadata(Tags);
+
+ if (auto *MD = Load->getMetadata(LLVMContext::MD_invariant_load))
+ NewLoad->setMetadata(LLVMContext::MD_invariant_load, MD);
+ if (auto *InvGroupMD = Load->getMetadata(LLVMContext::MD_invariant_group))
+ NewLoad->setMetadata(LLVMContext::MD_invariant_group, InvGroupMD);
+ if (auto *RangeMD = Load->getMetadata(LLVMContext::MD_range))
+ NewLoad->setMetadata(LLVMContext::MD_range, RangeMD);
+ if (auto *AccessMD = Load->getMetadata(LLVMContext::MD_access_group))
+ if (LI &&
+ LI->getLoopFor(Load->getParent()) == LI->getLoopFor(UnavailableBlock))
+ NewLoad->setMetadata(LLVMContext::MD_access_group, AccessMD);
+
+ // We do not propagate the old load's debug location, because the new
+ // load now lives in a different BB, and we want to avoid a jumpy line
+ // table.
+ // FIXME: How do we retain source locations without causing poor debugging
+ // behavior?
+
+ // Add the newly created load.
+ ValuesPerBlock.push_back(
+ AvailableValueInBlock::get(UnavailableBlock, NewLoad));
+ MD->invalidateCachedPointerInfo(LoadPtr);
+ LLVM_DEBUG(dbgs() << "GVN INSERTED " << *NewLoad << '\n');
+ }
+
+ // Perform PHI construction.
+ Value *V = ConstructSSAForLoadSet(Load, ValuesPerBlock, *this);
+ Load->replaceAllUsesWith(V);
+ if (isa<PHINode>(V))
+ V->takeName(Load);
+ if (Instruction *I = dyn_cast<Instruction>(V))
+ I->setDebugLoc(Load->getDebugLoc());
+ if (V->getType()->isPtrOrPtrVectorTy())
+ MD->invalidateCachedPointerInfo(V);
+ markInstructionForDeletion(Load);
+ ORE->emit([&]() {
+ return OptimizationRemark(DEBUG_TYPE, "LoadPRE", Load)
+ << "load eliminated by PRE";
+ });
+}
+
+bool GVN::PerformLoadPRE(LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
UnavailBlkVect &UnavailableBlocks) {
// Okay, we have *some* definitions of the value. This means that the value
// is available in some of our (transitive) predecessors. Lets think about
@@ -1137,7 +1272,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// Let's find the first basic block with more than one predecessor. Walk
// backwards through predecessors if needed.
- BasicBlock *LoadBB = LI->getParent();
+ BasicBlock *LoadBB = Load->getParent();
BasicBlock *TmpBB = LoadBB;
// Check that there is no implicit control flow instructions above our load in
@@ -1156,7 +1291,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// access the array.
// Check that there is no guard in this block above our instruction.
bool MustEnsureSafetyOfSpeculativeExecution =
- ICF->isDominatedByICFIFromSameBlock(LI);
+ ICF->isDominatedByICFIFromSameBlock(Load);
while (TmpBB->getSinglePredecessor()) {
TmpBB = TmpBB->getSinglePredecessor();
@@ -1197,7 +1332,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
if (Pred->getTerminator()->isEHPad()) {
LLVM_DEBUG(
dbgs() << "COULD NOT PRE LOAD BECAUSE OF AN EH PAD PREDECESSOR '"
- << Pred->getName() << "': " << *LI << '\n');
+ << Pred->getName() << "': " << *Load << '\n');
return false;
}
@@ -1209,7 +1344,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
if (isa<IndirectBrInst>(Pred->getTerminator())) {
LLVM_DEBUG(
dbgs() << "COULD NOT PRE LOAD BECAUSE OF INDBR CRITICAL EDGE '"
- << Pred->getName() << "': " << *LI << '\n');
+ << Pred->getName() << "': " << *Load << '\n');
return false;
}
@@ -1217,14 +1352,14 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
if (isa<CallBrInst>(Pred->getTerminator())) {
LLVM_DEBUG(
dbgs() << "COULD NOT PRE LOAD BECAUSE OF CALLBR CRITICAL EDGE '"
- << Pred->getName() << "': " << *LI << '\n');
+ << Pred->getName() << "': " << *Load << '\n');
return false;
}
if (LoadBB->isEHPad()) {
LLVM_DEBUG(
dbgs() << "COULD NOT PRE LOAD BECAUSE OF AN EH PAD CRITICAL EDGE '"
- << Pred->getName() << "': " << *LI << '\n');
+ << Pred->getName() << "': " << *Load << '\n');
return false;
}
@@ -1234,7 +1369,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
LLVM_DEBUG(
dbgs()
<< "COULD NOT PRE LOAD BECAUSE OF A BACKEDGE CRITICAL EDGE '"
- << Pred->getName() << "': " << *LI << '\n');
+ << Pred->getName() << "': " << *Load << '\n');
return false;
}
@@ -1252,7 +1387,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// If this load is unavailable in multiple predecessors, reject it.
// FIXME: If we could restructure the CFG, we could make a common pred with
- // all the preds that don't have an available LI and insert a new load into
+ // all the preds that don't have an available Load and insert a new load into
// that one block.
if (NumUnavailablePreds != 1)
return false;
@@ -1261,10 +1396,10 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// to speculatively execute the load at that points.
if (MustEnsureSafetyOfSpeculativeExecution) {
if (CriticalEdgePred.size())
- if (!isSafeToSpeculativelyExecute(LI, LoadBB->getFirstNonPHI(), DT))
+ if (!isSafeToSpeculativelyExecute(Load, LoadBB->getFirstNonPHI(), DT))
return false;
for (auto &PL : PredLoads)
- if (!isSafeToSpeculativelyExecute(LI, PL.first->getTerminator(), DT))
+ if (!isSafeToSpeculativelyExecute(Load, PL.first->getTerminator(), DT))
return false;
}
@@ -1279,21 +1414,21 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// Check if the load can safely be moved to all the unavailable predecessors.
bool CanDoPRE = true;
- const DataLayout &DL = LI->getModule()->getDataLayout();
+ const DataLayout &DL = Load->getModule()->getDataLayout();
SmallVector<Instruction*, 8> NewInsts;
for (auto &PredLoad : PredLoads) {
BasicBlock *UnavailablePred = PredLoad.first;
// Do PHI translation to get its value in the predecessor if necessary. The
// returned pointer (if non-null) is guaranteed to dominate UnavailablePred.
- // We do the translation for each edge we skipped by going from LI's block
+ // We do the translation for each edge we skipped by going from Load's block
// to LoadBB, otherwise we might miss pieces needing translation.
// If all preds have a single successor, then we know it is safe to insert
// the load on the pred (?!?), so we can insert code to materialize the
// pointer if it is not available.
- Value *LoadPtr = LI->getPointerOperand();
- BasicBlock *Cur = LI->getParent();
+ Value *LoadPtr = Load->getPointerOperand();
+ BasicBlock *Cur = Load->getParent();
while (Cur != LoadBB) {
PHITransAddr Address(LoadPtr, DL, AC);
LoadPtr = Address.PHITranslateWithInsertion(
@@ -1314,7 +1449,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// we fail PRE.
if (!LoadPtr) {
LLVM_DEBUG(dbgs() << "COULDN'T INSERT PHI TRANSLATED VALUE OF: "
- << *LI->getPointerOperand() << "\n");
+ << *Load->getPointerOperand() << "\n");
CanDoPRE = false;
break;
}
@@ -1339,10 +1474,10 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
// Okay, we can eliminate this load by inserting a reload in the predecessor
// and using PHI construction to get the value in the other predecessors, do
// it.
- LLVM_DEBUG(dbgs() << "GVN REMOVING PRE LOAD: " << *LI << '\n');
- LLVM_DEBUG(if (!NewInsts.empty()) dbgs()
- << "INSERTED " << NewInsts.size() << " INSTS: " << *NewInsts.back()
- << '\n');
+ LLVM_DEBUG(dbgs() << "GVN REMOVING PRE LOAD: " << *Load << '\n');
+ LLVM_DEBUG(if (!NewInsts.empty()) dbgs() << "INSERTED " << NewInsts.size()
+ << " INSTS: " << *NewInsts.back()
+ << '\n');
// Assign value numbers to the new instructions.
for (Instruction *I : NewInsts) {
@@ -1358,83 +1493,96 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock,
VN.lookupOrAdd(I);
}
- for (const auto &PredLoad : PredLoads) {
- BasicBlock *UnavailablePred = PredLoad.first;
- Value *LoadPtr = PredLoad.second;
+ eliminatePartiallyRedundantLoad(Load, ValuesPerBlock, PredLoads);
+ ++NumPRELoad;
+ return true;
+}
- auto *NewLoad = new LoadInst(
- LI->getType(), LoadPtr, LI->getName() + ".pre", LI->isVolatile(),
- LI->getAlign(), LI->getOrdering(), LI->getSyncScopeID(),
- UnavailablePred->getTerminator());
- NewLoad->setDebugLoc(LI->getDebugLoc());
- if (MSSAU) {
- auto *MSSA = MSSAU->getMemorySSA();
- // Get the defining access of the original load or use the load if it is a
- // MemoryDef (e.g. because it is volatile). The inserted loads are
- // guaranteed to load from the same definition.
- auto *LIAcc = MSSA->getMemoryAccess(LI);
- auto *DefiningAcc =
- isa<MemoryDef>(LIAcc) ? LIAcc : LIAcc->getDefiningAccess();
- auto *NewAccess = MSSAU->createMemoryAccessInBB(
- NewLoad, DefiningAcc, NewLoad->getParent(),
- MemorySSA::BeforeTerminator);
- if (auto *NewDef = dyn_cast<MemoryDef>(NewAccess))
- MSSAU->insertDef(NewDef, /*RenameUses=*/true);
- else
- MSSAU->insertUse(cast<MemoryUse>(NewAccess), /*RenameUses=*/true);
- }
+bool GVN::performLoopLoadPRE(LoadInst *Load, AvailValInBlkVect &ValuesPerBlock,
+ UnavailBlkVect &UnavailableBlocks) {
+ if (!LI)
+ return false;
- // Transfer the old load's AA tags to the new load.
- AAMDNodes Tags;
- LI->getAAMetadata(Tags);
- if (Tags)
- NewLoad->setAAMetadata(Tags);
+ const Loop *L = LI->getLoopFor(Load->getParent());
+ // TODO: Generalize to other loop blocks that dominate the latch.
+ if (!L || L->getHeader() != Load->getParent())
+ return false;
- if (auto *MD = LI->getMetadata(LLVMContext::MD_invariant_load))
- NewLoad->setMetadata(LLVMContext::MD_invariant_load, MD);
- if (auto *InvGroupMD = LI->getMetadata(LLVMContext::MD_invariant_group))
- NewLoad->setMetadata(LLVMContext::MD_invariant_group, InvGroupMD);
- if (auto *RangeMD = LI->getMetadata(LLVMContext::MD_range))
- NewLoad->setMetadata(LLVMContext::MD_range, RangeMD);
+ BasicBlock *Preheader = L->getLoopPreheader();
+ BasicBlock *Latch = L->getLoopLatch();
+ if (!Preheader || !Latch)
+ return false;
- // We do not propagate the old load's debug location, because the new
- // load now lives in a different BB, and we want to avoid a jumpy line
- // table.
- // FIXME: How do we retain source locations without causing poor debugging
- // behavior?
+ Value *LoadPtr = Load->getPointerOperand();
+ // Must be available in preheader.
+ if (!L->isLoopInvariant(LoadPtr))
+ return false;
- // Add the newly created load.
- ValuesPerBlock.push_back(AvailableValueInBlock::get(UnavailablePred,
- NewLoad));
- MD->invalidateCachedPointerInfo(LoadPtr);
- LLVM_DEBUG(dbgs() << "GVN INSERTED " << *NewLoad << '\n');
+ // We plan to hoist the load to preheader without introducing a new fault.
+ // In order to do it, we need to prove that we cannot side-exit the loop
+ // once loop header is first entered before execution of the load.
+ if (ICF->isDominatedByICFIFromSameBlock(Load))
+ return false;
+
+ BasicBlock *LoopBlock = nullptr;
+ for (auto *Blocker : UnavailableBlocks) {
+ // Blockers from outside the loop are handled in preheader.
+ if (!L->contains(Blocker))
+ continue;
+
+ // Only allow one loop block. Loop header is not less frequently executed
+ // than each loop block, and likely it is much more frequently executed. But
+ // in case of multiple loop blocks, we need extra information (such as block
+ // frequency info) to understand whether it is profitable to PRE into
+ // multiple loop blocks.
+ if (LoopBlock)
+ return false;
+
+ // Do not sink into inner loops. This may be non-profitable.
+ if (L != LI->getLoopFor(Blocker))
+ return false;
+
+ // Blocks that dominate the latch execute on every single iteration, maybe
+ // except the last one. So PREing into these blocks doesn't make much sense
+ // in most cases. But the blocks that do not necessarily execute on each
+ // iteration are sometimes much colder than the header, and this is when
+ // PRE is potentially profitable.
+ if (DT->dominates(Blocker, Latch))
+ return false;
+
+ // Make sure that the terminator itself doesn't clobber.
+ if (Blocker->getTerminator()->mayWriteToMemory())
+ return false;
+
+ LoopBlock = Blocker;
}
- // Perform PHI construction.
- Value *V = ConstructSSAForLoadSet(LI, ValuesPerBlock, *this);
- LI->replaceAllUsesWith(V);
- if (isa<PHINode>(V))
- V->takeName(LI);
- if (Instruction *I = dyn_cast<Instruction>(V))
- I->setDebugLoc(LI->getDebugLoc());
- if (V->getType()->isPtrOrPtrVectorTy())
- MD->invalidateCachedPointerInfo(V);
- markInstructionForDeletion(LI);
- ORE->emit([&]() {
- return OptimizationRemark(DEBUG_TYPE, "LoadPRE", LI)
- << "load eliminated by PRE";
- });
- ++NumPRELoad;
+ if (!LoopBlock)
+ return false;
+
+ // Make sure the memory at this pointer cannot be freed, therefore we can
+ // safely reload from it after clobber.
+ if (LoadPtr->canBeFreed())
+ return false;
+
+ // TODO: Support critical edge splitting if blocker has more than 1 successor.
+ MapVector<BasicBlock *, Value *> AvailableLoads;
+ AvailableLoads[LoopBlock] = LoadPtr;
+ AvailableLoads[Preheader] = LoadPtr;
+
+ LLVM_DEBUG(dbgs() << "GVN REMOVING PRE LOOP LOAD: " << *Load << '\n');
+ eliminatePartiallyRedundantLoad(Load, ValuesPerBlock, AvailableLoads);
+ ++NumPRELoopLoad;
return true;
}
-static void reportLoadElim(LoadInst *LI, Value *AvailableValue,
+static void reportLoadElim(LoadInst *Load, Value *AvailableValue,
OptimizationRemarkEmitter *ORE) {
using namespace ore;
ORE->emit([&]() {
- return OptimizationRemark(DEBUG_TYPE, "LoadElim", LI)
- << "load of type " << NV("Type", LI->getType()) << " eliminated"
+ return OptimizationRemark(DEBUG_TYPE, "LoadElim", Load)
+ << "load of type " << NV("Type", Load->getType()) << " eliminated"
<< setExtraArgs() << " in favor of "
<< NV("InfavorOfValue", AvailableValue);
});
@@ -1442,17 +1590,17 @@ static void reportLoadElim(LoadInst *LI, Value *AvailableValue,
/// Attempt to eliminate a load whose dependencies are
/// non-local by performing PHI construction.
-bool GVN::processNonLocalLoad(LoadInst *LI) {
+bool GVN::processNonLocalLoad(LoadInst *Load) {
// non-local speculations are not allowed under asan.
- if (LI->getParent()->getParent()->hasFnAttribute(
+ if (Load->getParent()->getParent()->hasFnAttribute(
Attribute::SanitizeAddress) ||
- LI->getParent()->getParent()->hasFnAttribute(
+ Load->getParent()->getParent()->hasFnAttribute(
Attribute::SanitizeHWAddress))
return false;
// Step 1: Find the non-local dependencies of the load.
LoadDepVect Deps;
- MD->getNonLocalPointerDependency(LI, Deps);
+ MD->getNonLocalPointerDependency(Load, Deps);
// If we had to process more than one hundred blocks to find the
// dependencies, this load isn't worth worrying about. Optimizing
@@ -1465,14 +1613,15 @@ bool GVN::processNonLocalLoad(LoadInst *LI) {
// clobber in the current block. Reject this early.
if (NumDeps == 1 &&
!Deps[0].getResult().isDef() && !Deps[0].getResult().isClobber()) {
- LLVM_DEBUG(dbgs() << "GVN: non-local load "; LI->printAsOperand(dbgs());
+ LLVM_DEBUG(dbgs() << "GVN: non-local load "; Load->printAsOperand(dbgs());
dbgs() << " has unknown dependencies\n";);
return false;
}
bool Changed = false;
// If this load follows a GEP, see if we can PRE the indices before analyzing.
- if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(LI->getOperand(0))) {
+ if (GetElementPtrInst *GEP =
+ dyn_cast<GetElementPtrInst>(Load->getOperand(0))) {
for (GetElementPtrInst::op_iterator OI = GEP->idx_begin(),
OE = GEP->idx_end();
OI != OE; ++OI)
@@ -1483,7 +1632,7 @@ bool GVN::processNonLocalLoad(LoadInst *LI) {
// Step 2: Analyze the availability of the load
AvailValInBlkVect ValuesPerBlock;
UnavailBlkVect UnavailableBlocks;
- AnalyzeLoadAvailability(LI, Deps, ValuesPerBlock, UnavailableBlocks);
+ AnalyzeLoadAvailability(Load, Deps, ValuesPerBlock, UnavailableBlocks);
// If we have no predecessors that produce a known value for this load, exit
// early.
@@ -1496,36 +1645,36 @@ bool GVN::processNonLocalLoad(LoadInst *LI) {
// load, then it is fully redundant and we can use PHI insertion to compute
// its value. Insert PHIs and remove the fully redundant value now.
if (UnavailableBlocks.empty()) {
- LLVM_DEBUG(dbgs() << "GVN REMOVING NONLOCAL LOAD: " << *LI << '\n');
+ LLVM_DEBUG(dbgs() << "GVN REMOVING NONLOCAL LOAD: " << *Load << '\n');
// Perform PHI construction.
- Value *V = ConstructSSAForLoadSet(LI, ValuesPerBlock, *this);
- LI->replaceAllUsesWith(V);
+ Value *V = ConstructSSAForLoadSet(Load, ValuesPerBlock, *this);
+ Load->replaceAllUsesWith(V);
if (isa<PHINode>(V))
- V->takeName(LI);
+ V->takeName(Load);
if (Instruction *I = dyn_cast<Instruction>(V))
// If instruction I has debug info, then we should not update it.
// Also, if I has a null DebugLoc, then it is still potentially incorrect
- // to propagate LI's DebugLoc because LI may not post-dominate I.
- if (LI->getDebugLoc() && LI->getParent() == I->getParent())
- I->setDebugLoc(LI->getDebugLoc());
+ // to propagate Load's DebugLoc because Load may not post-dominate I.
+ if (Load->getDebugLoc() && Load->getParent() == I->getParent())
+ I->setDebugLoc(Load->getDebugLoc());
if (V->getType()->isPtrOrPtrVectorTy())
MD->invalidateCachedPointerInfo(V);
- markInstructionForDeletion(LI);
+ markInstructionForDeletion(Load);
++NumGVNLoad;
- reportLoadElim(LI, V, ORE);
+ reportLoadElim(Load, V, ORE);
return true;
}
// Step 4: Eliminate partial redundancy.
if (!isPREEnabled() || !isLoadPREEnabled())
return Changed;
- if (!isLoadInLoopPREEnabled() && this->LI &&
- this->LI->getLoopFor(LI->getParent()))
+ if (!isLoadInLoopPREEnabled() && LI && LI->getLoopFor(Load->getParent()))
return Changed;
- return Changed || PerformLoadPRE(LI, ValuesPerBlock, UnavailableBlocks);
+ return Changed || PerformLoadPRE(Load, ValuesPerBlock, UnavailableBlocks) ||
+ performLoopLoadPRE(Load, ValuesPerBlock, UnavailableBlocks);
}
static bool impliesEquivalanceIfTrue(CmpInst* Cmp) {
@@ -1589,9 +1738,7 @@ static bool hasUsersIn(Value *V, BasicBlock *BB) {
return false;
}
-bool GVN::processAssumeIntrinsic(IntrinsicInst *IntrinsicI) {
- assert(IntrinsicI->getIntrinsicID() == Intrinsic::assume &&
- "This function can only be called with llvm.assume intrinsic");
+bool GVN::processAssumeIntrinsic(AssumeInst *IntrinsicI) {
Value *V = IntrinsicI->getArgOperand(0);
if (ConstantInt *Cond = dyn_cast<ConstantInt>(V)) {
@@ -1776,7 +1923,7 @@ bool GVN::processLoad(LoadInst *L) {
MSSAU->removeMemoryAccess(L);
++NumGVNLoad;
reportLoadElim(L, AvailableValue, ORE);
- // Tell MDA to rexamine the reused pointer since we might have more
+ // Tell MDA to reexamine the reused pointer since we might have more
// information after forwarding it.
if (MD && AvailableValue->getType()->isPtrOrPtrVectorTy())
MD->invalidateCachedPointerInfo(AvailableValue);
@@ -1852,8 +1999,8 @@ bool GVN::ValueTable::areCallValsEqual(uint32_t Num, uint32_t NewNum,
MD->getNonLocalCallDependency(Call);
// Check to see if the Call has no function local clobber.
- for (unsigned i = 0; i < deps.size(); i++) {
- if (deps[i].getResult().isNonFuncLocal())
+ for (const NonLocalDepEntry &D : deps) {
+ if (D.getResult().isNonFuncLocal())
return true;
}
return false;
@@ -2157,6 +2304,9 @@ bool GVN::processInstruction(Instruction *I) {
if (Value *V = SimplifyInstruction(I, {DL, TLI, DT, AC})) {
bool Changed = false;
if (!I->use_empty()) {
+ // Simplification can cause a special instruction to become not special.
+ // For example, devirtualization to a willreturn function.
+ ICF->removeUsersOf(I);
I->replaceAllUsesWith(V);
Changed = true;
}
@@ -2172,16 +2322,15 @@ bool GVN::processInstruction(Instruction *I) {
}
}
- if (IntrinsicInst *IntrinsicI = dyn_cast<IntrinsicInst>(I))
- if (IntrinsicI->getIntrinsicID() == Intrinsic::assume)
- return processAssumeIntrinsic(IntrinsicI);
+ if (auto *Assume = dyn_cast<AssumeInst>(I))
+ return processAssumeIntrinsic(Assume);
- if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
- if (processLoad(LI))
+ if (LoadInst *Load = dyn_cast<LoadInst>(I)) {
+ if (processLoad(Load))
return true;
- unsigned Num = VN.lookupOrAdd(LI);
- addToLeaderTable(Num, LI, LI->getParent());
+ unsigned Num = VN.lookupOrAdd(Load);
+ addToLeaderTable(Num, Load, Load->getParent());
return false;
}
@@ -2365,6 +2514,12 @@ bool GVN::processBlock(BasicBlock *BB) {
ReplaceOperandsWithMap.clear();
bool ChangedFunction = false;
+ // Since we may not have visited the input blocks of the phis, we can't
+ // use our normal hash approach for phis. Instead, simply look for
+ // obvious duplicates. The first pass of GVN will tend to create
+ // identical phis, and the second or later passes can eliminate them.
+ ChangedFunction |= EliminateDuplicatePHINodes(BB);
+
for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();
BI != BE;) {
if (!ReplaceOperandsWithMap.empty())
@@ -2447,6 +2602,8 @@ bool GVN::performScalarPREInsertion(Instruction *Instr, BasicBlock *Pred,
Instr->setName(Instr->getName() + ".pre");
Instr->setDebugLoc(Instr->getDebugLoc());
+ ICF->insertInstructionTo(Instr, Pred);
+
unsigned Num = VN.lookupOrAdd(Instr);
VN.add(Instr, Num);
@@ -2735,9 +2892,8 @@ void GVN::verifyRemoved(const Instruction *Inst) const {
// Walk through the value number scope to make sure the instruction isn't
// ferreted away in it.
- for (DenseMap<uint32_t, LeaderTableEntry>::const_iterator
- I = LeaderTable.begin(), E = LeaderTable.end(); I != E; ++I) {
- const LeaderTableEntry *Node = &I->second;
+ for (const auto &I : LeaderTable) {
+ const LeaderTableEntry *Node = &I.second;
assert(Node->Val != Inst && "Inst still in value numbering scope!");
while (Node->Next) {
@@ -2795,9 +2951,7 @@ void GVN::addDeadBlock(BasicBlock *BB) {
// For the dead blocks' live successors, update their phi nodes by replacing
// the operands corresponding to dead blocks with UndefVal.
- for(SmallSetVector<BasicBlock *, 4>::iterator I = DF.begin(), E = DF.end();
- I != E; I++) {
- BasicBlock *B = *I;
+ for (BasicBlock *B : DF) {
if (DeadBlocks.count(B))
continue;
diff --git a/llvm/lib/Transforms/Scalar/GVNHoist.cpp b/llvm/lib/Transforms/Scalar/GVNHoist.cpp
index 8d0bd5674964..790d71992da4 100644
--- a/llvm/lib/Transforms/Scalar/GVNHoist.cpp
+++ b/llvm/lib/Transforms/Scalar/GVNHoist.cpp
@@ -1243,7 +1243,6 @@ PreservedAnalyses GVNHoistPass::run(Function &F, FunctionAnalysisManager &AM) {
PreservedAnalyses PA;
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<MemorySSAAnalysis>();
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/GVNSink.cpp b/llvm/lib/Transforms/Scalar/GVNSink.cpp
index aef927ab6558..e612a82fc89a 100644
--- a/llvm/lib/Transforms/Scalar/GVNSink.cpp
+++ b/llvm/lib/Transforms/Scalar/GVNSink.cpp
@@ -912,10 +912,7 @@ PreservedAnalyses GVNSinkPass::run(Function &F, FunctionAnalysisManager &AM) {
GVNSink G;
if (!G.run(F))
return PreservedAnalyses::all();
-
- PreservedAnalyses PA;
- PA.preserve<GlobalsAA>();
- return PA;
+ return PreservedAnalyses::none();
}
char GVNSinkLegacyPass::ID = 0;
diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
index ae1fff0fa844..9ee2a2d0bf08 100644
--- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -875,7 +875,8 @@ static bool isLoopCounter(PHINode* Phi, Loop *L,
int LatchIdx = Phi->getBasicBlockIndex(L->getLoopLatch());
Value *IncV = Phi->getIncomingValue(LatchIdx);
- return (getLoopPhiForCounter(IncV, L) == Phi);
+ return (getLoopPhiForCounter(IncV, L) == Phi &&
+ isa<SCEVAddRecExpr>(SE->getSCEV(IncV)));
}
/// Search the loop header for a loop counter (anadd rec w/step of one)
@@ -1564,9 +1565,6 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) {
if (!LoopPredication)
return false;
- if (!SE->hasLoopInvariantBackedgeTakenCount(L))
- return false;
-
// Note: ExactBTC is the exact backedge taken count *iff* the loop exits
// through *explicit* control flow. We have to eliminate the possibility of
// implicit exits (see below) before we know it's truly exact.
@@ -1605,8 +1603,8 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) {
return true;
const SCEV *ExitCount = SE->getExitCount(L, ExitingBB);
- assert(!isa<SCEVCouldNotCompute>(ExactBTC) && "implied by having exact trip count");
- if (!SE->isLoopInvariant(ExitCount, L) ||
+ if (isa<SCEVCouldNotCompute>(ExitCount) ||
+ !SE->isLoopInvariant(ExitCount, L) ||
!isSafeToExpand(ExitCount, *SE))
return true;
@@ -1670,7 +1668,7 @@ bool IndVarSimplify::predicateLoopExits(Loop *L, SCEVExpander &Rewriter) {
for (BasicBlock *BB : L->blocks())
for (auto &I : *BB)
// TODO:isGuaranteedToTransfer
- if (I.mayHaveSideEffects() || I.mayThrow())
+ if (I.mayHaveSideEffects())
return false;
bool Changed = false;
diff --git a/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp b/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
index 6e09dec198c2..0e5653eeb7d5 100644
--- a/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp
@@ -360,7 +360,7 @@ void InductiveRangeCheck::extractRangeChecksFromCond(
return;
// TODO: Do the same for OR, XOR, NOT etc?
- if (match(Condition, m_And(m_Value(), m_Value()))) {
+ if (match(Condition, m_LogicalAnd(m_Value(), m_Value()))) {
extractRangeChecksFromCond(L, SE, cast<User>(Condition)->getOperandUse(0),
Checks, Visited);
extractRangeChecksFromCond(L, SE, cast<User>(Condition)->getOperandUse(1),
@@ -1785,8 +1785,11 @@ PreservedAnalyses IRCEPass::run(Function &F, FunctionAnalysisManager &AM) {
}
Changed |= CFGChanged;
- if (CFGChanged && !SkipProfitabilityChecks)
- AM.invalidate<BlockFrequencyAnalysis>(F);
+ if (CFGChanged && !SkipProfitabilityChecks) {
+ PreservedAnalyses PA = PreservedAnalyses::all();
+ PA.abandon<BlockFrequencyAnalysis>();
+ AM.invalidate(F, PA);
+ }
}
SmallPriorityWorklist<Loop *, 4> Worklist;
@@ -1800,8 +1803,11 @@ PreservedAnalyses IRCEPass::run(Function &F, FunctionAnalysisManager &AM) {
Loop *L = Worklist.pop_back_val();
if (IRCE.run(L, LPMAddNewLoop)) {
Changed = true;
- if (!SkipProfitabilityChecks)
- AM.invalidate<BlockFrequencyAnalysis>(F);
+ if (!SkipProfitabilityChecks) {
+ PreservedAnalyses PA = PreservedAnalyses::all();
+ PA.abandon<BlockFrequencyAnalysis>();
+ AM.invalidate(F, PA);
+ }
}
}
diff --git a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
index 332eb10ac16b..f7d631f5e785 100644
--- a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
+++ b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
@@ -471,7 +471,7 @@ InferAddressSpacesImpl::collectFlatAddressExpressions(Function &F) const {
} else if (auto *I2P = dyn_cast<IntToPtrInst>(&I)) {
if (isNoopPtrIntCastPair(cast<Operator>(I2P), *DL, TTI))
PushPtrOperand(
- cast<PtrToIntInst>(I2P->getOperand(0))->getPointerOperand());
+ cast<Operator>(I2P->getOperand(0))->getOperand(0));
}
}
@@ -508,8 +508,8 @@ static Value *operandWithNewAddressSpaceOrCreateUndef(
SmallVectorImpl<const Use *> *UndefUsesToFix) {
Value *Operand = OperandUse.get();
- Type *NewPtrTy =
- Operand->getType()->getPointerElementType()->getPointerTo(NewAddrSpace);
+ Type *NewPtrTy = PointerType::getWithSamePointeeType(
+ cast<PointerType>(Operand->getType()), NewAddrSpace);
if (Constant *C = dyn_cast<Constant>(Operand))
return ConstantExpr::getAddrSpaceCast(C, NewPtrTy);
@@ -537,8 +537,8 @@ Value *InferAddressSpacesImpl::cloneInstructionWithNewAddressSpace(
Instruction *I, unsigned NewAddrSpace,
const ValueToValueMapTy &ValueWithNewAddrSpace,
SmallVectorImpl<const Use *> *UndefUsesToFix) const {
- Type *NewPtrType =
- I->getType()->getPointerElementType()->getPointerTo(NewAddrSpace);
+ Type *NewPtrType = PointerType::getWithSamePointeeType(
+ cast<PointerType>(I->getType()), NewAddrSpace);
if (I->getOpcode() == Instruction::AddrSpaceCast) {
Value *Src = I->getOperand(0);
@@ -572,7 +572,8 @@ Value *InferAddressSpacesImpl::cloneInstructionWithNewAddressSpace(
if (AS != UninitializedAddressSpace) {
// For the assumed address space, insert an `addrspacecast` to make that
// explicit.
- auto *NewPtrTy = I->getType()->getPointerElementType()->getPointerTo(AS);
+ Type *NewPtrTy = PointerType::getWithSamePointeeType(
+ cast<PointerType>(I->getType()), AS);
auto *NewI = new AddrSpaceCastInst(I, NewPtrTy);
NewI->insertAfter(I);
return NewI;
@@ -634,8 +635,10 @@ static Value *cloneConstantExprWithNewAddressSpace(
ConstantExpr *CE, unsigned NewAddrSpace,
const ValueToValueMapTy &ValueWithNewAddrSpace, const DataLayout *DL,
const TargetTransformInfo *TTI) {
- Type *TargetType =
- CE->getType()->getPointerElementType()->getPointerTo(NewAddrSpace);
+ Type *TargetType = CE->getType()->isPointerTy()
+ ? PointerType::getWithSamePointeeType(
+ cast<PointerType>(CE->getType()), NewAddrSpace)
+ : CE->getType();
if (CE->getOpcode() == Instruction::AddrSpaceCast) {
// Because CE is flat, the source address space must be specific.
@@ -953,7 +956,13 @@ static bool handleMemIntrinsicPtrUse(MemIntrinsic *MI, Value *OldV,
if (Dest == OldV)
Dest = NewV;
- if (isa<MemCpyInst>(MTI)) {
+ if (isa<MemCpyInlineInst>(MTI)) {
+ MDNode *TBAAStruct = MTI->getMetadata(LLVMContext::MD_tbaa_struct);
+ B.CreateMemCpyInline(Dest, MTI->getDestAlign(), Src,
+ MTI->getSourceAlign(), MTI->getLength(),
+ false, // isVolatile
+ TBAA, TBAAStruct, ScopeMD, NoAliasMD);
+ } else if (isa<MemCpyInst>(MTI)) {
MDNode *TBAAStruct = MTI->getMetadata(LLVMContext::MD_tbaa_struct);
B.CreateMemCpy(Dest, MTI->getDestAlign(), Src, MTI->getSourceAlign(),
MTI->getLength(),
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 96aef90c1c1a..9dc3b0351346 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -31,6 +31,7 @@
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/Analysis/Loads.h"
#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
@@ -370,7 +371,6 @@ PreservedAnalyses JumpThreadingPass::run(Function &F,
if (!Changed)
return PreservedAnalyses::all();
PreservedAnalyses PA;
- PA.preserve<GlobalsAA>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<LazyValueAnalysis>();
return PA;
@@ -462,7 +462,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
BasicBlock *Succ = BI->getSuccessor(0);
if (
// The terminator must be the only non-phi instruction in BB.
- BB.getFirstNonPHIOrDbg()->isTerminator() &&
+ BB.getFirstNonPHIOrDbg(true)->isTerminator() &&
// Don't alter Loop headers and latches to ensure another pass can
// detect and transform nested loops later.
!LoopHeaders.count(&BB) && !LoopHeaders.count(Succ) &&
@@ -733,23 +733,26 @@ bool JumpThreadingPass::computeValueKnownInPredecessorsImpl(
// Handle some boolean conditions.
if (I->getType()->getPrimitiveSizeInBits() == 1) {
+ using namespace PatternMatch;
+
assert(Preference == WantInteger && "One-bit non-integer type?");
// X | true -> true
// X & false -> false
- if (I->getOpcode() == Instruction::Or ||
- I->getOpcode() == Instruction::And) {
+ Value *Op0, *Op1;
+ if (match(I, m_LogicalOr(m_Value(Op0), m_Value(Op1))) ||
+ match(I, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {
PredValueInfoTy LHSVals, RHSVals;
- computeValueKnownInPredecessorsImpl(I->getOperand(0), BB, LHSVals,
- WantInteger, RecursionSet, CxtI);
- computeValueKnownInPredecessorsImpl(I->getOperand(1), BB, RHSVals,
- WantInteger, RecursionSet, CxtI);
+ computeValueKnownInPredecessorsImpl(Op0, BB, LHSVals, WantInteger,
+ RecursionSet, CxtI);
+ computeValueKnownInPredecessorsImpl(Op1, BB, RHSVals, WantInteger,
+ RecursionSet, CxtI);
if (LHSVals.empty() && RHSVals.empty())
return false;
ConstantInt *InterestingVal;
- if (I->getOpcode() == Instruction::Or)
+ if (match(I, m_LogicalOr()))
InterestingVal = ConstantInt::getTrue(I->getContext());
else
InterestingVal = ConstantInt::getFalse(I->getContext());
@@ -1105,6 +1108,7 @@ bool JumpThreadingPass::processBlock(BasicBlock *BB) {
LLVM_DEBUG(dbgs() << " In block '" << BB->getName()
<< "' folding undef terminator: " << *BBTerm << '\n');
BranchInst::Create(BBTerm->getSuccessor(BestSucc), BBTerm);
+ ++NumFolds;
BBTerm->eraseFromParent();
DTU->applyUpdatesPermissive(Updates);
if (FI)
@@ -1150,8 +1154,8 @@ bool JumpThreadingPass::processBlock(BasicBlock *BB) {
assert(CondBr->isConditional() && "Threading on unconditional terminator");
LazyValueInfo::Tristate Ret =
- LVI->getPredicateAt(CondCmp->getPredicate(), CondCmp->getOperand(0),
- CondConst, CondBr);
+ LVI->getPredicateAt(CondCmp->getPredicate(), CondCmp->getOperand(0),
+ CondConst, CondBr, /*UseBlockValue=*/false);
if (Ret != LazyValueInfo::Unknown) {
unsigned ToRemove = Ret == LazyValueInfo::True ? 1 : 0;
unsigned ToKeep = Ret == LazyValueInfo::True ? 0 : 1;
@@ -1160,6 +1164,7 @@ bool JumpThreadingPass::processBlock(BasicBlock *BB) {
BranchInst *UncondBr =
BranchInst::Create(CondBr->getSuccessor(ToKeep), CondBr);
UncondBr->setDebugLoc(CondBr->getDebugLoc());
+ ++NumFolds;
CondBr->eraseFromParent();
if (CondCmp->use_empty())
CondCmp->eraseFromParent();
@@ -1275,6 +1280,7 @@ bool JumpThreadingPass::processImpliedCondition(BasicBlock *BB) {
RemoveSucc->removePredecessor(BB);
BranchInst *UncondBI = BranchInst::Create(KeepSucc, BI);
UncondBI->setDebugLoc(BI->getDebugLoc());
+ ++NumFolds;
BI->eraseFromParent();
DTU->applyUpdatesPermissive({{DominatorTree::Delete, BB, RemoveSucc}});
if (HasProfileData)
@@ -1384,10 +1390,14 @@ bool JumpThreadingPass::simplifyPartiallyRedundantLoad(LoadInst *LoadI) {
"Attempting to CSE volatile or atomic loads");
// If this is a load on a phi pointer, phi-translate it and search
// for available load/store to the pointer in predecessors.
- Value *Ptr = LoadedPtr->DoPHITranslation(LoadBB, PredBB);
- PredAvailable = FindAvailablePtrLoadStore(
- Ptr, LoadI->getType(), LoadI->isAtomic(), PredBB, BBIt,
- DefMaxInstsToScan, AA, &IsLoadCSE, &NumScanedInst);
+ Type *AccessTy = LoadI->getType();
+ const auto &DL = LoadI->getModule()->getDataLayout();
+ MemoryLocation Loc(LoadedPtr->DoPHITranslation(LoadBB, PredBB),
+ LocationSize::precise(DL.getTypeStoreSize(AccessTy)),
+ AATags);
+ PredAvailable = findAvailablePtrLoadStore(Loc, AccessTy, LoadI->isAtomic(),
+ PredBB, BBIt, DefMaxInstsToScan,
+ AA, &IsLoadCSE, &NumScanedInst);
// If PredBB has a single predecessor, continue scanning through the
// single predecessor.
@@ -1397,8 +1407,8 @@ bool JumpThreadingPass::simplifyPartiallyRedundantLoad(LoadInst *LoadI) {
SinglePredBB = SinglePredBB->getSinglePredecessor();
if (SinglePredBB) {
BBIt = SinglePredBB->end();
- PredAvailable = FindAvailablePtrLoadStore(
- Ptr, LoadI->getType(), LoadI->isAtomic(), SinglePredBB, BBIt,
+ PredAvailable = findAvailablePtrLoadStore(
+ Loc, AccessTy, LoadI->isAtomic(), SinglePredBB, BBIt,
(DefMaxInstsToScan - NumScanedInst), AA, &IsLoadCSE,
&NumScanedInst);
}
@@ -1720,6 +1730,7 @@ bool JumpThreadingPass::processThreadableEdges(Value *Cond, BasicBlock *BB,
// Finally update the terminator.
Instruction *Term = BB->getTerminator();
BranchInst::Create(OnlyDest, Term);
+ ++NumFolds;
Term->eraseFromParent();
DTU->applyUpdatesPermissive(Updates);
if (HasProfileData)
@@ -2076,6 +2087,15 @@ JumpThreadingPass::cloneInstructions(BasicBlock::iterator BI,
ValueMapping[PN] = NewPN;
}
+ // Clone noalias scope declarations in the threaded block. When threading a
+ // loop exit, we would otherwise end up with two idential scope declarations
+ // visible at the same time.
+ SmallVector<MDNode *> NoAliasScopes;
+ DenseMap<MDNode *, MDNode *> ClonedScopes;
+ LLVMContext &Context = PredBB->getContext();
+ identifyNoAliasScopesToClone(BI, BE, NoAliasScopes);
+ cloneNoAliasScopes(NoAliasScopes, ClonedScopes, "thread", Context);
+
// Clone the non-phi instructions of the source basic block into NewBB,
// keeping track of the mapping and using it to remap operands in the cloned
// instructions.
@@ -2084,6 +2104,7 @@ JumpThreadingPass::cloneInstructions(BasicBlock::iterator BI,
New->setName(BI->getName());
NewBB->getInstList().push_back(New);
ValueMapping[&*BI] = New;
+ adaptNoAliasScopes(New, ClonedScopes, Context);
// Remap operands to patch up intra-block references.
for (unsigned i = 0, e = New->getNumOperands(); i != e; ++i)
@@ -2727,7 +2748,8 @@ void JumpThreadingPass::unfoldSelectInstr(BasicBlock *Pred, BasicBlock *BB,
PredTerm->removeFromParent();
NewBB->getInstList().insert(NewBB->end(), PredTerm);
// Create a conditional branch and update PHI nodes.
- BranchInst::Create(NewBB, BB, SI->getCondition(), Pred);
+ auto *BI = BranchInst::Create(NewBB, BB, SI->getCondition(), Pred);
+ BI->applyMergedLocation(PredTerm->getDebugLoc(), SI->getDebugLoc());
SIUse->setIncomingValue(Idx, SI->getFalseValue());
SIUse->addIncoming(SI->getTrueValue(), NewBB);
@@ -2861,11 +2883,14 @@ bool JumpThreadingPass::tryToUnfoldSelectInCurrBB(BasicBlock *BB) {
continue;
auto isUnfoldCandidate = [BB](SelectInst *SI, Value *V) {
+ using namespace PatternMatch;
+
// Check if SI is in BB and use V as condition.
if (SI->getParent() != BB)
return false;
Value *Cond = SI->getCondition();
- return (Cond && Cond == V && Cond->getType()->isIntegerTy(1));
+ bool IsAndOr = match(SI, m_CombineOr(m_LogicalAnd(), m_LogicalOr()));
+ return Cond && Cond == V && Cond->getType()->isIntegerTy(1) && !IsAndOr;
};
SelectInst *SI = nullptr;
diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index d2b4ba296f41..30058df3ded5 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -162,6 +162,7 @@ static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT,
OptimizationRemarkEmitter *ORE);
static bool isSafeToExecuteUnconditionally(Instruction &Inst,
const DominatorTree *DT,
+ const TargetLibraryInfo *TLI,
const Loop *CurLoop,
const LoopSafetyInfo *SafetyInfo,
OptimizationRemarkEmitter *ORE,
@@ -185,12 +186,17 @@ static void moveInstructionBefore(Instruction &I, Instruction &Dest,
ICFLoopSafetyInfo &SafetyInfo,
MemorySSAUpdater *MSSAU, ScalarEvolution *SE);
+static void foreachMemoryAccess(MemorySSA *MSSA, Loop *L,
+ function_ref<void(Instruction *)> Fn);
+static SmallVector<SmallSetVector<Value *, 8>, 0>
+collectPromotionCandidates(MemorySSA *MSSA, AliasAnalysis *AA, Loop *L);
+
namespace {
struct LoopInvariantCodeMotion {
bool runOnLoop(Loop *L, AAResults *AA, LoopInfo *LI, DominatorTree *DT,
BlockFrequencyInfo *BFI, TargetLibraryInfo *TLI,
TargetTransformInfo *TTI, ScalarEvolution *SE, MemorySSA *MSSA,
- OptimizationRemarkEmitter *ORE);
+ OptimizationRemarkEmitter *ORE, bool LoopNestMode = false);
LoopInvariantCodeMotion(unsigned LicmMssaOptCap,
unsigned LicmMssaNoAccForPromotionCap)
@@ -203,9 +209,6 @@ private:
std::unique_ptr<AliasSetTracker>
collectAliasInfoForLoop(Loop *L, LoopInfo *LI, AAResults *AA);
- std::unique_ptr<AliasSetTracker>
- collectAliasInfoForLoopWithMSSA(Loop *L, AAResults *AA,
- MemorySSAUpdater *MSSAU);
};
struct LegacyLICMPass : public LoopPass {
@@ -292,6 +295,33 @@ PreservedAnalyses LICMPass::run(Loop &L, LoopAnalysisManager &AM,
return PA;
}
+PreservedAnalyses LNICMPass::run(LoopNest &LN, LoopAnalysisManager &AM,
+ LoopStandardAnalysisResults &AR,
+ LPMUpdater &) {
+ // For the new PM, we also can't use OptimizationRemarkEmitter as an analysis
+ // pass. Function analyses need to be preserved across loop transformations
+ // but ORE cannot be preserved (see comment before the pass definition).
+ OptimizationRemarkEmitter ORE(LN.getParent());
+
+ LoopInvariantCodeMotion LICM(LicmMssaOptCap, LicmMssaNoAccForPromotionCap);
+
+ Loop &OutermostLoop = LN.getOutermostLoop();
+ bool Changed = LICM.runOnLoop(&OutermostLoop, &AR.AA, &AR.LI, &AR.DT, AR.BFI,
+ &AR.TLI, &AR.TTI, &AR.SE, AR.MSSA, &ORE, true);
+
+ if (!Changed)
+ return PreservedAnalyses::all();
+
+ auto PA = getLoopPassPreservedAnalyses();
+
+ PA.preserve<DominatorTreeAnalysis>();
+ PA.preserve<LoopAnalysis>();
+ if (AR.MSSA)
+ PA.preserve<MemorySSAAnalysis>();
+
+ return PA;
+}
+
char LegacyLICMPass::ID = 0;
INITIALIZE_PASS_BEGIN(LegacyLICMPass, "licm", "Loop Invariant Code Motion",
false, false)
@@ -344,7 +374,8 @@ llvm::SinkAndHoistLICMFlags::SinkAndHoistLICMFlags(
bool LoopInvariantCodeMotion::runOnLoop(
Loop *L, AAResults *AA, LoopInfo *LI, DominatorTree *DT,
BlockFrequencyInfo *BFI, TargetLibraryInfo *TLI, TargetTransformInfo *TTI,
- ScalarEvolution *SE, MemorySSA *MSSA, OptimizationRemarkEmitter *ORE) {
+ ScalarEvolution *SE, MemorySSA *MSSA, OptimizationRemarkEmitter *ORE,
+ bool LoopNestMode) {
bool Changed = false;
assert(L->isLCSSAForm(*DT) && "Loop is not in LCSSA form.");
@@ -359,6 +390,22 @@ bool LoopInvariantCodeMotion::runOnLoop(
std::unique_ptr<MemorySSAUpdater> MSSAU;
std::unique_ptr<SinkAndHoistLICMFlags> Flags;
+ // Don't sink stores from loops with coroutine suspend instructions.
+ // LICM would sink instructions into the default destination of
+ // the coroutine switch. The default destination of the switch is to
+ // handle the case where the coroutine is suspended, by which point the
+ // coroutine frame may have been destroyed. No instruction can be sunk there.
+ // FIXME: This would unfortunately hurt the performance of coroutines, however
+ // there is currently no general solution for this. Similar issues could also
+ // potentially happen in other passes where instructions are being moved
+ // across that edge.
+ bool HasCoroSuspendInst = llvm::any_of(L->getBlocks(), [](BasicBlock *BB) {
+ return llvm::any_of(*BB, [](Instruction &I) {
+ IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
+ return II && II->getIntrinsicID() == Intrinsic::coro_suspend;
+ });
+ });
+
if (!MSSA) {
LLVM_DEBUG(dbgs() << "LICM: Using Alias Set Tracker.\n");
CurAST = collectAliasInfoForLoop(L, LI, AA);
@@ -395,7 +442,7 @@ bool LoopInvariantCodeMotion::runOnLoop(
if (Preheader)
Changed |= hoistRegion(DT->getNode(L->getHeader()), AA, LI, DT, BFI, TLI, L,
CurAST.get(), MSSAU.get(), SE, &SafetyInfo,
- *Flags.get(), ORE);
+ *Flags.get(), ORE, LoopNestMode);
// Now that all loop invariants have been removed from the loop, promote any
// memory references to scalars that we can.
@@ -405,7 +452,7 @@ bool LoopInvariantCodeMotion::runOnLoop(
// preheader for SSA updater, so also avoid sinking when no preheader
// is available.
if (!DisablePromotion && Preheader && L->hasDedicatedExits() &&
- !Flags->tooManyMemoryAccesses()) {
+ !Flags->tooManyMemoryAccesses() && !HasCoroSuspendInst) {
// Figure out the loop exits and their insertion points
SmallVector<BasicBlock *, 8> ExitBlocks;
L->getUniqueExitBlocks(ExitBlocks);
@@ -430,31 +477,43 @@ bool LoopInvariantCodeMotion::runOnLoop(
PredIteratorCache PIC;
bool Promoted = false;
+ if (CurAST.get()) {
+ // Loop over all of the alias sets in the tracker object.
+ for (AliasSet &AS : *CurAST) {
+ // We can promote this alias set if it has a store, if it is a "Must"
+ // alias set, if the pointer is loop invariant, and if we are not
+ // eliminating any volatile loads or stores.
+ if (AS.isForwardingAliasSet() || !AS.isMod() || !AS.isMustAlias() ||
+ !L->isLoopInvariant(AS.begin()->getValue()))
+ continue;
- // Build an AST using MSSA.
- if (!CurAST.get())
- CurAST = collectAliasInfoForLoopWithMSSA(L, AA, MSSAU.get());
-
- // Loop over all of the alias sets in the tracker object.
- for (AliasSet &AS : *CurAST) {
- // We can promote this alias set if it has a store, if it is a "Must"
- // alias set, if the pointer is loop invariant, and if we are not
- // eliminating any volatile loads or stores.
- if (AS.isForwardingAliasSet() || !AS.isMod() || !AS.isMustAlias() ||
- !L->isLoopInvariant(AS.begin()->getValue()))
- continue;
-
- assert(
- !AS.empty() &&
- "Must alias set should have at least one pointer element in it!");
+ assert(
+ !AS.empty() &&
+ "Must alias set should have at least one pointer element in it!");
- SmallSetVector<Value *, 8> PointerMustAliases;
- for (const auto &ASI : AS)
- PointerMustAliases.insert(ASI.getValue());
+ SmallSetVector<Value *, 8> PointerMustAliases;
+ for (const auto &ASI : AS)
+ PointerMustAliases.insert(ASI.getValue());
- Promoted |= promoteLoopAccessesToScalars(
- PointerMustAliases, ExitBlocks, InsertPts, MSSAInsertPts, PIC, LI,
- DT, TLI, L, CurAST.get(), MSSAU.get(), &SafetyInfo, ORE);
+ Promoted |= promoteLoopAccessesToScalars(
+ PointerMustAliases, ExitBlocks, InsertPts, MSSAInsertPts, PIC, LI,
+ DT, TLI, L, CurAST.get(), MSSAU.get(), &SafetyInfo, ORE);
+ }
+ } else {
+ // Promoting one set of accesses may make the pointers for another set
+ // loop invariant, so run this in a loop (with the MaybePromotable set
+ // decreasing in size over time).
+ bool LocalPromoted;
+ do {
+ LocalPromoted = false;
+ for (const SmallSetVector<Value *, 8> &PointerMustAliases :
+ collectPromotionCandidates(MSSA, AA, L)) {
+ LocalPromoted |= promoteLoopAccessesToScalars(
+ PointerMustAliases, ExitBlocks, InsertPts, MSSAInsertPts, PIC,
+ LI, DT, TLI, L, /*AST*/nullptr, MSSAU.get(), &SafetyInfo, ORE);
+ }
+ Promoted |= LocalPromoted;
+ } while (LocalPromoted);
}
// Once we have promoted values across the loop body we have to
@@ -521,8 +580,8 @@ bool llvm::sinkRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
for (BasicBlock::iterator II = BB->end(); II != BB->begin();) {
Instruction &I = *--II;
- // If the instruction is dead, we would try to sink it because it isn't
- // used in the loop, instead, just delete it.
+ // The instruction is not used in the loop if it is dead. In this case,
+ // we just delete it instead of sinking it.
if (isInstructionTriviallyDead(&I, TLI)) {
LLVM_DEBUG(dbgs() << "LICM deleting dead inst: " << I << '\n');
salvageKnowledge(&I);
@@ -828,7 +887,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
AliasSetTracker *CurAST, MemorySSAUpdater *MSSAU,
ScalarEvolution *SE, ICFLoopSafetyInfo *SafetyInfo,
SinkAndHoistLICMFlags &Flags,
- OptimizationRemarkEmitter *ORE) {
+ OptimizationRemarkEmitter *ORE, bool LoopNestMode) {
// Verify inputs.
assert(N != nullptr && AA != nullptr && LI != nullptr && DT != nullptr &&
CurLoop != nullptr && SafetyInfo != nullptr &&
@@ -851,7 +910,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
for (BasicBlock *BB : Worklist) {
// Only need to process the contents of this block if it is not part of a
// subloop (which would already have been processed).
- if (inSubLoop(BB, CurLoop, LI))
+ if (!LoopNestMode && inSubLoop(BB, CurLoop, LI))
continue;
for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E;) {
@@ -885,7 +944,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
ORE) &&
worthSinkOrHoistInst(I, CurLoop->getLoopPreheader(), ORE, BFI) &&
isSafeToExecuteUnconditionally(
- I, DT, CurLoop, SafetyInfo, ORE,
+ I, DT, TLI, CurLoop, SafetyInfo, ORE,
CurLoop->getLoopPreheader()->getTerminator())) {
hoist(I, DT, CurLoop, CFH.getOrCreateHoistedBlock(BB), SafetyInfo,
MSSAU, SE, ORE);
@@ -1089,7 +1148,7 @@ bool isHoistableAndSinkableInst(Instruction &I) {
isa<InsertValueInst>(I) || isa<FreezeInst>(I));
}
/// Return true if all of the alias sets within this AST are known not to
-/// contain a Mod, or if MSSA knows thare are no MemoryDefs in the loop.
+/// contain a Mod, or if MSSA knows there are no MemoryDefs in the loop.
bool isReadOnly(AliasSetTracker *CurAST, const MemorySSAUpdater *MSSAU,
const Loop *L) {
if (CurAST) {
@@ -1314,7 +1373,7 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT,
}
// Any call, while it may not be clobbering SI, it may be a use.
if (auto *CI = dyn_cast<CallInst>(MD->getMemoryInst())) {
- // Check if the call may read from the memory locattion written
+ // Check if the call may read from the memory location written
// to by SI. Check CI's attributes and arguments; the number of
// such checks performed is limited above by NoOfMemAccTooLarge.
ModRefInfo MRI = AA->getModRefInfo(CI, MemoryLocation::get(SI));
@@ -1466,25 +1525,23 @@ static Instruction *cloneInstructionInExitBlock(
}
}
- // Build LCSSA PHI nodes for any in-loop operands. Note that this is
- // particularly cheap because we can rip off the PHI node that we're
+ // Build LCSSA PHI nodes for any in-loop operands (if legal). Note that
+ // this is particularly cheap because we can rip off the PHI node that we're
// replacing for the number and blocks of the predecessors.
// OPT: If this shows up in a profile, we can instead finish sinking all
// invariant instructions, and then walk their operands to re-establish
// LCSSA. That will eliminate creating PHI nodes just to nuke them when
// sinking bottom-up.
- for (User::op_iterator OI = New->op_begin(), OE = New->op_end(); OI != OE;
- ++OI)
- if (Instruction *OInst = dyn_cast<Instruction>(*OI))
- if (Loop *OLoop = LI->getLoopFor(OInst->getParent()))
- if (!OLoop->contains(&PN)) {
- PHINode *OpPN =
- PHINode::Create(OInst->getType(), PN.getNumIncomingValues(),
- OInst->getName() + ".lcssa", &ExitBlock.front());
- for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i)
- OpPN->addIncoming(OInst, PN.getIncomingBlock(i));
- *OI = OpPN;
- }
+ for (Use &Op : New->operands())
+ if (LI->wouldBeOutOfLoopUseRequiringLCSSA(Op.get(), PN.getParent())) {
+ auto *OInst = cast<Instruction>(Op.get());
+ PHINode *OpPN =
+ PHINode::Create(OInst->getType(), PN.getNumIncomingValues(),
+ OInst->getName() + ".lcssa", &ExitBlock.front());
+ for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i)
+ OpPN->addIncoming(OInst, PN.getIncomingBlock(i));
+ Op = OpPN;
+ }
return New;
}
@@ -1627,17 +1684,8 @@ static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT,
BlockFrequencyInfo *BFI, const Loop *CurLoop,
ICFLoopSafetyInfo *SafetyInfo, MemorySSAUpdater *MSSAU,
OptimizationRemarkEmitter *ORE) {
- LLVM_DEBUG(dbgs() << "LICM sinking instruction: " << I << "\n");
- ORE->emit([&]() {
- return OptimizationRemark(DEBUG_TYPE, "InstSunk", &I)
- << "sinking " << ore::NV("Inst", &I);
- });
bool Changed = false;
- if (isa<LoadInst>(I))
- ++NumMovedLoads;
- else if (isa<CallInst>(I))
- ++NumMovedCalls;
- ++NumSunk;
+ LLVM_DEBUG(dbgs() << "LICM sinking instruction: " << I << "\n");
// Iterate over users to be ready for actual sinking. Replace users via
// unreachable blocks with undef and make all user PHIs trivially replaceable.
@@ -1689,6 +1737,16 @@ static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT,
if (VisitedUsers.empty())
return Changed;
+ ORE->emit([&]() {
+ return OptimizationRemark(DEBUG_TYPE, "InstSunk", &I)
+ << "sinking " << ore::NV("Inst", &I);
+ });
+ if (isa<LoadInst>(I))
+ ++NumMovedLoads;
+ else if (isa<CallInst>(I))
+ ++NumMovedCalls;
+ ++NumSunk;
+
#ifndef NDEBUG
SmallVector<BasicBlock *, 32> ExitBlocks;
CurLoop->getUniqueExitBlocks(ExitBlocks);
@@ -1752,12 +1810,16 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
// Conservatively strip all metadata on the instruction unless we were
// guaranteed to execute I if we entered the loop, in which case the metadata
// is valid in the loop preheader.
- if (I.hasMetadataOtherThanDebugLoc() &&
+ // Similarly, If I is a call and it is not guaranteed to execute in the loop,
+ // then moving to the preheader means we should strip attributes on the call
+ // that can cause UB since we may be hoisting above conditions that allowed
+ // inferring those attributes. They may not be valid at the preheader.
+ if ((I.hasMetadataOtherThanDebugLoc() || isa<CallInst>(I)) &&
// The check on hasMetadataOtherThanDebugLoc is to prevent us from burning
// time in isGuaranteedToExecute if we don't actually have anything to
// drop. It is a compile time optimization, not required for correctness.
!SafetyInfo->isGuaranteedToExecute(I, DT, CurLoop))
- I.dropUnknownNonDebugMetadata();
+ I.dropUndefImplyingAttrsAndUnknownMetadata();
if (isa<PHINode>(I))
// Move the new node to the end of the phi list in the destination block.
@@ -1780,11 +1842,12 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop,
/// or if it is a trapping instruction and is guaranteed to execute.
static bool isSafeToExecuteUnconditionally(Instruction &Inst,
const DominatorTree *DT,
+ const TargetLibraryInfo *TLI,
const Loop *CurLoop,
const LoopSafetyInfo *SafetyInfo,
OptimizationRemarkEmitter *ORE,
const Instruction *CtxI) {
- if (isSafeToSpeculativelyExecute(&Inst, CtxI, DT))
+ if (isSafeToSpeculativelyExecute(&Inst, CtxI, DT, TLI))
return true;
bool GuaranteedToExecute =
@@ -1821,19 +1884,21 @@ class LoopPromoter : public LoadAndStorePromoter {
AAMDNodes AATags;
ICFLoopSafetyInfo &SafetyInfo;
+ // We're about to add a use of V in a loop exit block. Insert an LCSSA phi
+ // (if legal) if doing so would add an out-of-loop use to an instruction
+ // defined in-loop.
Value *maybeInsertLCSSAPHI(Value *V, BasicBlock *BB) const {
- if (Instruction *I = dyn_cast<Instruction>(V))
- if (Loop *L = LI.getLoopFor(I->getParent()))
- if (!L->contains(BB)) {
- // We need to create an LCSSA PHI node for the incoming value and
- // store that.
- PHINode *PN = PHINode::Create(I->getType(), PredCache.size(BB),
- I->getName() + ".lcssa", &BB->front());
- for (BasicBlock *Pred : PredCache.get(BB))
- PN->addIncoming(I, Pred);
- return PN;
- }
- return V;
+ if (!LI.wouldBeOutOfLoopUseRequiringLCSSA(V, BB))
+ return V;
+
+ Instruction *I = cast<Instruction>(V);
+ // We need to create an LCSSA PHI node for the incoming value and
+ // store that.
+ PHINode *PN = PHINode::Create(I->getType(), PredCache.size(BB),
+ I->getName() + ".lcssa", &BB->front());
+ for (BasicBlock *Pred : PredCache.get(BB))
+ PN->addIncoming(I, Pred);
+ return PN;
}
public:
@@ -1911,10 +1976,21 @@ public:
}
};
+bool isNotCapturedBeforeOrInLoop(const Value *V, const Loop *L,
+ DominatorTree *DT) {
+ // We can perform the captured-before check against any instruction in the
+ // loop header, as the loop header is reachable from any instruction inside
+ // the loop.
+ // TODO: ReturnCaptures=true shouldn't be necessary here.
+ return !PointerMayBeCapturedBefore(V, /* ReturnCaptures */ true,
+ /* StoreCaptures */ true,
+ L->getHeader()->getTerminator(), DT);
+}
/// Return true iff we can prove that a caller of this function can not inspect
/// the contents of the provided object in a well defined program.
-bool isKnownNonEscaping(Value *Object, const TargetLibraryInfo *TLI) {
+bool isKnownNonEscaping(Value *Object, const Loop *L,
+ const TargetLibraryInfo *TLI, DominatorTree *DT) {
if (isa<AllocaInst>(Object))
// Since the alloca goes out of scope, we know the caller can't retain a
// reference to it and be well defined. Thus, we don't need to check for
@@ -1931,7 +2007,7 @@ bool isKnownNonEscaping(Value *Object, const TargetLibraryInfo *TLI) {
// weaker condition and handle only AllocLikeFunctions (which are
// known to be noalias). TODO
return isAllocLikeFn(Object, TLI) &&
- !PointerMayBeCaptured(Object, true, true);
+ isNotCapturedBeforeOrInLoop(Object, L, DT);
}
} // namespace
@@ -2017,7 +2093,7 @@ bool llvm::promoteLoopAccessesToScalars(
// this by proving that the caller can't have a reference to the object
// after return and thus can't possibly load from the object.
Value *Object = getUnderlyingObject(SomePtr);
- if (!isKnownNonEscaping(Object, TLI))
+ if (!isKnownNonEscaping(Object, CurLoop, TLI, DT))
return false;
// Subtlety: Alloca's aren't visible to callers, but *are* potentially
// visible to other threads if captured and used during their lifetimes.
@@ -2054,10 +2130,11 @@ bool llvm::promoteLoopAccessesToScalars(
// Note that proving a load safe to speculate requires proving
// sufficient alignment at the target location. Proving it guaranteed
// to execute does as well. Thus we can increase our guaranteed
- // alignment as well.
+ // alignment as well.
if (!DereferenceableInPH || (InstAlignment > Alignment))
- if (isSafeToExecuteUnconditionally(*Load, DT, CurLoop, SafetyInfo,
- ORE, Preheader->getTerminator())) {
+ if (isSafeToExecuteUnconditionally(*Load, DT, TLI, CurLoop,
+ SafetyInfo, ORE,
+ Preheader->getTerminator())) {
DereferenceableInPH = true;
Alignment = std::max(Alignment, InstAlignment);
}
@@ -2104,7 +2181,7 @@ bool llvm::promoteLoopAccessesToScalars(
if (!DereferenceableInPH) {
DereferenceableInPH = isDereferenceableAndAlignedPointer(
Store->getPointerOperand(), Store->getValueOperand()->getType(),
- Store->getAlign(), MDL, Preheader->getTerminator(), DT);
+ Store->getAlign(), MDL, Preheader->getTerminator(), DT, TLI);
}
} else
return false; // Not a load or store.
@@ -2151,7 +2228,7 @@ bool llvm::promoteLoopAccessesToScalars(
Value *Object = getUnderlyingObject(SomePtr);
SafeToInsertStore =
(isAllocLikeFn(Object, TLI) || isa<AllocaInst>(Object)) &&
- !PointerMayBeCaptured(Object, true, true);
+ isNotCapturedBeforeOrInLoop(Object, CurLoop, DT);
}
}
@@ -2218,6 +2295,67 @@ bool llvm::promoteLoopAccessesToScalars(
return true;
}
+static void foreachMemoryAccess(MemorySSA *MSSA, Loop *L,
+ function_ref<void(Instruction *)> Fn) {
+ for (const BasicBlock *BB : L->blocks())
+ if (const auto *Accesses = MSSA->getBlockAccesses(BB))
+ for (const auto &Access : *Accesses)
+ if (const auto *MUD = dyn_cast<MemoryUseOrDef>(&Access))
+ Fn(MUD->getMemoryInst());
+}
+
+static SmallVector<SmallSetVector<Value *, 8>, 0>
+collectPromotionCandidates(MemorySSA *MSSA, AliasAnalysis *AA, Loop *L) {
+ AliasSetTracker AST(*AA);
+
+ auto IsPotentiallyPromotable = [L](const Instruction *I) {
+ if (const auto *SI = dyn_cast<StoreInst>(I))
+ return L->isLoopInvariant(SI->getPointerOperand());
+ if (const auto *LI = dyn_cast<LoadInst>(I))
+ return L->isLoopInvariant(LI->getPointerOperand());
+ return false;
+ };
+
+ // Populate AST with potentially promotable accesses and remove them from
+ // MaybePromotable, so they will not be checked again on the next iteration.
+ SmallPtrSet<Value *, 16> AttemptingPromotion;
+ foreachMemoryAccess(MSSA, L, [&](Instruction *I) {
+ if (IsPotentiallyPromotable(I)) {
+ AttemptingPromotion.insert(I);
+ AST.add(I);
+ }
+ });
+
+ // We're only interested in must-alias sets that contain a mod.
+ SmallVector<const AliasSet *, 8> Sets;
+ for (AliasSet &AS : AST)
+ if (!AS.isForwardingAliasSet() && AS.isMod() && AS.isMustAlias())
+ Sets.push_back(&AS);
+
+ if (Sets.empty())
+ return {}; // Nothing to promote...
+
+ // Discard any sets for which there is an aliasing non-promotable access.
+ foreachMemoryAccess(MSSA, L, [&](Instruction *I) {
+ if (AttemptingPromotion.contains(I))
+ return;
+
+ llvm::erase_if(Sets, [&](const AliasSet *AS) {
+ return AS->aliasesUnknownInst(I, *AA);
+ });
+ });
+
+ SmallVector<SmallSetVector<Value *, 8>, 0> Result;
+ for (const AliasSet *Set : Sets) {
+ SmallSetVector<Value *, 8> PointerMustAliases;
+ for (const auto &ASI : *Set)
+ PointerMustAliases.insert(ASI.getValue());
+ Result.push_back(std::move(PointerMustAliases));
+ }
+
+ return Result;
+}
+
/// Returns an owning pointer to an alias set which incorporates aliasing info
/// from L and all subloops of L.
std::unique_ptr<AliasSetTracker>
@@ -2238,15 +2376,6 @@ LoopInvariantCodeMotion::collectAliasInfoForLoop(Loop *L, LoopInfo *LI,
return CurAST;
}
-std::unique_ptr<AliasSetTracker>
-LoopInvariantCodeMotion::collectAliasInfoForLoopWithMSSA(
- Loop *L, AAResults *AA, MemorySSAUpdater *MSSAU) {
- auto *MSSA = MSSAU->getMemorySSA();
- auto CurAST = std::make_unique<AliasSetTracker>(*AA, MSSA, L);
- CurAST->addAllInstructionsInLoopUsingMSSA();
- return CurAST;
-}
-
static bool pointerInvalidatedByLoop(MemoryLocation MemLoc,
AliasSetTracker *CurAST, Loop *CurLoop,
AAResults *AA) {
diff --git a/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp b/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
new file mode 100644
index 000000000000..993b154dc9a8
--- /dev/null
+++ b/llvm/lib/Transforms/Scalar/LoopBoundSplit.cpp
@@ -0,0 +1,439 @@
+//===------- LoopBoundSplit.cpp - Split Loop Bound --------------*- C++ -*-===//
+//
+// 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/Transforms/Scalar/LoopBoundSplit.h"
+#include "llvm/Analysis/LoopAccessAnalysis.h"
+#include "llvm/Analysis/LoopAnalysisManager.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/LoopIterator.h"
+#include "llvm/Analysis/LoopPass.h"
+#include "llvm/Analysis/MemorySSA.h"
+#include "llvm/Analysis/MemorySSAUpdater.h"
+#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
+#include "llvm/IR/PatternMatch.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/Transforms/Utils/LoopSimplify.h"
+#include "llvm/Transforms/Utils/LoopUtils.h"
+#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
+
+#define DEBUG_TYPE "loop-bound-split"
+
+namespace llvm {
+
+using namespace PatternMatch;
+
+namespace {
+struct ConditionInfo {
+ /// Branch instruction with this condition
+ BranchInst *BI;
+ /// ICmp instruction with this condition
+ ICmpInst *ICmp;
+ /// Preciate info
+ ICmpInst::Predicate Pred;
+ /// AddRec llvm value
+ Value *AddRecValue;
+ /// Bound llvm value
+ Value *BoundValue;
+ /// AddRec SCEV
+ const SCEV *AddRecSCEV;
+ /// Bound SCEV
+ const SCEV *BoundSCEV;
+
+ ConditionInfo()
+ : BI(nullptr), ICmp(nullptr), Pred(ICmpInst::BAD_ICMP_PREDICATE),
+ AddRecValue(nullptr), BoundValue(nullptr), AddRecSCEV(nullptr),
+ BoundSCEV(nullptr) {}
+};
+} // namespace
+
+static void analyzeICmp(ScalarEvolution &SE, ICmpInst *ICmp,
+ ConditionInfo &Cond) {
+ Cond.ICmp = ICmp;
+ if (match(ICmp, m_ICmp(Cond.Pred, m_Value(Cond.AddRecValue),
+ m_Value(Cond.BoundValue)))) {
+ Cond.AddRecSCEV = SE.getSCEV(Cond.AddRecValue);
+ Cond.BoundSCEV = SE.getSCEV(Cond.BoundValue);
+ // Locate AddRec in LHSSCEV and Bound in RHSSCEV.
+ if (isa<SCEVAddRecExpr>(Cond.BoundSCEV) &&
+ !isa<SCEVAddRecExpr>(Cond.AddRecSCEV)) {
+ std::swap(Cond.AddRecValue, Cond.BoundValue);
+ std::swap(Cond.AddRecSCEV, Cond.BoundSCEV);
+ Cond.Pred = ICmpInst::getSwappedPredicate(Cond.Pred);
+ }
+ }
+}
+
+static bool calculateUpperBound(const Loop &L, ScalarEvolution &SE,
+ ConditionInfo &Cond, bool IsExitCond) {
+ if (IsExitCond) {
+ const SCEV *ExitCount = SE.getExitCount(&L, Cond.ICmp->getParent());
+ if (isa<SCEVCouldNotCompute>(ExitCount))
+ return false;
+
+ Cond.BoundSCEV = ExitCount;
+ return true;
+ }
+
+ // For non-exit condtion, if pred is LT, keep existing bound.
+ if (Cond.Pred == ICmpInst::ICMP_SLT || Cond.Pred == ICmpInst::ICMP_ULT)
+ return true;
+
+ // For non-exit condition, if pre is LE, try to convert it to LT.
+ // Range Range
+ // AddRec <= Bound --> AddRec < Bound + 1
+ if (Cond.Pred != ICmpInst::ICMP_ULE && Cond.Pred != ICmpInst::ICMP_SLE)
+ return false;
+
+ if (IntegerType *BoundSCEVIntType =
+ dyn_cast<IntegerType>(Cond.BoundSCEV->getType())) {
+ unsigned BitWidth = BoundSCEVIntType->getBitWidth();
+ APInt Max = ICmpInst::isSigned(Cond.Pred)
+ ? APInt::getSignedMaxValue(BitWidth)
+ : APInt::getMaxValue(BitWidth);
+ const SCEV *MaxSCEV = SE.getConstant(Max);
+ // Check Bound < INT_MAX
+ ICmpInst::Predicate Pred =
+ ICmpInst::isSigned(Cond.Pred) ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT;
+ if (SE.isKnownPredicate(Pred, Cond.BoundSCEV, MaxSCEV)) {
+ const SCEV *BoundPlusOneSCEV =
+ SE.getAddExpr(Cond.BoundSCEV, SE.getOne(BoundSCEVIntType));
+ Cond.BoundSCEV = BoundPlusOneSCEV;
+ Cond.Pred = Pred;
+ return true;
+ }
+ }
+
+ // ToDo: Support ICMP_NE/EQ.
+
+ return false;
+}
+
+static bool hasProcessableCondition(const Loop &L, ScalarEvolution &SE,
+ ICmpInst *ICmp, ConditionInfo &Cond,
+ bool IsExitCond) {
+ analyzeICmp(SE, ICmp, Cond);
+
+ // The BoundSCEV should be evaluated at loop entry.
+ if (!SE.isAvailableAtLoopEntry(Cond.BoundSCEV, &L))
+ return false;
+
+ const SCEVAddRecExpr *AddRecSCEV = dyn_cast<SCEVAddRecExpr>(Cond.AddRecSCEV);
+ // Allowed AddRec as induction variable.
+ if (!AddRecSCEV)
+ return false;
+
+ if (!AddRecSCEV->isAffine())
+ return false;
+
+ const SCEV *StepRecSCEV = AddRecSCEV->getStepRecurrence(SE);
+ // Allowed constant step.
+ if (!isa<SCEVConstant>(StepRecSCEV))
+ return false;
+
+ ConstantInt *StepCI = cast<SCEVConstant>(StepRecSCEV)->getValue();
+ // Allowed positive step for now.
+ // TODO: Support negative step.
+ if (StepCI->isNegative() || StepCI->isZero())
+ return false;
+
+ // Calculate upper bound.
+ if (!calculateUpperBound(L, SE, Cond, IsExitCond))
+ return false;
+
+ return true;
+}
+
+static bool isProcessableCondBI(const ScalarEvolution &SE,
+ const BranchInst *BI) {
+ BasicBlock *TrueSucc = nullptr;
+ BasicBlock *FalseSucc = nullptr;
+ ICmpInst::Predicate Pred;
+ Value *LHS, *RHS;
+ if (!match(BI, m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)),
+ m_BasicBlock(TrueSucc), m_BasicBlock(FalseSucc))))
+ return false;
+
+ if (!SE.isSCEVable(LHS->getType()))
+ return false;
+ assert(SE.isSCEVable(RHS->getType()) && "Expected RHS's type is SCEVable");
+
+ if (TrueSucc == FalseSucc)
+ return false;
+
+ return true;
+}
+
+static bool canSplitLoopBound(const Loop &L, const DominatorTree &DT,
+ ScalarEvolution &SE, ConditionInfo &Cond) {
+ // Skip function with optsize.
+ if (L.getHeader()->getParent()->hasOptSize())
+ return false;
+
+ // Split only innermost loop.
+ if (!L.isInnermost())
+ return false;
+
+ // Check loop is in simplified form.
+ if (!L.isLoopSimplifyForm())
+ return false;
+
+ // Check loop is in LCSSA form.
+ if (!L.isLCSSAForm(DT))
+ return false;
+
+ // Skip loop that cannot be cloned.
+ if (!L.isSafeToClone())
+ return false;
+
+ BasicBlock *ExitingBB = L.getExitingBlock();
+ // Assumed only one exiting block.
+ if (!ExitingBB)
+ return false;
+
+ BranchInst *ExitingBI = dyn_cast<BranchInst>(ExitingBB->getTerminator());
+ if (!ExitingBI)
+ return false;
+
+ // Allowed only conditional branch with ICmp.
+ if (!isProcessableCondBI(SE, ExitingBI))
+ return false;
+
+ // Check the condition is processable.
+ ICmpInst *ICmp = cast<ICmpInst>(ExitingBI->getCondition());
+ if (!hasProcessableCondition(L, SE, ICmp, Cond, /*IsExitCond*/ true))
+ return false;
+
+ Cond.BI = ExitingBI;
+ return true;
+}
+
+static bool isProfitableToTransform(const Loop &L, const BranchInst *BI) {
+ // If the conditional branch splits a loop into two halves, we could
+ // generally say it is profitable.
+ //
+ // ToDo: Add more profitable cases here.
+
+ // Check this branch causes diamond CFG.
+ BasicBlock *Succ0 = BI->getSuccessor(0);
+ BasicBlock *Succ1 = BI->getSuccessor(1);
+
+ BasicBlock *Succ0Succ = Succ0->getSingleSuccessor();
+ BasicBlock *Succ1Succ = Succ1->getSingleSuccessor();
+ if (!Succ0Succ || !Succ1Succ || Succ0Succ != Succ1Succ)
+ return false;
+
+ // ToDo: Calculate each successor's instruction cost.
+
+ return true;
+}
+
+static BranchInst *findSplitCandidate(const Loop &L, ScalarEvolution &SE,
+ ConditionInfo &ExitingCond,
+ ConditionInfo &SplitCandidateCond) {
+ for (auto *BB : L.blocks()) {
+ // Skip condition of backedge.
+ if (L.getLoopLatch() == BB)
+ continue;
+
+ auto *BI = dyn_cast<BranchInst>(BB->getTerminator());
+ if (!BI)
+ continue;
+
+ // Check conditional branch with ICmp.
+ if (!isProcessableCondBI(SE, BI))
+ continue;
+
+ // Skip loop invariant condition.
+ if (L.isLoopInvariant(BI->getCondition()))
+ continue;
+
+ // Check the condition is processable.
+ ICmpInst *ICmp = cast<ICmpInst>(BI->getCondition());
+ if (!hasProcessableCondition(L, SE, ICmp, SplitCandidateCond,
+ /*IsExitCond*/ false))
+ continue;
+
+ if (ExitingCond.BoundSCEV->getType() !=
+ SplitCandidateCond.BoundSCEV->getType())
+ continue;
+
+ SplitCandidateCond.BI = BI;
+ return BI;
+ }
+
+ return nullptr;
+}
+
+static bool splitLoopBound(Loop &L, DominatorTree &DT, LoopInfo &LI,
+ ScalarEvolution &SE, LPMUpdater &U) {
+ ConditionInfo SplitCandidateCond;
+ ConditionInfo ExitingCond;
+
+ // Check we can split this loop's bound.
+ if (!canSplitLoopBound(L, DT, SE, ExitingCond))
+ return false;
+
+ if (!findSplitCandidate(L, SE, ExitingCond, SplitCandidateCond))
+ return false;
+
+ if (!isProfitableToTransform(L, SplitCandidateCond.BI))
+ return false;
+
+ // Now, we have a split candidate. Let's build a form as below.
+ // +--------------------+
+ // | preheader |
+ // | set up newbound |
+ // +--------------------+
+ // | /----------------\
+ // +--------v----v------+ |
+ // | header |---\ |
+ // | with true condition| | |
+ // +--------------------+ | |
+ // | | |
+ // +--------v-----------+ | |
+ // | if.then.BB | | |
+ // +--------------------+ | |
+ // | | |
+ // +--------v-----------<---/ |
+ // | latch >----------/
+ // | with newbound |
+ // +--------------------+
+ // |
+ // +--------v-----------+
+ // | preheader2 |--------------\
+ // | if (AddRec i != | |
+ // | org bound) | |
+ // +--------------------+ |
+ // | /----------------\ |
+ // +--------v----v------+ | |
+ // | header2 |---\ | |
+ // | conditional branch | | | |
+ // |with false condition| | | |
+ // +--------------------+ | | |
+ // | | | |
+ // +--------v-----------+ | | |
+ // | if.then.BB2 | | | |
+ // +--------------------+ | | |
+ // | | | |
+ // +--------v-----------<---/ | |
+ // | latch2 >----------/ |
+ // | with org bound | |
+ // +--------v-----------+ |
+ // | |
+ // | +---------------+ |
+ // +--> exit <-------/
+ // +---------------+
+
+ // Let's create post loop.
+ SmallVector<BasicBlock *, 8> PostLoopBlocks;
+ Loop *PostLoop;
+ ValueToValueMapTy VMap;
+ BasicBlock *PreHeader = L.getLoopPreheader();
+ BasicBlock *SplitLoopPH = SplitEdge(PreHeader, L.getHeader(), &DT, &LI);
+ PostLoop = cloneLoopWithPreheader(L.getExitBlock(), SplitLoopPH, &L, VMap,
+ ".split", &LI, &DT, PostLoopBlocks);
+ remapInstructionsInBlocks(PostLoopBlocks, VMap);
+
+ // Add conditional branch to check we can skip post-loop in its preheader.
+ BasicBlock *PostLoopPreHeader = PostLoop->getLoopPreheader();
+ IRBuilder<> Builder(PostLoopPreHeader);
+ Instruction *OrigBI = PostLoopPreHeader->getTerminator();
+ ICmpInst::Predicate Pred = ICmpInst::ICMP_NE;
+ Value *Cond =
+ Builder.CreateICmp(Pred, ExitingCond.AddRecValue, ExitingCond.BoundValue);
+ Builder.CreateCondBr(Cond, PostLoop->getHeader(), PostLoop->getExitBlock());
+ OrigBI->eraseFromParent();
+
+ // Create new loop bound and add it into preheader of pre-loop.
+ const SCEV *NewBoundSCEV = ExitingCond.BoundSCEV;
+ const SCEV *SplitBoundSCEV = SplitCandidateCond.BoundSCEV;
+ NewBoundSCEV = ICmpInst::isSigned(ExitingCond.Pred)
+ ? SE.getSMinExpr(NewBoundSCEV, SplitBoundSCEV)
+ : SE.getUMinExpr(NewBoundSCEV, SplitBoundSCEV);
+
+ SCEVExpander Expander(
+ SE, L.getHeader()->getParent()->getParent()->getDataLayout(), "split");
+ Instruction *InsertPt = SplitLoopPH->getTerminator();
+ Value *NewBoundValue =
+ Expander.expandCodeFor(NewBoundSCEV, NewBoundSCEV->getType(), InsertPt);
+ NewBoundValue->setName("new.bound");
+
+ // Replace exiting bound value of pre-loop NewBound.
+ ExitingCond.ICmp->setOperand(1, NewBoundValue);
+
+ // Replace IV's start value of post-loop by NewBound.
+ for (PHINode &PN : L.getHeader()->phis()) {
+ // Find PHI with exiting condition from pre-loop.
+ if (SE.isSCEVable(PN.getType()) && isa<SCEVAddRecExpr>(SE.getSCEV(&PN))) {
+ for (Value *Op : PN.incoming_values()) {
+ if (Op == ExitingCond.AddRecValue) {
+ // Find cloned PHI for post-loop.
+ PHINode *PostLoopPN = cast<PHINode>(VMap[&PN]);
+ PostLoopPN->setIncomingValueForBlock(PostLoopPreHeader,
+ NewBoundValue);
+ }
+ }
+ }
+ }
+
+ // Replace SplitCandidateCond.BI's condition of pre-loop by True.
+ LLVMContext &Context = PreHeader->getContext();
+ SplitCandidateCond.BI->setCondition(ConstantInt::getTrue(Context));
+
+ // Replace cloned SplitCandidateCond.BI's condition in post-loop by False.
+ BranchInst *ClonedSplitCandidateBI =
+ cast<BranchInst>(VMap[SplitCandidateCond.BI]);
+ ClonedSplitCandidateBI->setCondition(ConstantInt::getFalse(Context));
+
+ // Replace exit branch target of pre-loop by post-loop's preheader.
+ if (L.getExitBlock() == ExitingCond.BI->getSuccessor(0))
+ ExitingCond.BI->setSuccessor(0, PostLoopPreHeader);
+ else
+ ExitingCond.BI->setSuccessor(1, PostLoopPreHeader);
+
+ // Update dominator tree.
+ DT.changeImmediateDominator(PostLoopPreHeader, L.getExitingBlock());
+ DT.changeImmediateDominator(PostLoop->getExitBlock(), PostLoopPreHeader);
+
+ // Invalidate cached SE information.
+ SE.forgetLoop(&L);
+
+ // Canonicalize loops.
+ // TODO: Try to update LCSSA information according to above change.
+ formLCSSA(L, DT, &LI, &SE);
+ simplifyLoop(&L, &DT, &LI, &SE, nullptr, nullptr, true);
+ formLCSSA(*PostLoop, DT, &LI, &SE);
+ simplifyLoop(PostLoop, &DT, &LI, &SE, nullptr, nullptr, true);
+
+ // Add new post-loop to loop pass manager.
+ U.addSiblingLoops(PostLoop);
+
+ return true;
+}
+
+PreservedAnalyses LoopBoundSplitPass::run(Loop &L, LoopAnalysisManager &AM,
+ LoopStandardAnalysisResults &AR,
+ LPMUpdater &U) {
+ Function &F = *L.getHeader()->getParent();
+ (void)F;
+
+ LLVM_DEBUG(dbgs() << "Spliting bound of loop in " << F.getName() << ": " << L
+ << "\n");
+
+ if (!splitLoopBound(L, AR.DT, AR.LI, AR.SE, U))
+ return PreservedAnalyses::all();
+
+ assert(AR.DT.verify(DominatorTree::VerificationLevel::Fast));
+ AR.LI.verify(AR.DT);
+
+ return getLoopPassPreservedAnalyses();
+}
+
+} // end namespace llvm
diff --git a/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp b/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp
index 45cdcb2f37dd..a5d7835bd094 100644
--- a/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp
@@ -13,7 +13,6 @@
#include "llvm/Transforms/Scalar/LoopDataPrefetch.h"
#include "llvm/InitializePasses.h"
-#define DEBUG_TYPE "loop-data-prefetch"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
@@ -33,6 +32,9 @@
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
+
+#define DEBUG_TYPE "loop-data-prefetch"
+
using namespace llvm;
// By default, we limit this to creating 16 PHIs (which is a little over half
diff --git a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
index 1266c93316fa..f7e8442fae81 100644
--- a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
@@ -16,11 +16,15 @@
#include "llvm/Transforms/Scalar/LoopDeletion.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/GlobalsModRef.h"
+#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/LoopIterator.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/IR/Dominators.h"
+
#include "llvm/IR/PatternMatch.h"
#include "llvm/InitializePasses.h"
#include "llvm/Transforms/Scalar.h"
@@ -33,6 +37,11 @@ using namespace llvm;
STATISTIC(NumDeleted, "Number of loops deleted");
+static cl::opt<bool> EnableSymbolicExecution(
+ "loop-deletion-enable-symbolic-execution", cl::Hidden, cl::init(true),
+ cl::desc("Break backedge through symbolic execution of 1st iteration "
+ "attempting to prove that the backedge is never taken"));
+
enum class LoopDeletionResult {
Unmodified,
Modified,
@@ -54,7 +63,7 @@ static LoopDeletionResult merge(LoopDeletionResult A, LoopDeletionResult B) {
static bool isLoopDead(Loop *L, ScalarEvolution &SE,
SmallVectorImpl<BasicBlock *> &ExitingBlocks,
BasicBlock *ExitBlock, bool &Changed,
- BasicBlock *Preheader) {
+ BasicBlock *Preheader, LoopInfo &LI) {
// Make sure that all PHI entries coming from the loop are loop invariant.
// Because the code is in LCSSA form, any values used outside of the loop
// must pass through a PHI in the exit block, meaning that this check is
@@ -100,6 +109,36 @@ static bool isLoopDead(Loop *L, ScalarEvolution &SE,
return I.mayHaveSideEffects() && !I.isDroppable();
}))
return false;
+
+ // The loop or any of its sub-loops looping infinitely is legal. The loop can
+ // only be considered dead if either
+ // a. the function is mustprogress.
+ // b. all (sub-)loops are mustprogress or have a known trip-count.
+ if (L->getHeader()->getParent()->mustProgress())
+ return true;
+
+ LoopBlocksRPO RPOT(L);
+ RPOT.perform(&LI);
+ // If the loop contains an irreducible cycle, it may loop infinitely.
+ if (containsIrreducibleCFG<const BasicBlock *>(RPOT, LI))
+ return false;
+
+ SmallVector<Loop *, 8> WorkList;
+ WorkList.push_back(L);
+ while (!WorkList.empty()) {
+ Loop *Current = WorkList.pop_back_val();
+ if (hasMustProgress(Current))
+ continue;
+
+ const SCEV *S = SE.getConstantMaxBackedgeTakenCount(Current);
+ if (isa<SCEVCouldNotCompute>(S)) {
+ LLVM_DEBUG(
+ dbgs() << "Could not compute SCEV MaxBackedgeTakenCount and was "
+ "not required to make progress.\n");
+ return false;
+ }
+ WorkList.append(Current->begin(), Current->end());
+ }
return true;
}
@@ -114,7 +153,7 @@ static bool isLoopNeverExecuted(Loop *L) {
// predecessor.
assert(Preheader && "Needs preheader!");
- if (Preheader == &Preheader->getParent()->getEntryBlock())
+ if (Preheader->isEntryBlock())
return false;
// All predecessors of the preheader should have a constant conditional
// branch, with the loop's preheader as not-taken.
@@ -135,6 +174,213 @@ static bool isLoopNeverExecuted(Loop *L) {
return true;
}
+static Value *
+getValueOnFirstIteration(Value *V, DenseMap<Value *, Value *> &FirstIterValue,
+ const SimplifyQuery &SQ) {
+ // Quick hack: do not flood cache with non-instruction values.
+ if (!isa<Instruction>(V))
+ return V;
+ // Do we already know cached result?
+ auto Existing = FirstIterValue.find(V);
+ if (Existing != FirstIterValue.end())
+ return Existing->second;
+ Value *FirstIterV = nullptr;
+ if (auto *BO = dyn_cast<BinaryOperator>(V)) {
+ Value *LHS =
+ getValueOnFirstIteration(BO->getOperand(0), FirstIterValue, SQ);
+ Value *RHS =
+ getValueOnFirstIteration(BO->getOperand(1), FirstIterValue, SQ);
+ FirstIterV = SimplifyBinOp(BO->getOpcode(), LHS, RHS, SQ);
+ }
+ if (!FirstIterV)
+ FirstIterV = V;
+ FirstIterValue[V] = FirstIterV;
+ return FirstIterV;
+}
+
+// Try to prove that one of conditions that dominates the latch must exit on 1st
+// iteration.
+static bool canProveExitOnFirstIteration(Loop *L, DominatorTree &DT,
+ LoopInfo &LI) {
+ // Disabled by option.
+ if (!EnableSymbolicExecution)
+ return false;
+
+ BasicBlock *Predecessor = L->getLoopPredecessor();
+ BasicBlock *Latch = L->getLoopLatch();
+
+ if (!Predecessor || !Latch)
+ return false;
+
+ LoopBlocksRPO RPOT(L);
+ RPOT.perform(&LI);
+
+ // For the optimization to be correct, we need RPOT to have a property that
+ // each block is processed after all its predecessors, which may only be
+ // violated for headers of the current loop and all nested loops. Irreducible
+ // CFG provides multiple ways to break this assumption, so we do not want to
+ // deal with it.
+ if (containsIrreducibleCFG<const BasicBlock *>(RPOT, LI))
+ return false;
+
+ BasicBlock *Header = L->getHeader();
+ // Blocks that are reachable on the 1st iteration.
+ SmallPtrSet<BasicBlock *, 4> LiveBlocks;
+ // Edges that are reachable on the 1st iteration.
+ DenseSet<BasicBlockEdge> LiveEdges;
+ LiveBlocks.insert(Header);
+
+ SmallPtrSet<BasicBlock *, 4> Visited;
+ auto MarkLiveEdge = [&](BasicBlock *From, BasicBlock *To) {
+ assert(LiveBlocks.count(From) && "Must be live!");
+ assert((LI.isLoopHeader(To) || !Visited.count(To)) &&
+ "Only canonical backedges are allowed. Irreducible CFG?");
+ assert((LiveBlocks.count(To) || !Visited.count(To)) &&
+ "We already discarded this block as dead!");
+ LiveBlocks.insert(To);
+ LiveEdges.insert({ From, To });
+ };
+
+ auto MarkAllSuccessorsLive = [&](BasicBlock *BB) {
+ for (auto *Succ : successors(BB))
+ MarkLiveEdge(BB, Succ);
+ };
+
+ // Check if there is only one value coming from all live predecessor blocks.
+ // Note that because we iterate in RPOT, we have already visited all its
+ // (non-latch) predecessors.
+ auto GetSoleInputOnFirstIteration = [&](PHINode & PN)->Value * {
+ BasicBlock *BB = PN.getParent();
+ bool HasLivePreds = false;
+ (void)HasLivePreds;
+ if (BB == Header)
+ return PN.getIncomingValueForBlock(Predecessor);
+ Value *OnlyInput = nullptr;
+ for (auto *Pred : predecessors(BB))
+ if (LiveEdges.count({ Pred, BB })) {
+ HasLivePreds = true;
+ Value *Incoming = PN.getIncomingValueForBlock(Pred);
+ // Skip undefs. If they are present, we can assume they are equal to
+ // the non-undef input.
+ if (isa<UndefValue>(Incoming))
+ continue;
+ // Two inputs.
+ if (OnlyInput && OnlyInput != Incoming)
+ return nullptr;
+ OnlyInput = Incoming;
+ }
+
+ assert(HasLivePreds && "No live predecessors?");
+ // If all incoming live value were undefs, return undef.
+ return OnlyInput ? OnlyInput : UndefValue::get(PN.getType());
+ };
+ DenseMap<Value *, Value *> FirstIterValue;
+
+ // Use the following algorithm to prove we never take the latch on the 1st
+ // iteration:
+ // 1. Traverse in topological order, so that whenever we visit a block, all
+ // its predecessors are already visited.
+ // 2. If we can prove that the block may have only 1 predecessor on the 1st
+ // iteration, map all its phis onto input from this predecessor.
+ // 3a. If we can prove which successor of out block is taken on the 1st
+ // iteration, mark this successor live.
+ // 3b. If we cannot prove it, conservatively assume that all successors are
+ // live.
+ auto &DL = Header->getModule()->getDataLayout();
+ const SimplifyQuery SQ(DL);
+ for (auto *BB : RPOT) {
+ Visited.insert(BB);
+
+ // This block is not reachable on the 1st iterations.
+ if (!LiveBlocks.count(BB))
+ continue;
+
+ // Skip inner loops.
+ if (LI.getLoopFor(BB) != L) {
+ MarkAllSuccessorsLive(BB);
+ continue;
+ }
+
+ // If Phi has only one input from all live input blocks, use it.
+ for (auto &PN : BB->phis()) {
+ if (!PN.getType()->isIntegerTy())
+ continue;
+ auto *Incoming = GetSoleInputOnFirstIteration(PN);
+ if (Incoming && DT.dominates(Incoming, BB->getTerminator())) {
+ Value *FirstIterV =
+ getValueOnFirstIteration(Incoming, FirstIterValue, SQ);
+ FirstIterValue[&PN] = FirstIterV;
+ }
+ }
+
+ using namespace PatternMatch;
+ ICmpInst::Predicate Pred;
+ Value *LHS, *RHS;
+ BasicBlock *IfTrue, *IfFalse;
+ auto *Term = BB->getTerminator();
+ if (match(Term, m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)),
+ m_BasicBlock(IfTrue), m_BasicBlock(IfFalse)))) {
+ if (!LHS->getType()->isIntegerTy()) {
+ MarkAllSuccessorsLive(BB);
+ continue;
+ }
+
+ // Can we prove constant true or false for this condition?
+ LHS = getValueOnFirstIteration(LHS, FirstIterValue, SQ);
+ RHS = getValueOnFirstIteration(RHS, FirstIterValue, SQ);
+ auto *KnownCondition = SimplifyICmpInst(Pred, LHS, RHS, SQ);
+ if (!KnownCondition) {
+ // Failed to simplify.
+ MarkAllSuccessorsLive(BB);
+ continue;
+ }
+ if (isa<UndefValue>(KnownCondition)) {
+ // TODO: According to langref, branching by undef is undefined behavior.
+ // It means that, theoretically, we should be able to just continue
+ // without marking any successors as live. However, we are not certain
+ // how correct our compiler is at handling such cases. So we are being
+ // very conservative here.
+ //
+ // If there is a non-loop successor, always assume this branch leaves the
+ // loop. Otherwise, arbitrarily take IfTrue.
+ //
+ // Once we are certain that branching by undef is handled correctly by
+ // other transforms, we should not mark any successors live here.
+ if (L->contains(IfTrue) && L->contains(IfFalse))
+ MarkLiveEdge(BB, IfTrue);
+ continue;
+ }
+ auto *ConstCondition = dyn_cast<ConstantInt>(KnownCondition);
+ if (!ConstCondition) {
+ // Non-constant condition, cannot analyze any further.
+ MarkAllSuccessorsLive(BB);
+ continue;
+ }
+ if (ConstCondition->isAllOnesValue())
+ MarkLiveEdge(BB, IfTrue);
+ else
+ MarkLiveEdge(BB, IfFalse);
+ } else if (SwitchInst *SI = dyn_cast<SwitchInst>(Term)) {
+ auto *SwitchValue = SI->getCondition();
+ auto *SwitchValueOnFirstIter =
+ getValueOnFirstIteration(SwitchValue, FirstIterValue, SQ);
+ auto *ConstSwitchValue = dyn_cast<ConstantInt>(SwitchValueOnFirstIter);
+ if (!ConstSwitchValue) {
+ MarkAllSuccessorsLive(BB);
+ continue;
+ }
+ auto CaseIterator = SI->findCaseValue(ConstSwitchValue);
+ MarkLiveEdge(BB, CaseIterator->getCaseSuccessor());
+ } else {
+ MarkAllSuccessorsLive(BB);
+ continue;
+ }
+ }
+
+ // We can break the latch if it wasn't live.
+ return !LiveEdges.count({ Latch, Header });
+}
+
/// If we can prove the backedge is untaken, remove it. This destroys the
/// loop, but leaves the (now trivially loop invariant) control flow and
/// side effects (if any) in place.
@@ -148,7 +394,9 @@ breakBackedgeIfNotTaken(Loop *L, DominatorTree &DT, ScalarEvolution &SE,
return LoopDeletionResult::Unmodified;
auto *BTC = SE.getBackedgeTakenCount(L);
- if (!BTC->isZero())
+ if (!isa<SCEVCouldNotCompute>(BTC) && SE.isKnownNonZero(BTC))
+ return LoopDeletionResult::Unmodified;
+ if (!BTC->isZero() && !canProveExitOnFirstIteration(L, DT, LI))
return LoopDeletionResult::Unmodified;
breakLoopBackedge(L, DT, SE, LI, MSSA);
@@ -224,23 +472,12 @@ static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT,
}
// Finally, we have to check that the loop really is dead.
bool Changed = false;
- if (!isLoopDead(L, SE, ExitingBlocks, ExitBlock, Changed, Preheader)) {
+ if (!isLoopDead(L, SE, ExitingBlocks, ExitBlock, Changed, Preheader, LI)) {
LLVM_DEBUG(dbgs() << "Loop is not invariant, cannot delete.\n");
return Changed ? LoopDeletionResult::Modified
: LoopDeletionResult::Unmodified;
}
- // Don't remove loops for which we can't solve the trip count unless the loop
- // was required to make progress but has been determined to be dead.
- const SCEV *S = SE.getConstantMaxBackedgeTakenCount(L);
- if (isa<SCEVCouldNotCompute>(S) &&
- !L->getHeader()->getParent()->mustProgress() && !hasMustProgress(L)) {
- LLVM_DEBUG(dbgs() << "Could not compute SCEV MaxBackedgeTakenCount and was "
- "not required to make progress.\n");
- return Changed ? LoopDeletionResult::Modified
- : LoopDeletionResult::Unmodified;
- }
-
LLVM_DEBUG(dbgs() << "Loop is invariant, delete it!");
ORE.emit([&]() {
return OptimizationRemark(DEBUG_TYPE, "Invariant", L->getStartLoc(),
diff --git a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
index 1bd2529891b7..bac3dc0f3fb9 100644
--- a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp
@@ -1068,7 +1068,6 @@ PreservedAnalyses LoopDistributePass::run(Function &F,
PreservedAnalyses PA;
PA.preserve<LoopAnalysis>();
PA.preserve<DominatorTreeAnalysis>();
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/LoopFlatten.cpp b/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
index aaff68436c13..f54289f85ef5 100644
--- a/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
@@ -63,7 +63,7 @@ static cl::opt<bool>
AssumeNoOverflow("loop-flatten-assume-no-overflow", cl::Hidden,
cl::init(false),
cl::desc("Assume that the product of the two iteration "
- "limits will never overflow"));
+ "trip counts will never overflow"));
static cl::opt<bool>
WidenIV("loop-flatten-widen-iv", cl::Hidden,
@@ -74,10 +74,12 @@ static cl::opt<bool>
struct FlattenInfo {
Loop *OuterLoop = nullptr;
Loop *InnerLoop = nullptr;
+ // These PHINodes correspond to loop induction variables, which are expected
+ // to start at zero and increment by one on each loop.
PHINode *InnerInductionPHI = nullptr;
PHINode *OuterInductionPHI = nullptr;
- Value *InnerLimit = nullptr;
- Value *OuterLimit = nullptr;
+ Value *InnerTripCount = nullptr;
+ Value *OuterTripCount = nullptr;
BinaryOperator *InnerIncrement = nullptr;
BinaryOperator *OuterIncrement = nullptr;
BranchInst *InnerBranch = nullptr;
@@ -91,12 +93,12 @@ struct FlattenInfo {
FlattenInfo(Loop *OL, Loop *IL) : OuterLoop(OL), InnerLoop(IL) {};
};
-// Finds the induction variable, increment and limit for a simple loop that we
-// can flatten.
+// Finds the induction variable, increment and trip count for a simple loop that
+// we can flatten.
static bool findLoopComponents(
Loop *L, SmallPtrSetImpl<Instruction *> &IterationInstructions,
- PHINode *&InductionPHI, Value *&Limit, BinaryOperator *&Increment,
- BranchInst *&BackBranch, ScalarEvolution *SE) {
+ PHINode *&InductionPHI, Value *&TripCount, BinaryOperator *&Increment,
+ BranchInst *&BackBranch, ScalarEvolution *SE, bool IsWidened) {
LLVM_DEBUG(dbgs() << "Finding components of loop: " << L->getName() << "\n");
if (!L->isLoopSimplifyForm()) {
@@ -104,6 +106,13 @@ static bool findLoopComponents(
return false;
}
+ // Currently, to simplify the implementation, the Loop induction variable must
+ // start at zero and increment with a step size of one.
+ if (!L->isCanonical(*SE)) {
+ LLVM_DEBUG(dbgs() << "Loop is not canonical\n");
+ return false;
+ }
+
// There must be exactly one exiting block, and it must be the same at the
// latch.
BasicBlock *Latch = L->getLoopLatch();
@@ -111,33 +120,18 @@ static bool findLoopComponents(
LLVM_DEBUG(dbgs() << "Exiting and latch block are different\n");
return false;
}
- // Latch block must end in a conditional branch.
- BackBranch = dyn_cast<BranchInst>(Latch->getTerminator());
- if (!BackBranch || !BackBranch->isConditional()) {
- LLVM_DEBUG(dbgs() << "Could not find back-branch\n");
- return false;
- }
- IterationInstructions.insert(BackBranch);
- LLVM_DEBUG(dbgs() << "Found back branch: "; BackBranch->dump());
- bool ContinueOnTrue = L->contains(BackBranch->getSuccessor(0));
// Find the induction PHI. If there is no induction PHI, we can't do the
// transformation. TODO: could other variables trigger this? Do we have to
// search for the best one?
- InductionPHI = nullptr;
- for (PHINode &PHI : L->getHeader()->phis()) {
- InductionDescriptor ID;
- if (InductionDescriptor::isInductionPHI(&PHI, L, SE, ID)) {
- InductionPHI = &PHI;
- LLVM_DEBUG(dbgs() << "Found induction PHI: "; InductionPHI->dump());
- break;
- }
- }
+ InductionPHI = L->getInductionVariable(*SE);
if (!InductionPHI) {
LLVM_DEBUG(dbgs() << "Could not find induction PHI\n");
return false;
}
+ LLVM_DEBUG(dbgs() << "Found induction PHI: "; InductionPHI->dump());
+ bool ContinueOnTrue = L->contains(Latch->getTerminator()->getSuccessor(0));
auto IsValidPredicate = [&](ICmpInst::Predicate Pred) {
if (ContinueOnTrue)
return Pred == CmpInst::ICMP_NE || Pred == CmpInst::ICMP_ULT;
@@ -145,53 +139,64 @@ static bool findLoopComponents(
return Pred == CmpInst::ICMP_EQ;
};
- // Find Compare and make sure it is valid
- ICmpInst *Compare = dyn_cast<ICmpInst>(BackBranch->getCondition());
+ // Find Compare and make sure it is valid. getLatchCmpInst checks that the
+ // back branch of the latch is conditional.
+ ICmpInst *Compare = L->getLatchCmpInst();
if (!Compare || !IsValidPredicate(Compare->getUnsignedPredicate()) ||
Compare->hasNUsesOrMore(2)) {
LLVM_DEBUG(dbgs() << "Could not find valid comparison\n");
return false;
}
+ BackBranch = cast<BranchInst>(Latch->getTerminator());
+ IterationInstructions.insert(BackBranch);
+ LLVM_DEBUG(dbgs() << "Found back branch: "; BackBranch->dump());
IterationInstructions.insert(Compare);
LLVM_DEBUG(dbgs() << "Found comparison: "; Compare->dump());
- // Find increment and limit from the compare
- Increment = nullptr;
- if (match(Compare->getOperand(0),
- m_c_Add(m_Specific(InductionPHI), m_ConstantInt<1>()))) {
- Increment = dyn_cast<BinaryOperator>(Compare->getOperand(0));
- Limit = Compare->getOperand(1);
- } else if (Compare->getUnsignedPredicate() == CmpInst::ICMP_NE &&
- match(Compare->getOperand(1),
- m_c_Add(m_Specific(InductionPHI), m_ConstantInt<1>()))) {
- Increment = dyn_cast<BinaryOperator>(Compare->getOperand(1));
- Limit = Compare->getOperand(0);
- }
- if (!Increment || Increment->hasNUsesOrMore(3)) {
- LLVM_DEBUG(dbgs() << "Cound not find valid increment\n");
+ // Find increment and trip count.
+ // There are exactly 2 incoming values to the induction phi; one from the
+ // pre-header and one from the latch. The incoming latch value is the
+ // increment variable.
+ Increment =
+ dyn_cast<BinaryOperator>(InductionPHI->getIncomingValueForBlock(Latch));
+ if (Increment->hasNUsesOrMore(3)) {
+ LLVM_DEBUG(dbgs() << "Could not find valid increment\n");
return false;
}
+ // The trip count is the RHS of the compare. If this doesn't match the trip
+ // count computed by SCEV then this is either because the trip count variable
+ // has been widened (then leave the trip count as it is), or because it is a
+ // constant and another transformation has changed the compare, e.g.
+ // icmp ult %inc, tripcount -> icmp ult %j, tripcount-1, then we don't flatten
+ // the loop (yet).
+ TripCount = Compare->getOperand(1);
+ const SCEV *SCEVTripCount =
+ SE->getTripCountFromExitCount(SE->getBackedgeTakenCount(L));
+ if (SE->getSCEV(TripCount) != SCEVTripCount) {
+ if (!IsWidened) {
+ LLVM_DEBUG(dbgs() << "Could not find valid trip count\n");
+ return false;
+ }
+ auto TripCountInst = dyn_cast<Instruction>(TripCount);
+ if (!TripCountInst) {
+ LLVM_DEBUG(dbgs() << "Could not find valid extended trip count\n");
+ return false;
+ }
+ if ((!isa<ZExtInst>(TripCountInst) && !isa<SExtInst>(TripCountInst)) ||
+ SE->getSCEV(TripCountInst->getOperand(0)) != SCEVTripCount) {
+ LLVM_DEBUG(dbgs() << "Could not find valid extended trip count\n");
+ return false;
+ }
+ }
IterationInstructions.insert(Increment);
LLVM_DEBUG(dbgs() << "Found increment: "; Increment->dump());
- LLVM_DEBUG(dbgs() << "Found limit: "; Limit->dump());
-
- assert(InductionPHI->getNumIncomingValues() == 2);
- assert(InductionPHI->getIncomingValueForBlock(Latch) == Increment &&
- "PHI value is not increment inst");
-
- auto *CI = dyn_cast<ConstantInt>(
- InductionPHI->getIncomingValueForBlock(L->getLoopPreheader()));
- if (!CI || !CI->isZero()) {
- LLVM_DEBUG(dbgs() << "PHI value is not zero: "; CI->dump());
- return false;
- }
+ LLVM_DEBUG(dbgs() << "Found trip count: "; TripCount->dump());
LLVM_DEBUG(dbgs() << "Successfully found all loop components\n");
return true;
}
-static bool checkPHIs(struct FlattenInfo &FI,
- const TargetTransformInfo *TTI) {
+static bool checkPHIs(FlattenInfo &FI, const TargetTransformInfo *TTI) {
// All PHIs in the inner and outer headers must either be:
// - The induction PHI, which we are going to rewrite as one induction in
// the new loop. This is already checked by findLoopComponents.
@@ -272,7 +277,7 @@ static bool checkPHIs(struct FlattenInfo &FI,
}
static bool
-checkOuterLoopInsts(struct FlattenInfo &FI,
+checkOuterLoopInsts(FlattenInfo &FI,
SmallPtrSetImpl<Instruction *> &IterationInstructions,
const TargetTransformInfo *TTI) {
// Check for instructions in the outer but not inner loop. If any of these
@@ -280,7 +285,7 @@ checkOuterLoopInsts(struct FlattenInfo &FI,
// a significant amount of code here which can't be optimised out that it's
// not profitable (as these instructions would get executed for each
// iteration of the inner loop).
- unsigned RepeatedInstrCost = 0;
+ InstructionCost RepeatedInstrCost = 0;
for (auto *B : FI.OuterLoop->getBlocks()) {
if (FI.InnerLoop->contains(B))
continue;
@@ -308,9 +313,10 @@ checkOuterLoopInsts(struct FlattenInfo &FI,
// Multiplies of the outer iteration variable and inner iteration
// count will be optimised out.
if (match(&I, m_c_Mul(m_Specific(FI.OuterInductionPHI),
- m_Specific(FI.InnerLimit))))
+ m_Specific(FI.InnerTripCount))))
continue;
- int Cost = TTI->getUserCost(&I, TargetTransformInfo::TCK_SizeAndLatency);
+ InstructionCost Cost =
+ TTI->getUserCost(&I, TargetTransformInfo::TCK_SizeAndLatency);
LLVM_DEBUG(dbgs() << "Cost " << Cost << ": "; I.dump());
RepeatedInstrCost += Cost;
}
@@ -329,19 +335,19 @@ checkOuterLoopInsts(struct FlattenInfo &FI,
return true;
}
-static bool checkIVUsers(struct FlattenInfo &FI) {
+static bool checkIVUsers(FlattenInfo &FI) {
// We require all uses of both induction variables to match this pattern:
//
- // (OuterPHI * InnerLimit) + InnerPHI
+ // (OuterPHI * InnerTripCount) + InnerPHI
//
// Any uses of the induction variables not matching that pattern would
// require a div/mod to reconstruct in the flattened loop, so the
// transformation wouldn't be profitable.
- Value *InnerLimit = FI.InnerLimit;
+ Value *InnerTripCount = FI.InnerTripCount;
if (FI.Widened &&
- (isa<SExtInst>(InnerLimit) || isa<ZExtInst>(InnerLimit)))
- InnerLimit = cast<Instruction>(InnerLimit)->getOperand(0);
+ (isa<SExtInst>(InnerTripCount) || isa<ZExtInst>(InnerTripCount)))
+ InnerTripCount = cast<Instruction>(InnerTripCount)->getOperand(0);
// Check that all uses of the inner loop's induction variable match the
// expected pattern, recording the uses of the outer IV.
@@ -375,7 +381,7 @@ static bool checkIVUsers(struct FlattenInfo &FI) {
m_c_Mul(m_Trunc(m_Specific(FI.OuterInductionPHI)),
m_Value(MatchedItCount)));
- if ((IsAdd || IsAddTrunc) && MatchedItCount == InnerLimit) {
+ if ((IsAdd || IsAddTrunc) && MatchedItCount == InnerTripCount) {
LLVM_DEBUG(dbgs() << "Use is optimisable\n");
ValidOuterPHIUses.insert(MatchedMul);
FI.LinearIVUses.insert(U);
@@ -424,9 +430,9 @@ static bool checkIVUsers(struct FlattenInfo &FI) {
}
// Return an OverflowResult dependant on if overflow of the multiplication of
-// InnerLimit and OuterLimit can be assumed not to happen.
-static OverflowResult checkOverflow(struct FlattenInfo &FI,
- DominatorTree *DT, AssumptionCache *AC) {
+// InnerTripCount and OuterTripCount can be assumed not to happen.
+static OverflowResult checkOverflow(FlattenInfo &FI, DominatorTree *DT,
+ AssumptionCache *AC) {
Function *F = FI.OuterLoop->getHeader()->getParent();
const DataLayout &DL = F->getParent()->getDataLayout();
@@ -437,7 +443,7 @@ static OverflowResult checkOverflow(struct FlattenInfo &FI,
// Check if the multiply could not overflow due to known ranges of the
// input values.
OverflowResult OR = computeOverflowForUnsignedMul(
- FI.InnerLimit, FI.OuterLimit, DL, AC,
+ FI.InnerTripCount, FI.OuterTripCount, DL, AC,
FI.OuterLoop->getLoopPreheader()->getTerminator(), DT);
if (OR != OverflowResult::MayOverflow)
return OR;
@@ -464,25 +470,27 @@ static OverflowResult checkOverflow(struct FlattenInfo &FI,
return OverflowResult::MayOverflow;
}
-static bool CanFlattenLoopPair(struct FlattenInfo &FI, DominatorTree *DT,
- LoopInfo *LI, ScalarEvolution *SE,
- AssumptionCache *AC, const TargetTransformInfo *TTI) {
+static bool CanFlattenLoopPair(FlattenInfo &FI, DominatorTree *DT, LoopInfo *LI,
+ ScalarEvolution *SE, AssumptionCache *AC,
+ const TargetTransformInfo *TTI) {
SmallPtrSet<Instruction *, 8> IterationInstructions;
- if (!findLoopComponents(FI.InnerLoop, IterationInstructions, FI.InnerInductionPHI,
- FI.InnerLimit, FI.InnerIncrement, FI.InnerBranch, SE))
+ if (!findLoopComponents(FI.InnerLoop, IterationInstructions,
+ FI.InnerInductionPHI, FI.InnerTripCount,
+ FI.InnerIncrement, FI.InnerBranch, SE, FI.Widened))
return false;
- if (!findLoopComponents(FI.OuterLoop, IterationInstructions, FI.OuterInductionPHI,
- FI.OuterLimit, FI.OuterIncrement, FI.OuterBranch, SE))
+ if (!findLoopComponents(FI.OuterLoop, IterationInstructions,
+ FI.OuterInductionPHI, FI.OuterTripCount,
+ FI.OuterIncrement, FI.OuterBranch, SE, FI.Widened))
return false;
- // Both of the loop limit values must be invariant in the outer loop
+ // Both of the loop trip count values must be invariant in the outer loop
// (non-instructions are all inherently invariant).
- if (!FI.OuterLoop->isLoopInvariant(FI.InnerLimit)) {
- LLVM_DEBUG(dbgs() << "inner loop limit not invariant\n");
+ if (!FI.OuterLoop->isLoopInvariant(FI.InnerTripCount)) {
+ LLVM_DEBUG(dbgs() << "inner loop trip count not invariant\n");
return false;
}
- if (!FI.OuterLoop->isLoopInvariant(FI.OuterLimit)) {
- LLVM_DEBUG(dbgs() << "outer loop limit not invariant\n");
+ if (!FI.OuterLoop->isLoopInvariant(FI.OuterTripCount)) {
+ LLVM_DEBUG(dbgs() << "outer loop trip count not invariant\n");
return false;
}
@@ -508,9 +516,8 @@ static bool CanFlattenLoopPair(struct FlattenInfo &FI, DominatorTree *DT,
return true;
}
-static bool DoFlattenLoopPair(struct FlattenInfo &FI, DominatorTree *DT,
- LoopInfo *LI, ScalarEvolution *SE,
- AssumptionCache *AC,
+static bool DoFlattenLoopPair(FlattenInfo &FI, DominatorTree *DT, LoopInfo *LI,
+ ScalarEvolution *SE, AssumptionCache *AC,
const TargetTransformInfo *TTI) {
Function *F = FI.OuterLoop->getHeader()->getParent();
LLVM_DEBUG(dbgs() << "Checks all passed, doing the transformation\n");
@@ -523,9 +530,9 @@ static bool DoFlattenLoopPair(struct FlattenInfo &FI, DominatorTree *DT,
ORE.emit(Remark);
}
- Value *NewTripCount =
- BinaryOperator::CreateMul(FI.InnerLimit, FI.OuterLimit, "flatten.tripcount",
- FI.OuterLoop->getLoopPreheader()->getTerminator());
+ Value *NewTripCount = BinaryOperator::CreateMul(
+ FI.InnerTripCount, FI.OuterTripCount, "flatten.tripcount",
+ FI.OuterLoop->getLoopPreheader()->getTerminator());
LLVM_DEBUG(dbgs() << "Created new trip count in preheader: ";
NewTripCount->dump());
@@ -571,9 +578,9 @@ static bool DoFlattenLoopPair(struct FlattenInfo &FI, DominatorTree *DT,
return true;
}
-static bool CanWidenIV(struct FlattenInfo &FI, DominatorTree *DT,
- LoopInfo *LI, ScalarEvolution *SE,
- AssumptionCache *AC, const TargetTransformInfo *TTI) {
+static bool CanWidenIV(FlattenInfo &FI, DominatorTree *DT, LoopInfo *LI,
+ ScalarEvolution *SE, AssumptionCache *AC,
+ const TargetTransformInfo *TTI) {
if (!WidenIV) {
LLVM_DEBUG(dbgs() << "Widening the IVs is disabled\n");
return false;
@@ -589,7 +596,7 @@ static bool CanWidenIV(struct FlattenInfo &FI, DominatorTree *DT,
// If both induction types are less than the maximum legal integer width,
// promote both to the widest type available so we know calculating
- // (OuterLimit * InnerLimit) as the new trip count is safe.
+ // (OuterTripCount * InnerTripCount) as the new trip count is safe.
if (InnerType != OuterType ||
InnerType->getScalarSizeInBits() >= MaxLegalSize ||
MaxLegalType->getScalarSizeInBits() < InnerType->getScalarSizeInBits() * 2) {
@@ -602,28 +609,27 @@ static bool CanWidenIV(struct FlattenInfo &FI, DominatorTree *DT,
SmallVector<WeakTrackingVH, 4> DeadInsts;
WideIVs.push_back( {FI.InnerInductionPHI, MaxLegalType, false });
WideIVs.push_back( {FI.OuterInductionPHI, MaxLegalType, false });
- unsigned ElimExt;
- unsigned Widened;
+ unsigned ElimExt = 0;
+ unsigned Widened = 0;
- for (unsigned i = 0; i < WideIVs.size(); i++) {
- PHINode *WidePhi = createWideIV(WideIVs[i], LI, SE, Rewriter, DT, DeadInsts,
+ for (const auto &WideIV : WideIVs) {
+ PHINode *WidePhi = createWideIV(WideIV, LI, SE, Rewriter, DT, DeadInsts,
ElimExt, Widened, true /* HasGuards */,
true /* UsePostIncrementRanges */);
if (!WidePhi)
return false;
LLVM_DEBUG(dbgs() << "Created wide phi: "; WidePhi->dump());
- LLVM_DEBUG(dbgs() << "Deleting old phi: "; WideIVs[i].NarrowIV->dump());
- RecursivelyDeleteDeadPHINode(WideIVs[i].NarrowIV);
+ LLVM_DEBUG(dbgs() << "Deleting old phi: "; WideIV.NarrowIV->dump());
+ RecursivelyDeleteDeadPHINode(WideIV.NarrowIV);
}
// After widening, rediscover all the loop components.
- assert(Widened && "Widenend IV expected");
+ assert(Widened && "Widened IV expected");
FI.Widened = true;
return CanFlattenLoopPair(FI, DT, LI, SE, AC, TTI);
}
-static bool FlattenLoopPair(struct FlattenInfo &FI, DominatorTree *DT,
- LoopInfo *LI, ScalarEvolution *SE,
- AssumptionCache *AC,
+static bool FlattenLoopPair(FlattenInfo &FI, DominatorTree *DT, LoopInfo *LI,
+ ScalarEvolution *SE, AssumptionCache *AC,
const TargetTransformInfo *TTI) {
LLVM_DEBUG(
dbgs() << "Loop flattening running on outer loop "
@@ -656,33 +662,35 @@ static bool FlattenLoopPair(struct FlattenInfo &FI, DominatorTree *DT,
return DoFlattenLoopPair(FI, DT, LI, SE, AC, TTI);
}
-bool Flatten(DominatorTree *DT, LoopInfo *LI, ScalarEvolution *SE,
+bool Flatten(LoopNest &LN, DominatorTree *DT, LoopInfo *LI, ScalarEvolution *SE,
AssumptionCache *AC, TargetTransformInfo *TTI) {
bool Changed = false;
- for (auto *InnerLoop : LI->getLoopsInPreorder()) {
+ for (Loop *InnerLoop : LN.getLoops()) {
auto *OuterLoop = InnerLoop->getParentLoop();
if (!OuterLoop)
continue;
- struct FlattenInfo FI(OuterLoop, InnerLoop);
+ FlattenInfo FI(OuterLoop, InnerLoop);
Changed |= FlattenLoopPair(FI, DT, LI, SE, AC, TTI);
}
return Changed;
}
-PreservedAnalyses LoopFlattenPass::run(Function &F,
- FunctionAnalysisManager &AM) {
- auto *DT = &AM.getResult<DominatorTreeAnalysis>(F);
- auto *LI = &AM.getResult<LoopAnalysis>(F);
- auto *SE = &AM.getResult<ScalarEvolutionAnalysis>(F);
- auto *AC = &AM.getResult<AssumptionAnalysis>(F);
- auto *TTI = &AM.getResult<TargetIRAnalysis>(F);
+PreservedAnalyses LoopFlattenPass::run(LoopNest &LN, LoopAnalysisManager &LAM,
+ LoopStandardAnalysisResults &AR,
+ LPMUpdater &U) {
+
+ bool Changed = false;
+
+ // The loop flattening pass requires loops to be
+ // in simplified form, and also needs LCSSA. Running
+ // this pass will simplify all loops that contain inner loops,
+ // regardless of whether anything ends up being flattened.
+ Changed |= Flatten(LN, &AR.DT, &AR.LI, &AR.SE, &AR.AC, &AR.TTI);
- if (!Flatten(DT, LI, SE, AC, TTI))
+ if (!Changed)
return PreservedAnalyses::all();
- PreservedAnalyses PA;
- PA.preserveSet<CFGAnalyses>();
- return PA;
+ return PreservedAnalyses::none();
}
namespace {
@@ -724,5 +732,10 @@ bool LoopFlattenLegacyPass::runOnFunction(Function &F) {
auto &TTIP = getAnalysis<TargetTransformInfoWrapperPass>();
auto *TTI = &TTIP.getTTI(F);
auto *AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
- return Flatten(DT, LI, SE, AC, TTI);
+ bool Changed = false;
+ for (Loop *L : *LI) {
+ auto LN = LoopNest::getLoopNest(*L, *SE);
+ Changed |= Flatten(*LN, DT, LI, SE, AC, TTI);
+ }
+ return Changed;
}
diff --git a/llvm/lib/Transforms/Scalar/LoopFuse.cpp b/llvm/lib/Transforms/Scalar/LoopFuse.cpp
index b5f8dfa9aafb..ca19913e37ee 100644
--- a/llvm/lib/Transforms/Scalar/LoopFuse.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopFuse.cpp
@@ -99,6 +99,8 @@ STATISTIC(NonEmptyExitBlock, "Candidate has a non-empty exit block with "
STATISTIC(NonEmptyGuardBlock, "Candidate has a non-empty guard block with "
"instructions that cannot be moved");
STATISTIC(NotRotated, "Candidate is not rotated");
+STATISTIC(OnlySecondCandidateIsGuarded,
+ "The second candidate is guarded while the first one is not");
enum FusionDependenceAnalysisChoice {
FUSION_DEPENDENCE_ANALYSIS_SCEV,
@@ -370,11 +372,13 @@ private:
bool reportInvalidCandidate(llvm::Statistic &Stat) const {
using namespace ore;
assert(L && Preheader && "Fusion candidate not initialized properly!");
+#if LLVM_ENABLE_STATS
++Stat;
ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, Stat.getName(),
L->getStartLoc(), Preheader)
<< "[" << Preheader->getParent()->getName() << "]: "
<< "Loop is not a candidate for fusion: " << Stat.getDesc());
+#endif
return false;
}
};
@@ -891,6 +895,14 @@ private:
continue;
}
+ if (!FC0->GuardBranch && FC1->GuardBranch) {
+ LLVM_DEBUG(dbgs() << "The second candidate is guarded while the "
+ "first one is not. Not fusing.\n");
+ reportLoopFusion<OptimizationRemarkMissed>(
+ *FC0, *FC1, OnlySecondCandidateIsGuarded);
+ continue;
+ }
+
// Ensure that FC0 and FC1 have identical guards.
// If one (or both) are not guarded, this check is not necessary.
if (FC0->GuardBranch && FC1->GuardBranch &&
@@ -1523,6 +1535,7 @@ private:
assert(FC0.Preheader && FC1.Preheader &&
"Expecting valid fusion candidates");
using namespace ore;
+#if LLVM_ENABLE_STATS
++Stat;
ORE.emit(RemarkKind(DEBUG_TYPE, Stat.getName(), FC0.L->getStartLoc(),
FC0.Preheader)
@@ -1530,6 +1543,7 @@ private:
<< "]: " << NV("Cand1", StringRef(FC0.Preheader->getName()))
<< " and " << NV("Cand2", StringRef(FC1.Preheader->getName()))
<< ": " << Stat.getDesc());
+#endif
}
/// Fuse two guarded fusion candidates, creating a new fused loop.
diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
index 8064c02e2b39..3d60e205b002 100644
--- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
@@ -21,7 +21,7 @@
// TODO List:
//
// Future loop memory idioms to recognize:
-// memcmp, memmove, strlen, etc.
+// memcmp, strlen, etc.
// Future floating point idioms to recognize in -ffast-math mode:
// fpowi
// Future integer operation idioms to recognize:
@@ -90,6 +90,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/InstructionCost.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BuildLibCalls.h"
@@ -108,9 +109,12 @@ using namespace llvm;
STATISTIC(NumMemSet, "Number of memset's formed from loop stores");
STATISTIC(NumMemCpy, "Number of memcpy's formed from loop load+stores");
+STATISTIC(NumMemMove, "Number of memmove's formed from loop load+stores");
STATISTIC(
NumShiftUntilBitTest,
"Number of uncountable loops recognized as 'shift until bitttest' idiom");
+STATISTIC(NumShiftUntilZero,
+ "Number of uncountable loops recognized as 'shift until zero' idiom");
bool DisableLIRP::All;
static cl::opt<bool, true>
@@ -204,6 +208,13 @@ private:
enum class ForMemset { No, Yes };
bool processLoopStores(SmallVectorImpl<StoreInst *> &SL, const SCEV *BECount,
ForMemset For);
+
+ template <typename MemInst>
+ bool processLoopMemIntrinsic(
+ BasicBlock *BB,
+ bool (LoopIdiomRecognize::*Processor)(MemInst *, const SCEV *),
+ const SCEV *BECount);
+ bool processLoopMemCpy(MemCpyInst *MCI, const SCEV *BECount);
bool processLoopMemSet(MemSetInst *MSI, const SCEV *BECount);
bool processLoopStridedStore(Value *DestPtr, unsigned StoreSize,
@@ -213,6 +224,13 @@ private:
const SCEVAddRecExpr *Ev, const SCEV *BECount,
bool NegStride, bool IsLoopMemset = false);
bool processLoopStoreOfLoopLoad(StoreInst *SI, const SCEV *BECount);
+ bool processLoopStoreOfLoopLoad(Value *DestPtr, Value *SourcePtr,
+ unsigned StoreSize, MaybeAlign StoreAlign,
+ MaybeAlign LoadAlign, Instruction *TheStore,
+ Instruction *TheLoad,
+ const SCEVAddRecExpr *StoreEv,
+ const SCEVAddRecExpr *LoadEv,
+ const SCEV *BECount);
bool avoidLIRForMultiBlockLoop(bool IsMemset = false,
bool IsLoopMemset = false);
@@ -233,6 +251,7 @@ private:
bool IsCntPhiUsedOutsideLoop);
bool recognizeShiftUntilBitTest();
+ bool recognizeShiftUntilZero();
/// @}
};
@@ -501,7 +520,6 @@ LoopIdiomRecognize::isLegalStore(StoreInst *SI) {
// are stored. A store of i32 0x01020304 can never be turned into a memset,
// but it can be turned into memset_pattern if the target supports it.
Value *SplatValue = isBytewiseValue(StoredVal, *DL);
- Constant *PatternValue = nullptr;
// Note: memset and memset_pattern on unordered-atomic is yet not supported
bool UnorderedAtomic = SI->isUnordered() && !SI->isSimple();
@@ -514,10 +532,11 @@ LoopIdiomRecognize::isLegalStore(StoreInst *SI) {
CurLoop->isLoopInvariant(SplatValue)) {
// It looks like we can use SplatValue.
return LegalStoreKind::Memset;
- } else if (!UnorderedAtomic && HasMemsetPattern && !DisableLIRP::Memset &&
- // Don't create memset_pattern16s with address spaces.
- StorePtr->getType()->getPointerAddressSpace() == 0 &&
- (PatternValue = getMemSetPatternValue(StoredVal, DL))) {
+ }
+ if (!UnorderedAtomic && HasMemsetPattern && !DisableLIRP::Memset &&
+ // Don't create memset_pattern16s with address spaces.
+ StorePtr->getType()->getPointerAddressSpace() == 0 &&
+ getMemSetPatternValue(StoredVal, DL)) {
// It looks like we can use PatternValue!
return LegalStoreKind::MemsetPattern;
}
@@ -627,22 +646,10 @@ bool LoopIdiomRecognize::runOnLoopBlock(
for (auto &SI : StoreRefsForMemcpy)
MadeChange |= processLoopStoreOfLoopLoad(SI, BECount);
- for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E;) {
- Instruction *Inst = &*I++;
- // Look for memset instructions, which may be optimized to a larger memset.
- if (MemSetInst *MSI = dyn_cast<MemSetInst>(Inst)) {
- WeakTrackingVH InstPtr(&*I);
- if (!processLoopMemSet(MSI, BECount))
- continue;
- MadeChange = true;
-
- // If processing the memset invalidated our iterator, start over from the
- // top of the block.
- if (!InstPtr)
- I = BB->begin();
- continue;
- }
- }
+ MadeChange |= processLoopMemIntrinsic<MemCpyInst>(
+ BB, &LoopIdiomRecognize::processLoopMemCpy, BECount);
+ MadeChange |= processLoopMemIntrinsic<MemSetInst>(
+ BB, &LoopIdiomRecognize::processLoopMemSet, BECount);
return MadeChange;
}
@@ -791,6 +798,100 @@ bool LoopIdiomRecognize::processLoopStores(SmallVectorImpl<StoreInst *> &SL,
return Changed;
}
+/// processLoopMemIntrinsic - Template function for calling different processor
+/// functions based on mem instrinsic type.
+template <typename MemInst>
+bool LoopIdiomRecognize::processLoopMemIntrinsic(
+ BasicBlock *BB,
+ bool (LoopIdiomRecognize::*Processor)(MemInst *, const SCEV *),
+ const SCEV *BECount) {
+ bool MadeChange = false;
+ for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E;) {
+ Instruction *Inst = &*I++;
+ // Look for memory instructions, which may be optimized to a larger one.
+ if (MemInst *MI = dyn_cast<MemInst>(Inst)) {
+ WeakTrackingVH InstPtr(&*I);
+ if (!(this->*Processor)(MI, BECount))
+ continue;
+ MadeChange = true;
+
+ // If processing the instruction invalidated our iterator, start over from
+ // the top of the block.
+ if (!InstPtr)
+ I = BB->begin();
+ }
+ }
+ return MadeChange;
+}
+
+/// processLoopMemCpy - See if this memcpy can be promoted to a large memcpy
+bool LoopIdiomRecognize::processLoopMemCpy(MemCpyInst *MCI,
+ const SCEV *BECount) {
+ // We can only handle non-volatile memcpys with a constant size.
+ if (MCI->isVolatile() || !isa<ConstantInt>(MCI->getLength()))
+ return false;
+
+ // If we're not allowed to hack on memcpy, we fail.
+ if ((!HasMemcpy && !isa<MemCpyInlineInst>(MCI)) || DisableLIRP::Memcpy)
+ return false;
+
+ Value *Dest = MCI->getDest();
+ Value *Source = MCI->getSource();
+ if (!Dest || !Source)
+ return false;
+
+ // See if the load and store pointer expressions are AddRec like {base,+,1} on
+ // the current loop, which indicates a strided load and store. If we have
+ // something else, it's a random load or store we can't handle.
+ const SCEVAddRecExpr *StoreEv = dyn_cast<SCEVAddRecExpr>(SE->getSCEV(Dest));
+ if (!StoreEv || StoreEv->getLoop() != CurLoop || !StoreEv->isAffine())
+ return false;
+ const SCEVAddRecExpr *LoadEv = dyn_cast<SCEVAddRecExpr>(SE->getSCEV(Source));
+ if (!LoadEv || LoadEv->getLoop() != CurLoop || !LoadEv->isAffine())
+ return false;
+
+ // Reject memcpys that are so large that they overflow an unsigned.
+ uint64_t SizeInBytes = cast<ConstantInt>(MCI->getLength())->getZExtValue();
+ if ((SizeInBytes >> 32) != 0)
+ return false;
+
+ // Check if the stride matches the size of the memcpy. If so, then we know
+ // that every byte is touched in the loop.
+ const SCEVConstant *StoreStride =
+ dyn_cast<SCEVConstant>(StoreEv->getOperand(1));
+ const SCEVConstant *LoadStride =
+ dyn_cast<SCEVConstant>(LoadEv->getOperand(1));
+ if (!StoreStride || !LoadStride)
+ return false;
+
+ APInt StoreStrideValue = StoreStride->getAPInt();
+ APInt LoadStrideValue = LoadStride->getAPInt();
+ // Huge stride value - give up
+ if (StoreStrideValue.getBitWidth() > 64 || LoadStrideValue.getBitWidth() > 64)
+ return false;
+
+ if (SizeInBytes != StoreStrideValue && SizeInBytes != -StoreStrideValue) {
+ ORE.emit([&]() {
+ return OptimizationRemarkMissed(DEBUG_TYPE, "SizeStrideUnequal", MCI)
+ << ore::NV("Inst", "memcpy") << " in "
+ << ore::NV("Function", MCI->getFunction())
+ << " function will not be hoised: "
+ << ore::NV("Reason", "memcpy size is not equal to stride");
+ });
+ return false;
+ }
+
+ int64_t StoreStrideInt = StoreStrideValue.getSExtValue();
+ int64_t LoadStrideInt = LoadStrideValue.getSExtValue();
+ // Check if the load stride matches the store stride.
+ if (StoreStrideInt != LoadStrideInt)
+ return false;
+
+ return processLoopStoreOfLoopLoad(Dest, Source, (unsigned)SizeInBytes,
+ MCI->getDestAlign(), MCI->getSourceAlign(),
+ MCI, MCI, StoreEv, LoadEv, BECount);
+}
+
/// processLoopMemSet - See if this memset can be promoted to a large memset.
bool LoopIdiomRecognize::processLoopMemSet(MemSetInst *MSI,
const SCEV *BECount) {
@@ -799,7 +900,7 @@ bool LoopIdiomRecognize::processLoopMemSet(MemSetInst *MSI,
return false;
// If we're not allowed to hack on memset, we fail.
- if (!HasMemset)
+ if (!HasMemset || DisableLIRP::Memset)
return false;
Value *Pointer = MSI->getDest();
@@ -1039,9 +1140,11 @@ bool LoopIdiomRecognize::processLoopStridedStore(
ORE.emit([&]() {
return OptimizationRemark(DEBUG_TYPE, "ProcessLoopStridedStore",
NewCall->getDebugLoc(), Preheader)
- << "Transformed loop-strided store into a call to "
+ << "Transformed loop-strided store in "
+ << ore::NV("Function", TheStore->getFunction())
+ << " function into a call to "
<< ore::NV("NewFunction", NewCall->getCalledFunction())
- << "() function";
+ << "() intrinsic";
});
// Okay, the memset has been formed. Zap the original store and anything that
@@ -1067,9 +1170,7 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
Value *StorePtr = SI->getPointerOperand();
const SCEVAddRecExpr *StoreEv = cast<SCEVAddRecExpr>(SE->getSCEV(StorePtr));
- APInt Stride = getStoreStride(StoreEv);
unsigned StoreSize = DL->getTypeStoreSize(SI->getValueOperand()->getType());
- bool NegStride = StoreSize == -Stride;
// The store must be feeding a non-volatile load.
LoadInst *LI = cast<LoadInst>(SI->getValueOperand());
@@ -1078,8 +1179,24 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
// See if the pointer expression is an AddRec like {base,+,1} on the current
// loop, which indicates a strided load. If we have something else, it's a
// random load we can't handle.
- const SCEVAddRecExpr *LoadEv =
- cast<SCEVAddRecExpr>(SE->getSCEV(LI->getPointerOperand()));
+ Value *LoadPtr = LI->getPointerOperand();
+ const SCEVAddRecExpr *LoadEv = cast<SCEVAddRecExpr>(SE->getSCEV(LoadPtr));
+ return processLoopStoreOfLoopLoad(StorePtr, LoadPtr, StoreSize,
+ SI->getAlign(), LI->getAlign(), SI, LI,
+ StoreEv, LoadEv, BECount);
+}
+
+bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(
+ Value *DestPtr, Value *SourcePtr, unsigned StoreSize, MaybeAlign StoreAlign,
+ MaybeAlign LoadAlign, Instruction *TheStore, Instruction *TheLoad,
+ const SCEVAddRecExpr *StoreEv, const SCEVAddRecExpr *LoadEv,
+ const SCEV *BECount) {
+
+ // FIXME: until llvm.memcpy.inline supports dynamic sizes, we need to
+ // conservatively bail here, since otherwise we may have to transform
+ // llvm.memcpy.inline into llvm.memcpy which is illegal.
+ if (isa<MemCpyInlineInst>(TheStore))
+ return false;
// The trip count of the loop and the base pointer of the addrec SCEV is
// guaranteed to be loop invariant, which means that it should dominate the
@@ -1092,9 +1209,12 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
bool Changed = false;
const SCEV *StrStart = StoreEv->getStart();
- unsigned StrAS = SI->getPointerAddressSpace();
+ unsigned StrAS = DestPtr->getType()->getPointerAddressSpace();
Type *IntIdxTy = Builder.getIntNTy(DL->getIndexSizeInBits(StrAS));
+ APInt Stride = getStoreStride(StoreEv);
+ bool NegStride = StoreSize == -Stride;
+
// Handle negative strided loops.
if (NegStride)
StrStart = getStartForNegStride(StrStart, BECount, IntIdxTy, StoreSize, SE);
@@ -1117,14 +1237,34 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
// the return value will read this comment, and leave them alone.
Changed = true;
- SmallPtrSet<Instruction *, 1> Stores;
- Stores.insert(SI);
- if (mayLoopAccessLocation(StoreBasePtr, ModRefInfo::ModRef, CurLoop, BECount,
- StoreSize, *AA, Stores))
- return Changed;
+ SmallPtrSet<Instruction *, 2> Stores;
+ Stores.insert(TheStore);
+
+ bool IsMemCpy = isa<MemCpyInst>(TheStore);
+ const StringRef InstRemark = IsMemCpy ? "memcpy" : "load and store";
+
+ bool UseMemMove =
+ mayLoopAccessLocation(StoreBasePtr, ModRefInfo::ModRef, CurLoop, BECount,
+ StoreSize, *AA, Stores);
+ if (UseMemMove) {
+ Stores.insert(TheLoad);
+ if (mayLoopAccessLocation(StoreBasePtr, ModRefInfo::ModRef, CurLoop,
+ BECount, StoreSize, *AA, Stores)) {
+ ORE.emit([&]() {
+ return OptimizationRemarkMissed(DEBUG_TYPE, "LoopMayAccessStore",
+ TheStore)
+ << ore::NV("Inst", InstRemark) << " in "
+ << ore::NV("Function", TheStore->getFunction())
+ << " function will not be hoisted: "
+ << ore::NV("Reason", "The loop may access store location");
+ });
+ return Changed;
+ }
+ Stores.erase(TheLoad);
+ }
const SCEV *LdStart = LoadEv->getStart();
- unsigned LdAS = LI->getPointerAddressSpace();
+ unsigned LdAS = SourcePtr->getType()->getPointerAddressSpace();
// Handle negative strided loops.
if (NegStride)
@@ -1135,9 +1275,37 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
Value *LoadBasePtr = Expander.expandCodeFor(
LdStart, Builder.getInt8PtrTy(LdAS), Preheader->getTerminator());
+ // If the store is a memcpy instruction, we must check if it will write to
+ // the load memory locations. So remove it from the ignored stores.
+ if (IsMemCpy)
+ Stores.erase(TheStore);
if (mayLoopAccessLocation(LoadBasePtr, ModRefInfo::Mod, CurLoop, BECount,
- StoreSize, *AA, Stores))
+ StoreSize, *AA, Stores)) {
+ ORE.emit([&]() {
+ return OptimizationRemarkMissed(DEBUG_TYPE, "LoopMayAccessLoad", TheLoad)
+ << ore::NV("Inst", InstRemark) << " in "
+ << ore::NV("Function", TheStore->getFunction())
+ << " function will not be hoisted: "
+ << ore::NV("Reason", "The loop may access load location");
+ });
return Changed;
+ }
+ if (UseMemMove) {
+ // Ensure that LoadBasePtr is after StoreBasePtr or before StoreBasePtr for
+ // negative stride. LoadBasePtr shouldn't overlap with StoreBasePtr.
+ int64_t LoadOff = 0, StoreOff = 0;
+ const Value *BP1 = llvm::GetPointerBaseWithConstantOffset(
+ LoadBasePtr->stripPointerCasts(), LoadOff, *DL);
+ const Value *BP2 = llvm::GetPointerBaseWithConstantOffset(
+ StoreBasePtr->stripPointerCasts(), StoreOff, *DL);
+ int64_t LoadSize =
+ DL->getTypeSizeInBits(TheLoad->getType()).getFixedSize() / 8;
+ if (BP1 != BP2 || LoadSize != int64_t(StoreSize))
+ return Changed;
+ if ((!NegStride && LoadOff < StoreOff + int64_t(StoreSize)) ||
+ (NegStride && LoadOff + LoadSize > StoreOff))
+ return Changed;
+ }
if (avoidLIRForMultiBlockLoop())
return Changed;
@@ -1154,15 +1322,22 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
// Check whether to generate an unordered atomic memcpy:
// If the load or store are atomic, then they must necessarily be unordered
// by previous checks.
- if (!SI->isAtomic() && !LI->isAtomic())
- NewCall = Builder.CreateMemCpy(StoreBasePtr, SI->getAlign(), LoadBasePtr,
- LI->getAlign(), NumBytes);
- else {
+ if (!TheStore->isAtomic() && !TheLoad->isAtomic()) {
+ if (UseMemMove)
+ NewCall = Builder.CreateMemMove(StoreBasePtr, StoreAlign, LoadBasePtr,
+ LoadAlign, NumBytes);
+ else
+ NewCall = Builder.CreateMemCpy(StoreBasePtr, StoreAlign, LoadBasePtr,
+ LoadAlign, NumBytes);
+ } else {
+ // For now don't support unordered atomic memmove.
+ if (UseMemMove)
+ return Changed;
// We cannot allow unaligned ops for unordered load/store, so reject
// anything where the alignment isn't at least the element size.
- const Align StoreAlign = SI->getAlign();
- const Align LoadAlign = LI->getAlign();
- if (StoreAlign < StoreSize || LoadAlign < StoreSize)
+ assert((StoreAlign.hasValue() && LoadAlign.hasValue()) &&
+ "Expect unordered load/store to have align.");
+ if (StoreAlign.getValue() < StoreSize || LoadAlign.getValue() < StoreSize)
return Changed;
// If the element.atomic memcpy is not lowered into explicit
@@ -1176,10 +1351,10 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
// Note that unordered atomic loads/stores are *required* by the spec to
// have an alignment but non-atomic loads/stores may not.
NewCall = Builder.CreateElementUnorderedAtomicMemCpy(
- StoreBasePtr, StoreAlign, LoadBasePtr, LoadAlign, NumBytes,
- StoreSize);
+ StoreBasePtr, StoreAlign.getValue(), LoadBasePtr, LoadAlign.getValue(),
+ NumBytes, StoreSize);
}
- NewCall->setDebugLoc(SI->getDebugLoc());
+ NewCall->setDebugLoc(TheStore->getDebugLoc());
if (MSSAU) {
MemoryAccess *NewMemAcc = MSSAU->createMemoryAccessInBB(
@@ -1187,9 +1362,10 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
MSSAU->insertDef(cast<MemoryDef>(NewMemAcc), true);
}
- LLVM_DEBUG(dbgs() << " Formed memcpy: " << *NewCall << "\n"
- << " from load ptr=" << *LoadEv << " at: " << *LI << "\n"
- << " from store ptr=" << *StoreEv << " at: " << *SI
+ LLVM_DEBUG(dbgs() << " Formed new call: " << *NewCall << "\n"
+ << " from load ptr=" << *LoadEv << " at: " << *TheLoad
+ << "\n"
+ << " from store ptr=" << *StoreEv << " at: " << *TheStore
<< "\n");
ORE.emit([&]() {
@@ -1197,17 +1373,22 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI,
NewCall->getDebugLoc(), Preheader)
<< "Formed a call to "
<< ore::NV("NewFunction", NewCall->getCalledFunction())
- << "() function";
+ << "() intrinsic from " << ore::NV("Inst", InstRemark)
+ << " instruction in " << ore::NV("Function", TheStore->getFunction())
+ << " function";
});
// Okay, the memcpy has been formed. Zap the original store and anything that
// feeds into it.
if (MSSAU)
- MSSAU->removeMemoryAccess(SI, true);
- deleteDeadInstruction(SI);
+ MSSAU->removeMemoryAccess(TheStore, true);
+ deleteDeadInstruction(TheStore);
if (MSSAU && VerifyMemorySSA)
MSSAU->getMemorySSA()->verifyMemorySSA();
- ++NumMemCpy;
+ if (UseMemMove)
+ ++NumMemMove;
+ else
+ ++NumMemCpy;
ExpCleaner.markResultUsed();
return true;
}
@@ -1236,7 +1417,7 @@ bool LoopIdiomRecognize::runOnNoncountableLoop() {
<< CurLoop->getHeader()->getName() << "\n");
return recognizePopcount() || recognizeAndInsertFFS() ||
- recognizeShiftUntilBitTest();
+ recognizeShiftUntilBitTest() || recognizeShiftUntilZero();
}
/// Check if the given conditional branch is based on the comparison between
@@ -1587,9 +1768,8 @@ bool LoopIdiomRecognize::recognizeAndInsertFFS() {
// %inc = add nsw %i.0, 1
// br i1 %tobool
- const Value *Args[] = {
- InitX, ZeroCheck ? ConstantInt::getTrue(InitX->getContext())
- : ConstantInt::getFalse(InitX->getContext())};
+ const Value *Args[] = {InitX,
+ ConstantInt::getBool(InitX->getContext(), ZeroCheck)};
// @llvm.dbg doesn't count as they have no semantic effect.
auto InstWithoutDebugIt = CurLoop->getHeader()->instructionsWithoutDebug();
@@ -1597,7 +1777,7 @@ bool LoopIdiomRecognize::recognizeAndInsertFFS() {
std::distance(InstWithoutDebugIt.begin(), InstWithoutDebugIt.end());
IntrinsicCostAttributes Attrs(IntrinID, InitX->getType(), Args);
- int Cost =
+ InstructionCost Cost =
TTI->getIntrinsicInstrCost(Attrs, TargetTransformInfo::TCK_SizeAndLatency);
if (HeaderSize != IdiomCanonicalSize &&
Cost > TargetTransformInfo::TCC_Basic)
@@ -1675,7 +1855,7 @@ static CallInst *createPopcntIntrinsic(IRBuilder<> &IRBuilder, Value *Val,
static CallInst *createFFSIntrinsic(IRBuilder<> &IRBuilder, Value *Val,
const DebugLoc &DL, bool ZeroCheck,
Intrinsic::ID IID) {
- Value *Ops[] = {Val, ZeroCheck ? IRBuilder.getTrue() : IRBuilder.getFalse()};
+ Value *Ops[] = {Val, IRBuilder.getInt1(ZeroCheck)};
Type *Tys[] = {Val->getType()};
Module *M = IRBuilder.GetInsertBlock()->getParent()->getParent();
@@ -1727,6 +1907,7 @@ void LoopIdiomRecognize::transformLoopToCountable(
IRBuilder<> Builder(PreheaderBr);
Builder.SetCurrentDebugLocation(DL);
+ // If there are no uses of CntPhi crate:
// Count = BitWidth - CTLZ(InitX);
// NewCount = Count;
// If there are uses of CntPhi create:
@@ -1735,30 +1916,25 @@ void LoopIdiomRecognize::transformLoopToCountable(
Value *InitXNext;
if (IsCntPhiUsedOutsideLoop) {
if (DefX->getOpcode() == Instruction::AShr)
- InitXNext =
- Builder.CreateAShr(InitX, ConstantInt::get(InitX->getType(), 1));
+ InitXNext = Builder.CreateAShr(InitX, 1);
else if (DefX->getOpcode() == Instruction::LShr)
- InitXNext =
- Builder.CreateLShr(InitX, ConstantInt::get(InitX->getType(), 1));
+ InitXNext = Builder.CreateLShr(InitX, 1);
else if (DefX->getOpcode() == Instruction::Shl) // cttz
- InitXNext =
- Builder.CreateShl(InitX, ConstantInt::get(InitX->getType(), 1));
+ InitXNext = Builder.CreateShl(InitX, 1);
else
llvm_unreachable("Unexpected opcode!");
} else
InitXNext = InitX;
- Value *FFS = createFFSIntrinsic(Builder, InitXNext, DL, ZeroCheck, IntrinID);
- Value *Count = Builder.CreateSub(
- ConstantInt::get(FFS->getType(), FFS->getType()->getIntegerBitWidth()),
- FFS);
+ Value *Count =
+ createFFSIntrinsic(Builder, InitXNext, DL, ZeroCheck, IntrinID);
+ Type *CountTy = Count->getType();
+ Count = Builder.CreateSub(
+ ConstantInt::get(CountTy, CountTy->getIntegerBitWidth()), Count);
Value *NewCount = Count;
- if (IsCntPhiUsedOutsideLoop) {
- NewCount = Count;
- Count = Builder.CreateAdd(Count, ConstantInt::get(Count->getType(), 1));
- }
+ if (IsCntPhiUsedOutsideLoop)
+ Count = Builder.CreateAdd(Count, ConstantInt::get(CountTy, 1));
- NewCount = Builder.CreateZExtOrTrunc(NewCount,
- cast<IntegerType>(CntInst->getType()));
+ NewCount = Builder.CreateZExtOrTrunc(NewCount, CntInst->getType());
Value *CntInitVal = CntPhi->getIncomingValueForBlock(Preheader);
if (cast<ConstantInt>(CntInst->getOperand(1))->isOne()) {
@@ -1784,14 +1960,12 @@ void LoopIdiomRecognize::transformLoopToCountable(
BasicBlock *Body = *(CurLoop->block_begin());
auto *LbBr = cast<BranchInst>(Body->getTerminator());
ICmpInst *LbCond = cast<ICmpInst>(LbBr->getCondition());
- Type *Ty = Count->getType();
- PHINode *TcPhi = PHINode::Create(Ty, 2, "tcphi", &Body->front());
+ PHINode *TcPhi = PHINode::Create(CountTy, 2, "tcphi", &Body->front());
Builder.SetInsertPoint(LbCond);
- Instruction *TcDec = cast<Instruction>(
- Builder.CreateSub(TcPhi, ConstantInt::get(Ty, 1),
- "tcdec", false, true));
+ Instruction *TcDec = cast<Instruction>(Builder.CreateSub(
+ TcPhi, ConstantInt::get(CountTy, 1), "tcdec", false, true));
TcPhi->addIncoming(Count, Preheader);
TcPhi->addIncoming(TcDec, Body);
@@ -1800,7 +1974,7 @@ void LoopIdiomRecognize::transformLoopToCountable(
(LbBr->getSuccessor(0) == Body) ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ;
LbCond->setPredicate(Pred);
LbCond->setOperand(0, TcDec);
- LbCond->setOperand(1, ConstantInt::get(Ty, 0));
+ LbCond->setOperand(1, ConstantInt::get(CountTy, 0));
// Step 3: All the references to the original counter outside
// the loop are replaced with the NewCount
@@ -2033,6 +2207,9 @@ static bool detectShiftUntilBitTestIdiom(Loop *CurLoop, Value *&BaseX,
NextX =
dyn_cast<Instruction>(CurrXPN->getIncomingValueForBlock(LoopHeaderBB));
+ assert(CurLoop->isLoopInvariant(BaseX) &&
+ "Expected BaseX to be avaliable in the preheader!");
+
if (!NextX || !match(NextX, m_Shl(m_Specific(CurrX), m_One()))) {
// FIXME: support right-shift?
LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad recurrence.\n");
@@ -2132,13 +2309,14 @@ bool LoopIdiomRecognize::recognizeShiftUntilBitTest() {
assert(LoopPreheaderBB && "There is always a loop preheader.");
BasicBlock *SuccessorBB = CurLoop->getExitBlock();
- assert(LoopPreheaderBB && "There is only a single successor.");
+ assert(SuccessorBB && "There is only a single successor.");
IRBuilder<> Builder(LoopPreheaderBB->getTerminator());
Builder.SetCurrentDebugLocation(cast<Instruction>(XCurr)->getDebugLoc());
Intrinsic::ID IntrID = Intrinsic::ctlz;
Type *Ty = X->getType();
+ unsigned Bitwidth = Ty->getScalarSizeInBits();
TargetTransformInfo::TargetCostKind CostKind =
TargetTransformInfo::TCK_SizeAndLatency;
@@ -2148,7 +2326,7 @@ bool LoopIdiomRecognize::recognizeShiftUntilBitTest() {
// making the loop countable, even if nothing else changes.
IntrinsicCostAttributes Attrs(
IntrID, Ty, {UndefValue::get(Ty), /*is_zero_undef=*/Builder.getTrue()});
- int Cost = TTI->getIntrinsicInstrCost(Attrs, CostKind);
+ InstructionCost Cost = TTI->getIntrinsicInstrCost(Attrs, CostKind);
if (Cost > TargetTransformInfo::TCC_Basic) {
LLVM_DEBUG(dbgs() << DEBUG_TYPE
" Intrinsic is too costly, not beneficial\n");
@@ -2175,18 +2353,22 @@ bool LoopIdiomRecognize::recognizeShiftUntilBitTest() {
/*FMFSource=*/nullptr, XMasked->getName() + ".numleadingzeros");
Value *XMaskedNumActiveBits = Builder.CreateSub(
ConstantInt::get(Ty, Ty->getScalarSizeInBits()), XMaskedNumLeadingZeros,
- XMasked->getName() + ".numactivebits");
+ XMasked->getName() + ".numactivebits", /*HasNUW=*/true,
+ /*HasNSW=*/Bitwidth != 2);
Value *XMaskedLeadingOnePos =
Builder.CreateAdd(XMaskedNumActiveBits, Constant::getAllOnesValue(Ty),
- XMasked->getName() + ".leadingonepos");
+ XMasked->getName() + ".leadingonepos", /*HasNUW=*/false,
+ /*HasNSW=*/Bitwidth > 2);
Value *LoopBackedgeTakenCount = Builder.CreateSub(
- BitPos, XMaskedLeadingOnePos, CurLoop->getName() + ".backedgetakencount");
+ BitPos, XMaskedLeadingOnePos, CurLoop->getName() + ".backedgetakencount",
+ /*HasNUW=*/true, /*HasNSW=*/true);
// We know loop's backedge-taken count, but what's loop's trip count?
// Note that while NUW is always safe, while NSW is only for bitwidths != 2.
Value *LoopTripCount =
- Builder.CreateNUWAdd(LoopBackedgeTakenCount, ConstantInt::get(Ty, 1),
- CurLoop->getName() + ".tripcount");
+ Builder.CreateAdd(LoopBackedgeTakenCount, ConstantInt::get(Ty, 1),
+ CurLoop->getName() + ".tripcount", /*HasNUW=*/true,
+ /*HasNSW=*/Bitwidth != 2);
// Step 2: Compute the recurrence's final value without a loop.
@@ -2234,8 +2416,9 @@ bool LoopIdiomRecognize::recognizeShiftUntilBitTest() {
// The induction itself.
// Note that while NUW is always safe, while NSW is only for bitwidths != 2.
Builder.SetInsertPoint(LoopHeaderBB->getTerminator());
- auto *IVNext = Builder.CreateNUWAdd(IV, ConstantInt::get(Ty, 1),
- IV->getName() + ".next");
+ auto *IVNext =
+ Builder.CreateAdd(IV, ConstantInt::get(Ty, 1), IV->getName() + ".next",
+ /*HasNUW=*/true, /*HasNSW=*/Bitwidth != 2);
// The loop trip count check.
auto *IVCheck = Builder.CreateICmpEQ(IVNext, LoopTripCount,
@@ -2259,3 +2442,346 @@ bool LoopIdiomRecognize::recognizeShiftUntilBitTest() {
++NumShiftUntilBitTest;
return MadeChange;
}
+
+/// Return true if the idiom is detected in the loop.
+///
+/// The core idiom we are trying to detect is:
+/// \code
+/// entry:
+/// <...>
+/// %start = <...>
+/// %extraoffset = <...>
+/// <...>
+/// br label %for.cond
+///
+/// loop:
+/// %iv = phi i8 [ %start, %entry ], [ %iv.next, %for.cond ]
+/// %nbits = add nsw i8 %iv, %extraoffset
+/// %val.shifted = {{l,a}shr,shl} i8 %val, %nbits
+/// %val.shifted.iszero = icmp eq i8 %val.shifted, 0
+/// %iv.next = add i8 %iv, 1
+/// <...>
+/// br i1 %val.shifted.iszero, label %end, label %loop
+///
+/// end:
+/// %iv.res = phi i8 [ %iv, %loop ] <...>
+/// %nbits.res = phi i8 [ %nbits, %loop ] <...>
+/// %val.shifted.res = phi i8 [ %val.shifted, %loop ] <...>
+/// %val.shifted.iszero.res = phi i1 [ %val.shifted.iszero, %loop ] <...>
+/// %iv.next.res = phi i8 [ %iv.next, %loop ] <...>
+/// <...>
+/// \endcode
+static bool detectShiftUntilZeroIdiom(Loop *CurLoop, ScalarEvolution *SE,
+ Instruction *&ValShiftedIsZero,
+ Intrinsic::ID &IntrinID, Instruction *&IV,
+ Value *&Start, Value *&Val,
+ const SCEV *&ExtraOffsetExpr,
+ bool &InvertedCond) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE
+ " Performing shift-until-zero idiom detection.\n");
+
+ // Give up if the loop has multiple blocks or multiple backedges.
+ if (CurLoop->getNumBlocks() != 1 || CurLoop->getNumBackEdges() != 1) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad block/backedge count.\n");
+ return false;
+ }
+
+ Instruction *ValShifted, *NBits, *IVNext;
+ Value *ExtraOffset;
+
+ BasicBlock *LoopHeaderBB = CurLoop->getHeader();
+ BasicBlock *LoopPreheaderBB = CurLoop->getLoopPreheader();
+ assert(LoopPreheaderBB && "There is always a loop preheader.");
+
+ using namespace PatternMatch;
+
+ // Step 1: Check if the loop backedge, condition is in desirable form.
+
+ ICmpInst::Predicate Pred;
+ BasicBlock *TrueBB, *FalseBB;
+ if (!match(LoopHeaderBB->getTerminator(),
+ m_Br(m_Instruction(ValShiftedIsZero), m_BasicBlock(TrueBB),
+ m_BasicBlock(FalseBB))) ||
+ !match(ValShiftedIsZero,
+ m_ICmp(Pred, m_Instruction(ValShifted), m_Zero())) ||
+ !ICmpInst::isEquality(Pred)) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad backedge structure.\n");
+ return false;
+ }
+
+ // Step 2: Check if the comparison's operand is in desirable form.
+ // FIXME: Val could be a one-input PHI node, which we should look past.
+ if (!match(ValShifted, m_Shift(m_LoopInvariant(m_Value(Val), CurLoop),
+ m_Instruction(NBits)))) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad comparisons value computation.\n");
+ return false;
+ }
+ IntrinID = ValShifted->getOpcode() == Instruction::Shl ? Intrinsic::cttz
+ : Intrinsic::ctlz;
+
+ // Step 3: Check if the shift amount is in desirable form.
+
+ if (match(NBits, m_c_Add(m_Instruction(IV),
+ m_LoopInvariant(m_Value(ExtraOffset), CurLoop))) &&
+ (NBits->hasNoSignedWrap() || NBits->hasNoUnsignedWrap()))
+ ExtraOffsetExpr = SE->getNegativeSCEV(SE->getSCEV(ExtraOffset));
+ else if (match(NBits,
+ m_Sub(m_Instruction(IV),
+ m_LoopInvariant(m_Value(ExtraOffset), CurLoop))) &&
+ NBits->hasNoSignedWrap())
+ ExtraOffsetExpr = SE->getSCEV(ExtraOffset);
+ else {
+ IV = NBits;
+ ExtraOffsetExpr = SE->getZero(NBits->getType());
+ }
+
+ // Step 4: Check if the recurrence is in desirable form.
+ auto *IVPN = dyn_cast<PHINode>(IV);
+ if (!IVPN || IVPN->getParent() != LoopHeaderBB) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE " Not an expected PHI node.\n");
+ return false;
+ }
+
+ Start = IVPN->getIncomingValueForBlock(LoopPreheaderBB);
+ IVNext = dyn_cast<Instruction>(IVPN->getIncomingValueForBlock(LoopHeaderBB));
+
+ if (!IVNext || !match(IVNext, m_Add(m_Specific(IVPN), m_One()))) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad recurrence.\n");
+ return false;
+ }
+
+ // Step 4: Check if the backedge's destinations are in desirable form.
+
+ assert(ICmpInst::isEquality(Pred) &&
+ "Should only get equality predicates here.");
+
+ // cmp-br is commutative, so canonicalize to a single variant.
+ InvertedCond = Pred != ICmpInst::Predicate::ICMP_EQ;
+ if (InvertedCond) {
+ Pred = ICmpInst::getInversePredicate(Pred);
+ std::swap(TrueBB, FalseBB);
+ }
+
+ // We expect to exit loop when comparison yields true,
+ // so when it yields false we should branch back to loop header.
+ if (FalseBB != LoopHeaderBB) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad backedge flow.\n");
+ return false;
+ }
+
+ // The new, countable, loop will certainly only run a known number of
+ // iterations, It won't be infinite. But the old loop might be infinite
+ // under certain conditions. For logical shifts, the value will become zero
+ // after at most bitwidth(%Val) loop iterations. However, for arithmetic
+ // right-shift, iff the sign bit was set, the value will never become zero,
+ // and the loop may never finish.
+ if (ValShifted->getOpcode() == Instruction::AShr &&
+ !isMustProgress(CurLoop) && !SE->isKnownNonNegative(SE->getSCEV(Val))) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE " Can not prove the loop is finite.\n");
+ return false;
+ }
+
+ // Okay, idiom checks out.
+ return true;
+}
+
+/// Look for the following loop:
+/// \code
+/// entry:
+/// <...>
+/// %start = <...>
+/// %extraoffset = <...>
+/// <...>
+/// br label %for.cond
+///
+/// loop:
+/// %iv = phi i8 [ %start, %entry ], [ %iv.next, %for.cond ]
+/// %nbits = add nsw i8 %iv, %extraoffset
+/// %val.shifted = {{l,a}shr,shl} i8 %val, %nbits
+/// %val.shifted.iszero = icmp eq i8 %val.shifted, 0
+/// %iv.next = add i8 %iv, 1
+/// <...>
+/// br i1 %val.shifted.iszero, label %end, label %loop
+///
+/// end:
+/// %iv.res = phi i8 [ %iv, %loop ] <...>
+/// %nbits.res = phi i8 [ %nbits, %loop ] <...>
+/// %val.shifted.res = phi i8 [ %val.shifted, %loop ] <...>
+/// %val.shifted.iszero.res = phi i1 [ %val.shifted.iszero, %loop ] <...>
+/// %iv.next.res = phi i8 [ %iv.next, %loop ] <...>
+/// <...>
+/// \endcode
+///
+/// And transform it into:
+/// \code
+/// entry:
+/// <...>
+/// %start = <...>
+/// %extraoffset = <...>
+/// <...>
+/// %val.numleadingzeros = call i8 @llvm.ct{l,t}z.i8(i8 %val, i1 0)
+/// %val.numactivebits = sub i8 8, %val.numleadingzeros
+/// %extraoffset.neg = sub i8 0, %extraoffset
+/// %tmp = add i8 %val.numactivebits, %extraoffset.neg
+/// %iv.final = call i8 @llvm.smax.i8(i8 %tmp, i8 %start)
+/// %loop.tripcount = sub i8 %iv.final, %start
+/// br label %loop
+///
+/// loop:
+/// %loop.iv = phi i8 [ 0, %entry ], [ %loop.iv.next, %loop ]
+/// %loop.iv.next = add i8 %loop.iv, 1
+/// %loop.ivcheck = icmp eq i8 %loop.iv.next, %loop.tripcount
+/// %iv = add i8 %loop.iv, %start
+/// <...>
+/// br i1 %loop.ivcheck, label %end, label %loop
+///
+/// end:
+/// %iv.res = phi i8 [ %iv.final, %loop ] <...>
+/// <...>
+/// \endcode
+bool LoopIdiomRecognize::recognizeShiftUntilZero() {
+ bool MadeChange = false;
+
+ Instruction *ValShiftedIsZero;
+ Intrinsic::ID IntrID;
+ Instruction *IV;
+ Value *Start, *Val;
+ const SCEV *ExtraOffsetExpr;
+ bool InvertedCond;
+ if (!detectShiftUntilZeroIdiom(CurLoop, SE, ValShiftedIsZero, IntrID, IV,
+ Start, Val, ExtraOffsetExpr, InvertedCond)) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE
+ " shift-until-zero idiom detection failed.\n");
+ return MadeChange;
+ }
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE " shift-until-zero idiom detected!\n");
+
+ // Ok, it is the idiom we were looking for, we *could* transform this loop,
+ // but is it profitable to transform?
+
+ BasicBlock *LoopHeaderBB = CurLoop->getHeader();
+ BasicBlock *LoopPreheaderBB = CurLoop->getLoopPreheader();
+ assert(LoopPreheaderBB && "There is always a loop preheader.");
+
+ BasicBlock *SuccessorBB = CurLoop->getExitBlock();
+ assert(SuccessorBB && "There is only a single successor.");
+
+ IRBuilder<> Builder(LoopPreheaderBB->getTerminator());
+ Builder.SetCurrentDebugLocation(IV->getDebugLoc());
+
+ Type *Ty = Val->getType();
+ unsigned Bitwidth = Ty->getScalarSizeInBits();
+
+ TargetTransformInfo::TargetCostKind CostKind =
+ TargetTransformInfo::TCK_SizeAndLatency;
+
+ // The rewrite is considered to be unprofitable iff and only iff the
+ // intrinsic we'll use are not cheap. Note that we are okay with *just*
+ // making the loop countable, even if nothing else changes.
+ IntrinsicCostAttributes Attrs(
+ IntrID, Ty, {UndefValue::get(Ty), /*is_zero_undef=*/Builder.getFalse()});
+ InstructionCost Cost = TTI->getIntrinsicInstrCost(Attrs, CostKind);
+ if (Cost > TargetTransformInfo::TCC_Basic) {
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE
+ " Intrinsic is too costly, not beneficial\n");
+ return MadeChange;
+ }
+
+ // Ok, transform appears worthwhile.
+ MadeChange = true;
+
+ bool OffsetIsZero = false;
+ if (auto *ExtraOffsetExprC = dyn_cast<SCEVConstant>(ExtraOffsetExpr))
+ OffsetIsZero = ExtraOffsetExprC->isZero();
+
+ // Step 1: Compute the loop's final IV value / trip count.
+
+ CallInst *ValNumLeadingZeros = Builder.CreateIntrinsic(
+ IntrID, Ty, {Val, /*is_zero_undef=*/Builder.getFalse()},
+ /*FMFSource=*/nullptr, Val->getName() + ".numleadingzeros");
+ Value *ValNumActiveBits = Builder.CreateSub(
+ ConstantInt::get(Ty, Ty->getScalarSizeInBits()), ValNumLeadingZeros,
+ Val->getName() + ".numactivebits", /*HasNUW=*/true,
+ /*HasNSW=*/Bitwidth != 2);
+
+ SCEVExpander Expander(*SE, *DL, "loop-idiom");
+ Expander.setInsertPoint(&*Builder.GetInsertPoint());
+ Value *ExtraOffset = Expander.expandCodeFor(ExtraOffsetExpr);
+
+ Value *ValNumActiveBitsOffset = Builder.CreateAdd(
+ ValNumActiveBits, ExtraOffset, ValNumActiveBits->getName() + ".offset",
+ /*HasNUW=*/OffsetIsZero, /*HasNSW=*/true);
+ Value *IVFinal = Builder.CreateIntrinsic(Intrinsic::smax, {Ty},
+ {ValNumActiveBitsOffset, Start},
+ /*FMFSource=*/nullptr, "iv.final");
+
+ auto *LoopBackedgeTakenCount = cast<Instruction>(Builder.CreateSub(
+ IVFinal, Start, CurLoop->getName() + ".backedgetakencount",
+ /*HasNUW=*/OffsetIsZero, /*HasNSW=*/true));
+ // FIXME: or when the offset was `add nuw`
+
+ // We know loop's backedge-taken count, but what's loop's trip count?
+ Value *LoopTripCount =
+ Builder.CreateAdd(LoopBackedgeTakenCount, ConstantInt::get(Ty, 1),
+ CurLoop->getName() + ".tripcount", /*HasNUW=*/true,
+ /*HasNSW=*/Bitwidth != 2);
+
+ // Step 2: Adjust the successor basic block to recieve the original
+ // induction variable's final value instead of the orig. IV itself.
+
+ IV->replaceUsesOutsideBlock(IVFinal, LoopHeaderBB);
+
+ // Step 3: Rewrite the loop into a countable form, with canonical IV.
+
+ // The new canonical induction variable.
+ Builder.SetInsertPoint(&LoopHeaderBB->front());
+ auto *CIV = Builder.CreatePHI(Ty, 2, CurLoop->getName() + ".iv");
+
+ // The induction itself.
+ Builder.SetInsertPoint(LoopHeaderBB->getFirstNonPHI());
+ auto *CIVNext =
+ Builder.CreateAdd(CIV, ConstantInt::get(Ty, 1), CIV->getName() + ".next",
+ /*HasNUW=*/true, /*HasNSW=*/Bitwidth != 2);
+
+ // The loop trip count check.
+ auto *CIVCheck = Builder.CreateICmpEQ(CIVNext, LoopTripCount,
+ CurLoop->getName() + ".ivcheck");
+ auto *NewIVCheck = CIVCheck;
+ if (InvertedCond) {
+ NewIVCheck = Builder.CreateNot(CIVCheck);
+ NewIVCheck->takeName(ValShiftedIsZero);
+ }
+
+ // The original IV, but rebased to be an offset to the CIV.
+ auto *IVDePHId = Builder.CreateAdd(CIV, Start, "", /*HasNUW=*/false,
+ /*HasNSW=*/true); // FIXME: what about NUW?
+ IVDePHId->takeName(IV);
+
+ // The loop terminator.
+ Builder.SetInsertPoint(LoopHeaderBB->getTerminator());
+ Builder.CreateCondBr(CIVCheck, SuccessorBB, LoopHeaderBB);
+ LoopHeaderBB->getTerminator()->eraseFromParent();
+
+ // Populate the IV PHI.
+ CIV->addIncoming(ConstantInt::get(Ty, 0), LoopPreheaderBB);
+ CIV->addIncoming(CIVNext, LoopHeaderBB);
+
+ // Step 4: Forget the "non-computable" trip-count SCEV associated with the
+ // loop. The loop would otherwise not be deleted even if it becomes empty.
+
+ SE->forgetLoop(CurLoop);
+
+ // Step 5: Try to cleanup the loop's body somewhat.
+ IV->replaceAllUsesWith(IVDePHId);
+ IV->eraseFromParent();
+
+ ValShiftedIsZero->replaceAllUsesWith(NewIVCheck);
+ ValShiftedIsZero->eraseFromParent();
+
+ // Other passes will take care of actually deleting the loop if possible.
+
+ LLVM_DEBUG(dbgs() << DEBUG_TYPE " shift-until-zero idiom optimized!\n");
+
+ ++NumShiftUntilZero;
+ return MadeChange;
+}
diff --git a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
index d9dbc0deb42a..34545f35b3c3 100644
--- a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/DependenceAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/LoopNestAnalysis.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ScalarEvolution.h"
@@ -186,12 +187,8 @@ static bool populateDependencyMatrix(CharMatrix &DepMatrix, unsigned Level,
// matrix by exchanging the two columns.
static void interChangeDependencies(CharMatrix &DepMatrix, unsigned FromIndx,
unsigned ToIndx) {
- unsigned numRows = DepMatrix.size();
- for (unsigned i = 0; i < numRows; ++i) {
- char TmpVal = DepMatrix[i][ToIndx];
- DepMatrix[i][ToIndx] = DepMatrix[i][FromIndx];
- DepMatrix[i][FromIndx] = TmpVal;
- }
+ for (unsigned I = 0, E = DepMatrix.size(); I < E; ++I)
+ std::swap(DepMatrix[I][ToIndx], DepMatrix[I][FromIndx]);
}
// Checks if outermost non '=','S'or'I' dependence in the dependence matrix is
@@ -400,10 +397,8 @@ class LoopInterchangeTransform {
public:
LoopInterchangeTransform(Loop *Outer, Loop *Inner, ScalarEvolution *SE,
LoopInfo *LI, DominatorTree *DT,
- BasicBlock *LoopNestExit,
const LoopInterchangeLegality &LIL)
- : OuterLoop(Outer), InnerLoop(Inner), SE(SE), LI(LI), DT(DT),
- LoopExit(LoopNestExit), LIL(LIL) {}
+ : OuterLoop(Outer), InnerLoop(Inner), SE(SE), LI(LI), DT(DT), LIL(LIL) {}
/// Interchange OuterLoop and InnerLoop.
bool transform();
@@ -424,7 +419,6 @@ private:
LoopInfo *LI;
DominatorTree *DT;
- BasicBlock *LoopExit;
const LoopInterchangeLegality &LIL;
};
@@ -449,7 +443,15 @@ struct LoopInterchange {
return processLoopList(populateWorklist(*L));
}
- bool isComputableLoopNest(LoopVector LoopList) {
+ bool run(LoopNest &LN) {
+ const auto &LoopList = LN.getLoops();
+ for (unsigned I = 1; I < LoopList.size(); ++I)
+ if (LoopList[I]->getParentLoop() != LoopList[I - 1])
+ return false;
+ return processLoopList(LoopList);
+ }
+
+ bool isComputableLoopNest(ArrayRef<Loop *> LoopList) {
for (Loop *L : LoopList) {
const SCEV *ExitCountOuter = SE->getBackedgeTakenCount(L);
if (isa<SCEVCouldNotCompute>(ExitCountOuter)) {
@@ -468,13 +470,13 @@ struct LoopInterchange {
return true;
}
- unsigned selectLoopForInterchange(const LoopVector &LoopList) {
+ unsigned selectLoopForInterchange(ArrayRef<Loop *> LoopList) {
// TODO: Add a better heuristic to select the loop to be interchanged based
// on the dependence matrix. Currently we select the innermost loop.
return LoopList.size() - 1;
}
- bool processLoopList(LoopVector LoopList) {
+ bool processLoopList(ArrayRef<Loop *> LoopList) {
bool Changed = false;
unsigned LoopNestDepth = LoopList.size();
if (LoopNestDepth < 2) {
@@ -515,14 +517,12 @@ struct LoopInterchange {
unsigned SelecLoopId = selectLoopForInterchange(LoopList);
// Move the selected loop outwards to the best possible position.
+ Loop *LoopToBeInterchanged = LoopList[SelecLoopId];
for (unsigned i = SelecLoopId; i > 0; i--) {
- bool Interchanged =
- processLoop(LoopList, i, i - 1, LoopNestExit, DependencyMatrix);
+ bool Interchanged = processLoop(LoopToBeInterchanged, LoopList[i - 1], i,
+ i - 1, DependencyMatrix);
if (!Interchanged)
return Changed;
- // Loops interchanged reflect the same in LoopList
- std::swap(LoopList[i - 1], LoopList[i]);
-
// Update the DependencyMatrix
interChangeDependencies(DependencyMatrix, i, i - 1);
#ifdef DUMP_DEP_MATRICIES
@@ -534,14 +534,11 @@ struct LoopInterchange {
return Changed;
}
- bool processLoop(LoopVector LoopList, unsigned InnerLoopId,
- unsigned OuterLoopId, BasicBlock *LoopNestExit,
+ bool processLoop(Loop *InnerLoop, Loop *OuterLoop, unsigned InnerLoopId,
+ unsigned OuterLoopId,
std::vector<std::vector<char>> &DependencyMatrix) {
- LLVM_DEBUG(dbgs() << "Processing Inner Loop Id = " << InnerLoopId
+ LLVM_DEBUG(dbgs() << "Processing InnerLoopId = " << InnerLoopId
<< " and OuterLoopId = " << OuterLoopId << "\n");
- Loop *InnerLoop = LoopList[InnerLoopId];
- Loop *OuterLoop = LoopList[OuterLoopId];
-
LoopInterchangeLegality LIL(OuterLoop, InnerLoop, SE, ORE);
if (!LIL.canInterchangeLoops(InnerLoopId, OuterLoopId, DependencyMatrix)) {
LLVM_DEBUG(dbgs() << "Not interchanging loops. Cannot prove legality.\n");
@@ -561,8 +558,7 @@ struct LoopInterchange {
<< "Loop interchanged with enclosing loop.";
});
- LoopInterchangeTransform LIT(OuterLoop, InnerLoop, SE, LI, DT, LoopNestExit,
- LIL);
+ LoopInterchangeTransform LIT(OuterLoop, InnerLoop, SE, LI, DT, LIL);
LIT.transform();
LLVM_DEBUG(dbgs() << "Loops interchanged.\n");
LoopsInterchanged++;
@@ -618,6 +614,22 @@ bool LoopInterchangeLegality::tightlyNested(Loop *OuterLoop, Loop *InnerLoop) {
containsUnsafeInstructions(InnerLoopPreHeader))
return false;
+ BasicBlock *InnerLoopExit = InnerLoop->getExitBlock();
+ // Ensure the inner loop exit block flows to the outer loop latch possibly
+ // through empty blocks.
+ const BasicBlock &SuccInner =
+ LoopNest::skipEmptyBlockUntil(InnerLoopExit, OuterLoopLatch);
+ if (&SuccInner != OuterLoopLatch) {
+ LLVM_DEBUG(dbgs() << "Inner loop exit block " << *InnerLoopExit
+ << " does not lead to the outer loop latch.\n";);
+ return false;
+ }
+ // The inner loop exit block does flow to the outer loop latch and not some
+ // other BBs, now make sure it contains safe instructions, since it will be
+ // moved into the (new) inner loop after interchange.
+ if (containsUnsafeInstructions(InnerLoopExit))
+ return false;
+
LLVM_DEBUG(dbgs() << "Loops are perfectly nested\n");
// We have a perfect loop nest.
return true;
@@ -644,6 +656,65 @@ bool LoopInterchangeLegality::isLoopStructureUnderstood(
return false;
}
}
+
+ // TODO: Handle triangular loops of another form.
+ // e.g. for(int i=0;i<N;i++)
+ // for(int j=0;j<i;j++)
+ // or,
+ // for(int i=0;i<N;i++)
+ // for(int j=0;j*i<N;j++)
+ BasicBlock *InnerLoopLatch = InnerLoop->getLoopLatch();
+ BranchInst *InnerLoopLatchBI =
+ dyn_cast<BranchInst>(InnerLoopLatch->getTerminator());
+ if (!InnerLoopLatchBI->isConditional())
+ return false;
+ if (CmpInst *InnerLoopCmp =
+ dyn_cast<CmpInst>(InnerLoopLatchBI->getCondition())) {
+ Value *Op0 = InnerLoopCmp->getOperand(0);
+ Value *Op1 = InnerLoopCmp->getOperand(1);
+
+ // LHS and RHS of the inner loop exit condition, e.g.,
+ // in "for(int j=0;j<i;j++)", LHS is j and RHS is i.
+ Value *Left = nullptr;
+ Value *Right = nullptr;
+
+ // Check if V only involves inner loop induction variable.
+ // Return true if V is InnerInduction, or a cast from
+ // InnerInduction, or a binary operator that involves
+ // InnerInduction and a constant.
+ std::function<bool(Value *)> IsPathToIndVar;
+ IsPathToIndVar = [&InnerInduction, &IsPathToIndVar](Value *V) -> bool {
+ if (V == InnerInduction)
+ return true;
+ if (isa<Constant>(V))
+ return true;
+ Instruction *I = dyn_cast<Instruction>(V);
+ if (!I)
+ return false;
+ if (isa<CastInst>(I))
+ return IsPathToIndVar(I->getOperand(0));
+ if (isa<BinaryOperator>(I))
+ return IsPathToIndVar(I->getOperand(0)) &&
+ IsPathToIndVar(I->getOperand(1));
+ return false;
+ };
+
+ if (IsPathToIndVar(Op0) && !isa<Constant>(Op0)) {
+ Left = Op0;
+ Right = Op1;
+ } else if (IsPathToIndVar(Op1) && !isa<Constant>(Op1)) {
+ Left = Op1;
+ Right = Op0;
+ }
+
+ if (Left == nullptr)
+ return false;
+
+ const SCEV *S = SE->getSCEV(Right);
+ if (!SE->isLoopInvariant(S, OuterLoop))
+ return false;
+ }
+
return true;
}
@@ -951,6 +1022,40 @@ static bool areOuterLoopExitPHIsSupported(Loop *OuterLoop, Loop *InnerLoop) {
return true;
}
+// In case of multi-level nested loops, it may occur that lcssa phis exist in
+// the latch of InnerLoop, i.e., when defs of the incoming values are further
+// inside the loopnest. Sometimes those incoming values are not available
+// after interchange, since the original inner latch will become the new outer
+// latch which may have predecessor paths that do not include those incoming
+// values.
+// TODO: Handle transformation of lcssa phis in the InnerLoop latch in case of
+// multi-level loop nests.
+static bool areInnerLoopLatchPHIsSupported(Loop *OuterLoop, Loop *InnerLoop) {
+ if (InnerLoop->getSubLoops().empty())
+ return true;
+ // If the original outer latch has only one predecessor, then values defined
+ // further inside the looploop, e.g., in the innermost loop, will be available
+ // at the new outer latch after interchange.
+ if (OuterLoop->getLoopLatch()->getUniquePredecessor() != nullptr)
+ return true;
+
+ // The outer latch has more than one predecessors, i.e., the inner
+ // exit and the inner header.
+ // PHI nodes in the inner latch are lcssa phis where the incoming values
+ // are defined further inside the loopnest. Check if those phis are used
+ // in the original inner latch. If that is the case then bail out since
+ // those incoming values may not be available at the new outer latch.
+ BasicBlock *InnerLoopLatch = InnerLoop->getLoopLatch();
+ for (PHINode &PHI : InnerLoopLatch->phis()) {
+ for (auto *U : PHI.users()) {
+ Instruction *UI = cast<Instruction>(U);
+ if (InnerLoopLatch == UI->getParent())
+ return false;
+ }
+ }
+ return true;
+}
+
bool LoopInterchangeLegality::canInterchangeLoops(unsigned InnerLoopId,
unsigned OuterLoopId,
CharMatrix &DepMatrix) {
@@ -986,6 +1091,18 @@ bool LoopInterchangeLegality::canInterchangeLoops(unsigned InnerLoopId,
return false;
}
+ if (!areInnerLoopLatchPHIsSupported(OuterLoop, InnerLoop)) {
+ LLVM_DEBUG(dbgs() << "Found unsupported PHI nodes in inner loop latch.\n");
+ ORE->emit([&]() {
+ return OptimizationRemarkMissed(DEBUG_TYPE, "UnsupportedInnerLatchPHI",
+ InnerLoop->getStartLoc(),
+ InnerLoop->getHeader())
+ << "Cannot interchange loops because unsupported PHI nodes found "
+ "in inner loop latch.";
+ });
+ return false;
+ }
+
// TODO: The loops could not be interchanged due to current limitations in the
// transform module.
if (currentLimitations()) {
@@ -1269,9 +1386,7 @@ bool LoopInterchangeTransform::transform() {
assert(!NewI->mayHaveSideEffects() &&
"Moving instructions with side-effects may change behavior of "
"the loop nest!");
- for (auto UI = WorkList[i]->use_begin(), UE = WorkList[i]->use_end();
- UI != UE;) {
- Use &U = *UI++;
+ for (Use &U : llvm::make_early_inc_range(WorkList[i]->uses())) {
Instruction *UserI = cast<Instruction>(U.getUser());
if (!InnerLoop->contains(UserI->getParent()) ||
UserI->getParent() == NewLatch || UserI == InductionPHI)
@@ -1460,6 +1575,13 @@ static void moveLCSSAPhis(BasicBlock *InnerExit, BasicBlock *InnerHeader,
PHINode *NewPhi = dyn_cast<PHINode>(P.clone());
NewPhi->setIncomingValue(0, P.getIncomingValue(0));
NewPhi->setIncomingBlock(0, OuterLatch);
+ // We might have incoming edges from other BBs, i.e., the original outer
+ // header.
+ for (auto *Pred : predecessors(InnerLatch)) {
+ if (Pred == OuterLatch)
+ continue;
+ NewPhi->addIncoming(P.getIncomingValue(0), Pred);
+ }
NewPhi->insertBefore(InnerLatch->getFirstNonPHI());
P.setIncomingValue(0, NewPhi);
}
@@ -1537,9 +1659,12 @@ bool LoopInterchangeTransform::adjustLoopBranches() {
InnerLoopPreHeader, DTUpdates, /*MustUpdateOnce=*/false);
// The outer loop header might or might not branch to the outer latch.
// We are guaranteed to branch to the inner loop preheader.
- if (llvm::is_contained(OuterLoopHeaderBI->successors(), OuterLoopLatch))
- updateSuccessor(OuterLoopHeaderBI, OuterLoopLatch, LoopExit, DTUpdates,
+ if (llvm::is_contained(OuterLoopHeaderBI->successors(), OuterLoopLatch)) {
+ // In this case the outerLoopHeader should branch to the InnerLoopLatch.
+ updateSuccessor(OuterLoopHeaderBI, OuterLoopLatch, InnerLoopLatch,
+ DTUpdates,
/*MustUpdateOnce=*/false);
+ }
updateSuccessor(OuterLoopHeaderBI, InnerLoopPreHeader,
InnerLoopHeaderSuccessor, DTUpdates,
/*MustUpdateOnce=*/false);
@@ -1582,15 +1707,19 @@ bool LoopInterchangeTransform::adjustLoopBranches() {
// replaced by Inners'.
OuterLoopLatchSuccessor->replacePhiUsesWith(OuterLoopLatch, InnerLoopLatch);
+ auto &OuterInnerReductions = LIL.getOuterInnerReductions();
// Now update the reduction PHIs in the inner and outer loop headers.
SmallVector<PHINode *, 4> InnerLoopPHIs, OuterLoopPHIs;
- for (PHINode &PHI : drop_begin(InnerLoopHeader->phis()))
+ for (PHINode &PHI : InnerLoopHeader->phis()) {
+ if (OuterInnerReductions.find(&PHI) == OuterInnerReductions.end())
+ continue;
InnerLoopPHIs.push_back(cast<PHINode>(&PHI));
- for (PHINode &PHI : drop_begin(OuterLoopHeader->phis()))
+ }
+ for (PHINode &PHI : OuterLoopHeader->phis()) {
+ if (OuterInnerReductions.find(&PHI) == OuterInnerReductions.end())
+ continue;
OuterLoopPHIs.push_back(cast<PHINode>(&PHI));
-
- auto &OuterInnerReductions = LIL.getOuterInnerReductions();
- (void)OuterInnerReductions;
+ }
// Now move the remaining reduction PHIs from outer to inner loop header and
// vice versa. The PHI nodes must be part of a reduction across the inner and
@@ -1682,14 +1811,15 @@ Pass *llvm::createLoopInterchangePass() {
return new LoopInterchangeLegacyPass();
}
-PreservedAnalyses LoopInterchangePass::run(Loop &L, LoopAnalysisManager &AM,
+PreservedAnalyses LoopInterchangePass::run(LoopNest &LN,
+ LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &U) {
- Function &F = *L.getHeader()->getParent();
+ Function &F = *LN.getParent();
DependenceInfo DI(&F, &AR.AA, &AR.SE, &AR.LI);
OptimizationRemarkEmitter ORE(&F);
- if (!LoopInterchange(&AR.SE, &AR.LI, &DI, &AR.DT, &ORE).run(&L))
+ if (!LoopInterchange(&AR.SE, &AR.LI, &DI, &AR.DT, &ORE).run(LN))
return PreservedAnalyses::all();
return getLoopPassPreservedAnalyses();
}
diff --git a/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp b/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp
index 058612149a94..aaf586173e44 100644
--- a/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp
@@ -99,12 +99,11 @@ struct StoreToLoadForwardingCandidate {
Loop *L) const {
Value *LoadPtr = Load->getPointerOperand();
Value *StorePtr = Store->getPointerOperand();
- Type *LoadPtrType = LoadPtr->getType();
- Type *LoadType = LoadPtrType->getPointerElementType();
+ Type *LoadType = getLoadStoreType(Load);
- assert(LoadPtrType->getPointerAddressSpace() ==
+ assert(LoadPtr->getType()->getPointerAddressSpace() ==
StorePtr->getType()->getPointerAddressSpace() &&
- LoadType == StorePtr->getType()->getPointerElementType() &&
+ LoadType == getLoadStoreType(Store) &&
"Should be a known dependence");
// Currently we only support accesses with unit stride. FIXME: we should be
@@ -664,10 +663,11 @@ public:
auto *BFI = (PSI && PSI->hasProfileSummary()) ?
&getAnalysis<LazyBlockFrequencyInfoPass>().getBFI() :
nullptr;
+ auto *SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
// Process each loop nest in the function.
return eliminateLoadsAcrossLoops(
- F, LI, DT, BFI, PSI, /*SE*/ nullptr, /*AC*/ nullptr,
+ F, LI, DT, BFI, PSI, SE, /*AC*/ nullptr,
[&LAA](Loop &L) -> const LoopAccessInfo & { return LAA.getInfo(&L); });
}
diff --git a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
index 3fe8e7259114..f4fce4871331 100644
--- a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp
@@ -14,6 +14,7 @@
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/TimeProfiler.h"
using namespace llvm;
@@ -26,10 +27,6 @@ PreservedAnalyses
PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
LPMUpdater &>::run(Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &U) {
-
- if (DebugLogging)
- dbgs() << "Starting Loop pass manager run.\n";
-
// Runs loop-nest passes only when the current loop is a top-level one.
PreservedAnalyses PA = (L.isOutermost() && !LoopNestPasses.empty())
? runWithLoopNestPasses(L, AM, AR, U)
@@ -44,9 +41,6 @@ PassManager<Loop, LoopAnalysisManager, LoopStandardAnalysisResults &,
// be preserved, but unrolling should invalidate the parent loop's analyses.
PA.preserveSet<AllAnalysesOn<Loop>>();
- if (DebugLogging)
- dbgs() << "Finished Loop pass manager run.\n";
-
return PA;
}
@@ -114,6 +108,11 @@ LoopPassManager::runWithLoopNestPasses(Loop &L, LoopAnalysisManager &AM,
// Check if the current pass preserved the loop-nest object or not.
IsLoopNestPtrValid &= PassPA->getChecker<LoopNestAnalysis>().preserved();
+ // After running the loop pass, the parent loop might change and we need to
+ // notify the updater, otherwise U.ParentL might gets outdated and triggers
+ // assertion failures in addSiblingLoops and addChildLoops.
+ U.setParentLoop(L.getParentLoop());
+
// FIXME: Historically, the pass managers all called the LLVM context's
// yield function here. We don't have a generic way to acquire the
// context and it isn't yet clear what the right pattern is for yielding
@@ -158,6 +157,11 @@ LoopPassManager::runWithoutLoopNestPasses(Loop &L, LoopAnalysisManager &AM,
// aggregate preserved set for this pass manager.
PA.intersect(std::move(*PassPA));
+ // After running the loop pass, the parent loop might change and we need to
+ // notify the updater, otherwise U.ParentL might gets outdated and triggers
+ // assertion failures in addSiblingLoops and addChildLoops.
+ U.setParentLoop(L.getParentLoop());
+
// FIXME: Historically, the pass managers all called the LLVM context's
// yield function here. We don't have a generic way to acquire the
// context and it isn't yet clear what the right pattern is for yielding
@@ -281,8 +285,17 @@ PreservedAnalyses FunctionToLoopPassAdaptor::run(Function &F,
else
PI.runAfterPass<Loop>(*Pass, *L, PassPA);
- // FIXME: We should verify the set of analyses relevant to Loop passes
- // are preserved.
+#ifndef NDEBUG
+ // LoopAnalysisResults should always be valid.
+ // Note that we don't LAR.SE.verify() because that can change observed SE
+ // queries. See PR44815.
+ if (VerifyDomInfo)
+ LAR.DT.verify();
+ if (VerifyLoopInfo)
+ LAR.LI.verify(LAR.DT);
+ if (LAR.MSSA && VerifyMemorySSA)
+ LAR.MSSA->verifyMemorySSA();
+#endif
// If the loop hasn't been deleted, we need to handle invalidation here.
if (!Updater.skipCurrentLoop())
@@ -314,12 +327,6 @@ PreservedAnalyses FunctionToLoopPassAdaptor::run(Function &F,
PA.preserve<BlockFrequencyAnalysis>();
if (UseMemorySSA)
PA.preserve<MemorySSAAnalysis>();
- // FIXME: What we really want to do here is preserve an AA category, but
- // that concept doesn't exist yet.
- PA.preserve<AAManager>();
- PA.preserve<BasicAA>();
- PA.preserve<GlobalsAA>();
- PA.preserve<SCEVAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp b/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp
index b3bae47e96de..56d66b93dd69 100644
--- a/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp
@@ -716,9 +716,8 @@ void LoopReroll::DAGRootTracker::collectInLoopUserSet(
}
// We also want to collect single-user "feeder" values.
- for (User::op_iterator OI = I->op_begin(),
- OIE = I->op_end(); OI != OIE; ++OI) {
- if (Instruction *Op = dyn_cast<Instruction>(*OI))
+ for (Use &U : I->operands()) {
+ if (Instruction *Op = dyn_cast<Instruction>(U))
if (Op->hasOneUse() && L->contains(Op) && !Exclude.count(Op) &&
!Final.count(Op))
Queue.push_back(Op);
@@ -912,6 +911,8 @@ bool LoopReroll::DAGRootTracker::validateRootSet(DAGRootSet &DRS) {
// Check that the first root is evenly spaced.
unsigned N = DRS.Roots.size() + 1;
const SCEV *StepSCEV = SE->getMinusSCEV(SE->getSCEV(DRS.Roots[0]), ADR);
+ if (isa<SCEVCouldNotCompute>(StepSCEV) || StepSCEV->getType()->isPointerTy())
+ return false;
const SCEV *ScaleSCEV = SE->getConstant(StepSCEV->getType(), N);
if (ADR->getStepRecurrence(*SE) != SE->getMulExpr(StepSCEV, ScaleSCEV))
return false;
@@ -1081,6 +1082,12 @@ bool LoopReroll::DAGRootTracker::collectUsedInstructions(SmallInstructionSet &Po
DenseSet<Instruction*> V;
collectInLoopUserSet(LoopIncs, Exclude, PossibleRedSet, V);
for (auto *I : V) {
+ if (I->mayHaveSideEffects()) {
+ LLVM_DEBUG(dbgs() << "LRR: Aborting - "
+ << "An instruction which does not belong to any root "
+ << "sets must not have side effects: " << *I);
+ return false;
+ }
Uses[I].set(IL_All);
}
diff --git a/llvm/lib/Transforms/Scalar/LoopRotation.cpp b/llvm/lib/Transforms/Scalar/LoopRotation.cpp
index ad1cfc68ece0..6d5b19443c76 100644
--- a/llvm/lib/Transforms/Scalar/LoopRotation.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopRotation.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/LazyBlockFrequencyInfo.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
@@ -101,6 +102,11 @@ public:
if (EnableMSSALoopDependency)
AU.addPreserved<MemorySSAWrapperPass>();
getLoopAnalysisUsage(AU);
+
+ // Lazy BFI and BPI are marked as preserved here so LoopRotate
+ // can remain part of the same loop pass manager as LICM.
+ AU.addPreserved<LazyBlockFrequencyInfoPass>();
+ AU.addPreserved<LazyBranchProbabilityInfoPass>();
}
bool runOnLoop(Loop *L, LPPassManager &LPM) override {
diff --git a/llvm/lib/Transforms/Scalar/LoopSink.cpp b/llvm/lib/Transforms/Scalar/LoopSink.cpp
index 47698fdde69f..a01287f587d7 100644
--- a/llvm/lib/Transforms/Scalar/LoopSink.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopSink.cpp
@@ -31,6 +31,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Scalar/LoopSink.h"
+#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AliasSetTracker.h"
@@ -191,7 +192,7 @@ static bool sinkInstruction(
for (auto &U : I.uses()) {
Instruction *UI = cast<Instruction>(U.getUser());
// We cannot sink I to PHI-uses.
- if (dyn_cast<PHINode>(UI))
+ if (isa<PHINode>(UI))
return false;
// We cannot sink I if it has uses outside of the loop.
if (!L.contains(LI.getLoopFor(UI->getParent())))
@@ -212,11 +213,9 @@ static bool sinkInstruction(
return false;
// Return if any of the candidate blocks to sink into is non-cold.
- if (BBsToSinkInto.size() > 1) {
- for (auto *BB : BBsToSinkInto)
- if (!LoopBlockNumber.count(BB))
- return false;
- }
+ if (BBsToSinkInto.size() > 1 &&
+ !llvm::set_is_subset(BBsToSinkInto, LoopBlockNumber))
+ return false;
// Copy the final BBs into a vector and sort them using the total ordering
// of the loop block numbers as iterating the set doesn't give a useful
diff --git a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
index 5dec9b542076..5f210380ae5a 100644
--- a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
@@ -77,6 +77,7 @@
#include "llvm/Analysis/ScalarEvolutionNormalization.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
@@ -161,9 +162,18 @@ static cl::opt<bool> FilterSameScaledReg(
cl::desc("Narrow LSR search space by filtering non-optimal formulae"
" with the same ScaledReg and Scale"));
-static cl::opt<bool> EnableBackedgeIndexing(
- "lsr-backedge-indexing", cl::Hidden, cl::init(true),
- cl::desc("Enable the generation of cross iteration indexed memops"));
+static cl::opt<TTI::AddressingModeKind> PreferredAddresingMode(
+ "lsr-preferred-addressing-mode", cl::Hidden, cl::init(TTI::AMK_None),
+ cl::desc("A flag that overrides the target's preferred addressing mode."),
+ cl::values(clEnumValN(TTI::AMK_None,
+ "none",
+ "Don't prefer any addressing mode"),
+ clEnumValN(TTI::AMK_PreIndexed,
+ "preindexed",
+ "Prefer pre-indexed addressing mode"),
+ clEnumValN(TTI::AMK_PostIndexed,
+ "postindexed",
+ "Prefer post-indexed addressing mode")));
static cl::opt<unsigned> ComplexityLimit(
"lsr-complexity-limit", cl::Hidden,
@@ -501,9 +511,16 @@ bool Formula::isCanonical(const Loop &L) const {
void Formula::canonicalize(const Loop &L) {
if (isCanonical(L))
return;
- // So far we did not need this case. This is easy to implement but it is
- // useless to maintain dead code. Beside it could hurt compile time.
- assert(!BaseRegs.empty() && "1*reg => reg, should not be needed.");
+
+ if (BaseRegs.empty()) {
+ // No base reg? Use scale reg with scale = 1 as such.
+ assert(ScaledReg && "Expected 1*reg => reg");
+ assert(Scale == 1 && "Expected 1*reg => reg");
+ BaseRegs.push_back(ScaledReg);
+ Scale = 0;
+ ScaledReg = nullptr;
+ return;
+ }
// Keep the invariant sum in BaseRegs and one of the variant sum in ScaledReg.
if (!ScaledReg) {
@@ -523,6 +540,7 @@ void Formula::canonicalize(const Loop &L) {
if (I != BaseRegs.end())
std::swap(ScaledReg, *I);
}
+ assert(isCanonical(L) && "Failed to canonicalize?");
}
/// Get rid of the scale in the formula.
@@ -655,7 +673,7 @@ static bool isMulSExtable(const SCEVMulExpr *M, ScalarEvolution &SE) {
/// Return an expression for LHS /s RHS, if it can be determined and if the
/// remainder is known to be zero, or null otherwise. If IgnoreSignificantBits
-/// is true, expressions like (X * Y) /s Y are simplified to Y, ignoring that
+/// is true, expressions like (X * Y) /s Y are simplified to X, ignoring that
/// the multiplication may overflow, which is useful when the result will be
/// used in a context where the most significant bits are ignored.
static const SCEV *getExactSDiv(const SCEV *LHS, const SCEV *RHS,
@@ -671,8 +689,11 @@ static const SCEV *getExactSDiv(const SCEV *LHS, const SCEV *RHS,
const APInt &RA = RC->getAPInt();
// Handle x /s -1 as x * -1, to give ScalarEvolution a chance to do
// some folding.
- if (RA.isAllOnesValue())
+ if (RA.isAllOnesValue()) {
+ if (LHS->getType()->isPointerTy())
+ return nullptr;
return SE.getMulExpr(LHS, RC);
+ }
// Handle x /s 1 as x.
if (RA == 1)
return LHS;
@@ -723,6 +744,21 @@ static const SCEV *getExactSDiv(const SCEV *LHS, const SCEV *RHS,
// Check for a multiply operand that we can pull RHS out of.
if (const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(LHS)) {
if (IgnoreSignificantBits || isMulSExtable(Mul, SE)) {
+ // Handle special case C1*X*Y /s C2*X*Y.
+ if (const SCEVMulExpr *MulRHS = dyn_cast<SCEVMulExpr>(RHS)) {
+ if (IgnoreSignificantBits || isMulSExtable(MulRHS, SE)) {
+ const SCEVConstant *LC = dyn_cast<SCEVConstant>(Mul->getOperand(0));
+ const SCEVConstant *RC =
+ dyn_cast<SCEVConstant>(MulRHS->getOperand(0));
+ if (LC && RC) {
+ SmallVector<const SCEV *, 4> LOps(drop_begin(Mul->operands()));
+ SmallVector<const SCEV *, 4> ROps(drop_begin(MulRHS->operands()));
+ if (LOps == ROps)
+ return getExactSDiv(LC, RC, SE, IgnoreSignificantBits);
+ }
+ }
+ }
+
SmallVector<const SCEV *, 4> Ops;
bool Found = false;
for (const SCEV *S : Mul->operands()) {
@@ -999,9 +1035,9 @@ static bool isAMCompletelyFolded(const TargetTransformInfo &TTI,
const LSRUse &LU, const Formula &F);
// Get the cost of the scaling factor used in F for LU.
-static unsigned getScalingFactorCost(const TargetTransformInfo &TTI,
- const LSRUse &LU, const Formula &F,
- const Loop &L);
+static InstructionCost getScalingFactorCost(const TargetTransformInfo &TTI,
+ const LSRUse &LU, const Formula &F,
+ const Loop &L);
namespace {
@@ -1011,11 +1047,13 @@ class Cost {
ScalarEvolution *SE = nullptr;
const TargetTransformInfo *TTI = nullptr;
TargetTransformInfo::LSRCost C;
+ TTI::AddressingModeKind AMK = TTI::AMK_None;
public:
Cost() = delete;
- Cost(const Loop *L, ScalarEvolution &SE, const TargetTransformInfo &TTI) :
- L(L), SE(&SE), TTI(&TTI) {
+ Cost(const Loop *L, ScalarEvolution &SE, const TargetTransformInfo &TTI,
+ TTI::AddressingModeKind AMK) :
+ L(L), SE(&SE), TTI(&TTI), AMK(AMK) {
C.Insns = 0;
C.NumRegs = 0;
C.AddRecCost = 0;
@@ -1233,7 +1271,7 @@ void Cost::RateRegister(const Formula &F, const SCEV *Reg,
// for now LSR only handles innermost loops).
if (AR->getLoop() != L) {
// If the AddRec exists, consider it's register free and leave it alone.
- if (isExistingPhi(AR, *SE) && !TTI->shouldFavorPostInc())
+ if (isExistingPhi(AR, *SE) && AMK != TTI::AMK_PostIndexed)
return;
// It is bad to allow LSR for current loop to add induction variables
@@ -1254,13 +1292,11 @@ void Cost::RateRegister(const Formula &F, const SCEV *Reg,
// If the step size matches the base offset, we could use pre-indexed
// addressing.
- if (TTI->shouldFavorBackedgeIndex(L)) {
+ if (AMK == TTI::AMK_PreIndexed) {
if (auto *Step = dyn_cast<SCEVConstant>(AR->getStepRecurrence(*SE)))
if (Step->getAPInt() == F.BaseOffset)
LoopCost = 0;
- }
-
- if (TTI->shouldFavorPostInc()) {
+ } else if (AMK == TTI::AMK_PostIndexed) {
const SCEV *LoopStep = AR->getStepRecurrence(*SE);
if (isa<SCEVConstant>(LoopStep)) {
const SCEV *LoopStart = AR->getStart();
@@ -1350,7 +1386,7 @@ void Cost::RateFormula(const Formula &F,
C.NumBaseAdds += (F.UnfoldedOffset != 0);
// Accumulate non-free scaling amounts.
- C.ScaleCost += getScalingFactorCost(*TTI, LU, F, *L);
+ C.ScaleCost += *getScalingFactorCost(*TTI, LU, F, *L).getValue();
// Tally up the non-zero immediates.
for (const LSRFixup &Fixup : LU.Fixups) {
@@ -1747,9 +1783,9 @@ static bool isAMCompletelyFolded(const TargetTransformInfo &TTI,
F.Scale);
}
-static unsigned getScalingFactorCost(const TargetTransformInfo &TTI,
- const LSRUse &LU, const Formula &F,
- const Loop &L) {
+static InstructionCost getScalingFactorCost(const TargetTransformInfo &TTI,
+ const LSRUse &LU, const Formula &F,
+ const Loop &L) {
if (!F.Scale)
return 0;
@@ -1762,14 +1798,14 @@ static unsigned getScalingFactorCost(const TargetTransformInfo &TTI,
switch (LU.Kind) {
case LSRUse::Address: {
// Check the scaling factor cost with both the min and max offsets.
- int ScaleCostMinOffset = TTI.getScalingFactorCost(
+ InstructionCost ScaleCostMinOffset = TTI.getScalingFactorCost(
LU.AccessTy.MemTy, F.BaseGV, F.BaseOffset + LU.MinOffset, F.HasBaseReg,
F.Scale, LU.AccessTy.AddrSpace);
- int ScaleCostMaxOffset = TTI.getScalingFactorCost(
+ InstructionCost ScaleCostMaxOffset = TTI.getScalingFactorCost(
LU.AccessTy.MemTy, F.BaseGV, F.BaseOffset + LU.MaxOffset, F.HasBaseReg,
F.Scale, LU.AccessTy.AddrSpace);
- assert(ScaleCostMinOffset >= 0 && ScaleCostMaxOffset >= 0 &&
+ assert(ScaleCostMinOffset.isValid() && ScaleCostMaxOffset.isValid() &&
"Legal addressing mode has an illegal cost!");
return std::max(ScaleCostMinOffset, ScaleCostMaxOffset);
}
@@ -1908,7 +1944,7 @@ class LSRInstance {
const TargetTransformInfo &TTI;
Loop *const L;
MemorySSAUpdater *MSSAU;
- bool FavorBackedgeIndex = false;
+ TTI::AddressingModeKind AMK;
bool Changed = false;
/// This is the insert position that the current loop's induction variable
@@ -1945,6 +1981,9 @@ class LSRInstance {
/// IV users that belong to profitable IVChains.
SmallPtrSet<Use*, MaxChains> IVIncSet;
+ /// Induction variables that were generated and inserted by the SCEV Expander.
+ SmallVector<llvm::WeakVH, 2> ScalarEvolutionIVs;
+
void OptimizeShadowIV();
bool FindIVUserForCond(ICmpInst *Cond, IVStrideUse *&CondUse);
ICmpInst *OptimizeMax(ICmpInst *Cond, IVStrideUse* &CondUse);
@@ -2049,6 +2088,9 @@ public:
TargetLibraryInfo &TLI, MemorySSAUpdater *MSSAU);
bool getChanged() const { return Changed; }
+ const SmallVectorImpl<WeakVH> &getScalarEvolutionIVs() const {
+ return ScalarEvolutionIVs;
+ }
void print_factors_and_types(raw_ostream &OS) const;
void print_fixups(raw_ostream &OS) const;
@@ -2337,6 +2379,7 @@ ICmpInst *LSRInstance::OptimizeMax(ICmpInst *Cond, IVStrideUse* &CondUse) {
new ICmpInst(Cond, Pred, Cond->getOperand(0), NewRHS, "scmp");
// Delete the max calculation instructions.
+ NewCond->setDebugLoc(Cond->getDebugLoc());
Cond->replaceAllUsesWith(NewCond);
CondUse->setUser(NewCond);
Instruction *Cmp = cast<Instruction>(Sel->getOperand(0));
@@ -2466,7 +2509,7 @@ LSRInstance::OptimizeLoopTermCond() {
// It's possible for the setcc instruction to be anywhere in the loop, and
// possible for it to have multiple users. If it is not immediately before
// the exiting block branch, move it.
- if (&*++BasicBlock::iterator(Cond) != TermBr) {
+ if (Cond->getNextNonDebugInstruction() != TermBr) {
if (Cond->hasOneUse()) {
Cond->moveBefore(TermBr);
} else {
@@ -2686,13 +2729,13 @@ void LSRInstance::CollectInterestingTypesAndFactors() {
if (const SCEVConstant *Factor =
dyn_cast_or_null<SCEVConstant>(getExactSDiv(NewStride, OldStride,
SE, true))) {
- if (Factor->getAPInt().getMinSignedBits() <= 64)
+ if (Factor->getAPInt().getMinSignedBits() <= 64 && !Factor->isZero())
Factors.insert(Factor->getAPInt().getSExtValue());
} else if (const SCEVConstant *Factor =
dyn_cast_or_null<SCEVConstant>(getExactSDiv(OldStride,
NewStride,
SE, true))) {
- if (Factor->getAPInt().getMinSignedBits() <= 64)
+ if (Factor->getAPInt().getMinSignedBits() <= 64 && !Factor->isZero())
Factors.insert(Factor->getAPInt().getSExtValue());
}
}
@@ -2936,7 +2979,7 @@ void LSRInstance::ChainInstruction(Instruction *UserInst, Instruction *IVOper,
// The increment must be loop-invariant so it can be kept in a register.
const SCEV *PrevExpr = SE.getSCEV(PrevIV);
const SCEV *IncExpr = SE.getMinusSCEV(OperExpr, PrevExpr);
- if (!SE.isLoopInvariant(IncExpr, L))
+ if (isa<SCEVCouldNotCompute>(IncExpr) || !SE.isLoopInvariant(IncExpr, L))
continue;
if (Chain.isProfitableIncrement(OperExpr, IncExpr, SE)) {
@@ -3107,7 +3150,7 @@ void LSRInstance::CollectChains() {
void LSRInstance::FinalizeChain(IVChain &Chain) {
assert(!Chain.Incs.empty() && "empty IV chains are not allowed");
LLVM_DEBUG(dbgs() << "Final Chain: " << *Chain.Incs[0].UserInst << "\n");
-
+
for (const IVInc &Inc : Chain) {
LLVM_DEBUG(dbgs() << " Inc: " << *Inc.UserInst << "\n");
auto UseI = find(Inc.UserInst->operands(), Inc.IVOperand);
@@ -3289,7 +3332,9 @@ void LSRInstance::CollectFixupsAndInitialFormulae() {
// x == y --> x - y == 0
const SCEV *N = SE.getSCEV(NV);
- if (SE.isLoopInvariant(N, L) && isSafeToExpand(N, SE)) {
+ if (SE.isLoopInvariant(N, L) && isSafeToExpand(N, SE) &&
+ (!NV->getType()->isPointerTy() ||
+ SE.getPointerBase(N) == SE.getPointerBase(S))) {
// S is normalized, so normalize N before folding it into S
// to keep the result normalized.
N = normalizeForPostIncUse(N, TmpPostIncLoops, SE);
@@ -3420,6 +3465,9 @@ LSRInstance::CollectLoopInvariantFixupsAndFormulae() {
// Ignore non-instructions.
if (!UserInst)
continue;
+ // Don't bother if the instruction is an EHPad.
+ if (UserInst->isEHPad())
+ continue;
// Ignore instructions in other functions (as can happen with
// Constants).
if (UserInst->getParent()->getParent() != L->getHeader()->getParent())
@@ -3575,7 +3623,7 @@ void LSRInstance::GenerateReassociationsImpl(LSRUse &LU, unsigned LUIdx,
// may generate a post-increment operator. The reason is that the
// reassociations cause extra base+register formula to be created,
// and possibly chosen, but the post-increment is more efficient.
- if (TTI.shouldFavorPostInc() && mayUsePostIncMode(TTI, LU, BaseReg, L, SE))
+ if (AMK == TTI::AMK_PostIndexed && mayUsePostIncMode(TTI, LU, BaseReg, L, SE))
return;
SmallVector<const SCEV *, 8> AddOps;
const SCEV *Remainder = CollectSubexprs(BaseReg, nullptr, AddOps, L, SE);
@@ -3779,8 +3827,7 @@ void LSRInstance::GenerateConstantOffsetsImpl(
Formula F = Base;
F.BaseOffset = (uint64_t)Base.BaseOffset - Offset;
- if (isLegalUse(TTI, LU.MinOffset - Offset, LU.MaxOffset - Offset, LU.Kind,
- LU.AccessTy, F)) {
+ if (isLegalUse(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, F)) {
// Add the offset to the base register.
const SCEV *NewG = SE.getAddExpr(SE.getConstant(G->getType(), Offset), G);
// If it cancelled out, drop the base register, otherwise update it.
@@ -3810,7 +3857,7 @@ void LSRInstance::GenerateConstantOffsetsImpl(
// means that a single pre-indexed access can be generated to become the new
// base pointer for each iteration of the loop, resulting in no extra add/sub
// instructions for pointer updating.
- if (FavorBackedgeIndex && LU.Kind == LSRUse::Address) {
+ if (AMK == TTI::AMK_PreIndexed && LU.Kind == LSRUse::Address) {
if (auto *GAR = dyn_cast<SCEVAddRecExpr>(G)) {
if (auto *StepRec =
dyn_cast<SCEVConstant>(GAR->getStepRecurrence(SE))) {
@@ -3891,6 +3938,7 @@ void LSRInstance::GenerateICmpZeroScales(LSRUse &LU, unsigned LUIdx,
if (Base.BaseOffset == std::numeric_limits<int64_t>::min() && Factor == -1)
continue;
int64_t NewBaseOffset = (uint64_t)Base.BaseOffset * Factor;
+ assert(Factor != 0 && "Zero factor not expected!");
if (NewBaseOffset / Factor != Base.BaseOffset)
continue;
// If the offset will be truncated at this use, check that it is in bounds.
@@ -4031,7 +4079,8 @@ void LSRInstance::GenerateTruncates(LSRUse &LU, unsigned LUIdx, Formula Base) {
// Determine the integer type for the base formula.
Type *DstTy = Base.getType();
if (!DstTy) return;
- DstTy = SE.getEffectiveSCEVType(DstTy);
+ if (DstTy->isPointerTy())
+ return;
for (Type *SrcTy : Types) {
if (SrcTy != DstTy && TTI.isTruncateFree(SrcTy, DstTy)) {
@@ -4239,7 +4288,7 @@ void LSRInstance::GenerateCrossUseConstantOffsets() {
NewF.BaseOffset = (uint64_t)NewF.BaseOffset + Imm;
if (!isLegalUse(TTI, LU.MinOffset, LU.MaxOffset,
LU.Kind, LU.AccessTy, NewF)) {
- if (TTI.shouldFavorPostInc() &&
+ if (AMK == TTI::AMK_PostIndexed &&
mayUsePostIncMode(TTI, LU, OrigReg, this->L, SE))
continue;
if (!TTI.isLegalAddImmediate((uint64_t)NewF.UnfoldedOffset + Imm))
@@ -4342,7 +4391,7 @@ void LSRInstance::FilterOutUndesirableDedicatedRegisters() {
// avoids the need to recompute this information across formulae using the
// same bad AddRec. Passing LoserRegs is also essential unless we remove
// the corresponding bad register from the Regs set.
- Cost CostF(L, SE, TTI);
+ Cost CostF(L, SE, TTI, AMK);
Regs.clear();
CostF.RateFormula(F, Regs, VisitedRegs, LU, &LoserRegs);
if (CostF.isLoser()) {
@@ -4375,7 +4424,7 @@ void LSRInstance::FilterOutUndesirableDedicatedRegisters() {
Formula &Best = LU.Formulae[P.first->second];
- Cost CostBest(L, SE, TTI);
+ Cost CostBest(L, SE, TTI, AMK);
Regs.clear();
CostBest.RateFormula(Best, Regs, VisitedRegs, LU);
if (CostF.isLess(CostBest))
@@ -4495,7 +4544,7 @@ void LSRInstance::NarrowSearchSpaceByDetectingSupersets() {
/// When there are many registers for expressions like A, A+1, A+2, etc.,
/// allocate a single register for them.
void LSRInstance::NarrowSearchSpaceByCollapsingUnrolledCode() {
- if (EstimateSearchSpaceComplexity() < ComplexityLimit)
+ if (EstimateSearchSpaceComplexity() < ComplexityLimit)
return;
LLVM_DEBUG(
@@ -4628,8 +4677,8 @@ void LSRInstance::NarrowSearchSpaceByFilterFormulaWithSameScaledReg() {
// If the new register numbers are the same, choose the Formula with
// less Cost.
- Cost CostFA(L, SE, TTI);
- Cost CostFB(L, SE, TTI);
+ Cost CostFA(L, SE, TTI, AMK);
+ Cost CostFB(L, SE, TTI, AMK);
Regs.clear();
CostFA.RateFormula(FA, Regs, VisitedRegs, LU);
Regs.clear();
@@ -4679,7 +4728,7 @@ void LSRInstance::NarrowSearchSpaceByFilterFormulaWithSameScaledReg() {
/// If we are over the complexity limit, filter out any post-inc prefering
/// variables to only post-inc values.
void LSRInstance::NarrowSearchSpaceByFilterPostInc() {
- if (!TTI.shouldFavorPostInc())
+ if (AMK != TTI::AMK_PostIndexed)
return;
if (EstimateSearchSpaceComplexity() < ComplexityLimit)
return;
@@ -4970,7 +5019,7 @@ void LSRInstance::SolveRecurse(SmallVectorImpl<const Formula *> &Solution,
ReqRegs.insert(S);
SmallPtrSet<const SCEV *, 16> NewRegs;
- Cost NewCost(L, SE, TTI);
+ Cost NewCost(L, SE, TTI, AMK);
for (const Formula &F : LU.Formulae) {
// Ignore formulae which may not be ideal in terms of register reuse of
// ReqRegs. The formula should use all required registers before
@@ -4978,7 +5027,7 @@ void LSRInstance::SolveRecurse(SmallVectorImpl<const Formula *> &Solution,
// This can sometimes (notably when trying to favour postinc) lead to
// sub-optimial decisions. There it is best left to the cost modelling to
// get correct.
- if (!TTI.shouldFavorPostInc() || LU.Kind != LSRUse::Address) {
+ if (AMK != TTI::AMK_PostIndexed || LU.Kind != LSRUse::Address) {
int NumReqRegsToFind = std::min(F.getNumRegs(), ReqRegs.size());
for (const SCEV *Reg : ReqRegs) {
if ((F.ScaledReg && F.ScaledReg == Reg) ||
@@ -5026,9 +5075,9 @@ void LSRInstance::SolveRecurse(SmallVectorImpl<const Formula *> &Solution,
/// vector.
void LSRInstance::Solve(SmallVectorImpl<const Formula *> &Solution) const {
SmallVector<const Formula *, 8> Workspace;
- Cost SolutionCost(L, SE, TTI);
+ Cost SolutionCost(L, SE, TTI, AMK);
SolutionCost.Lose();
- Cost CurCost(L, SE, TTI);
+ Cost CurCost(L, SE, TTI, AMK);
SmallPtrSet<const SCEV *, 16> CurRegs;
DenseSet<const SCEV *> VisitedRegs;
Workspace.reserve(Uses.size());
@@ -5269,7 +5318,7 @@ Value *LSRInstance::Expand(const LSRUse &LU, const LSRFixup &LF,
if (F.BaseGV) {
// Flush the operand list to suppress SCEVExpander hoisting.
if (!Ops.empty()) {
- Value *FullV = Rewriter.expandCodeFor(SE.getAddExpr(Ops), Ty);
+ Value *FullV = Rewriter.expandCodeFor(SE.getAddExpr(Ops), IntTy);
Ops.clear();
Ops.push_back(SE.getUnknown(FullV));
}
@@ -5546,12 +5595,61 @@ void LSRInstance::ImplementSolution(
GenerateIVChain(Chain, Rewriter, DeadInsts);
Changed = true;
}
+
+ for (const WeakVH &IV : Rewriter.getInsertedIVs())
+ if (IV && dyn_cast<Instruction>(&*IV)->getParent())
+ ScalarEvolutionIVs.push_back(IV);
+
// Clean up after ourselves. This must be done before deleting any
// instructions.
Rewriter.clear();
Changed |= RecursivelyDeleteTriviallyDeadInstructionsPermissive(DeadInsts,
&TLI, MSSAU);
+
+ // In our cost analysis above, we assume that each addrec consumes exactly
+ // one register, and arrange to have increments inserted just before the
+ // latch to maximimize the chance this is true. However, if we reused
+ // existing IVs, we now need to move the increments to match our
+ // expectations. Otherwise, our cost modeling results in us having a
+ // chosen a non-optimal result for the actual schedule. (And yes, this
+ // scheduling decision does impact later codegen.)
+ for (PHINode &PN : L->getHeader()->phis()) {
+ BinaryOperator *BO = nullptr;
+ Value *Start = nullptr, *Step = nullptr;
+ if (!matchSimpleRecurrence(&PN, BO, Start, Step))
+ continue;
+
+ switch (BO->getOpcode()) {
+ case Instruction::Sub:
+ if (BO->getOperand(0) != &PN)
+ // sub is non-commutative - match handling elsewhere in LSR
+ continue;
+ break;
+ case Instruction::Add:
+ break;
+ default:
+ continue;
+ };
+
+ if (!isa<Constant>(Step))
+ // If not a constant step, might increase register pressure
+ // (We assume constants have been canonicalized to RHS)
+ continue;
+
+ if (BO->getParent() == IVIncInsertPos->getParent())
+ // Only bother moving across blocks. Isel can handle block local case.
+ continue;
+
+ // Can we legally schedule inc at the desired point?
+ if (!llvm::all_of(BO->uses(),
+ [&](Use &U) {return DT.dominates(IVIncInsertPos, U);}))
+ continue;
+ BO->moveBefore(IVIncInsertPos);
+ Changed = true;
+ }
+
+
}
LSRInstance::LSRInstance(Loop *L, IVUsers &IU, ScalarEvolution &SE,
@@ -5559,8 +5657,8 @@ LSRInstance::LSRInstance(Loop *L, IVUsers &IU, ScalarEvolution &SE,
const TargetTransformInfo &TTI, AssumptionCache &AC,
TargetLibraryInfo &TLI, MemorySSAUpdater *MSSAU)
: IU(IU), SE(SE), DT(DT), LI(LI), AC(AC), TLI(TLI), TTI(TTI), L(L),
- MSSAU(MSSAU), FavorBackedgeIndex(EnableBackedgeIndexing &&
- TTI.shouldFavorBackedgeIndex(L)) {
+ MSSAU(MSSAU), AMK(PreferredAddresingMode.getNumOccurrences() > 0 ?
+ PreferredAddresingMode : TTI.getPreferredAddressingMode(L, &SE)) {
// If LoopSimplify form is not available, stay out of trouble.
if (!L->isLoopSimplifyForm())
return;
@@ -5772,61 +5870,389 @@ void LoopStrengthReduce::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addPreserved<MemorySSAWrapperPass>();
}
-using EqualValues = SmallVector<std::tuple<WeakVH, int64_t, DIExpression *>, 4>;
-using EqualValuesMap = DenseMap<DbgValueInst *, EqualValues>;
+struct SCEVDbgValueBuilder {
+ SCEVDbgValueBuilder() = default;
+ SCEVDbgValueBuilder(const SCEVDbgValueBuilder &Base) {
+ Values = Base.Values;
+ Expr = Base.Expr;
+ }
+
+ /// The DIExpression as we translate the SCEV.
+ SmallVector<uint64_t, 6> Expr;
+ /// The location ops of the DIExpression.
+ SmallVector<llvm::ValueAsMetadata *, 2> Values;
+
+ void pushOperator(uint64_t Op) { Expr.push_back(Op); }
+ void pushUInt(uint64_t Operand) { Expr.push_back(Operand); }
+
+ /// Add a DW_OP_LLVM_arg to the expression, followed by the index of the value
+ /// in the set of values referenced by the expression.
+ void pushValue(llvm::Value *V) {
+ Expr.push_back(llvm::dwarf::DW_OP_LLVM_arg);
+ auto *It =
+ std::find(Values.begin(), Values.end(), llvm::ValueAsMetadata::get(V));
+ unsigned ArgIndex = 0;
+ if (It != Values.end()) {
+ ArgIndex = std::distance(Values.begin(), It);
+ } else {
+ ArgIndex = Values.size();
+ Values.push_back(llvm::ValueAsMetadata::get(V));
+ }
+ Expr.push_back(ArgIndex);
+ }
+
+ void pushValue(const SCEVUnknown *U) {
+ llvm::Value *V = cast<SCEVUnknown>(U)->getValue();
+ pushValue(V);
+ }
+
+ void pushConst(const SCEVConstant *C) {
+ Expr.push_back(llvm::dwarf::DW_OP_consts);
+ Expr.push_back(C->getAPInt().getSExtValue());
+ }
+
+ /// Several SCEV types are sequences of the same arithmetic operator applied
+ /// to constants and values that may be extended or truncated.
+ bool pushArithmeticExpr(const llvm::SCEVCommutativeExpr *CommExpr,
+ uint64_t DwarfOp) {
+ assert((isa<llvm::SCEVAddExpr>(CommExpr) || isa<SCEVMulExpr>(CommExpr)) &&
+ "Expected arithmetic SCEV type");
+ bool Success = true;
+ unsigned EmitOperator = 0;
+ for (auto &Op : CommExpr->operands()) {
+ Success &= pushSCEV(Op);
+
+ if (EmitOperator >= 1)
+ pushOperator(DwarfOp);
+ ++EmitOperator;
+ }
+ return Success;
+ }
+
+ // TODO: Identify and omit noop casts.
+ bool pushCast(const llvm::SCEVCastExpr *C, bool IsSigned) {
+ const llvm::SCEV *Inner = C->getOperand(0);
+ const llvm::Type *Type = C->getType();
+ uint64_t ToWidth = Type->getIntegerBitWidth();
+ bool Success = pushSCEV(Inner);
+ uint64_t CastOps[] = {dwarf::DW_OP_LLVM_convert, ToWidth,
+ IsSigned ? llvm::dwarf::DW_ATE_signed
+ : llvm::dwarf::DW_ATE_unsigned};
+ for (const auto &Op : CastOps)
+ pushOperator(Op);
+ return Success;
+ }
+
+ // TODO: MinMax - although these haven't been encountered in the test suite.
+ bool pushSCEV(const llvm::SCEV *S) {
+ bool Success = true;
+ if (const SCEVConstant *StartInt = dyn_cast<SCEVConstant>(S)) {
+ pushConst(StartInt);
+
+ } else if (const SCEVUnknown *U = dyn_cast<SCEVUnknown>(S)) {
+ if(!U->getValue())
+ return false;
+ pushValue(U->getValue());
+
+ } else if (const SCEVMulExpr *MulRec = dyn_cast<SCEVMulExpr>(S)) {
+ Success &= pushArithmeticExpr(MulRec, llvm::dwarf::DW_OP_mul);
+
+ } else if (const SCEVUDivExpr *UDiv = dyn_cast<SCEVUDivExpr>(S)) {
+ Success &= pushSCEV(UDiv->getLHS());
+ Success &= pushSCEV(UDiv->getRHS());
+ pushOperator(llvm::dwarf::DW_OP_div);
+
+ } else if (const SCEVCastExpr *Cast = dyn_cast<SCEVCastExpr>(S)) {
+ // Assert if a new and unknown SCEVCastEXpr type is encountered.
+ assert((isa<SCEVZeroExtendExpr>(Cast) || isa<SCEVTruncateExpr>(Cast) ||
+ isa<SCEVPtrToIntExpr>(Cast) || isa<SCEVSignExtendExpr>(Cast)) &&
+ "Unexpected cast type in SCEV.");
+ Success &= pushCast(Cast, (isa<SCEVSignExtendExpr>(Cast)));
+
+ } else if (const SCEVAddExpr *AddExpr = dyn_cast<SCEVAddExpr>(S)) {
+ Success &= pushArithmeticExpr(AddExpr, llvm::dwarf::DW_OP_plus);
+
+ } else if (isa<SCEVAddRecExpr>(S)) {
+ // Nested SCEVAddRecExpr are generated by nested loops and are currently
+ // unsupported.
+ return false;
+
+ } else {
+ return false;
+ }
+ return Success;
+ }
+
+ void setFinalExpression(llvm::DbgValueInst &DI, const DIExpression *OldExpr) {
+ // Re-state assumption that this dbg.value is not variadic. Any remaining
+ // opcodes in its expression operate on a single value already on the
+ // expression stack. Prepend our operations, which will re-compute and
+ // place that value on the expression stack.
+ assert(!DI.hasArgList());
+ auto *NewExpr =
+ DIExpression::prependOpcodes(OldExpr, Expr, /*StackValue*/ true);
+ DI.setExpression(NewExpr);
+
+ auto ValArrayRef = llvm::ArrayRef<llvm::ValueAsMetadata *>(Values);
+ DI.setRawLocation(llvm::DIArgList::get(DI.getContext(), ValArrayRef));
+ }
+
+ /// If a DVI can be emitted without a DIArgList, omit DW_OP_llvm_arg and the
+ /// location op index 0.
+ void setShortFinalExpression(llvm::DbgValueInst &DI,
+ const DIExpression *OldExpr) {
+ assert((Expr[0] == llvm::dwarf::DW_OP_LLVM_arg && Expr[1] == 0) &&
+ "Expected DW_OP_llvm_arg and 0.");
+ DI.replaceVariableLocationOp(
+ 0u, llvm::MetadataAsValue::get(DI.getContext(), Values[0]));
+
+ // See setFinalExpression: prepend our opcodes on the start of any old
+ // expression opcodes.
+ assert(!DI.hasArgList());
+ llvm::SmallVector<uint64_t, 6> FinalExpr(Expr.begin() + 2, Expr.end());
+ auto *NewExpr =
+ DIExpression::prependOpcodes(OldExpr, FinalExpr, /*StackValue*/ true);
+ DI.setExpression(NewExpr);
+ }
+
+ /// Once the IV and variable SCEV translation is complete, write it to the
+ /// source DVI.
+ void applyExprToDbgValue(llvm::DbgValueInst &DI,
+ const DIExpression *OldExpr) {
+ assert(!Expr.empty() && "Unexpected empty expression.");
+ // Emit a simpler form if only a single location is referenced.
+ if (Values.size() == 1 && Expr[0] == llvm::dwarf::DW_OP_LLVM_arg &&
+ Expr[1] == 0) {
+ setShortFinalExpression(DI, OldExpr);
+ } else {
+ setFinalExpression(DI, OldExpr);
+ }
+ }
+
+ /// Return true if the combination of arithmetic operator and underlying
+ /// SCEV constant value is an identity function.
+ bool isIdentityFunction(uint64_t Op, const SCEV *S) {
+ if (const SCEVConstant *C = dyn_cast<SCEVConstant>(S)) {
+ int64_t I = C->getAPInt().getSExtValue();
+ switch (Op) {
+ case llvm::dwarf::DW_OP_plus:
+ case llvm::dwarf::DW_OP_minus:
+ return I == 0;
+ case llvm::dwarf::DW_OP_mul:
+ case llvm::dwarf::DW_OP_div:
+ return I == 1;
+ }
+ }
+ return false;
+ }
+
+ /// Convert a SCEV of a value to a DIExpression that is pushed onto the
+ /// builder's expression stack. The stack should already contain an
+ /// expression for the iteration count, so that it can be multiplied by
+ /// the stride and added to the start.
+ /// Components of the expression are omitted if they are an identity function.
+ /// Chain (non-affine) SCEVs are not supported.
+ bool SCEVToValueExpr(const llvm::SCEVAddRecExpr &SAR, ScalarEvolution &SE) {
+ assert(SAR.isAffine() && "Expected affine SCEV");
+ // TODO: Is this check needed?
+ if (isa<SCEVAddRecExpr>(SAR.getStart()))
+ return false;
+
+ const SCEV *Start = SAR.getStart();
+ const SCEV *Stride = SAR.getStepRecurrence(SE);
+
+ // Skip pushing arithmetic noops.
+ if (!isIdentityFunction(llvm::dwarf::DW_OP_mul, Stride)) {
+ if (!pushSCEV(Stride))
+ return false;
+ pushOperator(llvm::dwarf::DW_OP_mul);
+ }
+ if (!isIdentityFunction(llvm::dwarf::DW_OP_plus, Start)) {
+ if (!pushSCEV(Start))
+ return false;
+ pushOperator(llvm::dwarf::DW_OP_plus);
+ }
+ return true;
+ }
+
+ /// Convert a SCEV of a value to a DIExpression that is pushed onto the
+ /// builder's expression stack. The stack should already contain an
+ /// expression for the iteration count, so that it can be multiplied by
+ /// the stride and added to the start.
+ /// Components of the expression are omitted if they are an identity function.
+ bool SCEVToIterCountExpr(const llvm::SCEVAddRecExpr &SAR,
+ ScalarEvolution &SE) {
+ assert(SAR.isAffine() && "Expected affine SCEV");
+ if (isa<SCEVAddRecExpr>(SAR.getStart())) {
+ LLVM_DEBUG(dbgs() << "scev-salvage: IV SCEV. Unsupported nested AddRec: "
+ << SAR << '\n');
+ return false;
+ }
+ const SCEV *Start = SAR.getStart();
+ const SCEV *Stride = SAR.getStepRecurrence(SE);
+
+ // Skip pushing arithmetic noops.
+ if (!isIdentityFunction(llvm::dwarf::DW_OP_minus, Start)) {
+ if (!pushSCEV(Start))
+ return false;
+ pushOperator(llvm::dwarf::DW_OP_minus);
+ }
+ if (!isIdentityFunction(llvm::dwarf::DW_OP_div, Stride)) {
+ if (!pushSCEV(Stride))
+ return false;
+ pushOperator(llvm::dwarf::DW_OP_div);
+ }
+ return true;
+ }
+};
+
+struct DVIRecoveryRec {
+ DbgValueInst *DVI;
+ DIExpression *Expr;
+ Metadata *LocationOp;
+ const llvm::SCEV *SCEV;
+};
+
+static bool RewriteDVIUsingIterCount(DVIRecoveryRec CachedDVI,
+ const SCEVDbgValueBuilder &IterationCount,
+ ScalarEvolution &SE) {
+ // LSR may add locations to previously single location-op DVIs which
+ // are currently not supported.
+ if (CachedDVI.DVI->getNumVariableLocationOps() != 1)
+ return false;
+
+ // SCEVs for SSA values are most frquently of the form
+ // {start,+,stride}, but sometimes they are ({start,+,stride} + %a + ..).
+ // This is because %a is a PHI node that is not the IV. However, these
+ // SCEVs have not been observed to result in debuginfo-lossy optimisations,
+ // so its not expected this point will be reached.
+ if (!isa<SCEVAddRecExpr>(CachedDVI.SCEV))
+ return false;
+
+ LLVM_DEBUG(dbgs() << "scev-salvage: Value to salvage SCEV: "
+ << *CachedDVI.SCEV << '\n');
+
+ const auto *Rec = cast<SCEVAddRecExpr>(CachedDVI.SCEV);
+ if (!Rec->isAffine())
+ return false;
+
+ // Initialise a new builder with the iteration count expression. In
+ // combination with the value's SCEV this enables recovery.
+ SCEVDbgValueBuilder RecoverValue(IterationCount);
+ if (!RecoverValue.SCEVToValueExpr(*Rec, SE))
+ return false;
+
+ LLVM_DEBUG(dbgs() << "scev-salvage: Updating: " << *CachedDVI.DVI << '\n');
+ RecoverValue.applyExprToDbgValue(*CachedDVI.DVI, CachedDVI.Expr);
+ LLVM_DEBUG(dbgs() << "scev-salvage: to: " << *CachedDVI.DVI << '\n');
+ return true;
+}
+
+static bool
+DbgRewriteSalvageableDVIs(llvm::Loop *L, ScalarEvolution &SE,
+ llvm::PHINode *LSRInductionVar,
+ SmallVector<DVIRecoveryRec, 2> &DVIToUpdate) {
+ if (DVIToUpdate.empty())
+ return false;
+
+ const llvm::SCEV *SCEVInductionVar = SE.getSCEV(LSRInductionVar);
+ assert(SCEVInductionVar &&
+ "Anticipated a SCEV for the post-LSR induction variable");
+
+ bool Changed = false;
+ if (const SCEVAddRecExpr *IVAddRec =
+ dyn_cast<SCEVAddRecExpr>(SCEVInductionVar)) {
+ SCEVDbgValueBuilder IterCountExpr;
+ IterCountExpr.pushValue(LSRInductionVar);
+ if (!IterCountExpr.SCEVToIterCountExpr(*IVAddRec, SE))
+ return false;
+
+ LLVM_DEBUG(dbgs() << "scev-salvage: IV SCEV: " << *SCEVInductionVar
+ << '\n');
+
+ // Needn't salvage if the location op hasn't been undef'd by LSR.
+ for (auto &DVIRec : DVIToUpdate) {
+ if (!DVIRec.DVI->isUndef())
+ continue;
+
+ // Some DVIs that were single location-op when cached are now multi-op,
+ // due to LSR optimisations. However, multi-op salvaging is not yet
+ // supported by SCEV salvaging. But, we can attempt a salvage by restoring
+ // the pre-LSR single-op expression.
+ if (DVIRec.DVI->hasArgList()) {
+ llvm::Type *Ty = DVIRec.DVI->getVariableLocationOp(0)->getType();
+ DVIRec.DVI->setRawLocation(
+ llvm::ValueAsMetadata::get(UndefValue::get(Ty)));
+ DVIRec.DVI->setExpression(DVIRec.Expr);
+ }
+
+ Changed |= RewriteDVIUsingIterCount(DVIRec, IterCountExpr, SE);
+ }
+ }
+ return Changed;
+}
-static void DbgGatherEqualValues(Loop *L, ScalarEvolution &SE,
- EqualValuesMap &DbgValueToEqualSet) {
+/// Identify and cache salvageable DVI locations and expressions along with the
+/// corresponding SCEV(s). Also ensure that the DVI is not deleted before
+static void
+DbgGatherSalvagableDVI(Loop *L, ScalarEvolution &SE,
+ SmallVector<DVIRecoveryRec, 2> &SalvageableDVISCEVs,
+ SmallSet<AssertingVH<DbgValueInst>, 2> &DVIHandles) {
for (auto &B : L->getBlocks()) {
for (auto &I : *B) {
auto DVI = dyn_cast<DbgValueInst>(&I);
if (!DVI)
continue;
- auto V = DVI->getVariableLocation();
- if (!V || !SE.isSCEVable(V->getType()))
+
+ if (DVI->hasArgList())
continue;
- auto DbgValueSCEV = SE.getSCEV(V);
- EqualValues EqSet;
- for (PHINode &Phi : L->getHeader()->phis()) {
- if (V->getType() != Phi.getType())
- continue;
- if (!SE.isSCEVable(Phi.getType()))
- continue;
- auto PhiSCEV = SE.getSCEV(&Phi);
- Optional<APInt> Offset =
- SE.computeConstantDifference(DbgValueSCEV, PhiSCEV);
- if (Offset && Offset->getMinSignedBits() <= 64)
- EqSet.emplace_back(std::make_tuple(
- &Phi, Offset.getValue().getSExtValue(), DVI->getExpression()));
- }
- DbgValueToEqualSet[DVI] = std::move(EqSet);
+
+ if (!SE.isSCEVable(DVI->getVariableLocationOp(0)->getType()))
+ continue;
+
+ SalvageableDVISCEVs.push_back(
+ {DVI, DVI->getExpression(), DVI->getRawLocation(),
+ SE.getSCEV(DVI->getVariableLocationOp(0))});
+ DVIHandles.insert(DVI);
}
}
}
-static void DbgApplyEqualValues(EqualValuesMap &DbgValueToEqualSet) {
- for (auto A : DbgValueToEqualSet) {
- auto DVI = A.first;
- // Only update those that are now undef.
- if (!isa_and_nonnull<UndefValue>(DVI->getVariableLocation()))
+/// Ideally pick the PHI IV inserted by ScalarEvolutionExpander. As a fallback
+/// any PHi from the loop header is usable, but may have less chance of
+/// surviving subsequent transforms.
+static llvm::PHINode *GetInductionVariable(const Loop &L, ScalarEvolution &SE,
+ const LSRInstance &LSR) {
+ // For now, just pick the first IV generated and inserted. Ideally pick an IV
+ // that is unlikely to be optimised away by subsequent transforms.
+ for (const WeakVH &IV : LSR.getScalarEvolutionIVs()) {
+ if (!IV)
continue;
- for (auto EV : A.second) {
- auto V = std::get<WeakVH>(EV);
- if (!V)
- continue;
- auto DbgDIExpr = std::get<DIExpression *>(EV);
- auto Offset = std::get<int64_t>(EV);
- auto &Ctx = DVI->getContext();
- DVI->setOperand(0, MetadataAsValue::get(Ctx, ValueAsMetadata::get(V)));
- if (Offset) {
- SmallVector<uint64_t, 8> Ops;
- DIExpression::appendOffset(Ops, Offset);
- DbgDIExpr = DIExpression::prependOpcodes(DbgDIExpr, Ops, true);
- }
- DVI->setOperand(2, MetadataAsValue::get(Ctx, DbgDIExpr));
- break;
+
+ assert(isa<PHINode>(&*IV) && "Expected PhI node.");
+ if (SE.isSCEVable((*IV).getType())) {
+ PHINode *Phi = dyn_cast<PHINode>(&*IV);
+ LLVM_DEBUG(const llvm::SCEV *S = SE.getSCEV(Phi);
+ dbgs() << "scev-salvage: IV : " << *IV << "with SCEV: " << *S
+ << "\n");
+ return Phi;
}
}
+
+ for (PHINode &Phi : L.getHeader()->phis()) {
+ if (!SE.isSCEVable(Phi.getType()))
+ continue;
+
+ const llvm::SCEV *PhiSCEV = SE.getSCEV(&Phi);
+ if (const llvm::SCEVAddRecExpr *Rec = dyn_cast<SCEVAddRecExpr>(PhiSCEV))
+ if (!Rec->isAffine())
+ continue;
+
+ LLVM_DEBUG(dbgs() << "scev-salvage: Selected IV from loop header: " << Phi
+ << " with SCEV: " << *PhiSCEV << "\n");
+ return &Phi;
+ }
+ return nullptr;
}
static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE,
@@ -5835,19 +6261,21 @@ static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE,
AssumptionCache &AC, TargetLibraryInfo &TLI,
MemorySSA *MSSA) {
+ // Debug preservation - before we start removing anything identify which DVI
+ // meet the salvageable criteria and store their DIExpression and SCEVs.
+ SmallVector<DVIRecoveryRec, 2> SalvageableDVI;
+ SmallSet<AssertingVH<DbgValueInst>, 2> DVIHandles;
+ DbgGatherSalvagableDVI(L, SE, SalvageableDVI, DVIHandles);
+
bool Changed = false;
std::unique_ptr<MemorySSAUpdater> MSSAU;
if (MSSA)
MSSAU = std::make_unique<MemorySSAUpdater>(MSSA);
// Run the main LSR transformation.
- Changed |=
- LSRInstance(L, IU, SE, DT, LI, TTI, AC, TLI, MSSAU.get()).getChanged();
-
- // Debug preservation - before we start removing anything create equivalence
- // sets for the llvm.dbg.value intrinsics.
- EqualValuesMap DbgValueToEqualSet;
- DbgGatherEqualValues(L, SE, DbgValueToEqualSet);
+ const LSRInstance &Reducer =
+ LSRInstance(L, IU, SE, DT, LI, TTI, AC, TLI, MSSAU.get());
+ Changed |= Reducer.getChanged();
// Remove any extra phis created by processing inner loops.
Changed |= DeleteDeadPHIs(L->getHeader(), &TLI, MSSAU.get());
@@ -5867,8 +6295,22 @@ static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE,
}
}
- DbgApplyEqualValues(DbgValueToEqualSet);
+ if (SalvageableDVI.empty())
+ return Changed;
+
+ // Obtain relevant IVs and attempt to rewrite the salvageable DVIs with
+ // expressions composed using the derived iteration count.
+ // TODO: Allow for multiple IV references for nested AddRecSCEVs
+ for (auto &L : LI) {
+ if (llvm::PHINode *IV = GetInductionVariable(*L, SE, Reducer))
+ DbgRewriteSalvageableDVIs(L, SE, IV, SalvageableDVI);
+ else {
+ LLVM_DEBUG(dbgs() << "scev-salvage: SCEV salvaging not possible. An IV "
+ "could not be identified.\n");
+ }
+ }
+ DVIHandles.clear();
return Changed;
}
diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp
index 495906e1a763..71eb393fcdd7 100644
--- a/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp
@@ -22,6 +22,7 @@
#include "llvm/Analysis/DependenceAnalysis.h"
#include "llvm/Analysis/LoopAnalysisManager.h"
#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/TargetTransformInfo.h"
@@ -41,13 +42,14 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils.h"
+#include "llvm/Transforms/Utils/LCSSA.h"
#include "llvm/Transforms/Utils/LoopPeel.h"
#include "llvm/Transforms/Utils/LoopSimplify.h"
#include "llvm/Transforms/Utils/LoopUtils.h"
#include "llvm/Transforms/Utils/UnrollLoop.h"
#include <cassert>
#include <cstdint>
-#include <vector>
namespace llvm {
class Instruction;
@@ -424,35 +426,29 @@ tryToUnrollAndJamLoop(Loop *L, DominatorTree &DT, LoopInfo *LI,
return UnrollResult;
}
-static bool tryToUnrollAndJamLoop(Function &F, DominatorTree &DT, LoopInfo &LI,
+static bool tryToUnrollAndJamLoop(LoopNest &LN, DominatorTree &DT, LoopInfo &LI,
ScalarEvolution &SE,
const TargetTransformInfo &TTI,
AssumptionCache &AC, DependenceInfo &DI,
- OptimizationRemarkEmitter &ORE,
- int OptLevel) {
+ OptimizationRemarkEmitter &ORE, int OptLevel,
+ LPMUpdater &U) {
bool DidSomething = false;
+ ArrayRef<Loop *> Loops = LN.getLoops();
+ Loop *OutmostLoop = &LN.getOutermostLoop();
- // The loop unroll and jam pass requires loops to be in simplified form, and
- // also needs LCSSA. Since simplification may add new inner loops, it has to
- // run before the legality and profitability checks. This means running the
- // loop unroll and jam pass will simplify all loops, regardless of whether
- // anything end up being unroll and jammed.
- for (auto &L : LI) {
- DidSomething |=
- simplifyLoop(L, &DT, &LI, &SE, &AC, nullptr, false /* PreserveLCSSA */);
- DidSomething |= formLCSSARecursively(*L, DT, &LI, &SE);
- }
-
- // Add the loop nests in the reverse order of LoopInfo. See method
+ // Add the loop nests in the reverse order of LN. See method
// declaration.
SmallPriorityWorklist<Loop *, 4> Worklist;
- appendLoopsToWorklist(LI, Worklist);
+ appendLoopsToWorklist(Loops, Worklist);
while (!Worklist.empty()) {
Loop *L = Worklist.pop_back_val();
+ std::string LoopName = std::string(L->getName());
LoopUnrollResult Result =
tryToUnrollAndJamLoop(L, DT, &LI, SE, TTI, AC, DI, ORE, OptLevel);
if (Result != LoopUnrollResult::Unmodified)
DidSomething = true;
+ if (L == OutmostLoop && Result == LoopUnrollResult::FullyUnrolled)
+ U.markLoopAsDeleted(*L, LoopName);
}
return DidSomething;
@@ -460,29 +456,35 @@ static bool tryToUnrollAndJamLoop(Function &F, DominatorTree &DT, LoopInfo &LI,
namespace {
-class LoopUnrollAndJam : public FunctionPass {
+class LoopUnrollAndJam : public LoopPass {
public:
static char ID; // Pass ID, replacement for typeid
unsigned OptLevel;
- LoopUnrollAndJam(int OptLevel = 2) : FunctionPass(ID), OptLevel(OptLevel) {
+ LoopUnrollAndJam(int OptLevel = 2) : LoopPass(ID), OptLevel(OptLevel) {
initializeLoopUnrollAndJamPass(*PassRegistry::getPassRegistry());
}
- bool runOnFunction(Function &F) override {
- if (skipFunction(F))
+ bool runOnLoop(Loop *L, LPPassManager &LPM) override {
+ if (skipLoop(L))
return false;
- auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
- LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
- ScalarEvolution &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
- const TargetTransformInfo &TTI =
- getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
- auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
+ auto *F = L->getHeader()->getParent();
+ auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
+ auto *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
auto &DI = getAnalysis<DependenceAnalysisWrapperPass>().getDI();
+ auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
+ auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(*F);
auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
+ auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(*F);
- return tryToUnrollAndJamLoop(F, DT, LI, SE, TTI, AC, DI, ORE, OptLevel);
+ LoopUnrollResult Result =
+ tryToUnrollAndJamLoop(L, DT, LI, SE, TTI, AC, DI, ORE, OptLevel);
+
+ if (Result == LoopUnrollResult::FullyUnrolled)
+ LPM.markLoopAsDeleted(*L);
+
+ return Result != LoopUnrollResult::Unmodified;
}
/// This transformation requires natural loop information & requires that
@@ -495,6 +497,7 @@ public:
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<DependenceAnalysisWrapperPass>();
AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
+ getLoopAnalysisUsage(AU);
}
};
@@ -505,7 +508,10 @@ char LoopUnrollAndJam::ID = 0;
INITIALIZE_PASS_BEGIN(LoopUnrollAndJam, "loop-unroll-and-jam",
"Unroll and Jam loops", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(LoopPass)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(LoopSimplify)
+INITIALIZE_PASS_DEPENDENCY(LCSSAWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
@@ -518,19 +524,20 @@ Pass *llvm::createLoopUnrollAndJamPass(int OptLevel) {
return new LoopUnrollAndJam(OptLevel);
}
-PreservedAnalyses LoopUnrollAndJamPass::run(Function &F,
- FunctionAnalysisManager &AM) {
- ScalarEvolution &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
- LoopInfo &LI = AM.getResult<LoopAnalysis>(F);
- TargetTransformInfo &TTI = AM.getResult<TargetIRAnalysis>(F);
- AssumptionCache &AC = AM.getResult<AssumptionAnalysis>(F);
- DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F);
- DependenceInfo &DI = AM.getResult<DependenceAnalysis>(F);
- OptimizationRemarkEmitter &ORE =
- AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
+PreservedAnalyses LoopUnrollAndJamPass::run(LoopNest &LN,
+ LoopAnalysisManager &AM,
+ LoopStandardAnalysisResults &AR,
+ LPMUpdater &U) {
+ Function &F = *LN.getParent();
+
+ DependenceInfo DI(&F, &AR.AA, &AR.SE, &AR.LI);
+ OptimizationRemarkEmitter ORE(&F);
- if (!tryToUnrollAndJamLoop(F, DT, LI, SE, TTI, AC, DI, ORE, OptLevel))
+ if (!tryToUnrollAndJamLoop(LN, AR.DT, AR.LI, AR.SE, AR.TTI, AR.AC, DI, ORE,
+ OptLevel, U))
return PreservedAnalyses::all();
- return getLoopPassPreservedAnalyses();
+ auto PA = getLoopPassPreservedAnalyses();
+ PA.preserve<LoopNestAnalysis>();
+ return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
index 1b974576a3cc..49501f324a49 100644
--- a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
@@ -356,19 +356,19 @@ static Optional<EstimatedUnrollCost> analyzeLoopUnrollCost(
SmallSetVector<BasicBlock *, 16> BBWorklist;
SmallSetVector<std::pair<BasicBlock *, BasicBlock *>, 4> ExitWorklist;
- DenseMap<Value *, Constant *> SimplifiedValues;
- SmallVector<std::pair<Value *, Constant *>, 4> SimplifiedInputValues;
+ DenseMap<Value *, Value *> SimplifiedValues;
+ SmallVector<std::pair<Value *, Value *>, 4> SimplifiedInputValues;
// The estimated cost of the unrolled form of the loop. We try to estimate
// this by simplifying as much as we can while computing the estimate.
- unsigned UnrolledCost = 0;
+ InstructionCost UnrolledCost = 0;
// We also track the estimated dynamic (that is, actually executed) cost in
// the rolled form. This helps identify cases when the savings from unrolling
// aren't just exposing dead control flows, but actual reduced dynamic
// instructions due to the simplifications which we expect to occur after
// unrolling.
- unsigned RolledDynamicCost = 0;
+ InstructionCost RolledDynamicCost = 0;
// We track the simplification of each instruction in each iteration. We use
// this to recursively merge costs into the unrolled cost on-demand so that
@@ -498,11 +498,9 @@ static Optional<EstimatedUnrollCost> analyzeLoopUnrollCost(
Value *V = PHI->getIncomingValueForBlock(
Iteration == 0 ? L->getLoopPreheader() : L->getLoopLatch());
- Constant *C = dyn_cast<Constant>(V);
- if (Iteration != 0 && !C)
- C = SimplifiedValues.lookup(V);
- if (C)
- SimplifiedInputValues.push_back({PHI, C});
+ if (Iteration != 0 && SimplifiedValues.count(V))
+ V = SimplifiedValues.lookup(V);
+ SimplifiedInputValues.push_back({PHI, V});
}
// Now clear and re-populate the map for the next iteration.
@@ -571,13 +569,18 @@ static Optional<EstimatedUnrollCost> analyzeLoopUnrollCost(
Instruction *TI = BB->getTerminator();
+ auto getSimplifiedConstant = [&](Value *V) -> Constant * {
+ if (SimplifiedValues.count(V))
+ V = SimplifiedValues.lookup(V);
+ return dyn_cast<Constant>(V);
+ };
+
// Add in the live successors by first checking whether we have terminator
// that may be simplified based on the values simplified by this call.
BasicBlock *KnownSucc = nullptr;
if (BranchInst *BI = dyn_cast<BranchInst>(TI)) {
if (BI->isConditional()) {
- if (Constant *SimpleCond =
- SimplifiedValues.lookup(BI->getCondition())) {
+ if (auto *SimpleCond = getSimplifiedConstant(BI->getCondition())) {
// Just take the first successor if condition is undef
if (isa<UndefValue>(SimpleCond))
KnownSucc = BI->getSuccessor(0);
@@ -587,8 +590,7 @@ static Optional<EstimatedUnrollCost> analyzeLoopUnrollCost(
}
}
} else if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) {
- if (Constant *SimpleCond =
- SimplifiedValues.lookup(SI->getCondition())) {
+ if (auto *SimpleCond = getSimplifiedConstant(SI->getCondition())) {
// Just take the first successor if condition is undef
if (isa<UndefValue>(SimpleCond))
KnownSucc = SI->getSuccessor(0);
@@ -639,10 +641,15 @@ static Optional<EstimatedUnrollCost> analyzeLoopUnrollCost(
}
}
+ assert(UnrolledCost.isValid() && RolledDynamicCost.isValid() &&
+ "All instructions must have a valid cost, whether the "
+ "loop is rolled or unrolled.");
+
LLVM_DEBUG(dbgs() << "Analysis finished:\n"
<< "UnrolledCost: " << UnrolledCost << ", "
<< "RolledDynamicCost: " << RolledDynamicCost << "\n");
- return {{UnrolledCost, RolledDynamicCost}};
+ return {{unsigned(*UnrolledCost.getValue()),
+ unsigned(*RolledDynamicCost.getValue())}};
}
/// ApproximateLoopSize - Approximate the size of the loop.
@@ -727,13 +734,24 @@ static unsigned getFullUnrollBoostingFactor(const EstimatedUnrollCost &Cost,
return MaxPercentThresholdBoost;
}
-// Returns loop size estimation for unrolled loop.
-static uint64_t getUnrolledLoopSize(
- unsigned LoopSize,
- TargetTransformInfo::UnrollingPreferences &UP) {
- assert(LoopSize >= UP.BEInsns && "LoopSize should not be less than BEInsns!");
- return (uint64_t)(LoopSize - UP.BEInsns) * UP.Count + UP.BEInsns;
-}
+// Produce an estimate of the unrolled cost of the specified loop. This
+// is used to a) produce a cost estimate for partial unrolling and b) to
+// cheaply estimate cost for full unrolling when we don't want to symbolically
+// evaluate all iterations.
+class UnrollCostEstimator {
+ const unsigned LoopSize;
+
+public:
+ UnrollCostEstimator(Loop &L, unsigned LoopSize) : LoopSize(LoopSize) {}
+
+ // Returns loop size estimation for unrolled loop, given the unrolling
+ // configuration specified by UP.
+ uint64_t getUnrolledLoopSize(TargetTransformInfo::UnrollingPreferences &UP) {
+ assert(LoopSize >= UP.BEInsns &&
+ "LoopSize should not be less than BEInsns!");
+ return (uint64_t)(LoopSize - UP.BEInsns) * UP.Count + UP.BEInsns;
+ }
+};
// Returns true if unroll count was set explicitly.
// Calculates unroll count and writes it to UP.Count.
@@ -746,11 +764,25 @@ static uint64_t getUnrolledLoopSize(
bool llvm::computeUnrollCount(
Loop *L, const TargetTransformInfo &TTI, DominatorTree &DT, LoopInfo *LI,
ScalarEvolution &SE, const SmallPtrSetImpl<const Value *> &EphValues,
- OptimizationRemarkEmitter *ORE, unsigned &TripCount, unsigned MaxTripCount,
- bool MaxOrZero, unsigned &TripMultiple, unsigned LoopSize,
+ OptimizationRemarkEmitter *ORE, unsigned TripCount, unsigned MaxTripCount,
+ bool MaxOrZero, unsigned TripMultiple, unsigned LoopSize,
TargetTransformInfo::UnrollingPreferences &UP,
TargetTransformInfo::PeelingPreferences &PP, bool &UseUpperBound) {
+ UnrollCostEstimator UCE(*L, LoopSize);
+
+ // Use an explicit peel count that has been specified for testing. In this
+ // case it's not permitted to also specify an explicit unroll count.
+ if (PP.PeelCount) {
+ if (UnrollCount.getNumOccurrences() > 0) {
+ report_fatal_error("Cannot specify both explicit peel count and "
+ "explicit unroll count");
+ }
+ UP.Count = 1;
+ UP.Runtime = false;
+ return true;
+ }
+
// Check for explicit Count.
// 1st priority is unroll count set by "unroll-count" option.
bool UserUnrollCount = UnrollCount.getNumOccurrences() > 0;
@@ -758,7 +790,7 @@ bool llvm::computeUnrollCount(
UP.Count = UnrollCount;
UP.AllowExpensiveTripCount = true;
UP.Force = true;
- if (UP.AllowRemainder && getUnrolledLoopSize(LoopSize, UP) < UP.Threshold)
+ if (UP.AllowRemainder && UCE.getUnrolledLoopSize(UP) < UP.Threshold)
return true;
}
@@ -770,13 +802,13 @@ bool llvm::computeUnrollCount(
UP.AllowExpensiveTripCount = true;
UP.Force = true;
if ((UP.AllowRemainder || (TripMultiple % PragmaCount == 0)) &&
- getUnrolledLoopSize(LoopSize, UP) < PragmaUnrollThreshold)
+ UCE.getUnrolledLoopSize(UP) < PragmaUnrollThreshold)
return true;
}
bool PragmaFullUnroll = hasUnrollFullPragma(L);
if (PragmaFullUnroll && TripCount != 0) {
UP.Count = TripCount;
- if (getUnrolledLoopSize(LoopSize, UP) < PragmaUnrollThreshold)
+ if (UCE.getUnrolledLoopSize(UP) < PragmaUnrollThreshold)
return false;
}
@@ -797,8 +829,6 @@ bool llvm::computeUnrollCount(
// Full unroll makes sense only when TripCount or its upper bound could be
// statically calculated.
// Also we need to check if we exceed FullUnrollMaxCount.
- // If using the upper bound to unroll, TripMultiple should be set to 1 because
- // we do not know when loop may exit.
// We can unroll by the upper bound amount if it's generally allowed or if
// we know that the loop is executed either the upper bound or zero times.
@@ -825,10 +855,8 @@ bool llvm::computeUnrollCount(
if (FullUnrollTripCount && FullUnrollTripCount <= UP.FullUnrollMaxCount) {
// When computing the unrolled size, note that BEInsns are not replicated
// like the rest of the loop body.
- if (getUnrolledLoopSize(LoopSize, UP) < UP.Threshold) {
+ if (UCE.getUnrolledLoopSize(UP) < UP.Threshold) {
UseUpperBound = (FullUnrollMaxTripCount == FullUnrollTripCount);
- TripCount = FullUnrollTripCount;
- TripMultiple = UP.UpperBound ? 1 : TripMultiple;
return ExplicitUnroll;
} else {
// The loop isn't that small, but we still can fully unroll it if that
@@ -842,8 +870,6 @@ bool llvm::computeUnrollCount(
getFullUnrollBoostingFactor(*Cost, UP.MaxPercentThresholdBoost);
if (Cost->UnrolledCost < UP.Threshold * Boost / 100) {
UseUpperBound = (FullUnrollMaxTripCount == FullUnrollTripCount);
- TripCount = FullUnrollTripCount;
- TripMultiple = UP.UpperBound ? 1 : TripMultiple;
return ExplicitUnroll;
}
}
@@ -872,7 +898,7 @@ bool llvm::computeUnrollCount(
UP.Count = TripCount;
if (UP.PartialThreshold != NoThreshold) {
// Reduce unroll count to be modulo of TripCount for partial unrolling.
- if (getUnrolledLoopSize(LoopSize, UP) > UP.PartialThreshold)
+ if (UCE.getUnrolledLoopSize(UP) > UP.PartialThreshold)
UP.Count =
(std::max(UP.PartialThreshold, UP.BEInsns + 1) - UP.BEInsns) /
(LoopSize - UP.BEInsns);
@@ -887,7 +913,7 @@ bool llvm::computeUnrollCount(
// remainder loop is allowed.
UP.Count = UP.DefaultUnrollRuntimeCount;
while (UP.Count != 0 &&
- getUnrolledLoopSize(LoopSize, UP) > UP.PartialThreshold)
+ UCE.getUnrolledLoopSize(UP) > UP.PartialThreshold)
UP.Count >>= 1;
}
if (UP.Count < 2) {
@@ -971,7 +997,7 @@ bool llvm::computeUnrollCount(
// Reduce unroll count to be the largest power-of-two factor of
// the original count which satisfies the threshold limit.
while (UP.Count != 0 &&
- getUnrolledLoopSize(LoopSize, UP) > UP.PartialThreshold)
+ UCE.getUnrolledLoopSize(UP) > UP.PartialThreshold)
UP.Count >>= 1;
#ifndef NDEBUG
@@ -1088,18 +1114,29 @@ static LoopUnrollResult tryToUnrollLoop(
return LoopUnrollResult::Unmodified;
}
- // Find trip count and trip multiple if count is not available
+ // Find the smallest exact trip count for any exit. This is an upper bound
+ // on the loop trip count, but an exit at an earlier iteration is still
+ // possible. An unroll by the smallest exact trip count guarantees that all
+ // brnaches relating to at least one exit can be eliminated. This is unlike
+ // the max trip count, which only guarantees that the backedge can be broken.
unsigned TripCount = 0;
unsigned TripMultiple = 1;
- // If there are multiple exiting blocks but one of them is the latch, use the
- // latch for the trip count estimation. Otherwise insist on a single exiting
- // block for the trip count estimation.
- BasicBlock *ExitingBlock = L->getLoopLatch();
- if (!ExitingBlock || !L->isLoopExiting(ExitingBlock))
- ExitingBlock = L->getExitingBlock();
- if (ExitingBlock) {
- TripCount = SE.getSmallConstantTripCount(L, ExitingBlock);
- TripMultiple = SE.getSmallConstantTripMultiple(L, ExitingBlock);
+ SmallVector<BasicBlock *, 8> ExitingBlocks;
+ L->getExitingBlocks(ExitingBlocks);
+ for (BasicBlock *ExitingBlock : ExitingBlocks)
+ if (unsigned TC = SE.getSmallConstantTripCount(L, ExitingBlock))
+ if (!TripCount || TC < TripCount)
+ TripCount = TripMultiple = TC;
+
+ if (!TripCount) {
+ // If no exact trip count is known, determine the trip multiple of either
+ // the loop latch or the single exiting block.
+ // TODO: Relax for multiple exits.
+ BasicBlock *ExitingBlock = L->getLoopLatch();
+ if (!ExitingBlock || !L->isLoopExiting(ExitingBlock))
+ ExitingBlock = L->getExitingBlock();
+ if (ExitingBlock)
+ TripMultiple = SE.getSmallConstantTripMultiple(L, ExitingBlock);
}
// If the loop contains a convergent operation, the prelude we'd add
@@ -1134,9 +1171,35 @@ static LoopUnrollResult tryToUnrollLoop(
TripMultiple, LoopSize, UP, PP, UseUpperBound);
if (!UP.Count)
return LoopUnrollResult::Unmodified;
- // Unroll factor (Count) must be less or equal to TripCount.
- if (TripCount && UP.Count > TripCount)
- UP.Count = TripCount;
+
+ if (PP.PeelCount) {
+ assert(UP.Count == 1 && "Cannot perform peel and unroll in the same step");
+ LLVM_DEBUG(dbgs() << "PEELING loop %" << L->getHeader()->getName()
+ << " with iteration count " << PP.PeelCount << "!\n");
+ ORE.emit([&]() {
+ return OptimizationRemark(DEBUG_TYPE, "Peeled", L->getStartLoc(),
+ L->getHeader())
+ << " peeled loop by " << ore::NV("PeelCount", PP.PeelCount)
+ << " iterations";
+ });
+
+ if (peelLoop(L, PP.PeelCount, LI, &SE, &DT, &AC, PreserveLCSSA)) {
+ simplifyLoopAfterUnroll(L, true, LI, &SE, &DT, &AC, &TTI);
+ // If the loop was peeled, we already "used up" the profile information
+ // we had, so we don't want to unroll or peel again.
+ if (PP.PeelProfiledIterations)
+ L->setLoopAlreadyUnrolled();
+ return LoopUnrollResult::PartiallyUnrolled;
+ }
+ return LoopUnrollResult::Unmodified;
+ }
+
+ // At this point, UP.Runtime indicates that run-time unrolling is allowed.
+ // However, we only want to actually perform it if we don't know the trip
+ // count and the unroll count doesn't divide the known trip multiple.
+ // TODO: This decision should probably be pushed up into
+ // computeUnrollCount().
+ UP.Runtime &= TripCount == 0 && TripMultiple % UP.Count != 0;
// Save loop properties before it is transformed.
MDNode *OrigLoopID = L->getLoopID();
@@ -1145,9 +1208,8 @@ static LoopUnrollResult tryToUnrollLoop(
Loop *RemainderLoop = nullptr;
LoopUnrollResult UnrollResult = UnrollLoop(
L,
- {UP.Count, TripCount, UP.Force, UP.Runtime, UP.AllowExpensiveTripCount,
- UseUpperBound, MaxOrZero, TripMultiple, PP.PeelCount, UP.UnrollRemainder,
- ForgetAllSCEV},
+ {UP.Count, UP.Force, UP.Runtime, UP.AllowExpensiveTripCount,
+ UP.UnrollRemainder, ForgetAllSCEV},
LI, &SE, &DT, &AC, &TTI, &ORE, PreserveLCSSA, &RemainderLoop);
if (UnrollResult == LoopUnrollResult::Unmodified)
return LoopUnrollResult::Unmodified;
@@ -1175,10 +1237,7 @@ static LoopUnrollResult tryToUnrollLoop(
// If loop has an unroll count pragma or unrolled by explicitly set count
// mark loop as unrolled to prevent unrolling beyond that requested.
- // If the loop was peeled, we already "used up" the profile information
- // we had, so we don't want to unroll or peel again.
- if (UnrollResult != LoopUnrollResult::FullyUnrolled &&
- (IsCountSetExplicitly || (PP.PeelProfiledIterations && PP.PeelCount)))
+ if (UnrollResult != LoopUnrollResult::FullyUnrolled && IsCountSetExplicitly)
L->setLoopAlreadyUnrolled();
return UnrollResult;
diff --git a/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp
index 18717394d384..9a854ff80246 100644
--- a/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp
@@ -26,6 +26,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
@@ -309,9 +310,8 @@ bool LUAnalysisCache::countLoop(const Loop *L, const TargetTransformInfo &TTI,
// consideration code simplification opportunities and code that can
// be shared by the resultant unswitched loops.
CodeMetrics Metrics;
- for (Loop::block_iterator I = L->block_begin(), E = L->block_end(); I != E;
- ++I)
- Metrics.analyzeBasicBlock(*I, TTI, EphValues);
+ for (BasicBlock *BB : L->blocks())
+ Metrics.analyzeBasicBlock(BB, TTI, EphValues);
Props.SizeEstimation = Metrics.NumInsts;
Props.CanBeUnswitchedCount = MaxSize / (Props.SizeEstimation);
@@ -387,8 +387,8 @@ void LUAnalysisCache::cloneData(const Loop *NewLoop, const Loop *OldLoop,
// Clone unswitched values info:
// for new loop switches we clone info about values that was
// already unswitched and has redundant successors.
- for (UnswitchedValsIt I = Insts.begin(); I != Insts.end(); ++I) {
- const SwitchInst *OldInst = I->first;
+ for (const auto &I : Insts) {
+ const SwitchInst *OldInst = I.first;
Value *NewI = VMap.lookup(OldInst);
const SwitchInst *NewInst = cast_or_null<SwitchInst>(NewI);
assert(NewInst && "All instructions that are in SrcBB must be in VMap.");
@@ -640,145 +640,6 @@ static bool equalityPropUnSafe(Value &LoopCond) {
return false;
}
-/// Check if the loop header has a conditional branch that is not
-/// loop-invariant, because it involves load instructions. If all paths from
-/// either the true or false successor to the header or loop exists do not
-/// modify the memory feeding the condition, perform 'partial unswitching'. That
-/// is, duplicate the instructions feeding the condition in the pre-header. Then
-/// unswitch on the duplicated condition. The condition is now known in the
-/// unswitched version for the 'invariant' path through the original loop.
-///
-/// If the branch condition of the header is partially invariant, return a pair
-/// containing the instructions to duplicate and a boolean Constant to update
-/// the condition in the loops created for the true or false successors.
-static std::pair<SmallVector<Instruction *, 4>, Constant *>
-hasPartialIVCondition(Loop *L, MemorySSA &MSSA, AAResults *AA) {
- SmallVector<Instruction *, 4> ToDuplicate;
-
- auto *TI = dyn_cast<BranchInst>(L->getHeader()->getTerminator());
- if (!TI || !TI->isConditional())
- return {};
-
- auto *CondI = dyn_cast<CmpInst>(TI->getCondition());
- // The case with the condition outside the loop should already be handled
- // earlier.
- if (!CondI || !L->contains(CondI))
- return {};
-
- ToDuplicate.push_back(CondI);
-
- SmallVector<Value *, 4> WorkList;
- WorkList.append(CondI->op_begin(), CondI->op_end());
-
- SmallVector<MemoryAccess *, 4> AccessesToCheck;
- SmallVector<MemoryLocation, 4> AccessedLocs;
- while (!WorkList.empty()) {
- Instruction *I = dyn_cast<Instruction>(WorkList.pop_back_val());
- if (!I || !L->contains(I))
- continue;
-
- // TODO: support additional instructions.
- if (!isa<LoadInst>(I) && !isa<GetElementPtrInst>(I))
- return {};
-
- // Do not duplicate volatile and atomic loads.
- if (auto *LI = dyn_cast<LoadInst>(I))
- if (LI->isVolatile() || LI->isAtomic())
- return {};
-
- ToDuplicate.push_back(I);
- if (MemoryAccess *MA = MSSA.getMemoryAccess(I)) {
- if (auto *MemUse = dyn_cast_or_null<MemoryUse>(MA)) {
- // Queue the defining access to check for alias checks.
- AccessesToCheck.push_back(MemUse->getDefiningAccess());
- AccessedLocs.push_back(MemoryLocation::get(I));
- } else {
- // MemoryDefs may clobber the location or may be atomic memory
- // operations. Bail out.
- return {};
- }
- }
- WorkList.append(I->op_begin(), I->op_end());
- }
-
- if (ToDuplicate.size() <= 1)
- return {};
-
- auto HasNoClobbersOnPath =
- [L, AA, &AccessedLocs](BasicBlock *Succ, BasicBlock *Header,
- SmallVector<MemoryAccess *, 4> AccessesToCheck) {
- // First, collect all blocks in the loop that are on a patch from Succ
- // to the header.
- SmallVector<BasicBlock *, 4> WorkList;
- WorkList.push_back(Succ);
- WorkList.push_back(Header);
- SmallPtrSet<BasicBlock *, 4> Seen;
- Seen.insert(Header);
- while (!WorkList.empty()) {
- BasicBlock *Current = WorkList.pop_back_val();
- if (!L->contains(Current))
- continue;
- const auto &SeenIns = Seen.insert(Current);
- if (!SeenIns.second)
- continue;
-
- WorkList.append(succ_begin(Current), succ_end(Current));
- }
-
- // Require at least 2 blocks on a path through the loop. This skips
- // paths that directly exit the loop.
- if (Seen.size() < 2)
- return false;
-
- // Next, check if there are any MemoryDefs that are on the path through
- // the loop (in the Seen set) and they may-alias any of the locations in
- // AccessedLocs. If that is the case, they may modify the condition and
- // partial unswitching is not possible.
- SmallPtrSet<MemoryAccess *, 4> SeenAccesses;
- while (!AccessesToCheck.empty()) {
- MemoryAccess *Current = AccessesToCheck.pop_back_val();
- auto SeenI = SeenAccesses.insert(Current);
- if (!SeenI.second || !Seen.contains(Current->getBlock()))
- continue;
-
- // Bail out if exceeded the threshold.
- if (SeenAccesses.size() >= MSSAThreshold)
- return false;
-
- // MemoryUse are read-only accesses.
- if (isa<MemoryUse>(Current))
- continue;
-
- // For a MemoryDef, check if is aliases any of the location feeding
- // the original condition.
- if (auto *CurrentDef = dyn_cast<MemoryDef>(Current)) {
- if (any_of(AccessedLocs, [AA, CurrentDef](MemoryLocation &Loc) {
- return isModSet(
- AA->getModRefInfo(CurrentDef->getMemoryInst(), Loc));
- }))
- return false;
- }
-
- for (Use &U : Current->uses())
- AccessesToCheck.push_back(cast<MemoryAccess>(U.getUser()));
- }
-
- return true;
- };
-
- // If we branch to the same successor, partial unswitching will not be
- // beneficial.
- if (TI->getSuccessor(0) == TI->getSuccessor(1))
- return {};
-
- if (HasNoClobbersOnPath(TI->getSuccessor(0), L->getHeader(), AccessesToCheck))
- return {ToDuplicate, ConstantInt::getTrue(TI->getContext())};
- if (HasNoClobbersOnPath(TI->getSuccessor(1), L->getHeader(), AccessesToCheck))
- return {ToDuplicate, ConstantInt::getFalse(TI->getContext())};
-
- return {};
-}
-
/// Do actual work and unswitch loop if possible and profitable.
bool LoopUnswitch::processCurrentLoop() {
bool Changed = false;
@@ -986,17 +847,57 @@ bool LoopUnswitch::processCurrentLoop() {
// metadata, to avoid unswitching the same loop multiple times.
if (MSSA &&
!findOptionMDForLoop(CurrentLoop, "llvm.loop.unswitch.partial.disable")) {
- auto ToDuplicate = hasPartialIVCondition(CurrentLoop, *MSSA, AA);
- if (!ToDuplicate.first.empty()) {
+ if (auto Info =
+ hasPartialIVCondition(*CurrentLoop, MSSAThreshold, *MSSA, *AA)) {
+ assert(!Info->InstToDuplicate.empty() &&
+ "need at least a partially invariant condition");
LLVM_DEBUG(dbgs() << "loop-unswitch: Found partially invariant condition "
- << *ToDuplicate.first[0] << "\n");
- ++NumBranches;
- unswitchIfProfitable(ToDuplicate.first[0], ToDuplicate.second,
- CurrentLoop->getHeader()->getTerminator(),
- ToDuplicate.first);
+ << *Info->InstToDuplicate[0] << "\n");
- RedoLoop = false;
- return true;
+ Instruction *TI = CurrentLoop->getHeader()->getTerminator();
+ Value *LoopCond = Info->InstToDuplicate[0];
+
+ // If the partially unswitched path is a no-op and has a single exit
+ // block, we do not need to do full unswitching. Instead, we can directly
+ // branch to the exit.
+ // TODO: Instead of duplicating the checks, we could also just directly
+ // branch to the exit from the conditional branch in the loop.
+ if (Info->PathIsNoop) {
+ if (HasBranchDivergence &&
+ getAnalysis<LegacyDivergenceAnalysis>().isDivergent(LoopCond)) {
+ LLVM_DEBUG(dbgs() << "NOT unswitching loop %"
+ << CurrentLoop->getHeader()->getName()
+ << " at non-trivial condition '"
+ << *Info->KnownValue << "' == " << *LoopCond << "\n"
+ << ". Condition is divergent.\n");
+ return false;
+ }
+
+ ++NumBranches;
+
+ BasicBlock *TrueDest = LoopHeader;
+ BasicBlock *FalseDest = Info->ExitForPath;
+ if (Info->KnownValue->isOneValue())
+ std::swap(TrueDest, FalseDest);
+
+ auto *OldBr =
+ cast<BranchInst>(CurrentLoop->getLoopPreheader()->getTerminator());
+ emitPreheaderBranchOnCondition(LoopCond, Info->KnownValue, TrueDest,
+ FalseDest, OldBr, TI,
+ Info->InstToDuplicate);
+ delete OldBr;
+ RedoLoop = false;
+ return true;
+ }
+
+ // Otherwise, the path is not a no-op. Run regular unswitching.
+ if (unswitchIfProfitable(LoopCond, Info->KnownValue,
+ CurrentLoop->getHeader()->getTerminator(),
+ Info->InstToDuplicate)) {
+ ++NumBranches;
+ RedoLoop = false;
+ return true;
+ }
}
}
@@ -1026,9 +927,9 @@ static bool isTrivialLoopExitBlockHelper(Loop *L, BasicBlock *BB,
}
// Otherwise, this is an unvisited intra-loop node. Check all successors.
- for (succ_iterator SI = succ_begin(BB), E = succ_end(BB); SI != E; ++SI) {
+ for (BasicBlock *Succ : successors(BB)) {
// Check to see if the successor is a trivial loop exit.
- if (!isTrivialLoopExitBlockHelper(L, *SI, ExitBB, Visited))
+ if (!isTrivialLoopExitBlockHelper(L, Succ, ExitBB, Visited))
return false;
}
@@ -1114,12 +1015,16 @@ void LoopUnswitch::emitPreheaderBranchOnCondition(
Loop *L = LI->getLoopFor(I->getParent());
auto *DefiningAccess = MemA->getDefiningAccess();
- // If the defining access is a MemoryPhi in the header, get the incoming
- // value for the pre-header as defining access.
- if (DefiningAccess->getBlock() == I->getParent()) {
+ // Get the first defining access before the loop.
+ while (L->contains(DefiningAccess->getBlock())) {
+ // If the defining access is a MemoryPhi, get the incoming
+ // value for the pre-header as defining access.
if (auto *MemPhi = dyn_cast<MemoryPhi>(DefiningAccess)) {
DefiningAccess =
MemPhi->getIncomingValueForBlock(L->getLoopPreheader());
+ } else {
+ DefiningAccess =
+ cast<MemoryDef>(DefiningAccess)->getDefiningAccess();
}
}
MSSAU->createMemoryAccessInBB(New, DefiningAccess, New->getParent(),
@@ -1518,9 +1423,7 @@ void LoopUnswitch::unswitchNontrivialCondition(
PHINode *PN = PHINode::Create(LPad->getType(), 0, "",
&*ExitSucc->getFirstInsertionPt());
- for (pred_iterator I = pred_begin(ExitSucc), E = pred_end(ExitSucc);
- I != E; ++I) {
- BasicBlock *BB = *I;
+ for (BasicBlock *BB : predecessors(ExitSucc)) {
LandingPadInst *LPI = BB->getLandingPadInst();
LPI->replaceAllUsesWith(PN);
PN->addIncoming(LPI, BB);
@@ -1533,9 +1436,8 @@ void LoopUnswitch::unswitchNontrivialCondition(
for (Instruction &I : *NewBlocks[NBI]) {
RemapInstruction(&I, VMap,
RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
- if (auto *II = dyn_cast<IntrinsicInst>(&I))
- if (II->getIntrinsicID() == Intrinsic::assume)
- AC->registerAssumption(II);
+ if (auto *II = dyn_cast<AssumeInst>(&I))
+ AC->registerAssumption(II);
}
}
diff --git a/llvm/lib/Transforms/Scalar/LowerAtomic.cpp b/llvm/lib/Transforms/Scalar/LowerAtomic.cpp
index d1f67b355b19..4063e4fe0472 100644
--- a/llvm/lib/Transforms/Scalar/LowerAtomic.cpp
+++ b/llvm/lib/Transforms/Scalar/LowerAtomic.cpp
@@ -40,7 +40,7 @@ static bool LowerAtomicCmpXchgInst(AtomicCmpXchgInst *CXI) {
return true;
}
-static bool LowerAtomicRMWInst(AtomicRMWInst *RMWI) {
+bool llvm::lowerAtomicRMWInst(AtomicRMWInst *RMWI) {
IRBuilder<> Builder(RMWI);
Value *Ptr = RMWI->getPointerOperand();
Value *Val = RMWI->getValOperand();
@@ -123,7 +123,7 @@ static bool runOnBasicBlock(BasicBlock &BB) {
else if (AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(&Inst))
Changed |= LowerAtomicCmpXchgInst(CXI);
else if (AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(&Inst))
- Changed |= LowerAtomicRMWInst(RMWI);
+ Changed |= lowerAtomicRMWInst(RMWI);
else if (LoadInst *LI = dyn_cast<LoadInst>(&Inst)) {
if (LI->isAtomic())
LowerLoadInst(LI);
diff --git a/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp b/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp
index bfe8db83b027..bd3001988369 100644
--- a/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp
+++ b/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp
@@ -15,12 +15,14 @@
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/DomTreeUpdater.h"
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
@@ -43,14 +45,15 @@ STATISTIC(ObjectSizeIntrinsicsHandled,
"Number of 'objectsize' intrinsic calls handled");
static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) {
- Value *Op = II->getOperand(0);
-
- return isa<Constant>(Op) ? ConstantInt::getTrue(II->getType())
- : ConstantInt::getFalse(II->getType());
+ if (auto *C = dyn_cast<Constant>(II->getOperand(0)))
+ if (C->isManifestConstant())
+ return ConstantInt::getTrue(II->getType());
+ return ConstantInt::getFalse(II->getType());
}
static bool replaceConditionalBranchesOnConstant(Instruction *II,
- Value *NewValue) {
+ Value *NewValue,
+ DomTreeUpdater *DTU) {
bool HasDeadBlocks = false;
SmallSetVector<Instruction *, 8> Worklist;
replaceAndRecursivelySimplify(II, NewValue, nullptr, nullptr, nullptr,
@@ -78,6 +81,8 @@ static bool replaceConditionalBranchesOnConstant(Instruction *II,
Other->removePredecessor(Source);
BI->eraseFromParent();
BranchInst::Create(Target, Source);
+ if (DTU)
+ DTU->applyUpdates({{DominatorTree::Delete, Source, Other}});
if (pred_empty(Other))
HasDeadBlocks = true;
}
@@ -85,7 +90,12 @@ static bool replaceConditionalBranchesOnConstant(Instruction *II,
return HasDeadBlocks;
}
-static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo *TLI) {
+static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo *TLI,
+ DominatorTree *DT) {
+ Optional<DomTreeUpdater> DTU;
+ if (DT)
+ DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy);
+
bool HasDeadBlocks = false;
const auto &DL = F.getParent()->getDataLayout();
SmallVector<WeakTrackingVH, 8> Worklist;
@@ -128,19 +138,20 @@ static bool lowerConstantIntrinsics(Function &F, const TargetLibraryInfo *TLI) {
ObjectSizeIntrinsicsHandled++;
break;
}
- HasDeadBlocks |= replaceConditionalBranchesOnConstant(II, NewValue);
+ HasDeadBlocks |= replaceConditionalBranchesOnConstant(
+ II, NewValue, DTU.hasValue() ? DTU.getPointer() : nullptr);
}
if (HasDeadBlocks)
- removeUnreachableBlocks(F);
+ removeUnreachableBlocks(F, DTU.hasValue() ? DTU.getPointer() : nullptr);
return !Worklist.empty();
}
PreservedAnalyses
LowerConstantIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) {
- if (lowerConstantIntrinsics(F,
- AM.getCachedResult<TargetLibraryAnalysis>(F))) {
+ if (lowerConstantIntrinsics(F, AM.getCachedResult<TargetLibraryAnalysis>(F),
+ AM.getCachedResult<DominatorTreeAnalysis>(F))) {
PreservedAnalyses PA;
- PA.preserve<GlobalsAA>();
+ PA.preserve<DominatorTreeAnalysis>();
return PA;
}
@@ -163,18 +174,25 @@ public:
bool runOnFunction(Function &F) override {
auto *TLIP = getAnalysisIfAvailable<TargetLibraryInfoWrapperPass>();
const TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI(F) : nullptr;
- return lowerConstantIntrinsics(F, TLI);
+ DominatorTree *DT = nullptr;
+ if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
+ DT = &DTWP->getDomTree();
+ return lowerConstantIntrinsics(F, TLI, DT);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addPreserved<GlobalsAAWrapperPass>();
+ AU.addPreserved<DominatorTreeWrapperPass>();
}
};
} // namespace
char LowerConstantIntrinsics::ID = 0;
-INITIALIZE_PASS(LowerConstantIntrinsics, "lower-constant-intrinsics",
- "Lower constant intrinsics", false, false)
+INITIALIZE_PASS_BEGIN(LowerConstantIntrinsics, "lower-constant-intrinsics",
+ "Lower constant intrinsics", false, false)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
+INITIALIZE_PASS_END(LowerConstantIntrinsics, "lower-constant-intrinsics",
+ "Lower constant intrinsics", false, false)
FunctionPass *llvm::createLowerConstantIntrinsicsPass() {
return new LowerConstantIntrinsics();
diff --git a/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp b/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp
index da13075dfee2..ead8082f3036 100644
--- a/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp
+++ b/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp
@@ -24,6 +24,7 @@
#include "llvm/IR/Metadata.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Scalar.h"
@@ -41,15 +42,15 @@ STATISTIC(ExpectIntrinsicsHandled,
// only be used in extreme cases, we could make this ratio higher. As it stands,
// programmers may be using __builtin_expect() / llvm.expect to annotate that a
// branch is likely or unlikely to be taken.
-//
-// There is a known dependency on this ratio in CodeGenPrepare when transforming
-// 'select' instructions. It may be worthwhile to hoist these values to some
-// shared space, so they can be used directly by other passes.
-cl::opt<uint32_t> llvm::LikelyBranchWeight(
+// WARNING: these values are internal implementation detail of the pass.
+// They should not be exposed to the outside of the pass, front-end codegen
+// should emit @llvm.expect intrinsics instead of using these weights directly.
+// Transforms should use TargetTransformInfo's getPredictableBranchThreshold().
+static cl::opt<uint32_t> LikelyBranchWeight(
"likely-branch-weight", cl::Hidden, cl::init(2000),
cl::desc("Weight of the branch likely to be taken (default = 2000)"));
-cl::opt<uint32_t> llvm::UnlikelyBranchWeight(
+static cl::opt<uint32_t> UnlikelyBranchWeight(
"unlikely-branch-weight", cl::Hidden, cl::init(1),
cl::desc("Weight of the branch unlikely to be taken (default = 1)"));
diff --git a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
index 8e251ca940a3..42c183a6408e 100644
--- a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
+++ b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp
@@ -34,6 +34,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/MatrixBuilder.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
@@ -50,11 +51,6 @@ using namespace PatternMatch;
#define DEBUG_TYPE "lower-matrix-intrinsics"
-static cl::opt<bool> EnableShapePropagation(
- "matrix-propagate-shape", cl::init(true), cl::Hidden,
- cl::desc("Enable/disable shape propagation from matrix intrinsics to other "
- "instructions."));
-
static cl::opt<bool>
FuseMatrix("fuse-matrix", cl::init(true), cl::Hidden,
cl::desc("Enable/disable fusing matrix instructions."));
@@ -200,11 +196,16 @@ class LowerMatrixIntrinsics {
unsigned NumLoads = 0;
/// Number of compute operations emitted to generate this matrix.
unsigned NumComputeOps = 0;
+ /// Most of the time transposes can be fused with matrix multiplies or can
+ /// be folded away via algebraic simplifications. This is the number of
+ /// transposes that we failed to make "free" via such optimizations.
+ unsigned NumExposedTransposes = 0;
OpInfoTy &operator+=(const OpInfoTy &RHS) {
NumStores += RHS.NumStores;
NumLoads += RHS.NumLoads;
NumComputeOps += RHS.NumComputeOps;
+ NumExposedTransposes += RHS.NumExposedTransposes;
return *this;
}
};
@@ -309,6 +310,11 @@ class LowerMatrixIntrinsics {
return *this;
}
+ MatrixTy &addNumExposedTransposes(unsigned N) {
+ OpInfo.NumExposedTransposes += N;
+ return *this;
+ }
+
MatrixTy &addNumComputeOps(unsigned N) {
OpInfo.NumComputeOps += N;
return *this;
@@ -384,8 +390,10 @@ class LowerMatrixIntrinsics {
/// the result value of the instruction, with the only exceptions being store
/// instructions and the matrix_column_major_store intrinsics. For those, the
/// shape information indicates that those instructions should be lowered
- /// using shape information as well.
- DenseMap<Value *, ShapeInfo> ShapeMap;
+ /// using shape information as well. A ValueMap is used so that when
+ /// sub-passes like optimizeTransposes performs RAUW the map stays
+ /// up-to-date.
+ ValueMap<Value *, ShapeInfo> ShapeMap;
/// List of instructions to remove. While lowering, we are not replacing all
/// users of a lowered instruction, if shape information is available and
@@ -395,6 +403,18 @@ class LowerMatrixIntrinsics {
/// Map from instructions to their produced column matrix.
MapVector<Value *, MatrixTy> Inst2ColumnMatrix;
+private:
+ static FastMathFlags getFastMathFlags(Instruction *Inst) {
+ FastMathFlags FMF;
+
+ if (isa<FPMathOperator>(*Inst))
+ FMF = Inst->getFastMathFlags();
+
+ FMF.setAllowContract(AllowContractEnabled || FMF.allowContract());
+
+ return FMF;
+ }
+
public:
LowerMatrixIntrinsics(Function &F, TargetTransformInfo &TTI,
AliasAnalysis *AA, DominatorTree *DT, LoopInfo *LI,
@@ -408,12 +428,18 @@ public:
cast<FixedVectorType>(VT)->getNumElements());
}
- //
+ /// Is this the minimal version executed in the backend pipelines.
+ bool isMinimal() const {
+ return !DT;
+ }
+
/// Return the estimated number of vector ops required for an operation on
/// \p VT * N.
unsigned getNumOps(Type *ST, unsigned N) {
return std::ceil((ST->getPrimitiveSizeInBits() * N).getFixedSize() /
- double(TTI.getRegisterBitWidth(true)));
+ double(TTI.getRegisterBitWidth(
+ TargetTransformInfo::RGK_FixedWidthVector)
+ .getFixedSize()));
}
/// Return the set of vectors that a matrix value is lowered to.
@@ -657,34 +683,161 @@ public:
return NewWorkList;
}
- bool Visit() {
- if (EnableShapePropagation) {
- SmallVector<Instruction *, 32> WorkList;
+ /// Try moving transposes in order to fold them away or into multiplies.
+ void optimizeTransposes() {
+ auto ReplaceAllUsesWith = [this](Instruction &Old, Value *New) {
+ // We need to remove Old from the ShapeMap otherwise RAUW will replace it
+ // with New. We should only add New it it supportsShapeInfo so we insert
+ // it conditionally instead.
+ auto S = ShapeMap.find(&Old);
+ if (S != ShapeMap.end()) {
+ ShapeMap.erase(S);
+ if (supportsShapeInfo(New))
+ ShapeMap.insert({New, S->second});
+ }
+ Old.replaceAllUsesWith(New);
+ };
- // Initially only the shape of matrix intrinsics is known.
- // Initialize the work list with ops carrying shape information.
- for (BasicBlock &BB : Func)
- for (Instruction &Inst : BB) {
- IntrinsicInst *II = dyn_cast<IntrinsicInst>(&Inst);
- if (!II)
- continue;
+ // First sink all transposes inside matmuls, hoping that we end up with NN,
+ // NT or TN variants.
+ for (BasicBlock &BB : reverse(Func)) {
+ for (auto II = BB.rbegin(); II != BB.rend();) {
+ Instruction &I = *II;
+ // We may remove II. By default continue on the next/prev instruction.
+ ++II;
+ // If we were to erase II, move again.
+ auto EraseFromParent = [&II](Value *V) {
+ auto *Inst = cast<Instruction>(V);
+ if (Inst->use_empty()) {
+ if (Inst == &*II) {
+ ++II;
+ }
+ Inst->eraseFromParent();
+ }
+ };
- switch (II->getIntrinsicID()) {
- case Intrinsic::matrix_multiply:
- case Intrinsic::matrix_transpose:
- case Intrinsic::matrix_column_major_load:
- case Intrinsic::matrix_column_major_store:
- WorkList.push_back(&Inst);
- break;
- default:
- break;
+ // If we're creating a new instruction, continue from there.
+ Instruction *NewInst = nullptr;
+
+ IRBuilder<> IB(&I);
+ MatrixBuilder<IRBuilder<>> Builder(IB);
+
+ Value *TA, *TAMA, *TAMB;
+ ConstantInt *R, *K, *C;
+ if (match(&I, m_Intrinsic<Intrinsic::matrix_transpose>(m_Value(TA)))) {
+
+ // Transpose of a transpose is a nop
+ Value *TATA;
+ if (match(TA,
+ m_Intrinsic<Intrinsic::matrix_transpose>(m_Value(TATA)))) {
+ ReplaceAllUsesWith(I, TATA);
+ EraseFromParent(&I);
+ EraseFromParent(TA);
}
+
+ // (A * B)^t -> B^t * A^t
+ // RxK KxC CxK KxR
+ else if (match(TA, m_Intrinsic<Intrinsic::matrix_multiply>(
+ m_Value(TAMA), m_Value(TAMB), m_ConstantInt(R),
+ m_ConstantInt(K), m_ConstantInt(C)))) {
+ Value *T0 = Builder.CreateMatrixTranspose(TAMB, K->getZExtValue(),
+ C->getZExtValue(),
+ TAMB->getName() + "_t");
+ // We are being run after shape prop, add shape for newly created
+ // instructions so that we lower them later.
+ setShapeInfo(T0, {C, K});
+ Value *T1 = Builder.CreateMatrixTranspose(TAMA, R->getZExtValue(),
+ K->getZExtValue(),
+ TAMA->getName() + "_t");
+ setShapeInfo(T1, {K, R});
+ NewInst = Builder.CreateMatrixMultiply(T0, T1, C->getZExtValue(),
+ K->getZExtValue(),
+ R->getZExtValue(), "mmul");
+ ReplaceAllUsesWith(I, NewInst);
+ EraseFromParent(&I);
+ EraseFromParent(TA);
+ }
+ }
+
+ // If we replaced I with a new instruction, continue from there.
+ if (NewInst)
+ II = std::next(BasicBlock::reverse_iterator(NewInst));
+ }
+ }
+
+ // If we have a TT matmul, lift the transpose. We may be able to fold into
+ // consuming multiply.
+ for (BasicBlock &BB : Func) {
+ for (BasicBlock::iterator II = BB.begin(); II != BB.end();) {
+ Instruction *I = &*II;
+ // We may remove I.
+ ++II;
+ Value *A, *B, *AT, *BT;
+ ConstantInt *R, *K, *C;
+ // A^t * B ^t -> (B * A)^t
+ if (match(&*I, m_Intrinsic<Intrinsic::matrix_multiply>(
+ m_Value(A), m_Value(B), m_ConstantInt(R),
+ m_ConstantInt(K), m_ConstantInt(C))) &&
+ match(A, m_Intrinsic<Intrinsic::matrix_transpose>(m_Value(AT))) &&
+ match(B, m_Intrinsic<Intrinsic::matrix_transpose>(m_Value((BT))))) {
+ IRBuilder<> IB(&*I);
+ MatrixBuilder<IRBuilder<>> Builder(IB);
+ Value *M = Builder.CreateMatrixMultiply(
+ BT, AT, C->getZExtValue(), K->getZExtValue(), R->getZExtValue());
+ setShapeInfo(M, {C, R});
+ Instruction *NewInst = Builder.CreateMatrixTranspose(
+ M, C->getZExtValue(), R->getZExtValue());
+ ReplaceAllUsesWith(*I, NewInst);
+ if (I->use_empty())
+ I->eraseFromParent();
+ if (A->use_empty())
+ cast<Instruction>(A)->eraseFromParent();
+ if (A != B && B->use_empty())
+ cast<Instruction>(B)->eraseFromParent();
+ }
+ }
+ }
+ }
+
+ bool Visit() {
+ SmallVector<Instruction *, 32> WorkList;
+
+ // Initially only the shape of matrix intrinsics is known.
+ // Initialize the work list with ops carrying shape information.
+ for (BasicBlock &BB : Func)
+ for (Instruction &Inst : BB) {
+ IntrinsicInst *II = dyn_cast<IntrinsicInst>(&Inst);
+ if (!II)
+ continue;
+
+ switch (II->getIntrinsicID()) {
+ case Intrinsic::matrix_multiply:
+ case Intrinsic::matrix_transpose:
+ case Intrinsic::matrix_column_major_load:
+ case Intrinsic::matrix_column_major_store:
+ WorkList.push_back(&Inst);
+ break;
+ default:
+ break;
}
- // Propagate shapes until nothing changes any longer.
- while (!WorkList.empty()) {
- WorkList = propagateShapeForward(WorkList);
- WorkList = propagateShapeBackward(WorkList);
}
+
+ // Avoid unnecessary work if there are no matrix intrinsics in the function.
+ if (WorkList.empty())
+ return false;
+
+ // Propagate shapes until nothing changes any longer.
+ while (!WorkList.empty()) {
+ WorkList = propagateShapeForward(WorkList);
+ WorkList = propagateShapeBackward(WorkList);
+ }
+
+ if (!isMinimal()) {
+ optimizeTransposes();
+ LLVM_DEBUG({
+ dbgs() << "Dump after matrix transpose optimization:\n";
+ Func.dump();
+ });
}
bool Changed = false;
@@ -736,8 +889,33 @@ public:
RemarkGen.emitRemarks();
}
- for (Instruction *Inst : reverse(ToRemove))
+ // Delete the instructions backwards, as it has a reduced likelihood of
+ // having to update as many def-use and use-def chains.
+ //
+ // Because we add to ToRemove during fusion we can't guarantee that defs
+ // are before uses. Change uses to undef temporarily as these should get
+ // removed as well.
+ //
+ // For verification, we keep track of where we changed uses to undefs in
+ // UndefedInsts and then check that we in fact remove them.
+ SmallSet<Instruction *, 16> UndefedInsts;
+ for (auto *Inst : reverse(ToRemove)) {
+ for (auto I = Inst->use_begin(), E = Inst->use_end(); I != E;) {
+ Use &U = *I++;
+ if (auto *Undefed = dyn_cast<Instruction>(U.getUser()))
+ UndefedInsts.insert(Undefed);
+ U.set(UndefValue::get(Inst->getType()));
+ }
Inst->eraseFromParent();
+ UndefedInsts.erase(Inst);
+ }
+ if (!UndefedInsts.empty()) {
+ // If we didn't remove all undefed instructions, it's a hard error.
+ dbgs() << "Undefed but present instructions:\n";
+ for (auto *I : UndefedInsts)
+ dbgs() << *I << "\n";
+ llvm_unreachable("Undefed but instruction not removed");
+ }
return Changed;
}
@@ -797,15 +975,16 @@ public:
/// vectors.
MatrixTy loadMatrix(Type *Ty, Value *Ptr, MaybeAlign MAlign, Value *Stride,
bool IsVolatile, ShapeInfo Shape, IRBuilder<> &Builder) {
- auto VType = cast<VectorType>(Ty);
- Value *EltPtr = createElementPtr(Ptr, VType->getElementType(), Builder);
+ auto *VType = cast<VectorType>(Ty);
+ Type *EltTy = VType->getElementType();
+ Type *VecTy = FixedVectorType::get(EltTy, Shape.getStride());
+ Value *EltPtr = createElementPtr(Ptr, EltTy, Builder);
MatrixTy Result;
for (unsigned I = 0, E = Shape.getNumVectors(); I < E; ++I) {
Value *GEP = computeVectorAddr(EltPtr, Builder.getInt64(I), Stride,
- Shape.getStride(), VType->getElementType(),
- Builder);
+ Shape.getStride(), EltTy, Builder);
Value *Vector = Builder.CreateAlignedLoad(
- GEP, getAlignForIndex(I, Stride, VType->getElementType(), MAlign),
+ VecTy, GEP, getAlignForIndex(I, Stride, EltTy, MAlign),
IsVolatile, "col.load");
Result.addVector(Vector);
@@ -987,18 +1166,19 @@ public:
}
/// Cache \p Matrix as result of \p Inst and update the uses of \p Inst. For
- /// users with shape information, there's nothing to do: the will use the
+ /// users with shape information, there's nothing to do: they will use the
/// cached value when they are lowered. For other users, \p Matrix is
/// flattened and the uses are updated to use it. Also marks \p Inst for
/// deletion.
void finalizeLowering(Instruction *Inst, MatrixTy Matrix,
IRBuilder<> &Builder) {
- Inst2ColumnMatrix.insert(std::make_pair(Inst, Matrix));
+ auto inserted = Inst2ColumnMatrix.insert(std::make_pair(Inst, Matrix));
+ (void)inserted;
+ assert(inserted.second && "multiple matrix lowering mapping");
ToRemove.push_back(Inst);
Value *Flattened = nullptr;
- for (auto I = Inst->use_begin(), E = Inst->use_end(); I != E;) {
- Use &U = *I++;
+ for (Use &U : llvm::make_early_inc_range(Inst->uses())) {
if (ShapeMap.find(U.getUser()) == ShapeMap.end()) {
if (!Flattened)
Flattened = Matrix.embedInVector(Builder);
@@ -1009,11 +1189,17 @@ public:
/// Compute \p Result += \p A * \p B for input matrices with left-associating
/// addition.
+ ///
+ /// We can fold a transpose into the operand that is used to extract scalars.
+ /// This is the first operands with row-major and the second with
+ /// column-major. If \p IsScalarMatrixTransposed we assume the appropriate
+ /// operand is transposed.
void emitMatrixMultiply(MatrixTy &Result, const MatrixTy &A,
- const MatrixTy &B, bool AllowContraction,
- IRBuilder<> &Builder, bool isTiled) {
+ const MatrixTy &B, IRBuilder<> &Builder, bool IsTiled,
+ bool IsScalarMatrixTransposed, FastMathFlags FMF) {
const unsigned VF = std::max<unsigned>(
- TTI.getRegisterBitWidth(true) /
+ TTI.getRegisterBitWidth(TargetTransformInfo::RGK_FixedWidthVector)
+ .getFixedSize() /
Result.getElementType()->getPrimitiveSizeInBits().getFixedSize(),
1U);
unsigned R = Result.getNumRows();
@@ -1025,6 +1211,9 @@ public:
Result.isColumnMajor() == A.isColumnMajor() &&
"operands must agree on matrix layout");
unsigned NumComputeOps = 0;
+
+ Builder.setFastMathFlags(FMF);
+
if (A.isColumnMajor()) {
// Multiply columns from the first operand with scalars from the second
// operand. Then move along the K axes and accumulate the columns. With
@@ -1039,15 +1228,17 @@ public:
while (I + BlockSize > R)
BlockSize /= 2;
- Value *Sum = isTiled ? Result.extractVector(I, J, BlockSize, Builder)
+ Value *Sum = IsTiled ? Result.extractVector(I, J, BlockSize, Builder)
: nullptr;
for (unsigned K = 0; K < M; ++K) {
Value *L = A.extractVector(I, K, BlockSize, Builder);
- Value *RH = Builder.CreateExtractElement(B.getColumn(J), K);
+ Value *RH = Builder.CreateExtractElement(
+ B.getColumn(IsScalarMatrixTransposed ? K : J),
+ IsScalarMatrixTransposed ? J : K);
Value *Splat = Builder.CreateVectorSplat(BlockSize, RH, "splat");
- Sum = createMulAdd(isSumZero && K == 0 ? nullptr : Sum, L, Splat,
- Result.getElementType()->isFloatingPointTy(),
- Builder, AllowContraction, NumComputeOps);
+ Sum =
+ createMulAdd(isSumZero && K == 0 ? nullptr : Sum, L, Splat,
+ IsFP, Builder, FMF.allowContract(), NumComputeOps);
}
Result.setVector(J,
insertVector(Result.getVector(J), I, Sum, Builder));
@@ -1068,10 +1259,13 @@ public:
Value *Sum = nullptr;
for (unsigned K = 0; K < M; ++K) {
Value *R = B.extractVector(K, J, BlockSize, Builder);
- Value *LH = Builder.CreateExtractElement(A.getVector(I), K);
+ Value *LH = Builder.CreateExtractElement(
+ A.getVector(IsScalarMatrixTransposed ? K : I),
+ IsScalarMatrixTransposed ? I : K);
Value *Splat = Builder.CreateVectorSplat(BlockSize, LH, "splat");
- Sum = createMulAdd(isSumZero && K == 0 ? nullptr : Sum, Splat, R,
- IsFP, Builder, AllowContraction, NumComputeOps);
+ Sum =
+ createMulAdd(isSumZero && K == 0 ? nullptr : Sum, Splat, R,
+ IsFP, Builder, FMF.allowContract(), NumComputeOps);
}
Result.setVector(I,
insertVector(Result.getVector(I), J, Sum, Builder));
@@ -1089,10 +1283,8 @@ public:
MemoryLocation StoreLoc = MemoryLocation::get(Store);
MemoryLocation LoadLoc = MemoryLocation::get(Load);
- AliasResult LdAliased = AA->alias(LoadLoc, StoreLoc);
-
// If we can statically determine noalias we're good.
- if (!LdAliased)
+ if (AA->isNoAlias(LoadLoc, StoreLoc))
return Load->getPointerOperand();
// Create code to check if the memory locations of the Load and Store
@@ -1179,10 +1371,11 @@ public:
const unsigned M = LShape.NumColumns;
auto *EltType = cast<VectorType>(MatMul->getType())->getElementType();
- const unsigned VF =
- std::max<unsigned>(TTI.getRegisterBitWidth(true) /
- EltType->getPrimitiveSizeInBits().getFixedSize(),
- 1U);
+ const unsigned VF = std::max<unsigned>(
+ TTI.getRegisterBitWidth(TargetTransformInfo::RGK_FixedWidthVector)
+ .getFixedSize() /
+ EltType->getPrimitiveSizeInBits().getFixedSize(),
+ 1U);
// Cost model for tiling
//
@@ -1210,8 +1403,7 @@ public:
}
void createTiledLoops(CallInst *MatMul, Value *LPtr, ShapeInfo LShape,
- Value *RPtr, ShapeInfo RShape, StoreInst *Store,
- bool AllowContract) {
+ Value *RPtr, ShapeInfo RShape, StoreInst *Store) {
auto *EltType = cast<VectorType>(MatMul->getType())->getElementType();
// Create the main tiling loop nest.
@@ -1247,7 +1439,8 @@ public:
{TileSize, TileSize}, EltType, Builder);
MatrixTy B = loadMatrix(RPtr, {}, false, RShape, TI.CurrentK, TI.CurrentCol,
{TileSize, TileSize}, EltType, Builder);
- emitMatrixMultiply(TileResult, A, B, AllowContract, Builder, true);
+ emitMatrixMultiply(TileResult, A, B, Builder, true, false,
+ getFastMathFlags(MatMul));
// Store result after the inner loop is done.
Builder.SetInsertPoint(TI.RowLoopLatch->getTerminator());
storeMatrix(TileResult, Store->getPointerOperand(), Store->getAlign(),
@@ -1286,11 +1479,8 @@ public:
Value *BPtr = getNonAliasingPointer(LoadOp1, Store, MatMul);
Value *CPtr = Store->getPointerOperand();
- bool AllowContract = AllowContractEnabled || (isa<FPMathOperator>(MatMul) &&
- MatMul->hasAllowContract());
if (TileUseLoops && (R % TileSize == 0 && C % TileSize == 0))
- createTiledLoops(MatMul, APtr, LShape, BPtr, RShape, Store,
- AllowContract);
+ createTiledLoops(MatMul, APtr, LShape, BPtr, RShape, Store);
else {
IRBuilder<> Builder(Store);
for (unsigned J = 0; J < C; J += TileSize)
@@ -1309,7 +1499,8 @@ public:
loadMatrix(BPtr, LoadOp1->getAlign(), LoadOp1->isVolatile(),
RShape, Builder.getInt64(K), Builder.getInt64(J),
{TileM, TileC}, EltType, Builder);
- emitMatrixMultiply(Res, A, B, AllowContract, Builder, true);
+ emitMatrixMultiply(Res, A, B, Builder, true, false,
+ getFastMathFlags(MatMul));
}
storeMatrix(Res, CPtr, Store->getAlign(), Store->isVolatile(), {R, M},
Builder.getInt64(I), Builder.getInt64(J), EltType,
@@ -1326,7 +1517,7 @@ public:
FusedInsts.insert(LoadOp0);
LoadOp0->eraseFromParent();
}
- if (LoadOp1->hasNUses(0)) {
+ if (LoadOp1 != LoadOp0 && LoadOp1->hasNUses(0)) {
FusedInsts.insert(LoadOp1);
LoadOp1->eraseFromParent();
}
@@ -1334,29 +1525,97 @@ public:
/// Try to lower matrix multiply chains by fusing operations.
///
- /// Currently we only lower {ld, ld} -> matmul -> st chains.
- //
- /// No need to return a MatrixTy object for the result of the operation, since
- /// the single store user will be lowered as part of this. Instructions that
- /// are completely eliminated by fusion are added to \p FusedInsts.
+ /// Call finalizeLowering on lowered instructions. Instructions that are
+ /// completely eliminated by fusion are added to \p FusedInsts.
void LowerMatrixMultiplyFused(CallInst *MatMul,
SmallPtrSetImpl<Instruction *> &FusedInsts) {
- if (!FuseMatrix || !MatMul->hasOneUse() ||
- MatrixLayout != MatrixLayoutTy::ColumnMajor || !DT)
+ if (!FuseMatrix || !DT)
return;
assert(AA && LI && "Analyses should be available");
- auto *LoadOp0 = dyn_cast<LoadInst>(MatMul->getOperand(0));
- auto *LoadOp1 = dyn_cast<LoadInst>(MatMul->getOperand(1));
+ Value *A = MatMul->getArgOperand(0);
+ Value *B = MatMul->getArgOperand(1);
+
+ // We can fold the transpose into the operand that is used to fetch scalars.
+ Value *T;
+ if (MatrixLayout == MatrixLayoutTy::ColumnMajor
+ ? match(B, m_Intrinsic<Intrinsic::matrix_transpose>(m_Value(T)))
+ : match(A, m_Intrinsic<Intrinsic::matrix_transpose>(m_Value(T)))) {
+ IRBuilder<> Builder(MatMul);
+ auto *EltType = cast<VectorType>(MatMul->getType())->getElementType();
+ ShapeInfo LShape(MatMul->getArgOperand(2), MatMul->getArgOperand(3));
+ ShapeInfo RShape(MatMul->getArgOperand(3), MatMul->getArgOperand(4));
+ const unsigned R = LShape.NumRows;
+ const unsigned M = LShape.NumColumns;
+ const unsigned C = RShape.NumColumns;
+
+ MatrixTy MA;
+ MatrixTy MB;
+
+ Value *Transpose;
+ if (MatrixLayout == MatrixLayoutTy::ColumnMajor) {
+ MA = getMatrix(A, ShapeInfo(R, M), Builder);
+ MB = getMatrix(T, ShapeInfo(C, M), Builder);
+ Transpose = B;
+ } else {
+ MA = getMatrix(T, ShapeInfo(R, M), Builder);
+ MB = getMatrix(B, ShapeInfo(C, M), Builder);
+ Transpose = A;
+ }
+
+ // Initialize the output
+ MatrixTy Result(R, C, EltType);
+
+ emitMatrixMultiply(Result, MA, MB, Builder, false, true,
+ getFastMathFlags(MatMul));
+
+ FusedInsts.insert(MatMul);
+ if (Transpose->hasOneUse()) {
+ FusedInsts.insert(cast<Instruction>(Transpose));
+ ToRemove.push_back(cast<Instruction>(Transpose));
+ // TODO: add a fake entry for the folded instruction so that this is
+ // included in the expression in the remark.
+ Inst2ColumnMatrix[Transpose] = MatrixTy(M, C, EltType);
+ }
+ finalizeLowering(MatMul, Result, Builder);
+ return;
+ }
+
+ if (!MatMul->hasOneUse() || MatrixLayout != MatrixLayoutTy::ColumnMajor)
+ return;
+
+ // Lower {ld, ld} -> matmul -> st chains. No need to call finalizeLowering
+ // since the single store user will be lowered as part of this.
+ auto *LoadOp0 = dyn_cast<LoadInst>(A);
+ auto *LoadOp1 = dyn_cast<LoadInst>(B);
auto *Store = dyn_cast<StoreInst>(*MatMul->user_begin());
if (LoadOp0 && LoadOp1 && Store) {
// The store address must dominate the MatMul instruction, otherwise
// we create invalid IR.
- // FIXME: See if we can hoist the store address computation.
- auto *AddrI = dyn_cast<Instruction>(Store->getOperand(1));
- if (AddrI && (!DT->dominates(AddrI, MatMul)))
- return;
+ SetVector<Value *> WorkList;
+ WorkList.insert(Store->getOperand(1));
+ SmallVector<Instruction *> ToHoist;
+ for (unsigned I = 0; I != WorkList.size(); ++I) {
+ Value *Current = WorkList[I];
+ auto *CurrI = dyn_cast<Instruction>(Current);
+ if (!CurrI)
+ continue;
+ if (isa<PHINode>(CurrI))
+ return;
+ if (DT->dominates(CurrI, MatMul))
+ continue;
+ if (CurrI->mayHaveSideEffects() || CurrI->mayReadFromMemory())
+ return;
+ ToHoist.push_back(CurrI);
+ WorkList.insert(CurrI->op_begin(), CurrI->op_end());
+ }
+
+ sort(ToHoist, [this](Instruction *A, Instruction *B) {
+ return DT->dominates(A, B);
+ });
+ for (Instruction *I : ToHoist)
+ I->moveBefore(MatMul);
emitSIMDTiling(MatMul, LoadOp0, LoadOp1, Store, FusedInsts);
return;
@@ -1384,9 +1643,8 @@ public:
assert(Lhs.getElementType() == Result.getElementType() &&
"Matrix multiply result element type does not match arguments.");
- bool AllowContract = AllowContractEnabled || (isa<FPMathOperator>(MatMul) &&
- MatMul->hasAllowContract());
- emitMatrixMultiply(Result, Lhs, Rhs, AllowContract, Builder, false);
+ emitMatrixMultiply(Result, Lhs, Rhs, Builder, false, false,
+ getFastMathFlags(MatMul));
finalizeLowering(MatMul, Result, Builder);
}
@@ -1423,7 +1681,8 @@ public:
// account for later simplifications/combines.
finalizeLowering(
Inst,
- Result.addNumComputeOps(2 * ArgShape.NumRows * ArgShape.NumColumns),
+ Result.addNumComputeOps(2 * ArgShape.NumRows * ArgShape.NumColumns)
+ .addNumExposedTransposes(1),
Builder);
}
@@ -1470,6 +1729,8 @@ public:
Result.isColumnMajor() == A.isColumnMajor() &&
"operands must agree on matrix layout");
+ Builder.setFastMathFlags(getFastMathFlags(Inst));
+
// Helper to perform binary op on vectors.
auto BuildVectorOp = [&Builder, Inst](Value *LHS, Value *RHS) {
switch (Inst->getOpcode()) {
@@ -1514,6 +1775,8 @@ public:
MatrixTy Result;
MatrixTy M = getMatrix(Op, Shape, Builder);
+ Builder.setFastMathFlags(getFastMathFlags(Inst));
+
// Helper to perform unary op on vectors.
auto BuildVectorOp = [&Builder, Inst](Value *Op) {
switch (Inst->getOpcode()) {
@@ -1631,7 +1894,7 @@ public:
return;
}
IntrinsicInst *II = dyn_cast<IntrinsicInst>(CI);
- write(StringRef(Intrinsic::getName(II->getIntrinsicID(), {}))
+ write(Intrinsic::getBaseName(II->getIntrinsicID())
.drop_front(StringRef("llvm.matrix.").size()));
write(".");
std::string Tmp;
@@ -1938,7 +2201,9 @@ public:
Rem << ore::NV("NumStores", Counts.NumStores) << " stores, "
<< ore::NV("NumLoads", Counts.NumLoads) << " loads, "
<< ore::NV("NumComputeOps", Counts.NumComputeOps)
- << " compute ops";
+ << " compute ops, "
+ << ore::NV("NumExposedTransposes", Counts.NumExposedTransposes)
+ << " exposed transposes";
if (SharedCounts.NumStores > 0 || SharedCounts.NumLoads > 0 ||
SharedCounts.NumComputeOps > 0) {
diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
index a4e695497f30..2e36c50b75fc 100644
--- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
@@ -68,7 +68,7 @@ using namespace llvm;
#define DEBUG_TYPE "memcpyopt"
static cl::opt<bool>
- EnableMemorySSA("enable-memcpyopt-memoryssa", cl::init(false), cl::Hidden,
+ EnableMemorySSA("enable-memcpyopt-memoryssa", cl::init(true), cl::Hidden,
cl::desc("Use MemorySSA-backed MemCpyOpt."));
STATISTIC(NumMemCpyInstr, "Number of memcpy instructions deleted");
@@ -308,6 +308,7 @@ INITIALIZE_PASS_DEPENDENCY(MemoryDependenceWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass)
INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass)
INITIALIZE_PASS_END(MemCpyOptLegacyPass, "memcpyopt", "MemCpy Optimization",
false, false)
@@ -398,6 +399,13 @@ Instruction *MemCpyOptPass::tryMergingIntoMemset(Instruction *StartInst,
}
}
+ // Calls that only access inaccessible memory do not block merging
+ // accessible stores.
+ if (auto *CB = dyn_cast<CallBase>(BI)) {
+ if (CB->onlyAccessesInaccessibleMemory())
+ continue;
+ }
+
if (!isa<StoreInst>(BI) && !isa<MemSetInst>(BI)) {
// If the instruction is readnone, ignore it, otherwise bail out. We
// don't even allow readonly here because we don't want something like:
@@ -683,7 +691,7 @@ bool MemCpyOptPass::processStore(StoreInst *SI, BasicBlock::iterator &BBI) {
// We found an instruction that may write to the loaded memory.
// We can try to promote at this position instead of the store
- // position if nothing alias the store memory after this and the store
+ // position if nothing aliases the store memory after this and the store
// destination is not in the range.
if (P && P != SI) {
if (!moveUp(SI, P, LI))
@@ -1049,10 +1057,12 @@ bool MemCpyOptPass::processMemCpyMemCpyDependence(MemCpyInst *M,
// Second, the length of the memcpy's must be the same, or the preceding one
// must be larger than the following one.
- ConstantInt *MDepLen = dyn_cast<ConstantInt>(MDep->getLength());
- ConstantInt *MLen = dyn_cast<ConstantInt>(M->getLength());
- if (!MDepLen || !MLen || MDepLen->getZExtValue() < MLen->getZExtValue())
- return false;
+ if (MDep->getLength() != M->getLength()) {
+ ConstantInt *MDepLen = dyn_cast<ConstantInt>(MDep->getLength());
+ ConstantInt *MLen = dyn_cast<ConstantInt>(M->getLength());
+ if (!MDepLen || !MLen || MDepLen->getZExtValue() < MLen->getZExtValue())
+ return false;
+ }
// Verify that the copied-from memory doesn't change in between the two
// transfers. For example, in:
@@ -1099,7 +1109,14 @@ bool MemCpyOptPass::processMemCpyMemCpyDependence(MemCpyInst *M,
NewM = Builder.CreateMemMove(M->getRawDest(), M->getDestAlign(),
MDep->getRawSource(), MDep->getSourceAlign(),
M->getLength(), M->isVolatile());
- else
+ else if (isa<MemCpyInlineInst>(M)) {
+ // llvm.memcpy may be promoted to llvm.memcpy.inline, but the converse is
+ // never allowed since that would allow the latter to be lowered as a call
+ // to an external function.
+ NewM = Builder.CreateMemCpyInline(
+ M->getRawDest(), M->getDestAlign(), MDep->getRawSource(),
+ MDep->getSourceAlign(), M->getLength(), M->isVolatile());
+ } else
NewM = Builder.CreateMemCpy(M->getRawDest(), M->getDestAlign(),
MDep->getRawSource(), MDep->getSourceAlign(),
M->getLength(), M->isVolatile());
@@ -1134,7 +1151,7 @@ bool MemCpyOptPass::processMemCpyMemCpyDependence(MemCpyInst *M,
bool MemCpyOptPass::processMemSetMemCpyDependence(MemCpyInst *MemCpy,
MemSetInst *MemSet) {
// We can only transform memset/memcpy with the same destination.
- if (MemSet->getDest() != MemCpy->getDest())
+ if (!AA->isMustAlias(MemSet->getDest(), MemCpy->getDest()))
return false;
// Check that src and dst of the memcpy aren't the same. While memcpy
@@ -1172,6 +1189,13 @@ bool MemCpyOptPass::processMemSetMemCpyDependence(MemCpyInst *MemCpy,
if (mayBeVisibleThroughUnwinding(Dest, MemSet, MemCpy))
return false;
+ // If the sizes are the same, simply drop the memset instead of generating
+ // a replacement with zero size.
+ if (DestSize == SrcSize) {
+ eraseInstruction(MemSet);
+ return true;
+ }
+
// By default, create an unaligned memset.
unsigned Align = 1;
// If Dest is aligned, and SrcSize is constant, use the minimum alignment
@@ -1197,8 +1221,11 @@ bool MemCpyOptPass::processMemSetMemCpyDependence(MemCpyInst *MemCpy,
Value *SizeDiff = Builder.CreateSub(DestSize, SrcSize);
Value *MemsetLen = Builder.CreateSelect(
Ule, ConstantInt::getNullValue(DestSize->getType()), SizeDiff);
+ unsigned DestAS = Dest->getType()->getPointerAddressSpace();
Instruction *NewMemSet = Builder.CreateMemSet(
- Builder.CreateGEP(Dest->getType()->getPointerElementType(), Dest,
+ Builder.CreateGEP(Builder.getInt8Ty(),
+ Builder.CreatePointerCast(Dest,
+ Builder.getInt8PtrTy(DestAS)),
SrcSize),
MemSet->getOperand(1), MemsetLen, MaybeAlign(Align));
@@ -1221,21 +1248,23 @@ bool MemCpyOptPass::processMemSetMemCpyDependence(MemCpyInst *MemCpy,
/// Determine whether the instruction has undefined content for the given Size,
/// either because it was freshly alloca'd or started its lifetime.
-static bool hasUndefContents(Instruction *I, ConstantInt *Size) {
+static bool hasUndefContents(Instruction *I, Value *Size) {
if (isa<AllocaInst>(I))
return true;
- if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
- if (II->getIntrinsicID() == Intrinsic::lifetime_start)
- if (ConstantInt *LTSize = dyn_cast<ConstantInt>(II->getArgOperand(0)))
- if (LTSize->getZExtValue() >= Size->getZExtValue())
- return true;
+ if (ConstantInt *CSize = dyn_cast<ConstantInt>(Size)) {
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
+ if (II->getIntrinsicID() == Intrinsic::lifetime_start)
+ if (ConstantInt *LTSize = dyn_cast<ConstantInt>(II->getArgOperand(0)))
+ if (LTSize->getZExtValue() >= CSize->getZExtValue())
+ return true;
+ }
return false;
}
static bool hasUndefContentsMSSA(MemorySSA *MSSA, AliasAnalysis *AA, Value *V,
- MemoryDef *Def, ConstantInt *Size) {
+ MemoryDef *Def, Value *Size) {
if (MSSA->isLiveOnEntryDef(Def))
return isa<AllocaInst>(getUnderlyingObject(V));
@@ -1243,9 +1272,24 @@ static bool hasUndefContentsMSSA(MemorySSA *MSSA, AliasAnalysis *AA, Value *V,
dyn_cast_or_null<IntrinsicInst>(Def->getMemoryInst())) {
if (II->getIntrinsicID() == Intrinsic::lifetime_start) {
ConstantInt *LTSize = cast<ConstantInt>(II->getArgOperand(0));
- if (AA->isMustAlias(V, II->getArgOperand(1)) &&
- LTSize->getZExtValue() >= Size->getZExtValue())
- return true;
+
+ if (ConstantInt *CSize = dyn_cast<ConstantInt>(Size)) {
+ if (AA->isMustAlias(V, II->getArgOperand(1)) &&
+ LTSize->getZExtValue() >= CSize->getZExtValue())
+ return true;
+ }
+
+ // If the lifetime.start covers a whole alloca (as it almost always
+ // does) and we're querying a pointer based on that alloca, then we know
+ // the memory is definitely undef, regardless of how exactly we alias.
+ // The size also doesn't matter, as an out-of-bounds access would be UB.
+ AllocaInst *Alloca = dyn_cast<AllocaInst>(getUnderlyingObject(V));
+ if (getUnderlyingObject(II->getArgOperand(1)) == Alloca) {
+ const DataLayout &DL = Alloca->getModule()->getDataLayout();
+ if (Optional<TypeSize> AllocaSize = Alloca->getAllocationSizeInBits(DL))
+ if (*AllocaSize == LTSize->getValue() * 8)
+ return true;
+ }
}
}
@@ -1264,8 +1308,6 @@ static bool hasUndefContentsMSSA(MemorySSA *MSSA, AliasAnalysis *AA, Value *V,
/// memset(dst2, c, dst2_size);
/// \endcode
/// When dst2_size <= dst1_size.
-///
-/// The \p MemCpy must have a Constant length.
bool MemCpyOptPass::performMemCpyToMemSetOptzn(MemCpyInst *MemCpy,
MemSetInst *MemSet) {
// Make sure that memcpy(..., memset(...), ...), that is we are memsetting and
@@ -1273,38 +1315,47 @@ bool MemCpyOptPass::performMemCpyToMemSetOptzn(MemCpyInst *MemCpy,
if (!AA->isMustAlias(MemSet->getRawDest(), MemCpy->getRawSource()))
return false;
- // A known memset size is required.
- ConstantInt *MemSetSize = dyn_cast<ConstantInt>(MemSet->getLength());
- if (!MemSetSize)
- return false;
+ Value *MemSetSize = MemSet->getLength();
+ Value *CopySize = MemCpy->getLength();
- // Make sure the memcpy doesn't read any more than what the memset wrote.
- // Don't worry about sizes larger than i64.
- ConstantInt *CopySize = cast<ConstantInt>(MemCpy->getLength());
- if (CopySize->getZExtValue() > MemSetSize->getZExtValue()) {
- // If the memcpy is larger than the memset, but the memory was undef prior
- // to the memset, we can just ignore the tail. Technically we're only
- // interested in the bytes from MemSetSize..CopySize here, but as we can't
- // easily represent this location, we use the full 0..CopySize range.
- MemoryLocation MemCpyLoc = MemoryLocation::getForSource(MemCpy);
- bool CanReduceSize = false;
- if (EnableMemorySSA) {
- MemoryUseOrDef *MemSetAccess = MSSA->getMemoryAccess(MemSet);
- MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess(
- MemSetAccess->getDefiningAccess(), MemCpyLoc);
- if (auto *MD = dyn_cast<MemoryDef>(Clobber))
- if (hasUndefContentsMSSA(MSSA, AA, MemCpy->getSource(), MD, CopySize))
- CanReduceSize = true;
- } else {
- MemDepResult DepInfo = MD->getPointerDependencyFrom(
- MemCpyLoc, true, MemSet->getIterator(), MemSet->getParent());
- if (DepInfo.isDef() && hasUndefContents(DepInfo.getInst(), CopySize))
- CanReduceSize = true;
- }
+ if (MemSetSize != CopySize) {
+ // Make sure the memcpy doesn't read any more than what the memset wrote.
+ // Don't worry about sizes larger than i64.
+
+ // A known memset size is required.
+ ConstantInt *CMemSetSize = dyn_cast<ConstantInt>(MemSetSize);
+ if (!CMemSetSize)
+ return false;
- if (!CanReduceSize)
+ // A known memcpy size is also required.
+ ConstantInt *CCopySize = dyn_cast<ConstantInt>(CopySize);
+ if (!CCopySize)
return false;
- CopySize = MemSetSize;
+ if (CCopySize->getZExtValue() > CMemSetSize->getZExtValue()) {
+ // If the memcpy is larger than the memset, but the memory was undef prior
+ // to the memset, we can just ignore the tail. Technically we're only
+ // interested in the bytes from MemSetSize..CopySize here, but as we can't
+ // easily represent this location, we use the full 0..CopySize range.
+ MemoryLocation MemCpyLoc = MemoryLocation::getForSource(MemCpy);
+ bool CanReduceSize = false;
+ if (EnableMemorySSA) {
+ MemoryUseOrDef *MemSetAccess = MSSA->getMemoryAccess(MemSet);
+ MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess(
+ MemSetAccess->getDefiningAccess(), MemCpyLoc);
+ if (auto *MD = dyn_cast<MemoryDef>(Clobber))
+ if (hasUndefContentsMSSA(MSSA, AA, MemCpy->getSource(), MD, CopySize))
+ CanReduceSize = true;
+ } else {
+ MemDepResult DepInfo = MD->getPointerDependencyFrom(
+ MemCpyLoc, true, MemSet->getIterator(), MemSet->getParent());
+ if (DepInfo.isDef() && hasUndefContents(DepInfo.getInst(), CopySize))
+ CanReduceSize = true;
+ }
+
+ if (!CanReduceSize)
+ return false;
+ CopySize = MemSetSize;
+ }
}
IRBuilder<> Builder(MemCpy);
@@ -1376,10 +1427,6 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
if (processMemSetMemCpyDependence(M, MDep))
return true;
- // The optimizations after this point require the memcpy size.
- ConstantInt *CopySize = dyn_cast<ConstantInt>(M->getLength());
- if (!CopySize) return false;
-
MemoryAccess *SrcClobber = MSSA->getWalker()->getClobberingMemoryAccess(
AnyClobber, MemoryLocation::getForSource(M));
@@ -1392,26 +1439,29 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
// d) memcpy from a just-memset'd source can be turned into memset.
if (auto *MD = dyn_cast<MemoryDef>(SrcClobber)) {
if (Instruction *MI = MD->getMemoryInst()) {
- if (auto *C = dyn_cast<CallInst>(MI)) {
- // The memcpy must post-dom the call. Limit to the same block for now.
- // Additionally, we need to ensure that there are no accesses to dest
- // between the call and the memcpy. Accesses to src will be checked
- // by performCallSlotOptzn().
- // TODO: Support non-local call-slot optimization?
- if (C->getParent() == M->getParent() &&
- !accessedBetween(*AA, DestLoc, MD, MA)) {
- // FIXME: Can we pass in either of dest/src alignment here instead
- // of conservatively taking the minimum?
- Align Alignment = std::min(M->getDestAlign().valueOrOne(),
- M->getSourceAlign().valueOrOne());
- if (performCallSlotOptzn(M, M, M->getDest(), M->getSource(),
- CopySize->getZExtValue(), Alignment, C)) {
- LLVM_DEBUG(dbgs() << "Performed call slot optimization:\n"
- << " call: " << *C << "\n"
- << " memcpy: " << *M << "\n");
- eraseInstruction(M);
- ++NumMemCpyInstr;
- return true;
+ if (ConstantInt *CopySize = dyn_cast<ConstantInt>(M->getLength())) {
+ if (auto *C = dyn_cast<CallInst>(MI)) {
+ // The memcpy must post-dom the call. Limit to the same block for
+ // now. Additionally, we need to ensure that there are no accesses
+ // to dest between the call and the memcpy. Accesses to src will be
+ // checked by performCallSlotOptzn().
+ // TODO: Support non-local call-slot optimization?
+ if (C->getParent() == M->getParent() &&
+ !accessedBetween(*AA, DestLoc, MD, MA)) {
+ // FIXME: Can we pass in either of dest/src alignment here instead
+ // of conservatively taking the minimum?
+ Align Alignment = std::min(M->getDestAlign().valueOrOne(),
+ M->getSourceAlign().valueOrOne());
+ if (performCallSlotOptzn(M, M, M->getDest(), M->getSource(),
+ CopySize->getZExtValue(), Alignment,
+ C)) {
+ LLVM_DEBUG(dbgs() << "Performed call slot optimization:\n"
+ << " call: " << *C << "\n"
+ << " memcpy: " << *M << "\n");
+ eraseInstruction(M);
+ ++NumMemCpyInstr;
+ return true;
+ }
}
}
}
@@ -1427,7 +1477,7 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
}
}
- if (hasUndefContentsMSSA(MSSA, AA, M->getSource(), MD, CopySize)) {
+ if (hasUndefContentsMSSA(MSSA, AA, M->getSource(), MD, M->getLength())) {
LLVM_DEBUG(dbgs() << "Removed memcpy from undef\n");
eraseInstruction(M);
++NumMemCpyInstr;
@@ -1444,10 +1494,6 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
if (processMemSetMemCpyDependence(M, MDep))
return true;
- // The optimizations after this point require the memcpy size.
- ConstantInt *CopySize = dyn_cast<ConstantInt>(M->getLength());
- if (!CopySize) return false;
-
// There are four possible optimizations we can do for memcpy:
// a) memcpy-memcpy xform which exposes redundance for DSE.
// b) call-memcpy xform for return slot optimization.
@@ -1455,17 +1501,19 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
// its lifetime copies undefined data, and we can therefore eliminate
// the memcpy in favor of the data that was already at the destination.
// d) memcpy from a just-memset'd source can be turned into memset.
- if (DepInfo.isClobber()) {
- if (CallInst *C = dyn_cast<CallInst>(DepInfo.getInst())) {
- // FIXME: Can we pass in either of dest/src alignment here instead
- // of conservatively taking the minimum?
- Align Alignment = std::min(M->getDestAlign().valueOrOne(),
- M->getSourceAlign().valueOrOne());
- if (performCallSlotOptzn(M, M, M->getDest(), M->getSource(),
- CopySize->getZExtValue(), Alignment, C)) {
- eraseInstruction(M);
- ++NumMemCpyInstr;
- return true;
+ if (ConstantInt *CopySize = dyn_cast<ConstantInt>(M->getLength())) {
+ if (DepInfo.isClobber()) {
+ if (CallInst *C = dyn_cast<CallInst>(DepInfo.getInst())) {
+ // FIXME: Can we pass in either of dest/src alignment here instead
+ // of conservatively taking the minimum?
+ Align Alignment = std::min(M->getDestAlign().valueOrOne(),
+ M->getSourceAlign().valueOrOne());
+ if (performCallSlotOptzn(M, M, M->getDest(), M->getSource(),
+ CopySize->getZExtValue(), Alignment, C)) {
+ eraseInstruction(M);
+ ++NumMemCpyInstr;
+ return true;
+ }
}
}
}
@@ -1478,7 +1526,7 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) {
if (MemCpyInst *MDep = dyn_cast<MemCpyInst>(SrcDepInfo.getInst()))
return processMemCpyMemCpyDependence(M, MDep);
} else if (SrcDepInfo.isDef()) {
- if (hasUndefContents(SrcDepInfo.getInst(), CopySize)) {
+ if (hasUndefContents(SrcDepInfo.getInst(), M->getLength())) {
eraseInstruction(M);
++NumMemCpyInstr;
return true;
@@ -1535,12 +1583,14 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) {
const DataLayout &DL = CB.getCaller()->getParent()->getDataLayout();
// Find out what feeds this byval argument.
Value *ByValArg = CB.getArgOperand(ArgNo);
- Type *ByValTy = cast<PointerType>(ByValArg->getType())->getElementType();
+ Type *ByValTy = CB.getParamByValType(ArgNo);
uint64_t ByValSize = DL.getTypeAllocSize(ByValTy);
MemoryLocation Loc(ByValArg, LocationSize::precise(ByValSize));
MemCpyInst *MDep = nullptr;
if (EnableMemorySSA) {
MemoryUseOrDef *CallAccess = MSSA->getMemoryAccess(&CB);
+ if (!CallAccess)
+ return false;
MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess(
CallAccess->getDefiningAccess(), Loc);
if (auto *MD = dyn_cast<MemoryDef>(Clobber))
@@ -1684,7 +1734,6 @@ PreservedAnalyses MemCpyOptPass::run(Function &F, FunctionAnalysisManager &AM) {
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
- PA.preserve<GlobalsAA>();
if (MD)
PA.preserve<MemoryDependenceAnalysis>();
if (MSSA)
diff --git a/llvm/lib/Transforms/Scalar/MergeICmps.cpp b/llvm/lib/Transforms/Scalar/MergeICmps.cpp
index 7f8b75ac8806..f13f24ad2027 100644
--- a/llvm/lib/Transforms/Scalar/MergeICmps.cpp
+++ b/llvm/lib/Transforms/Scalar/MergeICmps.cpp
@@ -176,40 +176,39 @@ BCEAtom visitICmpLoadOperand(Value *const Val, BaseIdentifier &BaseId) {
Offset);
}
-// A basic block with a comparison between two BCE atoms, e.g. `a == o.a` in the
-// example at the top.
-// The block might do extra work besides the atom comparison, in which case
-// doesOtherWork() returns true. Under some conditions, the block can be
-// split into the atom comparison part and the "other work" part
-// (see canSplit()).
+// A comparison between two BCE atoms, e.g. `a == o.a` in the example at the
+// top.
// Note: the terminology is misleading: the comparison is symmetric, so there
// is no real {l/r}hs. What we want though is to have the same base on the
// left (resp. right), so that we can detect consecutive loads. To ensure this
// we put the smallest atom on the left.
-class BCECmpBlock {
- public:
- BCECmpBlock() {}
+struct BCECmp {
+ BCEAtom Lhs;
+ BCEAtom Rhs;
+ int SizeBits;
+ const ICmpInst *CmpI;
- BCECmpBlock(BCEAtom L, BCEAtom R, int SizeBits)
- : Lhs_(std::move(L)), Rhs_(std::move(R)), SizeBits_(SizeBits) {
- if (Rhs_ < Lhs_) std::swap(Rhs_, Lhs_);
+ BCECmp(BCEAtom L, BCEAtom R, int SizeBits, const ICmpInst *CmpI)
+ : Lhs(std::move(L)), Rhs(std::move(R)), SizeBits(SizeBits), CmpI(CmpI) {
+ if (Rhs < Lhs) std::swap(Rhs, Lhs);
}
+};
- bool IsValid() const { return Lhs_.BaseId != 0 && Rhs_.BaseId != 0; }
+// A basic block with a comparison between two BCE atoms.
+// The block might do extra work besides the atom comparison, in which case
+// doesOtherWork() returns true. Under some conditions, the block can be
+// split into the atom comparison part and the "other work" part
+// (see canSplit()).
+class BCECmpBlock {
+ public:
+ typedef SmallDenseSet<const Instruction *, 8> InstructionSet;
- // Assert the block is consistent: If valid, it should also have
- // non-null members besides Lhs_ and Rhs_.
- void AssertConsistent() const {
- if (IsValid()) {
- assert(BB);
- assert(CmpI);
- assert(BranchI);
- }
- }
+ BCECmpBlock(BCECmp Cmp, BasicBlock *BB, InstructionSet BlockInsts)
+ : BB(BB), BlockInsts(std::move(BlockInsts)), Cmp(std::move(Cmp)) {}
- const BCEAtom &Lhs() const { return Lhs_; }
- const BCEAtom &Rhs() const { return Rhs_; }
- int SizeBits() const { return SizeBits_; }
+ const BCEAtom &Lhs() const { return Cmp.Lhs; }
+ const BCEAtom &Rhs() const { return Cmp.Rhs; }
+ int SizeBits() const { return Cmp.SizeBits; }
// Returns true if the block does other works besides comparison.
bool doesOtherWork() const;
@@ -222,8 +221,7 @@ class BCECmpBlock {
// be sunk below this instruction. By doing this, we know we can separate the
// BCE-cmp-block instructions from the non-BCE-cmp-block instructions in the
// block.
- bool canSinkBCECmpInst(const Instruction *, DenseSet<Instruction *> &,
- AliasAnalysis &AA) const;
+ bool canSinkBCECmpInst(const Instruction *, AliasAnalysis &AA) const;
// We can separate the BCE-cmp-block instructions and the non-BCE-cmp-block
// instructions. Split the old block and move all non-BCE-cmp-insts into the
@@ -231,54 +229,45 @@ class BCECmpBlock {
void split(BasicBlock *NewParent, AliasAnalysis &AA) const;
// The basic block where this comparison happens.
- BasicBlock *BB = nullptr;
- // The ICMP for this comparison.
- ICmpInst *CmpI = nullptr;
- // The terminating branch.
- BranchInst *BranchI = nullptr;
+ BasicBlock *BB;
+ // Instructions relating to the BCECmp and branch.
+ InstructionSet BlockInsts;
// The block requires splitting.
bool RequireSplit = false;
private:
- BCEAtom Lhs_;
- BCEAtom Rhs_;
- int SizeBits_ = 0;
+ BCECmp Cmp;
};
bool BCECmpBlock::canSinkBCECmpInst(const Instruction *Inst,
- DenseSet<Instruction *> &BlockInsts,
AliasAnalysis &AA) const {
- // If this instruction has side effects and its in middle of the BCE cmp block
- // instructions, then bail for now.
- if (Inst->mayHaveSideEffects()) {
+ // If this instruction may clobber the loads and is in middle of the BCE cmp
+ // block instructions, then bail for now.
+ if (Inst->mayWriteToMemory()) {
// Bail if this is not a simple load or store
if (!isSimpleLoadOrStore(Inst))
return false;
// Disallow stores that might alias the BCE operands
- MemoryLocation LLoc = MemoryLocation::get(Lhs_.LoadI);
- MemoryLocation RLoc = MemoryLocation::get(Rhs_.LoadI);
+ MemoryLocation LLoc = MemoryLocation::get(Cmp.Lhs.LoadI);
+ MemoryLocation RLoc = MemoryLocation::get(Cmp.Rhs.LoadI);
if (isModSet(AA.getModRefInfo(Inst, LLoc)) ||
isModSet(AA.getModRefInfo(Inst, RLoc)))
return false;
}
// Make sure this instruction does not use any of the BCE cmp block
// instructions as operand.
- for (auto BI : BlockInsts) {
- if (is_contained(Inst->operands(), BI))
- return false;
- }
- return true;
+ return llvm::none_of(Inst->operands(), [&](const Value *Op) {
+ const Instruction *OpI = dyn_cast<Instruction>(Op);
+ return OpI && BlockInsts.contains(OpI);
+ });
}
void BCECmpBlock::split(BasicBlock *NewParent, AliasAnalysis &AA) const {
- DenseSet<Instruction *> BlockInsts(
- {Lhs_.GEP, Rhs_.GEP, Lhs_.LoadI, Rhs_.LoadI, CmpI, BranchI});
llvm::SmallVector<Instruction *, 4> OtherInsts;
for (Instruction &Inst : *BB) {
if (BlockInsts.count(&Inst))
continue;
- assert(canSinkBCECmpInst(&Inst, BlockInsts, AA) &&
- "Split unsplittable block");
+ assert(canSinkBCECmpInst(&Inst, AA) && "Split unsplittable block");
// This is a non-BCE-cmp-block instruction. And it can be separated
// from the BCE-cmp-block instruction.
OtherInsts.push_back(&Inst);
@@ -291,11 +280,9 @@ void BCECmpBlock::split(BasicBlock *NewParent, AliasAnalysis &AA) const {
}
bool BCECmpBlock::canSplit(AliasAnalysis &AA) const {
- DenseSet<Instruction *> BlockInsts(
- {Lhs_.GEP, Rhs_.GEP, Lhs_.LoadI, Rhs_.LoadI, CmpI, BranchI});
for (Instruction &Inst : *BB) {
if (!BlockInsts.count(&Inst)) {
- if (!canSinkBCECmpInst(&Inst, BlockInsts, AA))
+ if (!canSinkBCECmpInst(&Inst, AA))
return false;
}
}
@@ -303,10 +290,6 @@ bool BCECmpBlock::canSplit(AliasAnalysis &AA) const {
}
bool BCECmpBlock::doesOtherWork() const {
- AssertConsistent();
- // All the instructions we care about in the BCE cmp block.
- DenseSet<Instruction *> BlockInsts(
- {Lhs_.GEP, Rhs_.GEP, Lhs_.LoadI, Rhs_.LoadI, CmpI, BranchI});
// TODO(courbet): Can we allow some other things ? This is very conservative.
// We might be able to get away with anything does not have any side
// effects outside of the basic block.
@@ -320,9 +303,9 @@ bool BCECmpBlock::doesOtherWork() const {
// Visit the given comparison. If this is a comparison between two valid
// BCE atoms, returns the comparison.
-BCECmpBlock visitICmp(const ICmpInst *const CmpI,
- const ICmpInst::Predicate ExpectedPredicate,
- BaseIdentifier &BaseId) {
+Optional<BCECmp> visitICmp(const ICmpInst *const CmpI,
+ const ICmpInst::Predicate ExpectedPredicate,
+ BaseIdentifier &BaseId) {
// The comparison can only be used once:
// - For intermediate blocks, as a branch condition.
// - For the final block, as an incoming value for the Phi.
@@ -330,65 +313,68 @@ BCECmpBlock visitICmp(const ICmpInst *const CmpI,
// other comparisons as we would create an orphan use of the value.
if (!CmpI->hasOneUse()) {
LLVM_DEBUG(dbgs() << "cmp has several uses\n");
- return {};
+ return None;
}
if (CmpI->getPredicate() != ExpectedPredicate)
- return {};
+ return None;
LLVM_DEBUG(dbgs() << "cmp "
<< (ExpectedPredicate == ICmpInst::ICMP_EQ ? "eq" : "ne")
<< "\n");
auto Lhs = visitICmpLoadOperand(CmpI->getOperand(0), BaseId);
if (!Lhs.BaseId)
- return {};
+ return None;
auto Rhs = visitICmpLoadOperand(CmpI->getOperand(1), BaseId);
if (!Rhs.BaseId)
- return {};
+ return None;
const auto &DL = CmpI->getModule()->getDataLayout();
- return BCECmpBlock(std::move(Lhs), std::move(Rhs),
- DL.getTypeSizeInBits(CmpI->getOperand(0)->getType()));
+ return BCECmp(std::move(Lhs), std::move(Rhs),
+ DL.getTypeSizeInBits(CmpI->getOperand(0)->getType()), CmpI);
}
// Visit the given comparison block. If this is a comparison between two valid
// BCE atoms, returns the comparison.
-BCECmpBlock visitCmpBlock(Value *const Val, BasicBlock *const Block,
- const BasicBlock *const PhiBlock,
- BaseIdentifier &BaseId) {
- if (Block->empty()) return {};
+Optional<BCECmpBlock> visitCmpBlock(Value *const Val, BasicBlock *const Block,
+ const BasicBlock *const PhiBlock,
+ BaseIdentifier &BaseId) {
+ if (Block->empty()) return None;
auto *const BranchI = dyn_cast<BranchInst>(Block->getTerminator());
- if (!BranchI) return {};
+ if (!BranchI) return None;
LLVM_DEBUG(dbgs() << "branch\n");
+ Value *Cond;
+ ICmpInst::Predicate ExpectedPredicate;
if (BranchI->isUnconditional()) {
// In this case, we expect an incoming value which is the result of the
// comparison. This is the last link in the chain of comparisons (note
// that this does not mean that this is the last incoming value, blocks
// can be reordered).
- auto *const CmpI = dyn_cast<ICmpInst>(Val);
- if (!CmpI) return {};
- LLVM_DEBUG(dbgs() << "icmp\n");
- auto Result = visitICmp(CmpI, ICmpInst::ICMP_EQ, BaseId);
- Result.CmpI = CmpI;
- Result.BranchI = BranchI;
- return Result;
+ Cond = Val;
+ ExpectedPredicate = ICmpInst::ICMP_EQ;
} else {
// In this case, we expect a constant incoming value (the comparison is
// chained).
const auto *const Const = cast<ConstantInt>(Val);
LLVM_DEBUG(dbgs() << "const\n");
- if (!Const->isZero()) return {};
+ if (!Const->isZero()) return None;
LLVM_DEBUG(dbgs() << "false\n");
- auto *const CmpI = dyn_cast<ICmpInst>(BranchI->getCondition());
- if (!CmpI) return {};
- LLVM_DEBUG(dbgs() << "icmp\n");
assert(BranchI->getNumSuccessors() == 2 && "expecting a cond branch");
BasicBlock *const FalseBlock = BranchI->getSuccessor(1);
- auto Result = visitICmp(
- CmpI, FalseBlock == PhiBlock ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE,
- BaseId);
- Result.CmpI = CmpI;
- Result.BranchI = BranchI;
- return Result;
+ Cond = BranchI->getCondition();
+ ExpectedPredicate =
+ FalseBlock == PhiBlock ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE;
}
- return {};
+
+ auto *CmpI = dyn_cast<ICmpInst>(Cond);
+ if (!CmpI) return None;
+ LLVM_DEBUG(dbgs() << "icmp\n");
+
+ Optional<BCECmp> Result = visitICmp(CmpI, ExpectedPredicate, BaseId);
+ if (!Result)
+ return None;
+
+ BCECmpBlock::InstructionSet BlockInsts(
+ {Result->Lhs.GEP, Result->Rhs.GEP, Result->Lhs.LoadI, Result->Rhs.LoadI,
+ Result->CmpI, BranchI});
+ return BCECmpBlock(std::move(*Result), Block, BlockInsts);
}
static inline void enqueueBlock(std::vector<BCECmpBlock> &Comparisons,
@@ -440,18 +426,16 @@ BCECmpChain::BCECmpChain(const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
// Now look inside blocks to check for BCE comparisons.
std::vector<BCECmpBlock> Comparisons;
BaseIdentifier BaseId;
- for (size_t BlockIdx = 0; BlockIdx < Blocks.size(); ++BlockIdx) {
- BasicBlock *const Block = Blocks[BlockIdx];
+ for (BasicBlock *const Block : Blocks) {
assert(Block && "invalid block");
- BCECmpBlock Comparison = visitCmpBlock(Phi.getIncomingValueForBlock(Block),
- Block, Phi.getParent(), BaseId);
- Comparison.BB = Block;
- if (!Comparison.IsValid()) {
+ Optional<BCECmpBlock> Comparison = visitCmpBlock(
+ Phi.getIncomingValueForBlock(Block), Block, Phi.getParent(), BaseId);
+ if (!Comparison) {
LLVM_DEBUG(dbgs() << "chain with invalid BCECmpBlock, no merge.\n");
return;
}
- if (Comparison.doesOtherWork()) {
- LLVM_DEBUG(dbgs() << "block '" << Comparison.BB->getName()
+ if (Comparison->doesOtherWork()) {
+ LLVM_DEBUG(dbgs() << "block '" << Comparison->BB->getName()
<< "' does extra work besides compare\n");
if (Comparisons.empty()) {
// This is the initial block in the chain, in case this block does other
@@ -467,15 +451,15 @@ BCECmpChain::BCECmpChain(const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
// and start anew.
//
// NOTE: we only handle blocks a with single predecessor for now.
- if (Comparison.canSplit(AA)) {
+ if (Comparison->canSplit(AA)) {
LLVM_DEBUG(dbgs()
- << "Split initial block '" << Comparison.BB->getName()
+ << "Split initial block '" << Comparison->BB->getName()
<< "' that does extra work besides compare\n");
- Comparison.RequireSplit = true;
- enqueueBlock(Comparisons, std::move(Comparison));
+ Comparison->RequireSplit = true;
+ enqueueBlock(Comparisons, std::move(*Comparison));
} else {
LLVM_DEBUG(dbgs()
- << "ignoring initial block '" << Comparison.BB->getName()
+ << "ignoring initial block '" << Comparison->BB->getName()
<< "' that does extra work besides compare\n");
}
continue;
@@ -505,7 +489,7 @@ BCECmpChain::BCECmpChain(const std::vector<BasicBlock *> &Blocks, PHINode &Phi,
// We could still merge bb1 and bb2 though.
return;
}
- enqueueBlock(Comparisons, std::move(Comparison));
+ enqueueBlock(Comparisons, std::move(*Comparison));
}
// It is possible we have no suitable comparison to merge.
@@ -597,7 +581,7 @@ private:
append(BB->getName());
}
}
- return StringRef(Scratch);
+ return Scratch.str();
}
};
} // namespace
@@ -733,8 +717,7 @@ bool BCECmpChain::simplify(const TargetLibraryInfo &TLI, AliasAnalysis &AA,
// If the old cmp chain was the function entry, we need to update the function
// entry.
- const bool ChainEntryIsFnEntry =
- (EntryBlock_ == &EntryBlock_->getParent()->getEntryBlock());
+ const bool ChainEntryIsFnEntry = EntryBlock_->isEntryBlock();
if (ChainEntryIsFnEntry && DTU.hasDomTree()) {
LLVM_DEBUG(dbgs() << "Changing function entry from "
<< EntryBlock_->getName() << " to "
@@ -940,7 +923,6 @@ PreservedAnalyses MergeICmpsPass::run(Function &F,
if (!MadeChanges)
return PreservedAnalyses::all();
PreservedAnalyses PA;
- PA.preserve<GlobalsAA>();
PA.preserve<DominatorTreeAnalysis>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp b/llvm/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp
index 69aa0cebe170..033fc168a67f 100644
--- a/llvm/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp
+++ b/llvm/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp
@@ -418,6 +418,5 @@ MergedLoadStoreMotionPass::run(Function &F, FunctionAnalysisManager &AM) {
PreservedAnalyses PA;
if (!Options.SplitFooterBB)
PA.preserveSet<CFGAnalyses>();
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/NaryReassociate.cpp b/llvm/lib/Transforms/Scalar/NaryReassociate.cpp
index 32bb62129e8f..ded5caf53b5a 100644
--- a/llvm/lib/Transforms/Scalar/NaryReassociate.cpp
+++ b/llvm/lib/Transforms/Scalar/NaryReassociate.cpp
@@ -80,6 +80,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/ScalarEvolution.h"
+#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
@@ -106,6 +107,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Local.h"
+#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h"
#include <cassert>
#include <cstdint>
@@ -222,15 +224,14 @@ bool NaryReassociatePass::doOneIteration(Function &F) {
SmallVector<WeakTrackingVH, 16> DeadInsts;
for (const auto Node : depth_first(DT)) {
BasicBlock *BB = Node->getBlock();
- for (auto I = BB->begin(); I != BB->end(); ++I) {
- Instruction *OrigI = &*I;
+ for (Instruction &OrigI : *BB) {
const SCEV *OrigSCEV = nullptr;
- if (Instruction *NewI = tryReassociate(OrigI, OrigSCEV)) {
+ if (Instruction *NewI = tryReassociate(&OrigI, OrigSCEV)) {
Changed = true;
- OrigI->replaceAllUsesWith(NewI);
+ OrigI.replaceAllUsesWith(NewI);
// Add 'OrigI' to the list of dead instructions.
- DeadInsts.push_back(WeakTrackingVH(OrigI));
+ DeadInsts.push_back(WeakTrackingVH(&OrigI));
// Add the rewritten instruction to SeenExprs; the original
// instruction is deleted.
const SCEV *NewSCEV = SE->getSCEV(NewI);
@@ -258,7 +259,7 @@ bool NaryReassociatePass::doOneIteration(Function &F) {
if (NewSCEV != OrigSCEV)
SeenExprs[OrigSCEV].push_back(WeakTrackingVH(NewI));
} else if (OrigSCEV)
- SeenExprs[OrigSCEV].push_back(WeakTrackingVH(OrigI));
+ SeenExprs[OrigSCEV].push_back(WeakTrackingVH(&OrigI));
}
}
// Delete all dead instructions from 'DeadInsts'.
@@ -269,6 +270,24 @@ bool NaryReassociatePass::doOneIteration(Function &F) {
return Changed;
}
+template <typename PredT>
+Instruction *
+NaryReassociatePass::matchAndReassociateMinOrMax(Instruction *I,
+ const SCEV *&OrigSCEV) {
+ Value *LHS = nullptr;
+ Value *RHS = nullptr;
+
+ auto MinMaxMatcher =
+ MaxMin_match<ICmpInst, bind_ty<Value>, bind_ty<Value>, PredT>(
+ m_Value(LHS), m_Value(RHS));
+ if (match(I, MinMaxMatcher)) {
+ OrigSCEV = SE->getSCEV(I);
+ return dyn_cast_or_null<Instruction>(
+ tryReassociateMinOrMax(I, MinMaxMatcher, LHS, RHS));
+ }
+ return nullptr;
+}
+
Instruction *NaryReassociatePass::tryReassociate(Instruction * I,
const SCEV *&OrigSCEV) {
@@ -284,10 +303,21 @@ Instruction *NaryReassociatePass::tryReassociate(Instruction * I,
OrigSCEV = SE->getSCEV(I);
return tryReassociateGEP(cast<GetElementPtrInst>(I));
default:
- return nullptr;
+ break;
}
- llvm_unreachable("should not be reached");
+ // Try to match signed/unsigned Min/Max.
+ Instruction *ResI = nullptr;
+ // TODO: Currently min/max reassociation is restricted to integer types only
+ // due to use of SCEVExpander which my introduce incompatible forms of min/max
+ // for pointer types.
+ if (I->getType()->isIntegerTy())
+ if ((ResI = matchAndReassociateMinOrMax<umin_pred_ty>(I, OrigSCEV)) ||
+ (ResI = matchAndReassociateMinOrMax<smin_pred_ty>(I, OrigSCEV)) ||
+ (ResI = matchAndReassociateMinOrMax<umax_pred_ty>(I, OrigSCEV)) ||
+ (ResI = matchAndReassociateMinOrMax<smax_pred_ty>(I, OrigSCEV)))
+ return ResI;
+
return nullptr;
}
@@ -364,8 +394,8 @@ NaryReassociatePass::tryReassociateGEPAtIndex(GetElementPtrInst *GEP,
// Look for GEP's closest dominator that has the same SCEV as GEP except that
// the I-th index is replaced with LHS.
SmallVector<const SCEV *, 4> IndexExprs;
- for (auto Index = GEP->idx_begin(); Index != GEP->idx_end(); ++Index)
- IndexExprs.push_back(SE->getSCEV(*Index));
+ for (Use &Index : GEP->indices())
+ IndexExprs.push_back(SE->getSCEV(Index));
// Replace the I-th index with LHS.
IndexExprs[I] = SE->getSCEV(LHS);
if (isKnownNonNegative(LHS, *DL, 0, AC, GEP, DT) &&
@@ -540,3 +570,84 @@ NaryReassociatePass::findClosestMatchingDominator(const SCEV *CandidateExpr,
}
return nullptr;
}
+
+template <typename MaxMinT> static SCEVTypes convertToSCEVype(MaxMinT &MM) {
+ if (std::is_same<smax_pred_ty, typename MaxMinT::PredType>::value)
+ return scSMaxExpr;
+ else if (std::is_same<umax_pred_ty, typename MaxMinT::PredType>::value)
+ return scUMaxExpr;
+ else if (std::is_same<smin_pred_ty, typename MaxMinT::PredType>::value)
+ return scSMinExpr;
+ else if (std::is_same<umin_pred_ty, typename MaxMinT::PredType>::value)
+ return scUMinExpr;
+
+ llvm_unreachable("Can't convert MinMax pattern to SCEV type");
+ return scUnknown;
+}
+
+// Parameters:
+// I - instruction matched by MaxMinMatch matcher
+// MaxMinMatch - min/max idiom matcher
+// LHS - first operand of I
+// RHS - second operand of I
+template <typename MaxMinT>
+Value *NaryReassociatePass::tryReassociateMinOrMax(Instruction *I,
+ MaxMinT MaxMinMatch,
+ Value *LHS, Value *RHS) {
+ Value *A = nullptr, *B = nullptr;
+ MaxMinT m_MaxMin(m_Value(A), m_Value(B));
+ for (unsigned int i = 0; i < 2; ++i) {
+ if (!LHS->hasNUsesOrMore(3) && match(LHS, m_MaxMin)) {
+ const SCEV *AExpr = SE->getSCEV(A), *BExpr = SE->getSCEV(B);
+ const SCEV *RHSExpr = SE->getSCEV(RHS);
+ for (unsigned int j = 0; j < 2; ++j) {
+ if (j == 0) {
+ if (BExpr == RHSExpr)
+ continue;
+ // Transform 'I = (A op B) op RHS' to 'I = (A op RHS) op B' on the
+ // first iteration.
+ std::swap(BExpr, RHSExpr);
+ } else {
+ if (AExpr == RHSExpr)
+ continue;
+ // Transform 'I = (A op RHS) op B' 'I = (B op RHS) op A' on the second
+ // iteration.
+ std::swap(AExpr, RHSExpr);
+ }
+
+ // The optimization is profitable only if LHS can be removed in the end.
+ // In other words LHS should be used (directly or indirectly) by I only.
+ if (llvm::any_of(LHS->users(), [&](auto *U) {
+ return U != I && !(U->hasOneUser() && *U->users().begin() == I);
+ }))
+ continue;
+
+ SCEVExpander Expander(*SE, *DL, "nary-reassociate");
+ SmallVector<const SCEV *, 2> Ops1{ BExpr, AExpr };
+ const SCEVTypes SCEVType = convertToSCEVype(m_MaxMin);
+ const SCEV *R1Expr = SE->getMinMaxExpr(SCEVType, Ops1);
+
+ Instruction *R1MinMax = findClosestMatchingDominator(R1Expr, I);
+
+ if (!R1MinMax)
+ continue;
+
+ LLVM_DEBUG(dbgs() << "NARY: Found common sub-expr: " << *R1MinMax
+ << "\n");
+
+ R1Expr = SE->getUnknown(R1MinMax);
+ SmallVector<const SCEV *, 2> Ops2{ RHSExpr, R1Expr };
+ const SCEV *R2Expr = SE->getMinMaxExpr(SCEVType, Ops2);
+
+ Value *NewMinMax = Expander.expandCodeFor(R2Expr, I->getType(), I);
+ NewMinMax->setName(Twine(I->getName()).concat(".nary"));
+
+ LLVM_DEBUG(dbgs() << "NARY: Deleting: " << *I << "\n"
+ << "NARY: Inserting: " << *NewMinMax << "\n");
+ return NewMinMax;
+ }
+ }
+ std::swap(LHS, RHS);
+ }
+ return nullptr;
+}
diff --git a/llvm/lib/Transforms/Scalar/NewGVN.cpp b/llvm/lib/Transforms/Scalar/NewGVN.cpp
index 281d47c8625f..a137d13c6ea0 100644
--- a/llvm/lib/Transforms/Scalar/NewGVN.cpp
+++ b/llvm/lib/Transforms/Scalar/NewGVN.cpp
@@ -62,6 +62,7 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SparseBitVector.h"
@@ -389,8 +390,7 @@ public:
if (Members.size() != Other->Members.size())
return false;
- return all_of(Members,
- [&](const Value *V) { return Other->Members.count(V); });
+ return llvm::set_is_subset(Members, Other->Members);
}
private:
@@ -668,8 +668,45 @@ public:
bool runGVN();
private:
+ /// Helper struct return a Expression with an optional extra dependency.
+ struct ExprResult {
+ const Expression *Expr;
+ Value *ExtraDep;
+ const PredicateBase *PredDep;
+
+ ExprResult(const Expression *Expr, Value *ExtraDep = nullptr,
+ const PredicateBase *PredDep = nullptr)
+ : Expr(Expr), ExtraDep(ExtraDep), PredDep(PredDep) {}
+ ExprResult(const ExprResult &) = delete;
+ ExprResult(ExprResult &&Other)
+ : Expr(Other.Expr), ExtraDep(Other.ExtraDep), PredDep(Other.PredDep) {
+ Other.Expr = nullptr;
+ Other.ExtraDep = nullptr;
+ Other.PredDep = nullptr;
+ }
+ ExprResult &operator=(const ExprResult &Other) = delete;
+ ExprResult &operator=(ExprResult &&Other) = delete;
+
+ ~ExprResult() { assert(!ExtraDep && "unhandled ExtraDep"); }
+
+ operator bool() const { return Expr; }
+
+ static ExprResult none() { return {nullptr, nullptr, nullptr}; }
+ static ExprResult some(const Expression *Expr, Value *ExtraDep = nullptr) {
+ return {Expr, ExtraDep, nullptr};
+ }
+ static ExprResult some(const Expression *Expr,
+ const PredicateBase *PredDep) {
+ return {Expr, nullptr, PredDep};
+ }
+ static ExprResult some(const Expression *Expr, Value *ExtraDep,
+ const PredicateBase *PredDep) {
+ return {Expr, ExtraDep, PredDep};
+ }
+ };
+
// Expression handling.
- const Expression *createExpression(Instruction *) const;
+ ExprResult createExpression(Instruction *) const;
const Expression *createBinaryExpression(unsigned, Type *, Value *, Value *,
Instruction *) const;
@@ -742,23 +779,22 @@ private:
void valueNumberInstruction(Instruction *);
// Symbolic evaluation.
- const Expression *checkSimplificationResults(Expression *, Instruction *,
- Value *) const;
- const Expression *performSymbolicEvaluation(Value *,
- SmallPtrSetImpl<Value *> &) const;
+ ExprResult checkExprResults(Expression *, Instruction *, Value *) const;
+ ExprResult performSymbolicEvaluation(Value *,
+ SmallPtrSetImpl<Value *> &) const;
const Expression *performSymbolicLoadCoercion(Type *, Value *, LoadInst *,
Instruction *,
MemoryAccess *) const;
const Expression *performSymbolicLoadEvaluation(Instruction *) const;
const Expression *performSymbolicStoreEvaluation(Instruction *) const;
- const Expression *performSymbolicCallEvaluation(Instruction *) const;
+ ExprResult performSymbolicCallEvaluation(Instruction *) const;
void sortPHIOps(MutableArrayRef<ValPair> Ops) const;
const Expression *performSymbolicPHIEvaluation(ArrayRef<ValPair>,
Instruction *I,
BasicBlock *PHIBlock) const;
const Expression *performSymbolicAggrValueEvaluation(Instruction *) const;
- const Expression *performSymbolicCmpEvaluation(Instruction *) const;
- const Expression *performSymbolicPredicateInfoEvaluation(Instruction *) const;
+ ExprResult performSymbolicCmpEvaluation(Instruction *) const;
+ ExprResult performSymbolicPredicateInfoEvaluation(Instruction *) const;
// Congruence finding.
bool someEquivalentDominates(const Instruction *, const Instruction *) const;
@@ -811,9 +847,9 @@ private:
void markValueLeaderChangeTouched(CongruenceClass *CC);
void markMemoryLeaderChangeTouched(CongruenceClass *CC);
void markPhiOfOpsChanged(const Expression *E);
- void addPredicateUsers(const PredicateBase *, Instruction *) const;
void addMemoryUsers(const MemoryAccess *To, MemoryAccess *U) const;
void addAdditionalUsers(Value *To, Value *User) const;
+ void addAdditionalUsers(ExprResult &Res, Instruction *User) const;
// Main loop of value numbering
void iterateTouchedInstructions();
@@ -1052,19 +1088,21 @@ const Expression *NewGVN::createBinaryExpression(unsigned Opcode, Type *T,
E->op_push_back(lookupOperandLeader(Arg2));
Value *V = SimplifyBinOp(Opcode, E->getOperand(0), E->getOperand(1), SQ);
- if (const Expression *SimplifiedE = checkSimplificationResults(E, I, V))
- return SimplifiedE;
+ if (auto Simplified = checkExprResults(E, I, V)) {
+ addAdditionalUsers(Simplified, I);
+ return Simplified.Expr;
+ }
return E;
}
// Take a Value returned by simplification of Expression E/Instruction
// I, and see if it resulted in a simpler expression. If so, return
// that expression.
-const Expression *NewGVN::checkSimplificationResults(Expression *E,
- Instruction *I,
- Value *V) const {
+NewGVN::ExprResult NewGVN::checkExprResults(Expression *E, Instruction *I,
+ Value *V) const {
if (!V)
- return nullptr;
+ return ExprResult::none();
+
if (auto *C = dyn_cast<Constant>(V)) {
if (I)
LLVM_DEBUG(dbgs() << "Simplified " << *I << " to "
@@ -1073,52 +1111,37 @@ const Expression *NewGVN::checkSimplificationResults(Expression *E,
assert(isa<BasicExpression>(E) &&
"We should always have had a basic expression here");
deleteExpression(E);
- return createConstantExpression(C);
+ return ExprResult::some(createConstantExpression(C));
} else if (isa<Argument>(V) || isa<GlobalVariable>(V)) {
if (I)
LLVM_DEBUG(dbgs() << "Simplified " << *I << " to "
<< " variable " << *V << "\n");
deleteExpression(E);
- return createVariableExpression(V);
+ return ExprResult::some(createVariableExpression(V));
}
CongruenceClass *CC = ValueToClass.lookup(V);
if (CC) {
if (CC->getLeader() && CC->getLeader() != I) {
- // If we simplified to something else, we need to communicate
- // that we're users of the value we simplified to.
- if (I != V) {
- // Don't add temporary instructions to the user lists.
- if (!AllTempInstructions.count(I))
- addAdditionalUsers(V, I);
- }
- return createVariableOrConstant(CC->getLeader());
+ return ExprResult::some(createVariableOrConstant(CC->getLeader()), V);
}
if (CC->getDefiningExpr()) {
- // If we simplified to something else, we need to communicate
- // that we're users of the value we simplified to.
- if (I != V) {
- // Don't add temporary instructions to the user lists.
- if (!AllTempInstructions.count(I))
- addAdditionalUsers(V, I);
- }
-
if (I)
LLVM_DEBUG(dbgs() << "Simplified " << *I << " to "
<< " expression " << *CC->getDefiningExpr() << "\n");
NumGVNOpsSimplified++;
deleteExpression(E);
- return CC->getDefiningExpr();
+ return ExprResult::some(CC->getDefiningExpr(), V);
}
}
- return nullptr;
+ return ExprResult::none();
}
// Create a value expression from the instruction I, replacing operands with
// their leaders.
-const Expression *NewGVN::createExpression(Instruction *I) const {
+NewGVN::ExprResult NewGVN::createExpression(Instruction *I) const {
auto *E = new (ExpressionAllocator) BasicExpression(I->getNumOperands());
bool AllConstant = setBasicExpressionInfo(I, E);
@@ -1149,8 +1172,8 @@ const Expression *NewGVN::createExpression(Instruction *I) const {
E->getOperand(1)->getType() == I->getOperand(1)->getType()));
Value *V =
SimplifyCmpInst(Predicate, E->getOperand(0), E->getOperand(1), SQ);
- if (const Expression *SimplifiedE = checkSimplificationResults(E, I, V))
- return SimplifiedE;
+ if (auto Simplified = checkExprResults(E, I, V))
+ return Simplified;
} else if (isa<SelectInst>(I)) {
if (isa<Constant>(E->getOperand(0)) ||
E->getOperand(1) == E->getOperand(2)) {
@@ -1158,24 +1181,24 @@ const Expression *NewGVN::createExpression(Instruction *I) const {
E->getOperand(2)->getType() == I->getOperand(2)->getType());
Value *V = SimplifySelectInst(E->getOperand(0), E->getOperand(1),
E->getOperand(2), SQ);
- if (const Expression *SimplifiedE = checkSimplificationResults(E, I, V))
- return SimplifiedE;
+ if (auto Simplified = checkExprResults(E, I, V))
+ return Simplified;
}
} else if (I->isBinaryOp()) {
Value *V =
SimplifyBinOp(E->getOpcode(), E->getOperand(0), E->getOperand(1), SQ);
- if (const Expression *SimplifiedE = checkSimplificationResults(E, I, V))
- return SimplifiedE;
+ if (auto Simplified = checkExprResults(E, I, V))
+ return Simplified;
} else if (auto *CI = dyn_cast<CastInst>(I)) {
Value *V =
SimplifyCastInst(CI->getOpcode(), E->getOperand(0), CI->getType(), SQ);
- if (const Expression *SimplifiedE = checkSimplificationResults(E, I, V))
- return SimplifiedE;
+ if (auto Simplified = checkExprResults(E, I, V))
+ return Simplified;
} else if (isa<GetElementPtrInst>(I)) {
Value *V = SimplifyGEPInst(
E->getType(), ArrayRef<Value *>(E->op_begin(), E->op_end()), SQ);
- if (const Expression *SimplifiedE = checkSimplificationResults(E, I, V))
- return SimplifiedE;
+ if (auto Simplified = checkExprResults(E, I, V))
+ return Simplified;
} else if (AllConstant) {
// We don't bother trying to simplify unless all of the operands
// were constant.
@@ -1189,10 +1212,10 @@ const Expression *NewGVN::createExpression(Instruction *I) const {
C.emplace_back(cast<Constant>(Arg));
if (Value *V = ConstantFoldInstOperands(I, C, DL, TLI))
- if (const Expression *SimplifiedE = checkSimplificationResults(E, I, V))
- return SimplifiedE;
+ if (auto Simplified = checkExprResults(E, I, V))
+ return Simplified;
}
- return E;
+ return ExprResult::some(E);
}
const AggregateValueExpression *
@@ -1527,17 +1550,17 @@ const Expression *NewGVN::performSymbolicLoadEvaluation(Instruction *I) const {
return LE;
}
-const Expression *
+NewGVN::ExprResult
NewGVN::performSymbolicPredicateInfoEvaluation(Instruction *I) const {
auto *PI = PredInfo->getPredicateInfoFor(I);
if (!PI)
- return nullptr;
+ return ExprResult::none();
LLVM_DEBUG(dbgs() << "Found predicate info from instruction !\n");
const Optional<PredicateConstraint> &Constraint = PI->getConstraint();
if (!Constraint)
- return nullptr;
+ return ExprResult::none();
CmpInst::Predicate Predicate = Constraint->Predicate;
Value *CmpOp0 = I->getOperand(0);
@@ -1554,45 +1577,43 @@ NewGVN::performSymbolicPredicateInfoEvaluation(Instruction *I) const {
AdditionallyUsedValue = CmpOp1;
}
- if (Predicate == CmpInst::ICMP_EQ) {
- addPredicateUsers(PI, I);
- addAdditionalUsers(AdditionallyUsedValue, I);
- return createVariableOrConstant(FirstOp);
- }
+ if (Predicate == CmpInst::ICMP_EQ)
+ return ExprResult::some(createVariableOrConstant(FirstOp),
+ AdditionallyUsedValue, PI);
// Handle the special case of floating point.
if (Predicate == CmpInst::FCMP_OEQ && isa<ConstantFP>(FirstOp) &&
- !cast<ConstantFP>(FirstOp)->isZero()) {
- addPredicateUsers(PI, I);
- addAdditionalUsers(AdditionallyUsedValue, I);
- return createConstantExpression(cast<Constant>(FirstOp));
- }
+ !cast<ConstantFP>(FirstOp)->isZero())
+ return ExprResult::some(createConstantExpression(cast<Constant>(FirstOp)),
+ AdditionallyUsedValue, PI);
- return nullptr;
+ return ExprResult::none();
}
// Evaluate read only and pure calls, and create an expression result.
-const Expression *NewGVN::performSymbolicCallEvaluation(Instruction *I) const {
+NewGVN::ExprResult NewGVN::performSymbolicCallEvaluation(Instruction *I) const {
auto *CI = cast<CallInst>(I);
if (auto *II = dyn_cast<IntrinsicInst>(I)) {
// Intrinsics with the returned attribute are copies of arguments.
if (auto *ReturnedValue = II->getReturnedArgOperand()) {
if (II->getIntrinsicID() == Intrinsic::ssa_copy)
- if (const auto *Result = performSymbolicPredicateInfoEvaluation(I))
- return Result;
- return createVariableOrConstant(ReturnedValue);
+ if (auto Res = performSymbolicPredicateInfoEvaluation(I))
+ return Res;
+ return ExprResult::some(createVariableOrConstant(ReturnedValue));
}
}
if (AA->doesNotAccessMemory(CI)) {
- return createCallExpression(CI, TOPClass->getMemoryLeader());
+ return ExprResult::some(
+ createCallExpression(CI, TOPClass->getMemoryLeader()));
} else if (AA->onlyReadsMemory(CI)) {
if (auto *MA = MSSA->getMemoryAccess(CI)) {
auto *DefiningAccess = MSSAWalker->getClobberingMemoryAccess(MA);
- return createCallExpression(CI, DefiningAccess);
+ return ExprResult::some(createCallExpression(CI, DefiningAccess));
} else // MSSA determined that CI does not access memory.
- return createCallExpression(CI, TOPClass->getMemoryLeader());
+ return ExprResult::some(
+ createCallExpression(CI, TOPClass->getMemoryLeader()));
}
- return nullptr;
+ return ExprResult::none();
}
// Retrieve the memory class for a given MemoryAccess.
@@ -1778,7 +1799,7 @@ NewGVN::performSymbolicAggrValueEvaluation(Instruction *I) const {
return createAggregateValueExpression(I);
}
-const Expression *NewGVN::performSymbolicCmpEvaluation(Instruction *I) const {
+NewGVN::ExprResult NewGVN::performSymbolicCmpEvaluation(Instruction *I) const {
assert(isa<CmpInst>(I) && "Expected a cmp instruction.");
auto *CI = cast<CmpInst>(I);
@@ -1798,14 +1819,17 @@ const Expression *NewGVN::performSymbolicCmpEvaluation(Instruction *I) const {
// of an assume.
auto *CmpPI = PredInfo->getPredicateInfoFor(I);
if (dyn_cast_or_null<PredicateAssume>(CmpPI))
- return createConstantExpression(ConstantInt::getTrue(CI->getType()));
+ return ExprResult::some(
+ createConstantExpression(ConstantInt::getTrue(CI->getType())));
if (Op0 == Op1) {
// This condition does not depend on predicates, no need to add users
if (CI->isTrueWhenEqual())
- return createConstantExpression(ConstantInt::getTrue(CI->getType()));
+ return ExprResult::some(
+ createConstantExpression(ConstantInt::getTrue(CI->getType())));
else if (CI->isFalseWhenEqual())
- return createConstantExpression(ConstantInt::getFalse(CI->getType()));
+ return ExprResult::some(
+ createConstantExpression(ConstantInt::getFalse(CI->getType())));
}
// NOTE: Because we are comparing both operands here and below, and using
@@ -1864,31 +1888,31 @@ const Expression *NewGVN::performSymbolicCmpEvaluation(Instruction *I) const {
// edge then we may be implied true or false.
if (CmpInst::isImpliedTrueByMatchingCmp(BranchPredicate,
OurPredicate)) {
- addPredicateUsers(PI, I);
- return createConstantExpression(
- ConstantInt::getTrue(CI->getType()));
+ return ExprResult::some(
+ createConstantExpression(ConstantInt::getTrue(CI->getType())),
+ PI);
}
if (CmpInst::isImpliedFalseByMatchingCmp(BranchPredicate,
OurPredicate)) {
- addPredicateUsers(PI, I);
- return createConstantExpression(
- ConstantInt::getFalse(CI->getType()));
+ return ExprResult::some(
+ createConstantExpression(ConstantInt::getFalse(CI->getType())),
+ PI);
}
} else {
// Just handle the ne and eq cases, where if we have the same
// operands, we may know something.
if (BranchPredicate == OurPredicate) {
- addPredicateUsers(PI, I);
// Same predicate, same ops,we know it was false, so this is false.
- return createConstantExpression(
- ConstantInt::getFalse(CI->getType()));
+ return ExprResult::some(
+ createConstantExpression(ConstantInt::getFalse(CI->getType())),
+ PI);
} else if (BranchPredicate ==
CmpInst::getInversePredicate(OurPredicate)) {
- addPredicateUsers(PI, I);
// Inverse predicate, we know the other was false, so this is true.
- return createConstantExpression(
- ConstantInt::getTrue(CI->getType()));
+ return ExprResult::some(
+ createConstantExpression(ConstantInt::getTrue(CI->getType())),
+ PI);
}
}
}
@@ -1899,9 +1923,10 @@ const Expression *NewGVN::performSymbolicCmpEvaluation(Instruction *I) const {
}
// Substitute and symbolize the value before value numbering.
-const Expression *
+NewGVN::ExprResult
NewGVN::performSymbolicEvaluation(Value *V,
SmallPtrSetImpl<Value *> &Visited) const {
+
const Expression *E = nullptr;
if (auto *C = dyn_cast<Constant>(V))
E = createConstantExpression(C);
@@ -1927,7 +1952,7 @@ NewGVN::performSymbolicEvaluation(Value *V,
E = performSymbolicPHIEvaluation(Ops, I, getBlockForValue(I));
} break;
case Instruction::Call:
- E = performSymbolicCallEvaluation(I);
+ return performSymbolicCallEvaluation(I);
break;
case Instruction::Store:
E = performSymbolicStoreEvaluation(I);
@@ -1937,11 +1962,11 @@ NewGVN::performSymbolicEvaluation(Value *V,
break;
case Instruction::BitCast:
case Instruction::AddrSpaceCast:
- E = createExpression(I);
+ return createExpression(I);
break;
case Instruction::ICmp:
case Instruction::FCmp:
- E = performSymbolicCmpEvaluation(I);
+ return performSymbolicCmpEvaluation(I);
break;
case Instruction::FNeg:
case Instruction::Add:
@@ -1977,16 +2002,16 @@ NewGVN::performSymbolicEvaluation(Value *V,
case Instruction::ExtractElement:
case Instruction::InsertElement:
case Instruction::GetElementPtr:
- E = createExpression(I);
+ return createExpression(I);
break;
case Instruction::ShuffleVector:
// FIXME: Add support for shufflevector to createExpression.
- return nullptr;
+ return ExprResult::none();
default:
- return nullptr;
+ return ExprResult::none();
}
}
- return E;
+ return ExprResult::some(E);
}
// Look up a container of values/instructions in a map, and touch all the
@@ -2007,6 +2032,20 @@ void NewGVN::addAdditionalUsers(Value *To, Value *User) const {
AdditionalUsers[To].insert(User);
}
+void NewGVN::addAdditionalUsers(ExprResult &Res, Instruction *User) const {
+ if (Res.ExtraDep && Res.ExtraDep != User)
+ addAdditionalUsers(Res.ExtraDep, User);
+ Res.ExtraDep = nullptr;
+
+ if (Res.PredDep) {
+ if (const auto *PBranch = dyn_cast<PredicateBranch>(Res.PredDep))
+ PredicateToUsers[PBranch->Condition].insert(User);
+ else if (const auto *PAssume = dyn_cast<PredicateAssume>(Res.PredDep))
+ PredicateToUsers[PAssume->Condition].insert(User);
+ }
+ Res.PredDep = nullptr;
+}
+
void NewGVN::markUsersTouched(Value *V) {
// Now mark the users as touched.
for (auto *User : V->users()) {
@@ -2033,18 +2072,6 @@ void NewGVN::markMemoryUsersTouched(const MemoryAccess *MA) {
touchAndErase(MemoryToUsers, MA);
}
-// Add I to the set of users of a given predicate.
-void NewGVN::addPredicateUsers(const PredicateBase *PB, Instruction *I) const {
- // Don't add temporary instructions to the user lists.
- if (AllTempInstructions.count(I))
- return;
-
- if (auto *PBranch = dyn_cast<PredicateBranch>(PB))
- PredicateToUsers[PBranch->Condition].insert(I);
- else if (auto *PAssume = dyn_cast<PredicateAssume>(PB))
- PredicateToUsers[PAssume->Condition].insert(I);
-}
-
// Touch all the predicates that depend on this instruction.
void NewGVN::markPredicateUsersTouched(Instruction *I) {
touchAndErase(PredicateToUsers, I);
@@ -2414,9 +2441,15 @@ void NewGVN::processOutgoingEdges(Instruction *TI, BasicBlock *B) {
Value *CondEvaluated = findConditionEquivalence(Cond);
if (!CondEvaluated) {
if (auto *I = dyn_cast<Instruction>(Cond)) {
- const Expression *E = createExpression(I);
- if (const auto *CE = dyn_cast<ConstantExpression>(E)) {
+ SmallPtrSet<Value *, 4> Visited;
+ auto Res = performSymbolicEvaluation(I, Visited);
+ if (const auto *CE = dyn_cast_or_null<ConstantExpression>(Res.Expr)) {
CondEvaluated = CE->getConstantValue();
+ addAdditionalUsers(Res, I);
+ } else {
+ // Did not use simplification result, no need to add the extra
+ // dependency.
+ Res.ExtraDep = nullptr;
}
} else if (isa<ConstantInt>(Cond)) {
CondEvaluated = Cond;
@@ -2600,7 +2633,9 @@ Value *NewGVN::findLeaderForInst(Instruction *TransInst,
TempToBlock.insert({TransInst, PredBB});
InstrDFS.insert({TransInst, IDFSNum});
- const Expression *E = performSymbolicEvaluation(TransInst, Visited);
+ auto Res = performSymbolicEvaluation(TransInst, Visited);
+ const Expression *E = Res.Expr;
+ addAdditionalUsers(Res, OrigInst);
InstrDFS.erase(TransInst);
AllTempInstructions.erase(TransInst);
TempToBlock.erase(TransInst);
@@ -2758,6 +2793,14 @@ NewGVN::makePossiblePHIOfOps(Instruction *I,
dbgs()
<< "Not creating real PHI of ops because it simplified to existing "
"value or constant\n");
+ // We have leaders for all operands, but do not create a real PHI node with
+ // those leaders as operands, so the link between the operands and the
+ // PHI-of-ops is not materialized in the IR. If any of those leaders
+ // changes, the PHI-of-op may change also, so we need to add the operands as
+ // additional users.
+ for (auto &O : PHIOps)
+ addAdditionalUsers(O.first, I);
+
return E;
}
auto *ValuePHI = RealToTemp.lookup(I);
@@ -3019,7 +3062,10 @@ void NewGVN::valueNumberInstruction(Instruction *I) {
const Expression *Symbolized = nullptr;
SmallPtrSet<Value *, 2> Visited;
if (DebugCounter::shouldExecute(VNCounter)) {
- Symbolized = performSymbolicEvaluation(I, Visited);
+ auto Res = performSymbolicEvaluation(I, Visited);
+ Symbolized = Res.Expr;
+ addAdditionalUsers(Res, I);
+
// Make a phi of ops if necessary
if (Symbolized && !isa<ConstantExpression>(Symbolized) &&
!isa<VariableExpression>(Symbolized) && PHINodeUses.count(I)) {
@@ -4176,6 +4222,5 @@ PreservedAnalyses NewGVNPass::run(Function &F, AnalysisManager<Function> &AM) {
return PreservedAnalyses::all();
PreservedAnalyses PA;
PA.preserve<DominatorTreeAnalysis>();
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/PartiallyInlineLibCalls.cpp b/llvm/lib/Transforms/Scalar/PartiallyInlineLibCalls.cpp
index 58763ec72ece..7872c553b412 100644
--- a/llvm/lib/Transforms/Scalar/PartiallyInlineLibCalls.cpp
+++ b/llvm/lib/Transforms/Scalar/PartiallyInlineLibCalls.cpp
@@ -13,8 +13,10 @@
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Scalar/PartiallyInlineLibCalls.h"
+#include "llvm/Analysis/DomTreeUpdater.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/IR/Dominators.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/DebugCounter.h"
@@ -30,7 +32,7 @@ DEBUG_COUNTER(PILCounter, "partially-inline-libcalls-transform",
static bool optimizeSQRT(CallInst *Call, Function *CalledFunc,
BasicBlock &CurrBB, Function::iterator &BB,
- const TargetTransformInfo *TTI) {
+ const TargetTransformInfo *TTI, DomTreeUpdater *DTU) {
// There is no need to change the IR, since backend will emit sqrt
// instruction if the call has already been marked read-only.
if (Call->onlyReadsMemory())
@@ -51,33 +53,44 @@ static bool optimizeSQRT(CallInst *Call, Function *CalledFunc,
// dst = phi(v0, v1)
//
- // Move all instructions following Call to newly created block JoinBB.
- // Create phi and replace all uses.
- BasicBlock *JoinBB = llvm::SplitBlock(&CurrBB, Call->getNextNode());
- IRBuilder<> Builder(JoinBB, JoinBB->begin());
Type *Ty = Call->getType();
+ IRBuilder<> Builder(Call->getNextNode());
+
+ // Split CurrBB right after the call, create a 'then' block (that branches
+ // back to split-off tail of CurrBB) into which we'll insert a libcall.
+ Instruction *LibCallTerm = SplitBlockAndInsertIfThen(
+ Builder.getTrue(), Call->getNextNode(), /*Unreachable=*/false,
+ /*BranchWeights*/ nullptr, DTU);
+
+ auto *CurrBBTerm = cast<BranchInst>(CurrBB.getTerminator());
+ // We want an 'else' block though, not a 'then' block.
+ cast<BranchInst>(CurrBBTerm)->swapSuccessors();
+
+ // Create phi that will merge results of either sqrt and replace all uses.
+ BasicBlock *JoinBB = LibCallTerm->getSuccessor(0);
+ JoinBB->setName(CurrBB.getName() + ".split");
+ Builder.SetInsertPoint(JoinBB, JoinBB->begin());
PHINode *Phi = Builder.CreatePHI(Ty, 2);
Call->replaceAllUsesWith(Phi);
- // Create basic block LibCallBB and insert a call to library function sqrt.
- BasicBlock *LibCallBB = BasicBlock::Create(CurrBB.getContext(), "call.sqrt",
- CurrBB.getParent(), JoinBB);
- Builder.SetInsertPoint(LibCallBB);
+ // Finally, insert the libcall into 'else' block.
+ BasicBlock *LibCallBB = LibCallTerm->getParent();
+ LibCallBB->setName("call.sqrt");
+ Builder.SetInsertPoint(LibCallTerm);
Instruction *LibCall = Call->clone();
Builder.Insert(LibCall);
- Builder.CreateBr(JoinBB);
// Add attribute "readnone" so that backend can use a native sqrt instruction
- // for this call. Insert a FP compare instruction and a conditional branch
- // at the end of CurrBB.
+ // for this call.
Call->addAttribute(AttributeList::FunctionIndex, Attribute::ReadNone);
- CurrBB.getTerminator()->eraseFromParent();
- Builder.SetInsertPoint(&CurrBB);
+
+ // Insert a FP compare instruction and use it as the CurrBB branch condition.
+ Builder.SetInsertPoint(CurrBBTerm);
Value *FCmp = TTI->isFCmpOrdCheaperThanFCmpZero(Ty)
? Builder.CreateFCmpORD(Call, Call)
: Builder.CreateFCmpOGE(Call->getOperand(0),
ConstantFP::get(Ty, 0.0));
- Builder.CreateCondBr(FCmp, JoinBB, LibCallBB);
+ CurrBBTerm->setCondition(FCmp);
// Add phi operands.
Phi->addIncoming(Call, &CurrBB);
@@ -88,7 +101,12 @@ static bool optimizeSQRT(CallInst *Call, Function *CalledFunc,
}
static bool runPartiallyInlineLibCalls(Function &F, TargetLibraryInfo *TLI,
- const TargetTransformInfo *TTI) {
+ const TargetTransformInfo *TTI,
+ DominatorTree *DT) {
+ Optional<DomTreeUpdater> DTU;
+ if (DT)
+ DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy);
+
bool Changed = false;
Function::iterator CurrBB;
@@ -103,7 +121,7 @@ static bool runPartiallyInlineLibCalls(Function &F, TargetLibraryInfo *TLI,
if (!Call || !(CalledFunc = Call->getCalledFunction()))
continue;
- if (Call->isNoBuiltin())
+ if (Call->isNoBuiltin() || Call->isStrictFP())
continue;
// Skip if function either has local linkage or is not a known library
@@ -117,7 +135,8 @@ static bool runPartiallyInlineLibCalls(Function &F, TargetLibraryInfo *TLI,
case LibFunc_sqrtf:
case LibFunc_sqrt:
if (TTI->haveFastSqrt(Call->getType()) &&
- optimizeSQRT(Call, CalledFunc, *CurrBB, BB, TTI))
+ optimizeSQRT(Call, CalledFunc, *CurrBB, BB, TTI,
+ DTU.hasValue() ? DTU.getPointer() : nullptr))
break;
continue;
default:
@@ -136,9 +155,12 @@ PreservedAnalyses
PartiallyInlineLibCallsPass::run(Function &F, FunctionAnalysisManager &AM) {
auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
auto &TTI = AM.getResult<TargetIRAnalysis>(F);
- if (!runPartiallyInlineLibCalls(F, &TLI, &TTI))
+ auto *DT = AM.getCachedResult<DominatorTreeAnalysis>(F);
+ if (!runPartiallyInlineLibCalls(F, &TLI, &TTI, DT))
return PreservedAnalyses::all();
- return PreservedAnalyses::none();
+ PreservedAnalyses PA;
+ PA.preserve<DominatorTreeAnalysis>();
+ return PA;
}
namespace {
@@ -154,6 +176,7 @@ public:
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<TargetLibraryInfoWrapperPass>();
AU.addRequired<TargetTransformInfoWrapperPass>();
+ AU.addPreserved<DominatorTreeWrapperPass>();
FunctionPass::getAnalysisUsage(AU);
}
@@ -165,7 +188,10 @@ public:
&getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
const TargetTransformInfo *TTI =
&getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
- return runPartiallyInlineLibCalls(F, TLI, TTI);
+ DominatorTree *DT = nullptr;
+ if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
+ DT = &DTWP->getDomTree();
+ return runPartiallyInlineLibCalls(F, TLI, TTI, DT);
}
};
}
@@ -176,6 +202,7 @@ INITIALIZE_PASS_BEGIN(PartiallyInlineLibCallsLegacyPass,
"Partially inline calls to library functions", false,
false)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
INITIALIZE_PASS_END(PartiallyInlineLibCallsLegacyPass,
"partially-inline-libcalls",
diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp
index dffeb7cc227b..888edc4d69a8 100644
--- a/llvm/lib/Transforms/Scalar/Reassociate.cpp
+++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp
@@ -975,12 +975,13 @@ static bool isLoadCombineCandidate(Instruction *Or) {
}
/// Return true if it may be profitable to convert this (X|Y) into (X+Y).
-static bool ShouldConvertOrWithNoCommonBitsToAdd(Instruction *Or) {
+static bool shouldConvertOrWithNoCommonBitsToAdd(Instruction *Or) {
// Don't bother to convert this up unless either the LHS is an associable add
// or subtract or mul or if this is only used by one of the above.
// This is only a compile-time improvement, it is not needed for correctness!
auto isInteresting = [](Value *V) {
- for (auto Op : {Instruction::Add, Instruction::Sub, Instruction::Mul})
+ for (auto Op : {Instruction::Add, Instruction::Sub, Instruction::Mul,
+ Instruction::Shl})
if (isReassociableOp(V, Op))
return true;
return false;
@@ -998,7 +999,7 @@ static bool ShouldConvertOrWithNoCommonBitsToAdd(Instruction *Or) {
/// If we have (X|Y), and iff X and Y have no common bits set,
/// transform this into (X+Y) to allow arithmetics reassociation.
-static BinaryOperator *ConvertOrWithNoCommonBitsToAdd(Instruction *Or) {
+static BinaryOperator *convertOrWithNoCommonBitsToAdd(Instruction *Or) {
// Convert an or into an add.
BinaryOperator *New =
CreateAdd(Or->getOperand(0), Or->getOperand(1), "", Or, Or);
@@ -2212,11 +2213,11 @@ void ReassociatePass::OptimizeInst(Instruction *I) {
// If this is a bitwise or instruction of operands
// with no common bits set, convert it to X+Y.
if (I->getOpcode() == Instruction::Or &&
- ShouldConvertOrWithNoCommonBitsToAdd(I) && !isLoadCombineCandidate(I) &&
+ shouldConvertOrWithNoCommonBitsToAdd(I) && !isLoadCombineCandidate(I) &&
haveNoCommonBitsSet(I->getOperand(0), I->getOperand(1),
I->getModule()->getDataLayout(), /*AC=*/nullptr, I,
/*DT=*/nullptr)) {
- Instruction *NI = ConvertOrWithNoCommonBitsToAdd(I);
+ Instruction *NI = convertOrWithNoCommonBitsToAdd(I);
RedoInsts.insert(I);
MadeChange = true;
I = NI;
@@ -2567,9 +2568,6 @@ PreservedAnalyses ReassociatePass::run(Function &F, FunctionAnalysisManager &) {
if (MadeChange) {
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
- PA.preserve<AAManager>();
- PA.preserve<BasicAA>();
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
index b7830555bf73..bc0fecc972fc 100644
--- a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
+++ b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
@@ -522,6 +522,14 @@ static BaseDefiningValueResult findBaseDefiningValue(Value *I) {
ConstantPointerNull::get(cast<PointerType>(I->getType())), true);
}
+ // inttoptrs in an integral address space are currently ill-defined. We
+ // treat them as defining base pointers here for consistency with the
+ // constant rule above and because we don't really have a better semantic
+ // to give them. Note that the optimizer is always free to insert undefined
+ // behavior on dynamically dead paths as well.
+ if (isa<IntToPtrInst>(I))
+ return BaseDefiningValueResult(I, true);
+
if (CastInst *CI = dyn_cast<CastInst>(I)) {
Value *Def = CI->stripPointerCasts();
// If stripping pointer casts changes the address space there is an
@@ -562,6 +570,8 @@ static BaseDefiningValueResult findBaseDefiningValue(Value *I) {
// implications much.
llvm_unreachable(
"interaction with the gcroot mechanism is not supported");
+ case Intrinsic::experimental_gc_get_pointer_base:
+ return findBaseDefiningValue(II->getOperand(0));
}
}
// We assume that functions in the source language only return base
@@ -594,6 +604,11 @@ static BaseDefiningValueResult findBaseDefiningValue(Value *I) {
assert(!isa<InsertValueInst>(I) &&
"Base pointer for a struct is meaningless");
+ // This value might have been generated by findBasePointer() called when
+ // substituting gc.get.pointer.base() intrinsic.
+ bool IsKnownBase =
+ isa<Instruction>(I) && cast<Instruction>(I)->getMetadata("is_base_value");
+
// An extractelement produces a base result exactly when it's input does.
// We may need to insert a parallel instruction to extract the appropriate
// element out of the base vector corresponding to the input. Given this,
@@ -602,7 +617,7 @@ static BaseDefiningValueResult findBaseDefiningValue(Value *I) {
// Note: There a lot of obvious peephole cases here. This are deliberately
// handled after the main base pointer inference algorithm to make writing
// test cases to exercise that code easier.
- return BaseDefiningValueResult(I, false);
+ return BaseDefiningValueResult(I, IsKnownBase);
// The last two cases here don't return a base pointer. Instead, they
// return a value which dynamically selects from among several base
@@ -610,7 +625,7 @@ static BaseDefiningValueResult findBaseDefiningValue(Value *I) {
// the caller to resolve these.
assert((isa<SelectInst>(I) || isa<PHINode>(I)) &&
"missing instruction case in findBaseDefiningValing");
- return BaseDefiningValueResult(I, false);
+ return BaseDefiningValueResult(I, IsKnownBase);
}
/// Returns the base defining value for this value.
@@ -676,26 +691,72 @@ namespace {
/// the base of this BDV.
class BDVState {
public:
- enum Status { Unknown, Base, Conflict };
+ enum StatusTy {
+ // Starting state of lattice
+ Unknown,
+ // Some specific base value -- does *not* mean that instruction
+ // propagates the base of the object
+ // ex: gep %arg, 16 -> %arg is the base value
+ Base,
+ // Need to insert a node to represent a merge.
+ Conflict
+ };
- BDVState() : BaseValue(nullptr) {}
+ BDVState() {
+ llvm_unreachable("missing state in map");
+ }
- explicit BDVState(Status Status, Value *BaseValue = nullptr)
- : Status(Status), BaseValue(BaseValue) {
+ explicit BDVState(Value *OriginalValue)
+ : OriginalValue(OriginalValue) {}
+ explicit BDVState(Value *OriginalValue, StatusTy Status, Value *BaseValue = nullptr)
+ : OriginalValue(OriginalValue), Status(Status), BaseValue(BaseValue) {
assert(Status != Base || BaseValue);
}
- explicit BDVState(Value *BaseValue) : Status(Base), BaseValue(BaseValue) {}
-
- Status getStatus() const { return Status; }
+ StatusTy getStatus() const { return Status; }
+ Value *getOriginalValue() const { return OriginalValue; }
Value *getBaseValue() const { return BaseValue; }
bool isBase() const { return getStatus() == Base; }
bool isUnknown() const { return getStatus() == Unknown; }
bool isConflict() const { return getStatus() == Conflict; }
+ // Values of type BDVState form a lattice, and this function implements the
+ // meet
+ // operation.
+ void meet(const BDVState &Other) {
+ auto markConflict = [&]() {
+ Status = BDVState::Conflict;
+ BaseValue = nullptr;
+ };
+ // Conflict is a final state.
+ if (isConflict())
+ return;
+ // if we are not known - just take other state.
+ if (isUnknown()) {
+ Status = Other.getStatus();
+ BaseValue = Other.getBaseValue();
+ return;
+ }
+ // We are base.
+ assert(isBase() && "Unknown state");
+ // If other is unknown - just keep our state.
+ if (Other.isUnknown())
+ return;
+ // If other is conflict - it is a final state.
+ if (Other.isConflict())
+ return markConflict();
+ // Other is base as well.
+ assert(Other.isBase() && "Unknown state");
+ // If bases are different - Conflict.
+ if (getBaseValue() != Other.getBaseValue())
+ return markConflict();
+ // We are identical, do nothing.
+ }
+
bool operator==(const BDVState &Other) const {
- return BaseValue == Other.BaseValue && Status == Other.Status;
+ return OriginalValue == OriginalValue && BaseValue == Other.BaseValue &&
+ Status == Other.Status;
}
bool operator!=(const BDVState &other) const { return !(*this == other); }
@@ -718,13 +779,15 @@ public:
OS << "C";
break;
}
- OS << " (" << getBaseValue() << " - "
- << (getBaseValue() ? getBaseValue()->getName() : "nullptr") << "): ";
+ OS << " (base " << getBaseValue() << " - "
+ << (getBaseValue() ? getBaseValue()->getName() : "nullptr") << ")"
+ << " for " << OriginalValue->getName() << ":";
}
private:
- Status Status = Unknown;
- AssertingVH<Value> BaseValue; // Non-null only if Status == Base.
+ AssertingVH<Value> OriginalValue; // instruction this state corresponds to
+ StatusTy Status = Unknown;
+ AssertingVH<Value> BaseValue = nullptr; // Non-null only if Status == Base.
};
} // end anonymous namespace
@@ -736,41 +799,6 @@ static raw_ostream &operator<<(raw_ostream &OS, const BDVState &State) {
}
#endif
-static BDVState meetBDVStateImpl(const BDVState &LHS, const BDVState &RHS) {
- switch (LHS.getStatus()) {
- case BDVState::Unknown:
- return RHS;
-
- case BDVState::Base:
- assert(LHS.getBaseValue() && "can't be null");
- if (RHS.isUnknown())
- return LHS;
-
- if (RHS.isBase()) {
- if (LHS.getBaseValue() == RHS.getBaseValue()) {
- assert(LHS == RHS && "equality broken!");
- return LHS;
- }
- return BDVState(BDVState::Conflict);
- }
- assert(RHS.isConflict() && "only three states!");
- return BDVState(BDVState::Conflict);
-
- case BDVState::Conflict:
- return LHS;
- }
- llvm_unreachable("only three states!");
-}
-
-// Values of type BDVState form a lattice, and this function implements the meet
-// operation.
-static BDVState meetBDVState(const BDVState &LHS, const BDVState &RHS) {
- BDVState Result = meetBDVStateImpl(LHS, RHS);
- assert(Result == meetBDVStateImpl(RHS, LHS) &&
- "Math is wrong: meet does not commute!");
- return Result;
-}
-
/// For a given value or instruction, figure out what base ptr its derived from.
/// For gc objects, this is simply itself. On success, returns a value which is
/// the base pointer. (This is reliable and can be used for relocation.) On
@@ -818,12 +846,44 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
// below. This is important for deterministic compilation.
MapVector<Value *, BDVState> States;
+#ifndef NDEBUG
+ auto VerifyStates = [&]() {
+ for (auto &Entry : States) {
+ assert(Entry.first == Entry.second.getOriginalValue());
+ }
+ };
+#endif
+
+ auto visitBDVOperands = [](Value *BDV, std::function<void (Value*)> F) {
+ if (PHINode *PN = dyn_cast<PHINode>(BDV)) {
+ for (Value *InVal : PN->incoming_values())
+ F(InVal);
+ } else if (SelectInst *SI = dyn_cast<SelectInst>(BDV)) {
+ F(SI->getTrueValue());
+ F(SI->getFalseValue());
+ } else if (auto *EE = dyn_cast<ExtractElementInst>(BDV)) {
+ F(EE->getVectorOperand());
+ } else if (auto *IE = dyn_cast<InsertElementInst>(BDV)) {
+ F(IE->getOperand(0));
+ F(IE->getOperand(1));
+ } else if (auto *SV = dyn_cast<ShuffleVectorInst>(BDV)) {
+ // For a canonical broadcast, ignore the undef argument
+ // (without this, we insert a parallel base shuffle for every broadcast)
+ F(SV->getOperand(0));
+ if (!SV->isZeroEltSplat())
+ F(SV->getOperand(1));
+ } else {
+ llvm_unreachable("unexpected BDV type");
+ }
+ };
+
+
// Recursively fill in all base defining values reachable from the initial
// one for which we don't already know a definite base value for
/* scope */ {
SmallVector<Value*, 16> Worklist;
Worklist.push_back(Def);
- States.insert({Def, BDVState()});
+ States.insert({Def, BDVState(Def)});
while (!Worklist.empty()) {
Value *Current = Worklist.pop_back_val();
assert(!isOriginalBaseResult(Current) && "why did it get added?");
@@ -839,45 +899,67 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
return;
assert(isExpectedBDVType(Base) && "the only non-base values "
"we see should be base defining values");
- if (States.insert(std::make_pair(Base, BDVState())).second)
+ if (States.insert(std::make_pair(Base, BDVState(Base))).second)
Worklist.push_back(Base);
};
- if (PHINode *PN = dyn_cast<PHINode>(Current)) {
- for (Value *InVal : PN->incoming_values())
- visitIncomingValue(InVal);
- } else if (SelectInst *SI = dyn_cast<SelectInst>(Current)) {
- visitIncomingValue(SI->getTrueValue());
- visitIncomingValue(SI->getFalseValue());
- } else if (auto *EE = dyn_cast<ExtractElementInst>(Current)) {
- visitIncomingValue(EE->getVectorOperand());
- } else if (auto *IE = dyn_cast<InsertElementInst>(Current)) {
- visitIncomingValue(IE->getOperand(0)); // vector operand
- visitIncomingValue(IE->getOperand(1)); // scalar operand
- } else if (auto *SV = dyn_cast<ShuffleVectorInst>(Current)) {
- visitIncomingValue(SV->getOperand(0));
- visitIncomingValue(SV->getOperand(1));
- }
- else {
- llvm_unreachable("Unimplemented instruction case");
- }
+
+ visitBDVOperands(Current, visitIncomingValue);
}
}
#ifndef NDEBUG
+ VerifyStates();
LLVM_DEBUG(dbgs() << "States after initialization:\n");
for (auto Pair : States) {
LLVM_DEBUG(dbgs() << " " << Pair.second << " for " << *Pair.first << "\n");
}
#endif
+ // Iterate forward through the value graph pruning any node from the state
+ // list where all of the inputs are base pointers. The purpose of this is to
+ // reuse existing values when the derived pointer we were asked to materialize
+ // a base pointer for happens to be a base pointer itself. (Or a sub-graph
+ // feeding it does.)
+ SmallVector<Value *> ToRemove;
+ do {
+ ToRemove.clear();
+ for (auto Pair : States) {
+ Value *BDV = Pair.first;
+ auto canPruneInput = [&](Value *V) {
+ Value *BDV = findBaseOrBDV(V, Cache);
+ if (V->stripPointerCasts() != BDV)
+ return false;
+ // The assumption is that anything not in the state list is
+ // propagates a base pointer.
+ return States.count(BDV) == 0;
+ };
+
+ bool CanPrune = true;
+ visitBDVOperands(BDV, [&](Value *Op) {
+ CanPrune = CanPrune && canPruneInput(Op);
+ });
+ if (CanPrune)
+ ToRemove.push_back(BDV);
+ }
+ for (Value *V : ToRemove) {
+ States.erase(V);
+ // Cache the fact V is it's own base for later usage.
+ Cache[V] = V;
+ }
+ } while (!ToRemove.empty());
+
+ // Did we manage to prove that Def itself must be a base pointer?
+ if (!States.count(Def))
+ return Def;
+
// Return a phi state for a base defining value. We'll generate a new
// base state for known bases and expect to find a cached state otherwise.
auto GetStateForBDV = [&](Value *BaseValue, Value *Input) {
- if (isKnownBaseResult(BaseValue) && areBothVectorOrScalar(BaseValue, Input))
- return BDVState(BaseValue);
auto I = States.find(BaseValue);
- assert(I != States.end() && "lookup failed!");
- return I->second;
+ if (I != States.end())
+ return I->second;
+ assert(areBothVectorOrScalar(BaseValue, Input));
+ return BDVState(BaseValue, BDVState::Base, BaseValue);
};
bool Progress = true;
@@ -899,38 +981,12 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
!areBothVectorOrScalar(BDV, Pair.second.getBaseValue())) &&
"why did it get added?");
- // Given an input value for the current instruction, return a BDVState
- // instance which represents the BDV of that value.
- auto getStateForInput = [&](Value *V) mutable {
- Value *BDV = findBaseOrBDV(V, Cache);
- return GetStateForBDV(BDV, V);
- };
-
- BDVState NewState;
- if (SelectInst *SI = dyn_cast<SelectInst>(BDV)) {
- NewState = meetBDVState(NewState, getStateForInput(SI->getTrueValue()));
- NewState =
- meetBDVState(NewState, getStateForInput(SI->getFalseValue()));
- } else if (PHINode *PN = dyn_cast<PHINode>(BDV)) {
- for (Value *Val : PN->incoming_values())
- NewState = meetBDVState(NewState, getStateForInput(Val));
- } else if (auto *EE = dyn_cast<ExtractElementInst>(BDV)) {
- // The 'meet' for an extractelement is slightly trivial, but it's still
- // useful in that it drives us to conflict if our input is.
- NewState =
- meetBDVState(NewState, getStateForInput(EE->getVectorOperand()));
- } else if (auto *IE = dyn_cast<InsertElementInst>(BDV)){
- // Given there's a inherent type mismatch between the operands, will
- // *always* produce Conflict.
- NewState = meetBDVState(NewState, getStateForInput(IE->getOperand(0)));
- NewState = meetBDVState(NewState, getStateForInput(IE->getOperand(1)));
- } else {
- // The only instance this does not return a Conflict is when both the
- // vector operands are the same vector.
- auto *SV = cast<ShuffleVectorInst>(BDV);
- NewState = meetBDVState(NewState, getStateForInput(SV->getOperand(0)));
- NewState = meetBDVState(NewState, getStateForInput(SV->getOperand(1)));
- }
+ BDVState NewState(BDV);
+ visitBDVOperands(BDV, [&](Value *Op) {
+ Value *BDV = findBaseOrBDV(Op, Cache);
+ auto OpState = GetStateForBDV(BDV, Op);
+ NewState.meet(OpState);
+ });
BDVState OldState = States[BDV];
if (OldState != NewState) {
@@ -944,6 +1000,7 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
}
#ifndef NDEBUG
+ VerifyStates();
LLVM_DEBUG(dbgs() << "States after meet iteration:\n");
for (auto Pair : States) {
LLVM_DEBUG(dbgs() << " " << Pair.second << " for " << *Pair.first << "\n");
@@ -977,17 +1034,21 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
auto *BaseInst = ExtractElementInst::Create(
State.getBaseValue(), EE->getIndexOperand(), "base_ee", EE);
BaseInst->setMetadata("is_base_value", MDNode::get(I->getContext(), {}));
- States[I] = BDVState(BDVState::Base, BaseInst);
+ States[I] = BDVState(I, BDVState::Base, BaseInst);
} else if (!isa<VectorType>(I->getType())) {
// We need to handle cases that have a vector base but the instruction is
// a scalar type (these could be phis or selects or any instruction that
// are of scalar type, but the base can be a vector type). We
// conservatively set this as conflict. Setting the base value for these
// conflicts is handled in the next loop which traverses States.
- States[I] = BDVState(BDVState::Conflict);
+ States[I] = BDVState(I, BDVState::Conflict);
}
}
+#ifndef NDEBUG
+ VerifyStates();
+#endif
+
// Insert Phis for all conflicts
// TODO: adjust naming patterns to avoid this order of iteration dependency
for (auto Pair : States) {
@@ -1008,45 +1069,32 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
if (!State.isConflict())
continue;
- /// Create and insert a new instruction which will represent the base of
- /// the given instruction 'I'.
- auto MakeBaseInstPlaceholder = [](Instruction *I) -> Instruction* {
+ auto getMangledName = [](Instruction *I) -> std::string {
if (isa<PHINode>(I)) {
- BasicBlock *BB = I->getParent();
- int NumPreds = pred_size(BB);
- assert(NumPreds > 0 && "how did we reach here");
- std::string Name = suffixed_name_or(I, ".base", "base_phi");
- return PHINode::Create(I->getType(), NumPreds, Name, I);
- } else if (SelectInst *SI = dyn_cast<SelectInst>(I)) {
- // The undef will be replaced later
- UndefValue *Undef = UndefValue::get(SI->getType());
- std::string Name = suffixed_name_or(I, ".base", "base_select");
- return SelectInst::Create(SI->getCondition(), Undef, Undef, Name, SI);
- } else if (auto *EE = dyn_cast<ExtractElementInst>(I)) {
- UndefValue *Undef = UndefValue::get(EE->getVectorOperand()->getType());
- std::string Name = suffixed_name_or(I, ".base", "base_ee");
- return ExtractElementInst::Create(Undef, EE->getIndexOperand(), Name,
- EE);
- } else if (auto *IE = dyn_cast<InsertElementInst>(I)) {
- UndefValue *VecUndef = UndefValue::get(IE->getOperand(0)->getType());
- UndefValue *ScalarUndef = UndefValue::get(IE->getOperand(1)->getType());
- std::string Name = suffixed_name_or(I, ".base", "base_ie");
- return InsertElementInst::Create(VecUndef, ScalarUndef,
- IE->getOperand(2), Name, IE);
+ return suffixed_name_or(I, ".base", "base_phi");
+ } else if (isa<SelectInst>(I)) {
+ return suffixed_name_or(I, ".base", "base_select");
+ } else if (isa<ExtractElementInst>(I)) {
+ return suffixed_name_or(I, ".base", "base_ee");
+ } else if (isa<InsertElementInst>(I)) {
+ return suffixed_name_or(I, ".base", "base_ie");
} else {
- auto *SV = cast<ShuffleVectorInst>(I);
- UndefValue *VecUndef = UndefValue::get(SV->getOperand(0)->getType());
- std::string Name = suffixed_name_or(I, ".base", "base_sv");
- return new ShuffleVectorInst(VecUndef, VecUndef, SV->getShuffleMask(),
- Name, SV);
+ return suffixed_name_or(I, ".base", "base_sv");
}
};
- Instruction *BaseInst = MakeBaseInstPlaceholder(I);
+
+ Instruction *BaseInst = I->clone();
+ BaseInst->insertBefore(I);
+ BaseInst->setName(getMangledName(I));
// Add metadata marking this as a base value
BaseInst->setMetadata("is_base_value", MDNode::get(I->getContext(), {}));
- States[I] = BDVState(BDVState::Conflict, BaseInst);
+ States[I] = BDVState(I, BDVState::Conflict, BaseInst);
}
+#ifndef NDEBUG
+ VerifyStates();
+#endif
+
// Returns a instruction which produces the base pointer for a given
// instruction. The instruction is assumed to be an input to one of the BDVs
// seen in the inference algorithm above. As such, we must either already
@@ -1058,7 +1106,8 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
auto getBaseForInput = [&](Value *Input, Instruction *InsertPt) {
Value *BDV = findBaseOrBDV(Input, Cache);
Value *Base = nullptr;
- if (isKnownBaseResult(BDV) && areBothVectorOrScalar(BDV, Input)) {
+ if (!States.count(BDV)) {
+ assert(areBothVectorOrScalar(BDV, Input));
Base = BDV;
} else {
// Either conflict or base.
@@ -1091,26 +1140,21 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
if (PHINode *BasePHI = dyn_cast<PHINode>(State.getBaseValue())) {
PHINode *PN = cast<PHINode>(BDV);
- unsigned NumPHIValues = PN->getNumIncomingValues();
+ const unsigned NumPHIValues = PN->getNumIncomingValues();
+
+ // The IR verifier requires phi nodes with multiple entries from the
+ // same basic block to have the same incoming value for each of those
+ // entries. Since we're inserting bitcasts in the loop, make sure we
+ // do so at least once per incoming block.
+ DenseMap<BasicBlock *, Value*> BlockToValue;
for (unsigned i = 0; i < NumPHIValues; i++) {
Value *InVal = PN->getIncomingValue(i);
BasicBlock *InBB = PN->getIncomingBlock(i);
-
- // If we've already seen InBB, add the same incoming value
- // we added for it earlier. The IR verifier requires phi
- // nodes with multiple entries from the same basic block
- // to have the same incoming value for each of those
- // entries. If we don't do this check here and basephi
- // has a different type than base, we'll end up adding two
- // bitcasts (and hence two distinct values) as incoming
- // values for the same basic block.
-
- int BlockIndex = BasePHI->getBasicBlockIndex(InBB);
- if (BlockIndex != -1) {
- Value *OldBase = BasePHI->getIncomingValue(BlockIndex);
- BasePHI->addIncoming(OldBase, InBB);
-
+ if (!BlockToValue.count(InBB))
+ BlockToValue[InBB] = getBaseForInput(InVal, InBB->getTerminator());
+ else {
#ifndef NDEBUG
+ Value *OldBase = BlockToValue[InBB];
Value *Base = getBaseForInput(InVal, nullptr);
// In essence this assert states: the only way two values
// incoming from the same basic block may be different is by
@@ -1121,16 +1165,10 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
assert(Base->stripPointerCasts() == OldBase->stripPointerCasts() &&
"Sanity -- findBaseOrBDV should be pure!");
#endif
- continue;
}
-
- // Find the instruction which produces the base for each input. We may
- // need to insert a bitcast in the incoming block.
- // TODO: Need to split critical edges if insertion is needed
- Value *Base = getBaseForInput(InVal, InBB->getTerminator());
- BasePHI->addIncoming(Base, InBB);
+ Value *Base = BlockToValue[InBB];
+ BasePHI->setIncomingValue(i, Base);
}
- assert(BasePHI->getNumIncomingValues() == NumPHIValues);
} else if (SelectInst *BaseSI =
dyn_cast<SelectInst>(State.getBaseValue())) {
SelectInst *SI = cast<SelectInst>(BDV);
@@ -1163,10 +1201,20 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
BaseSV->setOperand(OperandIdx, Base);
};
UpdateOperand(0); // vector operand
- UpdateOperand(1); // vector operand
+ if (!BdvSV->isZeroEltSplat())
+ UpdateOperand(1); // vector operand
+ else {
+ // Never read, so just use undef
+ Value *InVal = BdvSV->getOperand(1);
+ BaseSV->setOperand(1, UndefValue::get(InVal->getType()));
+ }
}
}
+#ifndef NDEBUG
+ VerifyStates();
+#endif
+
// Cache all of our results so we can cheaply reuse them
// NOTE: This is actually two caches: one of the base defining value
// relation and one of the base pointer relation! FIXME
@@ -1186,14 +1234,6 @@ static Value *findBasePointer(Value *I, DefiningValueMapTy &Cache) {
<< (Cache.count(BDV) ? Cache[BDV]->getName().str() : "none")
<< " to: " << Base->getName() << "\n");
- if (Cache.count(BDV)) {
- assert(isKnownBaseResult(Base) &&
- "must be something we 'know' is a base pointer");
- // Once we transition from the BDV relation being store in the Cache to
- // the base relation being stored, it must be stable
- assert((!isKnownBaseResult(Cache[BDV]) || Cache[BDV] == Base) &&
- "base relation should be stable");
- }
Cache[BDV] = Base;
}
assert(Cache.count(Def));
@@ -1236,7 +1276,20 @@ static void findBasePointers(DominatorTree &DT, DefiningValueMapTy &DVCache,
CallBase *Call,
PartiallyConstructedSafepointRecord &result) {
MapVector<Value *, Value *> PointerToBase;
- findBasePointers(result.LiveSet, PointerToBase, &DT, DVCache);
+ StatepointLiveSetTy PotentiallyDerivedPointers = result.LiveSet;
+ // We assume that all pointers passed to deopt are base pointers; as an
+ // optimization, we can use this to avoid seperately materializing the base
+ // pointer graph. This is only relevant since we're very conservative about
+ // generating new conflict nodes during base pointer insertion. If we were
+ // smarter there, this would be irrelevant.
+ if (auto Opt = Call->getOperandBundle(LLVMContext::OB_deopt))
+ for (Value *V : Opt->Inputs) {
+ if (!PotentiallyDerivedPointers.count(V))
+ continue;
+ PotentiallyDerivedPointers.remove(V);
+ PointerToBase[V] = V;
+ }
+ findBasePointers(PotentiallyDerivedPointers, PointerToBase, &DT, DVCache);
if (PrintBasePointers) {
errs() << "Base Pairs (w/o Relocation):\n";
@@ -1295,6 +1348,27 @@ normalizeForInvokeSafepoint(BasicBlock *BB, BasicBlock *InvokeParent,
return Ret;
}
+// List of all function attributes which must be stripped when lowering from
+// abstract machine model to physical machine model. Essentially, these are
+// all the effects a safepoint might have which we ignored in the abstract
+// machine model for purposes of optimization. We have to strip these on
+// both function declarations and call sites.
+static constexpr Attribute::AttrKind FnAttrsToStrip[] =
+ {Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly,
+ Attribute::ArgMemOnly, Attribute::InaccessibleMemOnly,
+ Attribute::InaccessibleMemOrArgMemOnly,
+ Attribute::NoSync, Attribute::NoFree};
+
+// List of all parameter and return attributes which must be stripped when
+// lowering from the abstract machine model. Note that we list attributes
+// here which aren't valid as return attributes, that is okay. There are
+// also some additional attributes with arguments which are handled
+// explicitly and are not in this list.
+static constexpr Attribute::AttrKind ParamAttrsToStrip[] =
+ {Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly,
+ Attribute::NoAlias, Attribute::NoFree};
+
+
// Create new attribute set containing only attributes which can be transferred
// from original call to the safepoint.
static AttributeList legalizeCallAttributes(LLVMContext &Ctx,
@@ -1304,8 +1378,9 @@ static AttributeList legalizeCallAttributes(LLVMContext &Ctx,
// Remove the readonly, readnone, and statepoint function attributes.
AttrBuilder FnAttrs = AL.getFnAttributes();
- FnAttrs.removeAttribute(Attribute::ReadNone);
- FnAttrs.removeAttribute(Attribute::ReadOnly);
+ for (auto Attr : FnAttrsToStrip)
+ FnAttrs.removeAttribute(Attr);
+
for (Attribute A : AL.getFnAttributes()) {
if (isStatepointDirectiveAttr(A))
FnAttrs.remove(A);
@@ -2324,9 +2399,60 @@ static void rematerializeLiveValues(CallBase *Call,
}
}
+static bool inlineGetBaseAndOffset(Function &F,
+ SmallVectorImpl<CallInst *> &Intrinsics,
+ DefiningValueMapTy &DVCache) {
+ auto &Context = F.getContext();
+ auto &DL = F.getParent()->getDataLayout();
+ bool Changed = false;
+
+ for (auto *Callsite : Intrinsics)
+ switch (Callsite->getIntrinsicID()) {
+ case Intrinsic::experimental_gc_get_pointer_base: {
+ Changed = true;
+ Value *Base = findBasePointer(Callsite->getOperand(0), DVCache);
+ assert(!DVCache.count(Callsite));
+ auto *BaseBC = IRBuilder<>(Callsite).CreateBitCast(
+ Base, Callsite->getType(), suffixed_name_or(Base, ".cast", ""));
+ if (BaseBC != Base)
+ DVCache[BaseBC] = Base;
+ Callsite->replaceAllUsesWith(BaseBC);
+ if (!BaseBC->hasName())
+ BaseBC->takeName(Callsite);
+ Callsite->eraseFromParent();
+ break;
+ }
+ case Intrinsic::experimental_gc_get_pointer_offset: {
+ Changed = true;
+ Value *Derived = Callsite->getOperand(0);
+ Value *Base = findBasePointer(Derived, DVCache);
+ assert(!DVCache.count(Callsite));
+ unsigned AddressSpace = Derived->getType()->getPointerAddressSpace();
+ unsigned IntPtrSize = DL.getPointerSizeInBits(AddressSpace);
+ IRBuilder<> Builder(Callsite);
+ Value *BaseInt =
+ Builder.CreatePtrToInt(Base, Type::getIntNTy(Context, IntPtrSize),
+ suffixed_name_or(Base, ".int", ""));
+ Value *DerivedInt =
+ Builder.CreatePtrToInt(Derived, Type::getIntNTy(Context, IntPtrSize),
+ suffixed_name_or(Derived, ".int", ""));
+ Value *Offset = Builder.CreateSub(DerivedInt, BaseInt);
+ Callsite->replaceAllUsesWith(Offset);
+ Offset->takeName(Callsite);
+ Callsite->eraseFromParent();
+ break;
+ }
+ default:
+ llvm_unreachable("Unknown intrinsic");
+ }
+
+ return Changed;
+}
+
static bool insertParsePoints(Function &F, DominatorTree &DT,
TargetTransformInfo &TTI,
- SmallVectorImpl<CallBase *> &ToUpdate) {
+ SmallVectorImpl<CallBase *> &ToUpdate,
+ DefiningValueMapTy &DVCache) {
#ifndef NDEBUG
// sanity check the input
std::set<CallBase *> Uniqued;
@@ -2377,17 +2503,10 @@ static bool insertParsePoints(Function &F, DominatorTree &DT,
findLiveReferences(F, DT, ToUpdate, Records);
// B) Find the base pointers for each live pointer
- /* scope for caching */ {
- // Cache the 'defining value' relation used in the computation and
- // insertion of base phis and selects. This ensures that we don't insert
- // large numbers of duplicate base_phis.
- DefiningValueMapTy DVCache;
-
- for (size_t i = 0; i < Records.size(); i++) {
- PartiallyConstructedSafepointRecord &info = Records[i];
- findBasePointers(DT, DVCache, ToUpdate[i], info);
- }
- } // end of cache scope
+ for (size_t i = 0; i < Records.size(); i++) {
+ PartiallyConstructedSafepointRecord &info = Records[i];
+ findBasePointers(DT, DVCache, ToUpdate[i], info);
+ }
// The base phi insertion logic (for any safepoint) may have inserted new
// instructions which are now live at some safepoint. The simplest such
@@ -2543,8 +2662,9 @@ static void RemoveNonValidAttrAtIndex(LLVMContext &Ctx, AttrHolder &AH,
if (AH.getDereferenceableOrNullBytes(Index))
R.addAttribute(Attribute::get(Ctx, Attribute::DereferenceableOrNull,
AH.getDereferenceableOrNullBytes(Index)));
- if (AH.getAttributes().hasAttribute(Index, Attribute::NoAlias))
- R.addAttribute(Attribute::NoAlias);
+ for (auto Attr : ParamAttrsToStrip)
+ if (AH.getAttributes().hasAttribute(Index, Attr))
+ R.addAttribute(Attr);
if (!R.empty())
AH.setAttributes(AH.getAttributes().removeAttributes(Ctx, Index, R));
@@ -2553,6 +2673,16 @@ static void RemoveNonValidAttrAtIndex(LLVMContext &Ctx, AttrHolder &AH,
static void stripNonValidAttributesFromPrototype(Function &F) {
LLVMContext &Ctx = F.getContext();
+ // Intrinsics are very delicate. Lowering sometimes depends the presence
+ // of certain attributes for correctness, but we may have also inferred
+ // additional ones in the abstract machine model which need stripped. This
+ // assumes that the attributes defined in Intrinsic.td are conservatively
+ // correct for both physical and abstract model.
+ if (Intrinsic::ID id = F.getIntrinsicID()) {
+ F.setAttributes(Intrinsic::getAttributes(Ctx, id));
+ return;
+ }
+
for (Argument &A : F.args())
if (isa<PointerType>(A.getType()))
RemoveNonValidAttrAtIndex(Ctx, F,
@@ -2560,6 +2690,9 @@ static void stripNonValidAttributesFromPrototype(Function &F) {
if (isa<PointerType>(F.getReturnType()))
RemoveNonValidAttrAtIndex(Ctx, F, AttributeList::ReturnIndex);
+
+ for (auto Attr : FnAttrsToStrip)
+ F.removeFnAttr(Attr);
}
/// Certain metadata on instructions are invalid after running RS4GC.
@@ -2711,6 +2844,7 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT,
// consider those in reachable code since we need to ask dominance queries
// when rewriting. We'll delete the unreachable ones in a moment.
SmallVector<CallBase *, 64> ParsePointNeeded;
+ SmallVector<CallInst *, 64> Intrinsics;
for (Instruction &I : instructions(F)) {
// TODO: only the ones with the flag set!
if (NeedsRewrite(I)) {
@@ -2722,10 +2856,14 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT,
"no unreachable blocks expected");
ParsePointNeeded.push_back(cast<CallBase>(&I));
}
+ if (auto *CI = dyn_cast<CallInst>(&I))
+ if (CI->getIntrinsicID() == Intrinsic::experimental_gc_get_pointer_base ||
+ CI->getIntrinsicID() == Intrinsic::experimental_gc_get_pointer_offset)
+ Intrinsics.emplace_back(CI);
}
// Return early if no work to do.
- if (ParsePointNeeded.empty())
+ if (ParsePointNeeded.empty() && Intrinsics.empty())
return MadeChange;
// As a prepass, go ahead and aggressively destroy single entry phi nodes.
@@ -2794,7 +2932,20 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT,
}
}
- MadeChange |= insertParsePoints(F, DT, TTI, ParsePointNeeded);
+ // Cache the 'defining value' relation used in the computation and
+ // insertion of base phis and selects. This ensures that we don't insert
+ // large numbers of duplicate base_phis. Use one cache for both
+ // inlineGetBaseAndOffset() and insertParsePoints().
+ DefiningValueMapTy DVCache;
+
+ if (!Intrinsics.empty())
+ // Inline @gc.get.pointer.base() and @gc.get.pointer.offset() before finding
+ // live references.
+ MadeChange |= inlineGetBaseAndOffset(F, Intrinsics, DVCache);
+
+ if (!ParsePointNeeded.empty())
+ MadeChange |= insertParsePoints(F, DT, TTI, ParsePointNeeded, DVCache);
+
return MadeChange;
}
@@ -2986,11 +3137,7 @@ static void recomputeLiveInValues(GCPtrLivenessData &RevisedLivenessData,
// We may have base pointers which are now live that weren't before. We need
// to update the PointerToBase structure to reflect this.
for (auto V : Updated)
- if (Info.PointerToBase.insert({V, V}).second) {
- assert(isKnownBaseResult(V) &&
- "Can't find base for unexpected live value!");
- continue;
- }
+ Info.PointerToBase.insert({V, V});
#ifndef NDEBUG
for (auto V : Updated)
diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp
index de6be52adf21..b09f896d0157 100644
--- a/llvm/lib/Transforms/Scalar/SCCP.cpp
+++ b/llvm/lib/Transforms/Scalar/SCCP.cpp
@@ -80,22 +80,11 @@ STATISTIC(
IPNumInstReplaced,
"Number of instructions replaced with (simpler) instruction by IPSCCP");
-// The maximum number of range extensions allowed for operations requiring
-// widening.
-static const unsigned MaxNumRangeExtensions = 10;
-
-/// Returns MergeOptions with MaxWidenSteps set to MaxNumRangeExtensions.
-static ValueLatticeElement::MergeOptions getMaxWidenStepsOpts() {
- return ValueLatticeElement::MergeOptions().setMaxWidenSteps(
- MaxNumRangeExtensions);
-}
-namespace {
-
// Helper to check if \p LV is either a constant or a constant
// range with a single element. This should cover exactly the same cases as the
// old ValueLatticeElement::isConstant() and is intended to be used in the
// transition to ValueLatticeElement.
-bool isConstant(const ValueLatticeElement &LV) {
+static bool isConstant(const ValueLatticeElement &LV) {
return LV.isConstant() ||
(LV.isConstantRange() && LV.getConstantRange().isSingleElement());
}
@@ -104,1525 +93,10 @@ bool isConstant(const ValueLatticeElement &LV) {
// than a single element. This should cover exactly the same cases as the old
// ValueLatticeElement::isOverdefined() and is intended to be used in the
// transition to ValueLatticeElement.
-bool isOverdefined(const ValueLatticeElement &LV) {
+static bool isOverdefined(const ValueLatticeElement &LV) {
return !LV.isUnknownOrUndef() && !isConstant(LV);
}
-//===----------------------------------------------------------------------===//
-//
-/// SCCPSolver - This class is a general purpose solver for Sparse Conditional
-/// Constant Propagation.
-///
-class SCCPSolver : public InstVisitor<SCCPSolver> {
- const DataLayout &DL;
- std::function<const TargetLibraryInfo &(Function &)> GetTLI;
- SmallPtrSet<BasicBlock *, 8> BBExecutable; // The BBs that are executable.
- DenseMap<Value *, ValueLatticeElement>
- ValueState; // The state each value is in.
-
- /// StructValueState - This maintains ValueState for values that have
- /// StructType, for example for formal arguments, calls, insertelement, etc.
- DenseMap<std::pair<Value *, unsigned>, ValueLatticeElement> StructValueState;
-
- /// GlobalValue - If we are tracking any values for the contents of a global
- /// variable, we keep a mapping from the constant accessor to the element of
- /// the global, to the currently known value. If the value becomes
- /// overdefined, it's entry is simply removed from this map.
- DenseMap<GlobalVariable *, ValueLatticeElement> TrackedGlobals;
-
- /// TrackedRetVals - If we are tracking arguments into and the return
- /// value out of a function, it will have an entry in this map, indicating
- /// what the known return value for the function is.
- MapVector<Function *, ValueLatticeElement> TrackedRetVals;
-
- /// TrackedMultipleRetVals - Same as TrackedRetVals, but used for functions
- /// that return multiple values.
- MapVector<std::pair<Function *, unsigned>, ValueLatticeElement>
- TrackedMultipleRetVals;
-
- /// MRVFunctionsTracked - Each function in TrackedMultipleRetVals is
- /// represented here for efficient lookup.
- SmallPtrSet<Function *, 16> MRVFunctionsTracked;
-
- /// MustTailFunctions - Each function here is a callee of non-removable
- /// musttail call site.
- SmallPtrSet<Function *, 16> MustTailCallees;
-
- /// TrackingIncomingArguments - This is the set of functions for whose
- /// arguments we make optimistic assumptions about and try to prove as
- /// constants.
- SmallPtrSet<Function *, 16> TrackingIncomingArguments;
-
- /// The reason for two worklists is that overdefined is the lowest state
- /// on the lattice, and moving things to overdefined as fast as possible
- /// makes SCCP converge much faster.
- ///
- /// By having a separate worklist, we accomplish this because everything
- /// possibly overdefined will become overdefined at the soonest possible
- /// point.
- SmallVector<Value *, 64> OverdefinedInstWorkList;
- SmallVector<Value *, 64> InstWorkList;
-
- // The BasicBlock work list
- SmallVector<BasicBlock *, 64> BBWorkList;
-
- /// KnownFeasibleEdges - Entries in this set are edges which have already had
- /// PHI nodes retriggered.
- using Edge = std::pair<BasicBlock *, BasicBlock *>;
- DenseSet<Edge> KnownFeasibleEdges;
-
- DenseMap<Function *, AnalysisResultsForFn> AnalysisResults;
- DenseMap<Value *, SmallPtrSet<User *, 2>> AdditionalUsers;
-
- LLVMContext &Ctx;
-
-public:
- void addAnalysis(Function &F, AnalysisResultsForFn A) {
- AnalysisResults.insert({&F, std::move(A)});
- }
-
- const PredicateBase *getPredicateInfoFor(Instruction *I) {
- auto A = AnalysisResults.find(I->getParent()->getParent());
- if (A == AnalysisResults.end())
- return nullptr;
- return A->second.PredInfo->getPredicateInfoFor(I);
- }
-
- DomTreeUpdater getDTU(Function &F) {
- auto A = AnalysisResults.find(&F);
- assert(A != AnalysisResults.end() && "Need analysis results for function.");
- return {A->second.DT, A->second.PDT, DomTreeUpdater::UpdateStrategy::Lazy};
- }
-
- SCCPSolver(const DataLayout &DL,
- std::function<const TargetLibraryInfo &(Function &)> GetTLI,
- LLVMContext &Ctx)
- : DL(DL), GetTLI(std::move(GetTLI)), Ctx(Ctx) {}
-
- /// MarkBlockExecutable - This method can be used by clients to mark all of
- /// the blocks that are known to be intrinsically live in the processed unit.
- ///
- /// This returns true if the block was not considered live before.
- bool MarkBlockExecutable(BasicBlock *BB) {
- if (!BBExecutable.insert(BB).second)
- return false;
- LLVM_DEBUG(dbgs() << "Marking Block Executable: " << BB->getName() << '\n');
- BBWorkList.push_back(BB); // Add the block to the work list!
- return true;
- }
-
- /// TrackValueOfGlobalVariable - Clients can use this method to
- /// inform the SCCPSolver that it should track loads and stores to the
- /// specified global variable if it can. This is only legal to call if
- /// performing Interprocedural SCCP.
- void TrackValueOfGlobalVariable(GlobalVariable *GV) {
- // We only track the contents of scalar globals.
- if (GV->getValueType()->isSingleValueType()) {
- ValueLatticeElement &IV = TrackedGlobals[GV];
- if (!isa<UndefValue>(GV->getInitializer()))
- IV.markConstant(GV->getInitializer());
- }
- }
-
- /// AddTrackedFunction - If the SCCP solver is supposed to track calls into
- /// and out of the specified function (which cannot have its address taken),
- /// this method must be called.
- void AddTrackedFunction(Function *F) {
- // Add an entry, F -> undef.
- if (auto *STy = dyn_cast<StructType>(F->getReturnType())) {
- MRVFunctionsTracked.insert(F);
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
- TrackedMultipleRetVals.insert(
- std::make_pair(std::make_pair(F, i), ValueLatticeElement()));
- } else if (!F->getReturnType()->isVoidTy())
- TrackedRetVals.insert(std::make_pair(F, ValueLatticeElement()));
- }
-
- /// AddMustTailCallee - If the SCCP solver finds that this function is called
- /// from non-removable musttail call site.
- void AddMustTailCallee(Function *F) {
- MustTailCallees.insert(F);
- }
-
- /// Returns true if the given function is called from non-removable musttail
- /// call site.
- bool isMustTailCallee(Function *F) {
- return MustTailCallees.count(F);
- }
-
- void AddArgumentTrackedFunction(Function *F) {
- TrackingIncomingArguments.insert(F);
- }
-
- /// Returns true if the given function is in the solver's set of
- /// argument-tracked functions.
- bool isArgumentTrackedFunction(Function *F) {
- return TrackingIncomingArguments.count(F);
- }
-
- /// Solve - Solve for constants and executable blocks.
- void Solve();
-
- /// ResolvedUndefsIn - While solving the dataflow for a function, we assume
- /// that branches on undef values cannot reach any of their successors.
- /// However, this is not a safe assumption. After we solve dataflow, this
- /// method should be use to handle this. If this returns true, the solver
- /// should be rerun.
- bool ResolvedUndefsIn(Function &F);
-
- bool isBlockExecutable(BasicBlock *BB) const {
- return BBExecutable.count(BB);
- }
-
- // isEdgeFeasible - Return true if the control flow edge from the 'From' basic
- // block to the 'To' basic block is currently feasible.
- bool isEdgeFeasible(BasicBlock *From, BasicBlock *To) const;
-
- std::vector<ValueLatticeElement> getStructLatticeValueFor(Value *V) const {
- std::vector<ValueLatticeElement> StructValues;
- auto *STy = dyn_cast<StructType>(V->getType());
- assert(STy && "getStructLatticeValueFor() can be called only on structs");
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- auto I = StructValueState.find(std::make_pair(V, i));
- assert(I != StructValueState.end() && "Value not in valuemap!");
- StructValues.push_back(I->second);
- }
- return StructValues;
- }
-
- void removeLatticeValueFor(Value *V) { ValueState.erase(V); }
-
- const ValueLatticeElement &getLatticeValueFor(Value *V) const {
- assert(!V->getType()->isStructTy() &&
- "Should use getStructLatticeValueFor");
- DenseMap<Value *, ValueLatticeElement>::const_iterator I =
- ValueState.find(V);
- assert(I != ValueState.end() &&
- "V not found in ValueState nor Paramstate map!");
- return I->second;
- }
-
- /// getTrackedRetVals - Get the inferred return value map.
- const MapVector<Function *, ValueLatticeElement> &getTrackedRetVals() {
- return TrackedRetVals;
- }
-
- /// getTrackedGlobals - Get and return the set of inferred initializers for
- /// global variables.
- const DenseMap<GlobalVariable *, ValueLatticeElement> &getTrackedGlobals() {
- return TrackedGlobals;
- }
-
- /// getMRVFunctionsTracked - Get the set of functions which return multiple
- /// values tracked by the pass.
- const SmallPtrSet<Function *, 16> getMRVFunctionsTracked() {
- return MRVFunctionsTracked;
- }
-
- /// getMustTailCallees - Get the set of functions which are called
- /// from non-removable musttail call sites.
- const SmallPtrSet<Function *, 16> getMustTailCallees() {
- return MustTailCallees;
- }
-
- /// markOverdefined - Mark the specified value overdefined. This
- /// works with both scalars and structs.
- void markOverdefined(Value *V) {
- if (auto *STy = dyn_cast<StructType>(V->getType()))
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
- markOverdefined(getStructValueState(V, i), V);
- else
- markOverdefined(ValueState[V], V);
- }
-
- // isStructLatticeConstant - Return true if all the lattice values
- // corresponding to elements of the structure are constants,
- // false otherwise.
- bool isStructLatticeConstant(Function *F, StructType *STy) {
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- const auto &It = TrackedMultipleRetVals.find(std::make_pair(F, i));
- assert(It != TrackedMultipleRetVals.end());
- ValueLatticeElement LV = It->second;
- if (!isConstant(LV))
- return false;
- }
- return true;
- }
-
- /// Helper to return a Constant if \p LV is either a constant or a constant
- /// range with a single element.
- Constant *getConstant(const ValueLatticeElement &LV) const {
- if (LV.isConstant())
- return LV.getConstant();
-
- if (LV.isConstantRange()) {
- auto &CR = LV.getConstantRange();
- if (CR.getSingleElement())
- return ConstantInt::get(Ctx, *CR.getSingleElement());
- }
- return nullptr;
- }
-
-private:
- ConstantInt *getConstantInt(const ValueLatticeElement &IV) const {
- return dyn_cast_or_null<ConstantInt>(getConstant(IV));
- }
-
- // pushToWorkList - Helper for markConstant/markOverdefined
- void pushToWorkList(ValueLatticeElement &IV, Value *V) {
- if (IV.isOverdefined())
- return OverdefinedInstWorkList.push_back(V);
- InstWorkList.push_back(V);
- }
-
- // Helper to push \p V to the worklist, after updating it to \p IV. Also
- // prints a debug message with the updated value.
- void pushToWorkListMsg(ValueLatticeElement &IV, Value *V) {
- LLVM_DEBUG(dbgs() << "updated " << IV << ": " << *V << '\n');
- pushToWorkList(IV, V);
- }
-
- // markConstant - Make a value be marked as "constant". If the value
- // is not already a constant, add it to the instruction work list so that
- // the users of the instruction are updated later.
- bool markConstant(ValueLatticeElement &IV, Value *V, Constant *C,
- bool MayIncludeUndef = false) {
- if (!IV.markConstant(C, MayIncludeUndef))
- return false;
- LLVM_DEBUG(dbgs() << "markConstant: " << *C << ": " << *V << '\n');
- pushToWorkList(IV, V);
- return true;
- }
-
- bool markConstant(Value *V, Constant *C) {
- assert(!V->getType()->isStructTy() && "structs should use mergeInValue");
- return markConstant(ValueState[V], V, C);
- }
-
- // markOverdefined - Make a value be marked as "overdefined". If the
- // value is not already overdefined, add it to the overdefined instruction
- // work list so that the users of the instruction are updated later.
- bool markOverdefined(ValueLatticeElement &IV, Value *V) {
- if (!IV.markOverdefined()) return false;
-
- LLVM_DEBUG(dbgs() << "markOverdefined: ";
- if (auto *F = dyn_cast<Function>(V)) dbgs()
- << "Function '" << F->getName() << "'\n";
- else dbgs() << *V << '\n');
- // Only instructions go on the work list
- pushToWorkList(IV, V);
- return true;
- }
-
- /// Merge \p MergeWithV into \p IV and push \p V to the worklist, if \p IV
- /// changes.
- bool mergeInValue(ValueLatticeElement &IV, Value *V,
- ValueLatticeElement MergeWithV,
- ValueLatticeElement::MergeOptions Opts = {
- /*MayIncludeUndef=*/false, /*CheckWiden=*/false}) {
- if (IV.mergeIn(MergeWithV, Opts)) {
- pushToWorkList(IV, V);
- LLVM_DEBUG(dbgs() << "Merged " << MergeWithV << " into " << *V << " : "
- << IV << "\n");
- return true;
- }
- return false;
- }
-
- bool mergeInValue(Value *V, ValueLatticeElement MergeWithV,
- ValueLatticeElement::MergeOptions Opts = {
- /*MayIncludeUndef=*/false, /*CheckWiden=*/false}) {
- assert(!V->getType()->isStructTy() &&
- "non-structs should use markConstant");
- return mergeInValue(ValueState[V], V, MergeWithV, Opts);
- }
-
- /// getValueState - Return the ValueLatticeElement object that corresponds to
- /// the value. This function handles the case when the value hasn't been seen
- /// yet by properly seeding constants etc.
- ValueLatticeElement &getValueState(Value *V) {
- assert(!V->getType()->isStructTy() && "Should use getStructValueState");
-
- auto I = ValueState.insert(std::make_pair(V, ValueLatticeElement()));
- ValueLatticeElement &LV = I.first->second;
-
- if (!I.second)
- return LV; // Common case, already in the map.
-
- if (auto *C = dyn_cast<Constant>(V))
- LV.markConstant(C); // Constants are constant
-
- // All others are unknown by default.
- return LV;
- }
-
- /// getStructValueState - Return the ValueLatticeElement object that
- /// corresponds to the value/field pair. This function handles the case when
- /// the value hasn't been seen yet by properly seeding constants etc.
- ValueLatticeElement &getStructValueState(Value *V, unsigned i) {
- assert(V->getType()->isStructTy() && "Should use getValueState");
- assert(i < cast<StructType>(V->getType())->getNumElements() &&
- "Invalid element #");
-
- auto I = StructValueState.insert(
- std::make_pair(std::make_pair(V, i), ValueLatticeElement()));
- ValueLatticeElement &LV = I.first->second;
-
- if (!I.second)
- return LV; // Common case, already in the map.
-
- if (auto *C = dyn_cast<Constant>(V)) {
- Constant *Elt = C->getAggregateElement(i);
-
- if (!Elt)
- LV.markOverdefined(); // Unknown sort of constant.
- else if (isa<UndefValue>(Elt))
- ; // Undef values remain unknown.
- else
- LV.markConstant(Elt); // Constants are constant.
- }
-
- // All others are underdefined by default.
- return LV;
- }
-
- /// markEdgeExecutable - Mark a basic block as executable, adding it to the BB
- /// work list if it is not already executable.
- bool markEdgeExecutable(BasicBlock *Source, BasicBlock *Dest) {
- if (!KnownFeasibleEdges.insert(Edge(Source, Dest)).second)
- return false; // This edge is already known to be executable!
-
- if (!MarkBlockExecutable(Dest)) {
- // If the destination is already executable, we just made an *edge*
- // feasible that wasn't before. Revisit the PHI nodes in the block
- // because they have potentially new operands.
- LLVM_DEBUG(dbgs() << "Marking Edge Executable: " << Source->getName()
- << " -> " << Dest->getName() << '\n');
-
- for (PHINode &PN : Dest->phis())
- visitPHINode(PN);
- }
- return true;
- }
-
- // getFeasibleSuccessors - Return a vector of booleans to indicate which
- // successors are reachable from a given terminator instruction.
- void getFeasibleSuccessors(Instruction &TI, SmallVectorImpl<bool> &Succs);
-
- // OperandChangedState - This method is invoked on all of the users of an
- // instruction that was just changed state somehow. Based on this
- // information, we need to update the specified user of this instruction.
- void OperandChangedState(Instruction *I) {
- if (BBExecutable.count(I->getParent())) // Inst is executable?
- visit(*I);
- }
-
- // Add U as additional user of V.
- void addAdditionalUser(Value *V, User *U) {
- auto Iter = AdditionalUsers.insert({V, {}});
- Iter.first->second.insert(U);
- }
-
- // Mark I's users as changed, including AdditionalUsers.
- void markUsersAsChanged(Value *I) {
- // Functions include their arguments in the use-list. Changed function
- // values mean that the result of the function changed. We only need to
- // update the call sites with the new function result and do not have to
- // propagate the call arguments.
- if (isa<Function>(I)) {
- for (User *U : I->users()) {
- if (auto *CB = dyn_cast<CallBase>(U))
- handleCallResult(*CB);
- }
- } else {
- for (User *U : I->users())
- if (auto *UI = dyn_cast<Instruction>(U))
- OperandChangedState(UI);
- }
-
- auto Iter = AdditionalUsers.find(I);
- if (Iter != AdditionalUsers.end()) {
- for (User *U : Iter->second)
- if (auto *UI = dyn_cast<Instruction>(U))
- OperandChangedState(UI);
- }
- }
- void handleCallOverdefined(CallBase &CB);
- void handleCallResult(CallBase &CB);
- void handleCallArguments(CallBase &CB);
-
-private:
- friend class InstVisitor<SCCPSolver>;
-
- // visit implementations - Something changed in this instruction. Either an
- // operand made a transition, or the instruction is newly executable. Change
- // the value type of I to reflect these changes if appropriate.
- void visitPHINode(PHINode &I);
-
- // Terminators
-
- void visitReturnInst(ReturnInst &I);
- void visitTerminator(Instruction &TI);
-
- void visitCastInst(CastInst &I);
- void visitSelectInst(SelectInst &I);
- void visitUnaryOperator(Instruction &I);
- void visitBinaryOperator(Instruction &I);
- void visitCmpInst(CmpInst &I);
- void visitExtractValueInst(ExtractValueInst &EVI);
- void visitInsertValueInst(InsertValueInst &IVI);
-
- void visitCatchSwitchInst(CatchSwitchInst &CPI) {
- markOverdefined(&CPI);
- visitTerminator(CPI);
- }
-
- // Instructions that cannot be folded away.
-
- void visitStoreInst (StoreInst &I);
- void visitLoadInst (LoadInst &I);
- void visitGetElementPtrInst(GetElementPtrInst &I);
-
- void visitCallInst (CallInst &I) {
- visitCallBase(I);
- }
-
- void visitInvokeInst (InvokeInst &II) {
- visitCallBase(II);
- visitTerminator(II);
- }
-
- void visitCallBrInst (CallBrInst &CBI) {
- visitCallBase(CBI);
- visitTerminator(CBI);
- }
-
- void visitCallBase (CallBase &CB);
- void visitResumeInst (ResumeInst &I) { /*returns void*/ }
- void visitUnreachableInst(UnreachableInst &I) { /*returns void*/ }
- void visitFenceInst (FenceInst &I) { /*returns void*/ }
-
- void visitInstruction(Instruction &I) {
- // All the instructions we don't do any special handling for just
- // go to overdefined.
- LLVM_DEBUG(dbgs() << "SCCP: Don't know how to handle: " << I << '\n');
- markOverdefined(&I);
- }
-};
-
-} // end anonymous namespace
-
-// getFeasibleSuccessors - Return a vector of booleans to indicate which
-// successors are reachable from a given terminator instruction.
-void SCCPSolver::getFeasibleSuccessors(Instruction &TI,
- SmallVectorImpl<bool> &Succs) {
- Succs.resize(TI.getNumSuccessors());
- if (auto *BI = dyn_cast<BranchInst>(&TI)) {
- if (BI->isUnconditional()) {
- Succs[0] = true;
- return;
- }
-
- ValueLatticeElement BCValue = getValueState(BI->getCondition());
- ConstantInt *CI = getConstantInt(BCValue);
- if (!CI) {
- // Overdefined condition variables, and branches on unfoldable constant
- // conditions, mean the branch could go either way.
- if (!BCValue.isUnknownOrUndef())
- Succs[0] = Succs[1] = true;
- return;
- }
-
- // Constant condition variables mean the branch can only go a single way.
- Succs[CI->isZero()] = true;
- return;
- }
-
- // Unwinding instructions successors are always executable.
- if (TI.isExceptionalTerminator()) {
- Succs.assign(TI.getNumSuccessors(), true);
- return;
- }
-
- if (auto *SI = dyn_cast<SwitchInst>(&TI)) {
- if (!SI->getNumCases()) {
- Succs[0] = true;
- return;
- }
- const ValueLatticeElement &SCValue = getValueState(SI->getCondition());
- if (ConstantInt *CI = getConstantInt(SCValue)) {
- Succs[SI->findCaseValue(CI)->getSuccessorIndex()] = true;
- return;
- }
-
- // TODO: Switch on undef is UB. Stop passing false once the rest of LLVM
- // is ready.
- if (SCValue.isConstantRange(/*UndefAllowed=*/false)) {
- const ConstantRange &Range = SCValue.getConstantRange();
- for (const auto &Case : SI->cases()) {
- const APInt &CaseValue = Case.getCaseValue()->getValue();
- if (Range.contains(CaseValue))
- Succs[Case.getSuccessorIndex()] = true;
- }
-
- // TODO: Determine whether default case is reachable.
- Succs[SI->case_default()->getSuccessorIndex()] = true;
- return;
- }
-
- // Overdefined or unknown condition? All destinations are executable!
- if (!SCValue.isUnknownOrUndef())
- Succs.assign(TI.getNumSuccessors(), true);
- return;
- }
-
- // In case of indirect branch and its address is a blockaddress, we mark
- // the target as executable.
- if (auto *IBR = dyn_cast<IndirectBrInst>(&TI)) {
- // Casts are folded by visitCastInst.
- ValueLatticeElement IBRValue = getValueState(IBR->getAddress());
- BlockAddress *Addr = dyn_cast_or_null<BlockAddress>(getConstant(IBRValue));
- if (!Addr) { // Overdefined or unknown condition?
- // All destinations are executable!
- if (!IBRValue.isUnknownOrUndef())
- Succs.assign(TI.getNumSuccessors(), true);
- return;
- }
-
- BasicBlock* T = Addr->getBasicBlock();
- assert(Addr->getFunction() == T->getParent() &&
- "Block address of a different function ?");
- for (unsigned i = 0; i < IBR->getNumSuccessors(); ++i) {
- // This is the target.
- if (IBR->getDestination(i) == T) {
- Succs[i] = true;
- return;
- }
- }
-
- // If we didn't find our destination in the IBR successor list, then we
- // have undefined behavior. Its ok to assume no successor is executable.
- return;
- }
-
- // In case of callbr, we pessimistically assume that all successors are
- // feasible.
- if (isa<CallBrInst>(&TI)) {
- Succs.assign(TI.getNumSuccessors(), true);
- return;
- }
-
- LLVM_DEBUG(dbgs() << "Unknown terminator instruction: " << TI << '\n');
- llvm_unreachable("SCCP: Don't know how to handle this terminator!");
-}
-
-// isEdgeFeasible - Return true if the control flow edge from the 'From' basic
-// block to the 'To' basic block is currently feasible.
-bool SCCPSolver::isEdgeFeasible(BasicBlock *From, BasicBlock *To) const {
- // Check if we've called markEdgeExecutable on the edge yet. (We could
- // be more aggressive and try to consider edges which haven't been marked
- // yet, but there isn't any need.)
- return KnownFeasibleEdges.count(Edge(From, To));
-}
-
-// visit Implementations - Something changed in this instruction, either an
-// operand made a transition, or the instruction is newly executable. Change
-// the value type of I to reflect these changes if appropriate. This method
-// makes sure to do the following actions:
-//
-// 1. If a phi node merges two constants in, and has conflicting value coming
-// from different branches, or if the PHI node merges in an overdefined
-// value, then the PHI node becomes overdefined.
-// 2. If a phi node merges only constants in, and they all agree on value, the
-// PHI node becomes a constant value equal to that.
-// 3. If V <- x (op) y && isConstant(x) && isConstant(y) V = Constant
-// 4. If V <- x (op) y && (isOverdefined(x) || isOverdefined(y)) V = Overdefined
-// 5. If V <- MEM or V <- CALL or V <- (unknown) then V = Overdefined
-// 6. If a conditional branch has a value that is constant, make the selected
-// destination executable
-// 7. If a conditional branch has a value that is overdefined, make all
-// successors executable.
-void SCCPSolver::visitPHINode(PHINode &PN) {
- // If this PN returns a struct, just mark the result overdefined.
- // TODO: We could do a lot better than this if code actually uses this.
- if (PN.getType()->isStructTy())
- return (void)markOverdefined(&PN);
-
- if (getValueState(&PN).isOverdefined())
- return; // Quick exit
-
- // Super-extra-high-degree PHI nodes are unlikely to ever be marked constant,
- // and slow us down a lot. Just mark them overdefined.
- if (PN.getNumIncomingValues() > 64)
- return (void)markOverdefined(&PN);
-
- unsigned NumActiveIncoming = 0;
-
- // Look at all of the executable operands of the PHI node. If any of them
- // are overdefined, the PHI becomes overdefined as well. If they are all
- // constant, and they agree with each other, the PHI becomes the identical
- // constant. If they are constant and don't agree, the PHI is a constant
- // range. If there are no executable operands, the PHI remains unknown.
- ValueLatticeElement PhiState = getValueState(&PN);
- for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i) {
- if (!isEdgeFeasible(PN.getIncomingBlock(i), PN.getParent()))
- continue;
-
- ValueLatticeElement IV = getValueState(PN.getIncomingValue(i));
- PhiState.mergeIn(IV);
- NumActiveIncoming++;
- if (PhiState.isOverdefined())
- break;
- }
-
- // We allow up to 1 range extension per active incoming value and one
- // additional extension. Note that we manually adjust the number of range
- // extensions to match the number of active incoming values. This helps to
- // limit multiple extensions caused by the same incoming value, if other
- // incoming values are equal.
- mergeInValue(&PN, PhiState,
- ValueLatticeElement::MergeOptions().setMaxWidenSteps(
- NumActiveIncoming + 1));
- ValueLatticeElement &PhiStateRef = getValueState(&PN);
- PhiStateRef.setNumRangeExtensions(
- std::max(NumActiveIncoming, PhiStateRef.getNumRangeExtensions()));
-}
-
-void SCCPSolver::visitReturnInst(ReturnInst &I) {
- if (I.getNumOperands() == 0) return; // ret void
-
- Function *F = I.getParent()->getParent();
- Value *ResultOp = I.getOperand(0);
-
- // If we are tracking the return value of this function, merge it in.
- if (!TrackedRetVals.empty() && !ResultOp->getType()->isStructTy()) {
- auto TFRVI = TrackedRetVals.find(F);
- if (TFRVI != TrackedRetVals.end()) {
- mergeInValue(TFRVI->second, F, getValueState(ResultOp));
- return;
- }
- }
-
- // Handle functions that return multiple values.
- if (!TrackedMultipleRetVals.empty()) {
- if (auto *STy = dyn_cast<StructType>(ResultOp->getType()))
- if (MRVFunctionsTracked.count(F))
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
- mergeInValue(TrackedMultipleRetVals[std::make_pair(F, i)], F,
- getStructValueState(ResultOp, i));
- }
-}
-
-void SCCPSolver::visitTerminator(Instruction &TI) {
- SmallVector<bool, 16> SuccFeasible;
- getFeasibleSuccessors(TI, SuccFeasible);
-
- BasicBlock *BB = TI.getParent();
-
- // Mark all feasible successors executable.
- for (unsigned i = 0, e = SuccFeasible.size(); i != e; ++i)
- if (SuccFeasible[i])
- markEdgeExecutable(BB, TI.getSuccessor(i));
-}
-
-void SCCPSolver::visitCastInst(CastInst &I) {
- // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
- // discover a concrete value later.
- if (ValueState[&I].isOverdefined())
- return;
-
- ValueLatticeElement OpSt = getValueState(I.getOperand(0));
- if (Constant *OpC = getConstant(OpSt)) {
- // Fold the constant as we build.
- Constant *C = ConstantFoldCastOperand(I.getOpcode(), OpC, I.getType(), DL);
- if (isa<UndefValue>(C))
- return;
- // Propagate constant value
- markConstant(&I, C);
- } else if (OpSt.isConstantRange() && I.getDestTy()->isIntegerTy()) {
- auto &LV = getValueState(&I);
- ConstantRange OpRange = OpSt.getConstantRange();
- Type *DestTy = I.getDestTy();
- // Vectors where all elements have the same known constant range are treated
- // as a single constant range in the lattice. When bitcasting such vectors,
- // there is a mis-match between the width of the lattice value (single
- // constant range) and the original operands (vector). Go to overdefined in
- // that case.
- if (I.getOpcode() == Instruction::BitCast &&
- I.getOperand(0)->getType()->isVectorTy() &&
- OpRange.getBitWidth() < DL.getTypeSizeInBits(DestTy))
- return (void)markOverdefined(&I);
-
- ConstantRange Res =
- OpRange.castOp(I.getOpcode(), DL.getTypeSizeInBits(DestTy));
- mergeInValue(LV, &I, ValueLatticeElement::getRange(Res));
- } else if (!OpSt.isUnknownOrUndef())
- markOverdefined(&I);
-}
-
-void SCCPSolver::visitExtractValueInst(ExtractValueInst &EVI) {
- // If this returns a struct, mark all elements over defined, we don't track
- // structs in structs.
- if (EVI.getType()->isStructTy())
- return (void)markOverdefined(&EVI);
-
- // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
- // discover a concrete value later.
- if (ValueState[&EVI].isOverdefined())
- return (void)markOverdefined(&EVI);
-
- // If this is extracting from more than one level of struct, we don't know.
- if (EVI.getNumIndices() != 1)
- return (void)markOverdefined(&EVI);
-
- Value *AggVal = EVI.getAggregateOperand();
- if (AggVal->getType()->isStructTy()) {
- unsigned i = *EVI.idx_begin();
- ValueLatticeElement EltVal = getStructValueState(AggVal, i);
- mergeInValue(getValueState(&EVI), &EVI, EltVal);
- } else {
- // Otherwise, must be extracting from an array.
- return (void)markOverdefined(&EVI);
- }
-}
-
-void SCCPSolver::visitInsertValueInst(InsertValueInst &IVI) {
- auto *STy = dyn_cast<StructType>(IVI.getType());
- if (!STy)
- return (void)markOverdefined(&IVI);
-
- // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
- // discover a concrete value later.
- if (isOverdefined(ValueState[&IVI]))
- return (void)markOverdefined(&IVI);
-
- // If this has more than one index, we can't handle it, drive all results to
- // undef.
- if (IVI.getNumIndices() != 1)
- return (void)markOverdefined(&IVI);
-
- Value *Aggr = IVI.getAggregateOperand();
- unsigned Idx = *IVI.idx_begin();
-
- // Compute the result based on what we're inserting.
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- // This passes through all values that aren't the inserted element.
- if (i != Idx) {
- ValueLatticeElement EltVal = getStructValueState(Aggr, i);
- mergeInValue(getStructValueState(&IVI, i), &IVI, EltVal);
- continue;
- }
-
- Value *Val = IVI.getInsertedValueOperand();
- if (Val->getType()->isStructTy())
- // We don't track structs in structs.
- markOverdefined(getStructValueState(&IVI, i), &IVI);
- else {
- ValueLatticeElement InVal = getValueState(Val);
- mergeInValue(getStructValueState(&IVI, i), &IVI, InVal);
- }
- }
-}
-
-void SCCPSolver::visitSelectInst(SelectInst &I) {
- // If this select returns a struct, just mark the result overdefined.
- // TODO: We could do a lot better than this if code actually uses this.
- if (I.getType()->isStructTy())
- return (void)markOverdefined(&I);
-
- // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
- // discover a concrete value later.
- if (ValueState[&I].isOverdefined())
- return (void)markOverdefined(&I);
-
- ValueLatticeElement CondValue = getValueState(I.getCondition());
- if (CondValue.isUnknownOrUndef())
- return;
-
- if (ConstantInt *CondCB = getConstantInt(CondValue)) {
- Value *OpVal = CondCB->isZero() ? I.getFalseValue() : I.getTrueValue();
- mergeInValue(&I, getValueState(OpVal));
- return;
- }
-
- // Otherwise, the condition is overdefined or a constant we can't evaluate.
- // See if we can produce something better than overdefined based on the T/F
- // value.
- ValueLatticeElement TVal = getValueState(I.getTrueValue());
- ValueLatticeElement FVal = getValueState(I.getFalseValue());
-
- bool Changed = ValueState[&I].mergeIn(TVal);
- Changed |= ValueState[&I].mergeIn(FVal);
- if (Changed)
- pushToWorkListMsg(ValueState[&I], &I);
-}
-
-// Handle Unary Operators.
-void SCCPSolver::visitUnaryOperator(Instruction &I) {
- ValueLatticeElement V0State = getValueState(I.getOperand(0));
-
- ValueLatticeElement &IV = ValueState[&I];
- // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
- // discover a concrete value later.
- if (isOverdefined(IV))
- return (void)markOverdefined(&I);
-
- if (isConstant(V0State)) {
- Constant *C = ConstantExpr::get(I.getOpcode(), getConstant(V0State));
-
- // op Y -> undef.
- if (isa<UndefValue>(C))
- return;
- return (void)markConstant(IV, &I, C);
- }
-
- // If something is undef, wait for it to resolve.
- if (!isOverdefined(V0State))
- return;
-
- markOverdefined(&I);
-}
-
-// Handle Binary Operators.
-void SCCPSolver::visitBinaryOperator(Instruction &I) {
- ValueLatticeElement V1State = getValueState(I.getOperand(0));
- ValueLatticeElement V2State = getValueState(I.getOperand(1));
-
- ValueLatticeElement &IV = ValueState[&I];
- if (IV.isOverdefined())
- return;
-
- // If something is undef, wait for it to resolve.
- if (V1State.isUnknownOrUndef() || V2State.isUnknownOrUndef())
- return;
-
- if (V1State.isOverdefined() && V2State.isOverdefined())
- return (void)markOverdefined(&I);
-
- // If either of the operands is a constant, try to fold it to a constant.
- // TODO: Use information from notconstant better.
- if ((V1State.isConstant() || V2State.isConstant())) {
- Value *V1 = isConstant(V1State) ? getConstant(V1State) : I.getOperand(0);
- Value *V2 = isConstant(V2State) ? getConstant(V2State) : I.getOperand(1);
- Value *R = SimplifyBinOp(I.getOpcode(), V1, V2, SimplifyQuery(DL));
- auto *C = dyn_cast_or_null<Constant>(R);
- if (C) {
- // X op Y -> undef.
- if (isa<UndefValue>(C))
- return;
- // Conservatively assume that the result may be based on operands that may
- // be undef. Note that we use mergeInValue to combine the constant with
- // the existing lattice value for I, as different constants might be found
- // after one of the operands go to overdefined, e.g. due to one operand
- // being a special floating value.
- ValueLatticeElement NewV;
- NewV.markConstant(C, /*MayIncludeUndef=*/true);
- return (void)mergeInValue(&I, NewV);
- }
- }
-
- // Only use ranges for binary operators on integers.
- if (!I.getType()->isIntegerTy())
- return markOverdefined(&I);
-
- // Try to simplify to a constant range.
- ConstantRange A = ConstantRange::getFull(I.getType()->getScalarSizeInBits());
- ConstantRange B = ConstantRange::getFull(I.getType()->getScalarSizeInBits());
- if (V1State.isConstantRange())
- A = V1State.getConstantRange();
- if (V2State.isConstantRange())
- B = V2State.getConstantRange();
-
- ConstantRange R = A.binaryOp(cast<BinaryOperator>(&I)->getOpcode(), B);
- mergeInValue(&I, ValueLatticeElement::getRange(R));
-
- // TODO: Currently we do not exploit special values that produce something
- // better than overdefined with an overdefined operand for vector or floating
- // point types, like and <4 x i32> overdefined, zeroinitializer.
-}
-
-// Handle ICmpInst instruction.
-void SCCPSolver::visitCmpInst(CmpInst &I) {
- // Do not cache this lookup, getValueState calls later in the function might
- // invalidate the reference.
- if (isOverdefined(ValueState[&I]))
- return (void)markOverdefined(&I);
-
- Value *Op1 = I.getOperand(0);
- Value *Op2 = I.getOperand(1);
-
- // For parameters, use ParamState which includes constant range info if
- // available.
- auto V1State = getValueState(Op1);
- auto V2State = getValueState(Op2);
-
- Constant *C = V1State.getCompare(I.getPredicate(), I.getType(), V2State);
- if (C) {
- if (isa<UndefValue>(C))
- return;
- ValueLatticeElement CV;
- CV.markConstant(C);
- mergeInValue(&I, CV);
- return;
- }
-
- // If operands are still unknown, wait for it to resolve.
- if ((V1State.isUnknownOrUndef() || V2State.isUnknownOrUndef()) &&
- !isConstant(ValueState[&I]))
- return;
-
- markOverdefined(&I);
-}
-
-// Handle getelementptr instructions. If all operands are constants then we
-// can turn this into a getelementptr ConstantExpr.
-void SCCPSolver::visitGetElementPtrInst(GetElementPtrInst &I) {
- if (isOverdefined(ValueState[&I]))
- return (void)markOverdefined(&I);
-
- SmallVector<Constant*, 8> Operands;
- Operands.reserve(I.getNumOperands());
-
- for (unsigned i = 0, e = I.getNumOperands(); i != e; ++i) {
- ValueLatticeElement State = getValueState(I.getOperand(i));
- if (State.isUnknownOrUndef())
- return; // Operands are not resolved yet.
-
- if (isOverdefined(State))
- return (void)markOverdefined(&I);
-
- if (Constant *C = getConstant(State)) {
- Operands.push_back(C);
- continue;
- }
-
- return (void)markOverdefined(&I);
- }
-
- Constant *Ptr = Operands[0];
- auto Indices = makeArrayRef(Operands.begin() + 1, Operands.end());
- Constant *C =
- ConstantExpr::getGetElementPtr(I.getSourceElementType(), Ptr, Indices);
- if (isa<UndefValue>(C))
- return;
- markConstant(&I, C);
-}
-
-void SCCPSolver::visitStoreInst(StoreInst &SI) {
- // If this store is of a struct, ignore it.
- if (SI.getOperand(0)->getType()->isStructTy())
- return;
-
- if (TrackedGlobals.empty() || !isa<GlobalVariable>(SI.getOperand(1)))
- return;
-
- GlobalVariable *GV = cast<GlobalVariable>(SI.getOperand(1));
- auto I = TrackedGlobals.find(GV);
- if (I == TrackedGlobals.end())
- return;
-
- // Get the value we are storing into the global, then merge it.
- mergeInValue(I->second, GV, getValueState(SI.getOperand(0)),
- ValueLatticeElement::MergeOptions().setCheckWiden(false));
- if (I->second.isOverdefined())
- TrackedGlobals.erase(I); // No need to keep tracking this!
-}
-
-static ValueLatticeElement getValueFromMetadata(const Instruction *I) {
- if (MDNode *Ranges = I->getMetadata(LLVMContext::MD_range))
- if (I->getType()->isIntegerTy())
- return ValueLatticeElement::getRange(
- getConstantRangeFromMetadata(*Ranges));
- if (I->hasMetadata(LLVMContext::MD_nonnull))
- return ValueLatticeElement::getNot(
- ConstantPointerNull::get(cast<PointerType>(I->getType())));
- return ValueLatticeElement::getOverdefined();
-}
-
-// Handle load instructions. If the operand is a constant pointer to a constant
-// global, we can replace the load with the loaded constant value!
-void SCCPSolver::visitLoadInst(LoadInst &I) {
- // If this load is of a struct or the load is volatile, just mark the result
- // as overdefined.
- if (I.getType()->isStructTy() || I.isVolatile())
- return (void)markOverdefined(&I);
-
- // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
- // discover a concrete value later.
- if (ValueState[&I].isOverdefined())
- return (void)markOverdefined(&I);
-
- ValueLatticeElement PtrVal = getValueState(I.getOperand(0));
- if (PtrVal.isUnknownOrUndef())
- return; // The pointer is not resolved yet!
-
- ValueLatticeElement &IV = ValueState[&I];
-
- if (isConstant(PtrVal)) {
- Constant *Ptr = getConstant(PtrVal);
-
- // load null is undefined.
- if (isa<ConstantPointerNull>(Ptr)) {
- if (NullPointerIsDefined(I.getFunction(), I.getPointerAddressSpace()))
- return (void)markOverdefined(IV, &I);
- else
- return;
- }
-
- // Transform load (constant global) into the value loaded.
- if (auto *GV = dyn_cast<GlobalVariable>(Ptr)) {
- if (!TrackedGlobals.empty()) {
- // If we are tracking this global, merge in the known value for it.
- auto It = TrackedGlobals.find(GV);
- if (It != TrackedGlobals.end()) {
- mergeInValue(IV, &I, It->second, getMaxWidenStepsOpts());
- return;
- }
- }
- }
-
- // Transform load from a constant into a constant if possible.
- if (Constant *C = ConstantFoldLoadFromConstPtr(Ptr, I.getType(), DL)) {
- if (isa<UndefValue>(C))
- return;
- return (void)markConstant(IV, &I, C);
- }
- }
-
- // Fall back to metadata.
- mergeInValue(&I, getValueFromMetadata(&I));
-}
-
-void SCCPSolver::visitCallBase(CallBase &CB) {
- handleCallResult(CB);
- handleCallArguments(CB);
-}
-
-void SCCPSolver::handleCallOverdefined(CallBase &CB) {
- Function *F = CB.getCalledFunction();
-
- // Void return and not tracking callee, just bail.
- if (CB.getType()->isVoidTy())
- return;
-
- // Always mark struct return as overdefined.
- if (CB.getType()->isStructTy())
- return (void)markOverdefined(&CB);
-
- // Otherwise, if we have a single return value case, and if the function is
- // a declaration, maybe we can constant fold it.
- if (F && F->isDeclaration() && canConstantFoldCallTo(&CB, F)) {
- SmallVector<Constant *, 8> Operands;
- for (auto AI = CB.arg_begin(), E = CB.arg_end(); AI != E; ++AI) {
- if (AI->get()->getType()->isStructTy())
- return markOverdefined(&CB); // Can't handle struct args.
- ValueLatticeElement State = getValueState(*AI);
-
- if (State.isUnknownOrUndef())
- return; // Operands are not resolved yet.
- if (isOverdefined(State))
- return (void)markOverdefined(&CB);
- assert(isConstant(State) && "Unknown state!");
- Operands.push_back(getConstant(State));
- }
-
- if (isOverdefined(getValueState(&CB)))
- return (void)markOverdefined(&CB);
-
- // If we can constant fold this, mark the result of the call as a
- // constant.
- if (Constant *C = ConstantFoldCall(&CB, F, Operands, &GetTLI(*F))) {
- // call -> undef.
- if (isa<UndefValue>(C))
- return;
- return (void)markConstant(&CB, C);
- }
- }
-
- // Fall back to metadata.
- mergeInValue(&CB, getValueFromMetadata(&CB));
-}
-
-void SCCPSolver::handleCallArguments(CallBase &CB) {
- Function *F = CB.getCalledFunction();
- // If this is a local function that doesn't have its address taken, mark its
- // entry block executable and merge in the actual arguments to the call into
- // the formal arguments of the function.
- if (!TrackingIncomingArguments.empty() &&
- TrackingIncomingArguments.count(F)) {
- MarkBlockExecutable(&F->front());
-
- // Propagate information from this call site into the callee.
- auto CAI = CB.arg_begin();
- for (Function::arg_iterator AI = F->arg_begin(), E = F->arg_end(); AI != E;
- ++AI, ++CAI) {
- // If this argument is byval, and if the function is not readonly, there
- // will be an implicit copy formed of the input aggregate.
- if (AI->hasByValAttr() && !F->onlyReadsMemory()) {
- markOverdefined(&*AI);
- continue;
- }
-
- if (auto *STy = dyn_cast<StructType>(AI->getType())) {
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- ValueLatticeElement CallArg = getStructValueState(*CAI, i);
- mergeInValue(getStructValueState(&*AI, i), &*AI, CallArg,
- getMaxWidenStepsOpts());
- }
- } else
- mergeInValue(&*AI, getValueState(*CAI), getMaxWidenStepsOpts());
- }
- }
-}
-
-void SCCPSolver::handleCallResult(CallBase &CB) {
- Function *F = CB.getCalledFunction();
-
- if (auto *II = dyn_cast<IntrinsicInst>(&CB)) {
- if (II->getIntrinsicID() == Intrinsic::ssa_copy) {
- if (ValueState[&CB].isOverdefined())
- return;
-
- Value *CopyOf = CB.getOperand(0);
- ValueLatticeElement CopyOfVal = getValueState(CopyOf);
- auto *PI = getPredicateInfoFor(&CB);
- assert(PI && "Missing predicate info for ssa.copy");
-
- const Optional<PredicateConstraint> &Constraint = PI->getConstraint();
- if (!Constraint) {
- mergeInValue(ValueState[&CB], &CB, CopyOfVal);
- return;
- }
-
- CmpInst::Predicate Pred = Constraint->Predicate;
- Value *OtherOp = Constraint->OtherOp;
-
- // Wait until OtherOp is resolved.
- if (getValueState(OtherOp).isUnknown()) {
- addAdditionalUser(OtherOp, &CB);
- return;
- }
-
- // TODO: Actually filp MayIncludeUndef for the created range to false,
- // once most places in the optimizer respect the branches on
- // undef/poison are UB rule. The reason why the new range cannot be
- // undef is as follows below:
- // The new range is based on a branch condition. That guarantees that
- // neither of the compare operands can be undef in the branch targets,
- // unless we have conditions that are always true/false (e.g. icmp ule
- // i32, %a, i32_max). For the latter overdefined/empty range will be
- // inferred, but the branch will get folded accordingly anyways.
- bool MayIncludeUndef = !isa<PredicateAssume>(PI);
-
- ValueLatticeElement CondVal = getValueState(OtherOp);
- ValueLatticeElement &IV = ValueState[&CB];
- if (CondVal.isConstantRange() || CopyOfVal.isConstantRange()) {
- auto ImposedCR =
- ConstantRange::getFull(DL.getTypeSizeInBits(CopyOf->getType()));
-
- // Get the range imposed by the condition.
- if (CondVal.isConstantRange())
- ImposedCR = ConstantRange::makeAllowedICmpRegion(
- Pred, CondVal.getConstantRange());
-
- // Combine range info for the original value with the new range from the
- // condition.
- auto CopyOfCR = CopyOfVal.isConstantRange()
- ? CopyOfVal.getConstantRange()
- : ConstantRange::getFull(
- DL.getTypeSizeInBits(CopyOf->getType()));
- auto NewCR = ImposedCR.intersectWith(CopyOfCR);
- // If the existing information is != x, do not use the information from
- // a chained predicate, as the != x information is more likely to be
- // helpful in practice.
- if (!CopyOfCR.contains(NewCR) && CopyOfCR.getSingleMissingElement())
- NewCR = CopyOfCR;
-
- addAdditionalUser(OtherOp, &CB);
- mergeInValue(
- IV, &CB,
- ValueLatticeElement::getRange(NewCR, MayIncludeUndef));
- return;
- } else if (Pred == CmpInst::ICMP_EQ && CondVal.isConstant()) {
- // For non-integer values or integer constant expressions, only
- // propagate equal constants.
- addAdditionalUser(OtherOp, &CB);
- mergeInValue(IV, &CB, CondVal);
- return;
- } else if (Pred == CmpInst::ICMP_NE && CondVal.isConstant() &&
- !MayIncludeUndef) {
- // Propagate inequalities.
- addAdditionalUser(OtherOp, &CB);
- mergeInValue(IV, &CB,
- ValueLatticeElement::getNot(CondVal.getConstant()));
- return;
- }
-
- return (void)mergeInValue(IV, &CB, CopyOfVal);
- }
-
- if (ConstantRange::isIntrinsicSupported(II->getIntrinsicID())) {
- // Compute result range for intrinsics supported by ConstantRange.
- // Do this even if we don't know a range for all operands, as we may
- // still know something about the result range, e.g. of abs(x).
- SmallVector<ConstantRange, 2> OpRanges;
- for (Value *Op : II->args()) {
- const ValueLatticeElement &State = getValueState(Op);
- if (State.isConstantRange())
- OpRanges.push_back(State.getConstantRange());
- else
- OpRanges.push_back(
- ConstantRange::getFull(Op->getType()->getScalarSizeInBits()));
- }
-
- ConstantRange Result =
- ConstantRange::intrinsic(II->getIntrinsicID(), OpRanges);
- return (void)mergeInValue(II, ValueLatticeElement::getRange(Result));
- }
- }
-
- // The common case is that we aren't tracking the callee, either because we
- // are not doing interprocedural analysis or the callee is indirect, or is
- // external. Handle these cases first.
- if (!F || F->isDeclaration())
- return handleCallOverdefined(CB);
-
- // If this is a single/zero retval case, see if we're tracking the function.
- if (auto *STy = dyn_cast<StructType>(F->getReturnType())) {
- if (!MRVFunctionsTracked.count(F))
- return handleCallOverdefined(CB); // Not tracking this callee.
-
- // If we are tracking this callee, propagate the result of the function
- // into this call site.
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i)
- mergeInValue(getStructValueState(&CB, i), &CB,
- TrackedMultipleRetVals[std::make_pair(F, i)],
- getMaxWidenStepsOpts());
- } else {
- auto TFRVI = TrackedRetVals.find(F);
- if (TFRVI == TrackedRetVals.end())
- return handleCallOverdefined(CB); // Not tracking this callee.
-
- // If so, propagate the return value of the callee into this call result.
- mergeInValue(&CB, TFRVI->second, getMaxWidenStepsOpts());
- }
-}
-
-void SCCPSolver::Solve() {
- // Process the work lists until they are empty!
- while (!BBWorkList.empty() || !InstWorkList.empty() ||
- !OverdefinedInstWorkList.empty()) {
- // Process the overdefined instruction's work list first, which drives other
- // things to overdefined more quickly.
- while (!OverdefinedInstWorkList.empty()) {
- Value *I = OverdefinedInstWorkList.pop_back_val();
-
- LLVM_DEBUG(dbgs() << "\nPopped off OI-WL: " << *I << '\n');
-
- // "I" got into the work list because it either made the transition from
- // bottom to constant, or to overdefined.
- //
- // Anything on this worklist that is overdefined need not be visited
- // since all of its users will have already been marked as overdefined
- // Update all of the users of this instruction's value.
- //
- markUsersAsChanged(I);
- }
-
- // Process the instruction work list.
- while (!InstWorkList.empty()) {
- Value *I = InstWorkList.pop_back_val();
-
- LLVM_DEBUG(dbgs() << "\nPopped off I-WL: " << *I << '\n');
-
- // "I" got into the work list because it made the transition from undef to
- // constant.
- //
- // Anything on this worklist that is overdefined need not be visited
- // since all of its users will have already been marked as overdefined.
- // Update all of the users of this instruction's value.
- //
- if (I->getType()->isStructTy() || !getValueState(I).isOverdefined())
- markUsersAsChanged(I);
- }
-
- // Process the basic block work list.
- while (!BBWorkList.empty()) {
- BasicBlock *BB = BBWorkList.pop_back_val();
-
- LLVM_DEBUG(dbgs() << "\nPopped off BBWL: " << *BB << '\n');
-
- // Notify all instructions in this basic block that they are newly
- // executable.
- visit(BB);
- }
- }
-}
-
-/// ResolvedUndefsIn - While solving the dataflow for a function, we assume
-/// that branches on undef values cannot reach any of their successors.
-/// However, this is not a safe assumption. After we solve dataflow, this
-/// method should be use to handle this. If this returns true, the solver
-/// should be rerun.
-///
-/// This method handles this by finding an unresolved branch and marking it one
-/// of the edges from the block as being feasible, even though the condition
-/// doesn't say it would otherwise be. This allows SCCP to find the rest of the
-/// CFG and only slightly pessimizes the analysis results (by marking one,
-/// potentially infeasible, edge feasible). This cannot usefully modify the
-/// constraints on the condition of the branch, as that would impact other users
-/// of the value.
-///
-/// This scan also checks for values that use undefs. It conservatively marks
-/// them as overdefined.
-bool SCCPSolver::ResolvedUndefsIn(Function &F) {
- bool MadeChange = false;
- for (BasicBlock &BB : F) {
- if (!BBExecutable.count(&BB))
- continue;
-
- for (Instruction &I : BB) {
- // Look for instructions which produce undef values.
- if (I.getType()->isVoidTy()) continue;
-
- if (auto *STy = dyn_cast<StructType>(I.getType())) {
- // Only a few things that can be structs matter for undef.
-
- // Tracked calls must never be marked overdefined in ResolvedUndefsIn.
- if (auto *CB = dyn_cast<CallBase>(&I))
- if (Function *F = CB->getCalledFunction())
- if (MRVFunctionsTracked.count(F))
- continue;
-
- // extractvalue and insertvalue don't need to be marked; they are
- // tracked as precisely as their operands.
- if (isa<ExtractValueInst>(I) || isa<InsertValueInst>(I))
- continue;
- // Send the results of everything else to overdefined. We could be
- // more precise than this but it isn't worth bothering.
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
- ValueLatticeElement &LV = getStructValueState(&I, i);
- if (LV.isUnknownOrUndef()) {
- markOverdefined(LV, &I);
- MadeChange = true;
- }
- }
- continue;
- }
-
- ValueLatticeElement &LV = getValueState(&I);
- if (!LV.isUnknownOrUndef())
- continue;
-
- // There are two reasons a call can have an undef result
- // 1. It could be tracked.
- // 2. It could be constant-foldable.
- // Because of the way we solve return values, tracked calls must
- // never be marked overdefined in ResolvedUndefsIn.
- if (auto *CB = dyn_cast<CallBase>(&I))
- if (Function *F = CB->getCalledFunction())
- if (TrackedRetVals.count(F))
- continue;
-
- if (isa<LoadInst>(I)) {
- // A load here means one of two things: a load of undef from a global,
- // a load from an unknown pointer. Either way, having it return undef
- // is okay.
- continue;
- }
-
- markOverdefined(&I);
- MadeChange = true;
- }
-
- // Check to see if we have a branch or switch on an undefined value. If so
- // we force the branch to go one way or the other to make the successor
- // values live. It doesn't really matter which way we force it.
- Instruction *TI = BB.getTerminator();
- if (auto *BI = dyn_cast<BranchInst>(TI)) {
- if (!BI->isConditional()) continue;
- if (!getValueState(BI->getCondition()).isUnknownOrUndef())
- continue;
-
- // If the input to SCCP is actually branch on undef, fix the undef to
- // false.
- if (isa<UndefValue>(BI->getCondition())) {
- BI->setCondition(ConstantInt::getFalse(BI->getContext()));
- markEdgeExecutable(&BB, TI->getSuccessor(1));
- MadeChange = true;
- continue;
- }
-
- // Otherwise, it is a branch on a symbolic value which is currently
- // considered to be undef. Make sure some edge is executable, so a
- // branch on "undef" always flows somewhere.
- // FIXME: Distinguish between dead code and an LLVM "undef" value.
- BasicBlock *DefaultSuccessor = TI->getSuccessor(1);
- if (markEdgeExecutable(&BB, DefaultSuccessor))
- MadeChange = true;
-
- continue;
- }
-
- if (auto *IBR = dyn_cast<IndirectBrInst>(TI)) {
- // Indirect branch with no successor ?. Its ok to assume it branches
- // to no target.
- if (IBR->getNumSuccessors() < 1)
- continue;
-
- if (!getValueState(IBR->getAddress()).isUnknownOrUndef())
- continue;
-
- // If the input to SCCP is actually branch on undef, fix the undef to
- // the first successor of the indirect branch.
- if (isa<UndefValue>(IBR->getAddress())) {
- IBR->setAddress(BlockAddress::get(IBR->getSuccessor(0)));
- markEdgeExecutable(&BB, IBR->getSuccessor(0));
- MadeChange = true;
- continue;
- }
-
- // Otherwise, it is a branch on a symbolic value which is currently
- // considered to be undef. Make sure some edge is executable, so a
- // branch on "undef" always flows somewhere.
- // FIXME: IndirectBr on "undef" doesn't actually need to go anywhere:
- // we can assume the branch has undefined behavior instead.
- BasicBlock *DefaultSuccessor = IBR->getSuccessor(0);
- if (markEdgeExecutable(&BB, DefaultSuccessor))
- MadeChange = true;
-
- continue;
- }
-
- if (auto *SI = dyn_cast<SwitchInst>(TI)) {
- if (!SI->getNumCases() ||
- !getValueState(SI->getCondition()).isUnknownOrUndef())
- continue;
-
- // If the input to SCCP is actually switch on undef, fix the undef to
- // the first constant.
- if (isa<UndefValue>(SI->getCondition())) {
- SI->setCondition(SI->case_begin()->getCaseValue());
- markEdgeExecutable(&BB, SI->case_begin()->getCaseSuccessor());
- MadeChange = true;
- continue;
- }
-
- // Otherwise, it is a branch on a symbolic value which is currently
- // considered to be undef. Make sure some edge is executable, so a
- // branch on "undef" always flows somewhere.
- // FIXME: Distinguish between dead code and an LLVM "undef" value.
- BasicBlock *DefaultSuccessor = SI->case_begin()->getCaseSuccessor();
- if (markEdgeExecutable(&BB, DefaultSuccessor))
- MadeChange = true;
-
- continue;
- }
- }
-
- return MadeChange;
-}
-
static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) {
Constant *Const = nullptr;
if (V->getType()->isStructTy()) {
@@ -1650,16 +124,19 @@ static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) {
assert(Const && "Constant is nullptr here!");
// Replacing `musttail` instructions with constant breaks `musttail` invariant
- // unless the call itself can be removed
- CallInst *CI = dyn_cast<CallInst>(V);
- if (CI && CI->isMustTailCall() && !CI->isSafeToRemove()) {
- Function *F = CI->getCalledFunction();
+ // unless the call itself can be removed.
+ // Calls with "clang.arc.attachedcall" implicitly use the return value and
+ // those uses cannot be updated with a constant.
+ CallBase *CB = dyn_cast<CallBase>(V);
+ if (CB && ((CB->isMustTailCall() && !CB->isSafeToRemove()) ||
+ CB->getOperandBundle(LLVMContext::OB_clang_arc_attachedcall))) {
+ Function *F = CB->getCalledFunction();
// Don't zap returns of the callee
if (F)
- Solver.AddMustTailCallee(F);
+ Solver.addToMustPreserveReturnsInFunctions(F);
- LLVM_DEBUG(dbgs() << " Can\'t treat the result of musttail call : " << *CI
+ LLVM_DEBUG(dbgs() << " Can\'t treat the result of call " << *CB
<< " as a constant\n");
return false;
}
@@ -1682,7 +159,7 @@ static bool simplifyInstsInBlock(SCCPSolver &Solver, BasicBlock &BB,
if (tryToReplaceWithConstant(Solver, &Inst)) {
if (Inst.isSafeToRemove())
Inst.eraseFromParent();
- // Hey, we just changed something!
+
MadeChanges = true;
++InstRemovedStat;
} else if (isa<SExtInst>(&Inst)) {
@@ -1716,7 +193,7 @@ static bool runSCCP(Function &F, const DataLayout &DL,
F.getContext());
// Mark the first block of the function as being executable.
- Solver.MarkBlockExecutable(&F.front());
+ Solver.markBlockExecutable(&F.front());
// Mark all arguments to the function as being overdefined.
for (Argument &AI : F.args())
@@ -1725,9 +202,9 @@ static bool runSCCP(Function &F, const DataLayout &DL,
// Solve for constants.
bool ResolvedUndefs = true;
while (ResolvedUndefs) {
- Solver.Solve();
+ Solver.solve();
LLVM_DEBUG(dbgs() << "RESOLVING UNDEFs\n");
- ResolvedUndefs = Solver.ResolvedUndefsIn(F);
+ ResolvedUndefs = Solver.resolvedUndefsIn(F);
}
bool MadeChanges = false;
@@ -1762,7 +239,6 @@ PreservedAnalyses SCCPPass::run(Function &F, FunctionAnalysisManager &AM) {
return PreservedAnalyses::all();
auto PA = PreservedAnalyses();
- PA.preserve<GlobalsAA>();
PA.preserveSet<CFGAnalyses>();
return PA;
}
@@ -1821,11 +297,12 @@ static void findReturnsToZap(Function &F,
if (!Solver.isArgumentTrackedFunction(&F))
return;
- // There is a non-removable musttail call site of this function. Zapping
- // returns is not allowed.
- if (Solver.isMustTailCallee(&F)) {
- LLVM_DEBUG(dbgs() << "Can't zap returns of the function : " << F.getName()
- << " due to present musttail call of it\n");
+ if (Solver.mustPreserveReturn(&F)) {
+ LLVM_DEBUG(
+ dbgs()
+ << "Can't zap returns of the function : " << F.getName()
+ << " due to present musttail or \"clang.arc.attachedcall\" call of "
+ "it\n");
return;
}
@@ -1946,17 +423,17 @@ bool llvm::runIPSCCP(
// Determine if we can track the function's return values. If so, add the
// function to the solver's set of return-tracked functions.
if (canTrackReturnsInterprocedurally(&F))
- Solver.AddTrackedFunction(&F);
+ Solver.addTrackedFunction(&F);
// Determine if we can track the function's arguments. If so, add the
// function to the solver's set of argument-tracked functions.
if (canTrackArgumentsInterprocedurally(&F)) {
- Solver.AddArgumentTrackedFunction(&F);
+ Solver.addArgumentTrackedFunction(&F);
continue;
}
// Assume the function is called.
- Solver.MarkBlockExecutable(&F.front());
+ Solver.markBlockExecutable(&F.front());
// Assume nothing about the incoming arguments.
for (Argument &AI : F.args())
@@ -1969,21 +446,21 @@ bool llvm::runIPSCCP(
for (GlobalVariable &G : M.globals()) {
G.removeDeadConstantUsers();
if (canTrackGlobalVariableInterprocedurally(&G))
- Solver.TrackValueOfGlobalVariable(&G);
+ Solver.trackValueOfGlobalVariable(&G);
}
// Solve for constants.
bool ResolvedUndefs = true;
- Solver.Solve();
+ Solver.solve();
while (ResolvedUndefs) {
LLVM_DEBUG(dbgs() << "RESOLVING UNDEFS\n");
ResolvedUndefs = false;
for (Function &F : M) {
- if (Solver.ResolvedUndefsIn(F))
+ if (Solver.resolvedUndefsIn(F))
ResolvedUndefs = true;
}
if (ResolvedUndefs)
- Solver.Solve();
+ Solver.solve();
}
bool MadeChanges = false;
@@ -2049,13 +526,11 @@ bool llvm::runIPSCCP(
// nodes in executable blocks we found values for. The function's entry
// block is not part of BlocksToErase, so we have to handle it separately.
for (BasicBlock *BB : BlocksToErase) {
- NumInstRemoved +=
- changeToUnreachable(BB->getFirstNonPHI(), /*UseLLVMTrap=*/false,
- /*PreserveLCSSA=*/false, &DTU);
+ NumInstRemoved += changeToUnreachable(BB->getFirstNonPHI(),
+ /*PreserveLCSSA=*/false, &DTU);
}
if (!Solver.isBlockExecutable(&F.front()))
NumInstRemoved += changeToUnreachable(F.front().getFirstNonPHI(),
- /*UseLLVMTrap=*/false,
/*PreserveLCSSA=*/false, &DTU);
for (BasicBlock &BB : F)
diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index d111a6ba4241..5ec01454e5b2 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -768,7 +768,8 @@ private:
// We allow splitting of non-volatile loads and stores where the type is an
// integer type. These may be used to implement 'memcpy' or other "transfer
// of bits" patterns.
- bool IsSplittable = Ty->isIntegerTy() && !IsVolatile;
+ bool IsSplittable =
+ Ty->isIntegerTy() && !IsVolatile && DL.typeSizeEqualsStoreSize(Ty);
insertUse(I, Offset, Size, IsSplittable);
}
@@ -926,7 +927,8 @@ private:
"Map index doesn't point back to a slice with this user.");
}
- // Disable SRoA for any intrinsics except for lifetime invariants.
+ // Disable SRoA for any intrinsics except for lifetime invariants and
+ // invariant group.
// FIXME: What about debug intrinsics? This matches old behavior, but
// doesn't make sense.
void visitIntrinsicInst(IntrinsicInst &II) {
@@ -946,6 +948,11 @@ private:
return;
}
+ if (II.isLaunderOrStripInvariantGroup()) {
+ enqueueUsers(II);
+ return;
+ }
+
Base::visitIntrinsicInst(II);
}
@@ -2461,14 +2468,17 @@ private:
Pass.DeadInsts.push_back(I);
}
- Value *rewriteVectorizedLoadInst() {
+ Value *rewriteVectorizedLoadInst(LoadInst &LI) {
unsigned BeginIndex = getIndex(NewBeginOffset);
unsigned EndIndex = getIndex(NewEndOffset);
assert(EndIndex > BeginIndex && "Empty vector!");
- Value *V = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI,
- NewAI.getAlign(), "load");
- return extractVector(IRB, V, BeginIndex, EndIndex, "vec");
+ LoadInst *Load = IRB.CreateAlignedLoad(NewAI.getAllocatedType(), &NewAI,
+ NewAI.getAlign(), "load");
+
+ Load->copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
+ LLVMContext::MD_access_group});
+ return extractVector(IRB, Load, BeginIndex, EndIndex, "vec");
}
Value *rewriteIntegerLoad(LoadInst &LI) {
@@ -2512,7 +2522,7 @@ private:
bool IsPtrAdjusted = false;
Value *V;
if (VecTy) {
- V = rewriteVectorizedLoadInst();
+ V = rewriteVectorizedLoadInst(LI);
} else if (IntTy && LI.getType()->isIntegerTy()) {
V = rewriteIntegerLoad(LI);
} else if (NewBeginOffset == NewAllocaBeginOffset &&
@@ -2524,7 +2534,7 @@ private:
NewAI.getAlign(), LI.isVolatile(),
LI.getName());
if (AATags)
- NewLI->setAAMetadata(AATags);
+ NewLI->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
if (LI.isVolatile())
NewLI->setAtomic(LI.getOrdering(), LI.getSyncScopeID());
if (NewLI->isAtomic())
@@ -2563,9 +2573,11 @@ private:
IRB.CreateAlignedLoad(TargetTy, getNewAllocaSlicePtr(IRB, LTy),
getSliceAlign(), LI.isVolatile(), LI.getName());
if (AATags)
- NewLI->setAAMetadata(AATags);
+ NewLI->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
if (LI.isVolatile())
NewLI->setAtomic(LI.getOrdering(), LI.getSyncScopeID());
+ NewLI->copyMetadata(LI, {LLVMContext::MD_mem_parallel_loop_access,
+ LLVMContext::MD_access_group});
V = NewLI;
IsPtrAdjusted = true;
@@ -2625,8 +2637,10 @@ private:
V = insertVector(IRB, Old, V, BeginIndex, "vec");
}
StoreInst *Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlign());
+ Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
+ LLVMContext::MD_access_group});
if (AATags)
- Store->setAAMetadata(AATags);
+ Store->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
Pass.DeadInsts.push_back(&SI);
LLVM_DEBUG(dbgs() << " to: " << *Store << "\n");
@@ -2650,7 +2664,7 @@ private:
Store->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
LLVMContext::MD_access_group});
if (AATags)
- Store->setAAMetadata(AATags);
+ Store->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
Pass.DeadInsts.push_back(&SI);
LLVM_DEBUG(dbgs() << " to: " << *Store << "\n");
return true;
@@ -2720,7 +2734,7 @@ private:
NewSI->copyMetadata(SI, {LLVMContext::MD_mem_parallel_loop_access,
LLVMContext::MD_access_group});
if (AATags)
- NewSI->setAAMetadata(AATags);
+ NewSI->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
if (SI.isVolatile())
NewSI->setAtomic(SI.getOrdering(), SI.getSyncScopeID());
if (NewSI->isAtomic())
@@ -2775,7 +2789,7 @@ private:
// If the memset has a variable size, it cannot be split, just adjust the
// pointer to the new alloca.
- if (!isa<Constant>(II.getLength())) {
+ if (!isa<ConstantInt>(II.getLength())) {
assert(!IsSplit);
assert(NewBeginOffset == BeginOffset);
II.setDest(getNewAllocaSlicePtr(IRB, OldPtr->getType()));
@@ -2816,7 +2830,7 @@ private:
getNewAllocaSlicePtr(IRB, OldPtr->getType()), II.getValue(), Size,
MaybeAlign(getSliceAlign()), II.isVolatile());
if (AATags)
- New->setAAMetadata(AATags);
+ New->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
LLVM_DEBUG(dbgs() << " to: " << *New << "\n");
return false;
}
@@ -2884,8 +2898,10 @@ private:
StoreInst *New =
IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlign(), II.isVolatile());
+ New->copyMetadata(II, {LLVMContext::MD_mem_parallel_loop_access,
+ LLVMContext::MD_access_group});
if (AATags)
- New->setAAMetadata(AATags);
+ New->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
LLVM_DEBUG(dbgs() << " to: " << *New << "\n");
return !II.isVolatile();
}
@@ -3006,7 +3022,7 @@ private:
CallInst *New = IRB.CreateMemCpy(DestPtr, DestAlign, SrcPtr, SrcAlign,
Size, II.isVolatile());
if (AATags)
- New->setAAMetadata(AATags);
+ New->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
LLVM_DEBUG(dbgs() << " to: " << *New << "\n");
return false;
}
@@ -3059,8 +3075,10 @@ private:
} else {
LoadInst *Load = IRB.CreateAlignedLoad(OtherTy, SrcPtr, SrcAlign,
II.isVolatile(), "copyload");
+ Load->copyMetadata(II, {LLVMContext::MD_mem_parallel_loop_access,
+ LLVMContext::MD_access_group});
if (AATags)
- Load->setAAMetadata(AATags);
+ Load->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
Src = Load;
}
@@ -3079,8 +3097,10 @@ private:
StoreInst *Store = cast<StoreInst>(
IRB.CreateAlignedStore(Src, DstPtr, DstAlign, II.isVolatile()));
+ Store->copyMetadata(II, {LLVMContext::MD_mem_parallel_loop_access,
+ LLVMContext::MD_access_group});
if (AATags)
- Store->setAAMetadata(AATags);
+ Store->setAAMetadata(AATags.shift(NewBeginOffset - BeginOffset));
LLVM_DEBUG(dbgs() << " to: " << *Store << "\n");
return !II.isVolatile();
}
@@ -3381,8 +3401,13 @@ private:
IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name + ".gep");
LoadInst *Load =
IRB.CreateAlignedLoad(Ty, GEP, Alignment, Name + ".load");
- if (AATags)
- Load->setAAMetadata(AATags);
+
+ APInt Offset(
+ DL.getIndexSizeInBits(Ptr->getType()->getPointerAddressSpace()), 0);
+ if (AATags &&
+ GEPOperator::accumulateConstantOffset(BaseTy, GEPIndices, DL, Offset))
+ Load->setAAMetadata(AATags.shift(Offset.getZExtValue()));
+
Agg = IRB.CreateInsertValue(Agg, Load, Indices, Name + ".insert");
LLVM_DEBUG(dbgs() << " to: " << *Load << "\n");
}
@@ -3428,8 +3453,13 @@ private:
IRB.CreateInBoundsGEP(BaseTy, Ptr, GEPIndices, Name + ".gep");
StoreInst *Store =
IRB.CreateAlignedStore(ExtractValue, InBoundsGEP, Alignment);
- if (AATags)
- Store->setAAMetadata(AATags);
+
+ APInt Offset(
+ DL.getIndexSizeInBits(Ptr->getType()->getPointerAddressSpace()), 0);
+ if (AATags &&
+ GEPOperator::accumulateConstantOffset(BaseTy, GEPIndices, DL, Offset))
+ Store->setAAMetadata(AATags.shift(Offset.getZExtValue()));
+
LLVM_DEBUG(dbgs() << " to: " << *Store << "\n");
}
};
@@ -3478,20 +3508,22 @@ private:
SmallVector<Value *, 4> Index(GEPI.indices());
bool IsInBounds = GEPI.isInBounds();
+ Type *Ty = GEPI.getSourceElementType();
Value *True = Sel->getTrueValue();
Value *NTrue =
IsInBounds
- ? Builder.CreateInBoundsGEP(True, Index,
+ ? Builder.CreateInBoundsGEP(Ty, True, Index,
True->getName() + ".sroa.gep")
- : Builder.CreateGEP(True, Index, True->getName() + ".sroa.gep");
+ : Builder.CreateGEP(Ty, True, Index, True->getName() + ".sroa.gep");
Value *False = Sel->getFalseValue();
Value *NFalse =
IsInBounds
- ? Builder.CreateInBoundsGEP(False, Index,
+ ? Builder.CreateInBoundsGEP(Ty, False, Index,
False->getName() + ".sroa.gep")
- : Builder.CreateGEP(False, Index, False->getName() + ".sroa.gep");
+ : Builder.CreateGEP(Ty, False, Index,
+ False->getName() + ".sroa.gep");
Value *NSel = Builder.CreateSelect(Sel->getCondition(), NTrue, NFalse,
Sel->getName() + ".sroa.sel");
@@ -3545,9 +3577,10 @@ private:
Instruction *In = cast<Instruction>(PHI->getIncomingValue(I));
IRBuilderTy B(In->getParent(), std::next(In->getIterator()));
+ Type *Ty = GEPI.getSourceElementType();
NewVal = IsInBounds
- ? B.CreateInBoundsGEP(In, Index, In->getName() + ".sroa.gep")
- : B.CreateGEP(In, Index, In->getName() + ".sroa.gep");
+ ? B.CreateInBoundsGEP(Ty, In, Index, In->getName() + ".sroa.gep")
+ : B.CreateGEP(Ty, In, Index, In->getName() + ".sroa.gep");
}
NewPN->addIncoming(NewVal, B);
}
@@ -3970,6 +4003,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
SplitLoads.clear();
IntegerType *Ty = cast<IntegerType>(LI->getType());
+ assert(Ty->getBitWidth() % 8 == 0);
uint64_t LoadSize = Ty->getBitWidth() / 8;
assert(LoadSize > 0 && "Cannot have a zero-sized integer load!");
@@ -4056,7 +4090,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
PartPtrTy, StoreBasePtr->getName() + "."),
getAdjustedAlignment(SI, PartOffset),
/*IsVolatile*/ false);
- PStore->copyMetadata(*LI, {LLVMContext::MD_mem_parallel_loop_access,
+ PStore->copyMetadata(*SI, {LLVMContext::MD_mem_parallel_loop_access,
LLVMContext::MD_access_group});
LLVM_DEBUG(dbgs() << " +" << PartOffset << ":" << *PStore << "\n");
}
@@ -4094,6 +4128,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
for (StoreInst *SI : Stores) {
auto *LI = cast<LoadInst>(SI->getValueOperand());
IntegerType *Ty = cast<IntegerType>(LI->getType());
+ assert(Ty->getBitWidth() % 8 == 0);
uint64_t StoreSize = Ty->getBitWidth() / 8;
assert(StoreSize > 0 && "Cannot have a zero-sized integer store!");
@@ -4141,6 +4176,8 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
LoadPartPtrTy, LoadBasePtr->getName() + "."),
getAdjustedAlignment(LI, PartOffset),
/*IsVolatile*/ false, LI->getName());
+ PLoad->copyMetadata(*LI, {LLVMContext::MD_mem_parallel_loop_access,
+ LLVMContext::MD_access_group});
}
// And store this partition.
@@ -4153,6 +4190,8 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) {
StorePartPtrTy, StoreBasePtr->getName() + "."),
getAdjustedAlignment(SI, PartOffset),
/*IsVolatile*/ false);
+ PStore->copyMetadata(*SI, {LLVMContext::MD_mem_parallel_loop_access,
+ LLVMContext::MD_access_group});
// Now build a new slice for the alloca.
NewSlices.push_back(
@@ -4761,7 +4800,6 @@ PreservedAnalyses SROA::runImpl(Function &F, DominatorTree &RunDT,
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/Scalar.cpp b/llvm/lib/Transforms/Scalar/Scalar.cpp
index dba3dba24e25..a041af0d70d0 100644
--- a/llvm/lib/Transforms/Scalar/Scalar.cpp
+++ b/llvm/lib/Transforms/Scalar/Scalar.cpp
@@ -60,6 +60,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
initializeInferAddressSpacesPass(Registry);
initializeInstSimplifyLegacyPassPass(Registry);
initializeJumpThreadingPass(Registry);
+ initializeDFAJumpThreadingLegacyPassPass(Registry);
initializeLegacyLICMPassPass(Registry);
initializeLegacyLoopSinkPassPass(Registry);
initializeLoopFuseLegacyPass(Registry);
diff --git a/llvm/lib/Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp b/llvm/lib/Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp
index afa2d1bc7966..ca288a533f46 100644
--- a/llvm/lib/Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp
+++ b/llvm/lib/Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp
@@ -15,11 +15,13 @@
#include "llvm/Transforms/Scalar/ScalarizeMaskedMemIntrin.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Analysis/DomTreeUpdater.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstrTypes.h"
@@ -33,6 +35,7 @@
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include <algorithm>
#include <cassert>
@@ -59,16 +62,18 @@ public:
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<TargetTransformInfoWrapperPass>();
+ AU.addPreserved<DominatorTreeWrapperPass>();
}
};
} // end anonymous namespace
static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT,
- const TargetTransformInfo &TTI, const DataLayout &DL);
+ const TargetTransformInfo &TTI, const DataLayout &DL,
+ DomTreeUpdater *DTU);
static bool optimizeCallInst(CallInst *CI, bool &ModifiedDT,
const TargetTransformInfo &TTI,
- const DataLayout &DL);
+ const DataLayout &DL, DomTreeUpdater *DTU);
char ScalarizeMaskedMemIntrinLegacyPass::ID = 0;
@@ -76,6 +81,7 @@ INITIALIZE_PASS_BEGIN(ScalarizeMaskedMemIntrinLegacyPass, DEBUG_TYPE,
"Scalarize unsupported masked memory intrinsics", false,
false)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_END(ScalarizeMaskedMemIntrinLegacyPass, DEBUG_TYPE,
"Scalarize unsupported masked memory intrinsics", false,
false)
@@ -99,6 +105,11 @@ static bool isConstantIntVector(Value *Mask) {
return true;
}
+static unsigned adjustForEndian(const DataLayout &DL, unsigned VectorWidth,
+ unsigned Idx) {
+ return DL.isBigEndian() ? VectorWidth - 1 - Idx : Idx;
+}
+
// Translate a masked load intrinsic like
// <16 x i32 > @llvm.masked.load( <16 x i32>* %addr, i32 align,
// <16 x i1> %mask, <16 x i32> %passthru)
@@ -131,7 +142,8 @@ static bool isConstantIntVector(Value *Mask) {
// %10 = extractelement <16 x i1> %mask, i32 2
// br i1 %10, label %cond.load4, label %else5
//
-static void scalarizeMaskedLoad(CallInst *CI, bool &ModifiedDT) {
+static void scalarizeMaskedLoad(const DataLayout &DL, CallInst *CI,
+ DomTreeUpdater *DTU, bool &ModifiedDT) {
Value *Ptr = CI->getArgOperand(0);
Value *Alignment = CI->getArgOperand(1);
Value *Mask = CI->getArgOperand(2);
@@ -200,7 +212,8 @@ static void scalarizeMaskedLoad(CallInst *CI, bool &ModifiedDT) {
//
Value *Predicate;
if (VectorWidth != 1) {
- Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx));
+ Value *Mask = Builder.getInt(APInt::getOneBitSet(
+ VectorWidth, adjustForEndian(DL, VectorWidth, Idx)));
Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask),
Builder.getIntN(VectorWidth, 0));
} else {
@@ -213,25 +226,26 @@ static void scalarizeMaskedLoad(CallInst *CI, bool &ModifiedDT) {
// %Elt = load i32* %EltAddr
// VResult = insertelement <16 x i32> VResult, i32 %Elt, i32 Idx
//
- BasicBlock *CondBlock = IfBlock->splitBasicBlock(InsertPt->getIterator(),
- "cond.load");
- Builder.SetInsertPoint(InsertPt);
+ Instruction *ThenTerm =
+ SplitBlockAndInsertIfThen(Predicate, InsertPt, /*Unreachable=*/false,
+ /*BranchWeights=*/nullptr, DTU);
+
+ BasicBlock *CondBlock = ThenTerm->getParent();
+ CondBlock->setName("cond.load");
+ Builder.SetInsertPoint(CondBlock->getTerminator());
Value *Gep = Builder.CreateConstInBoundsGEP1_32(EltTy, FirstEltPtr, Idx);
LoadInst *Load = Builder.CreateAlignedLoad(EltTy, Gep, AdjustedAlignVal);
Value *NewVResult = Builder.CreateInsertElement(VResult, Load, Idx);
// Create "else" block, fill it in the next iteration
- BasicBlock *NewIfBlock =
- CondBlock->splitBasicBlock(InsertPt->getIterator(), "else");
- Builder.SetInsertPoint(InsertPt);
- Instruction *OldBr = IfBlock->getTerminator();
- BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr);
- OldBr->eraseFromParent();
+ BasicBlock *NewIfBlock = ThenTerm->getSuccessor(0);
+ NewIfBlock->setName("else");
BasicBlock *PrevIfBlock = IfBlock;
IfBlock = NewIfBlock;
// Create the phi to join the new and previous value.
+ Builder.SetInsertPoint(NewIfBlock, NewIfBlock->begin());
PHINode *Phi = Builder.CreatePHI(VecType, 2, "res.phi.else");
Phi->addIncoming(NewVResult, CondBlock);
Phi->addIncoming(VResult, PrevIfBlock);
@@ -270,7 +284,8 @@ static void scalarizeMaskedLoad(CallInst *CI, bool &ModifiedDT) {
// store i32 %6, i32* %7
// br label %else2
// . . .
-static void scalarizeMaskedStore(CallInst *CI, bool &ModifiedDT) {
+static void scalarizeMaskedStore(const DataLayout &DL, CallInst *CI,
+ DomTreeUpdater *DTU, bool &ModifiedDT) {
Value *Src = CI->getArgOperand(0);
Value *Ptr = CI->getArgOperand(1);
Value *Alignment = CI->getArgOperand(2);
@@ -283,7 +298,6 @@ static void scalarizeMaskedStore(CallInst *CI, bool &ModifiedDT) {
IRBuilder<> Builder(CI->getContext());
Instruction *InsertPt = CI;
- BasicBlock *IfBlock = CI->getParent();
Builder.SetInsertPoint(InsertPt);
Builder.SetCurrentDebugLocation(CI->getDebugLoc());
@@ -332,7 +346,8 @@ static void scalarizeMaskedStore(CallInst *CI, bool &ModifiedDT) {
//
Value *Predicate;
if (VectorWidth != 1) {
- Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx));
+ Value *Mask = Builder.getInt(APInt::getOneBitSet(
+ VectorWidth, adjustForEndian(DL, VectorWidth, Idx)));
Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask),
Builder.getIntN(VectorWidth, 0));
} else {
@@ -345,22 +360,23 @@ static void scalarizeMaskedStore(CallInst *CI, bool &ModifiedDT) {
// %EltAddr = getelementptr i32* %1, i32 0
// %store i32 %OneElt, i32* %EltAddr
//
- BasicBlock *CondBlock =
- IfBlock->splitBasicBlock(InsertPt->getIterator(), "cond.store");
- Builder.SetInsertPoint(InsertPt);
+ Instruction *ThenTerm =
+ SplitBlockAndInsertIfThen(Predicate, InsertPt, /*Unreachable=*/false,
+ /*BranchWeights=*/nullptr, DTU);
+
+ BasicBlock *CondBlock = ThenTerm->getParent();
+ CondBlock->setName("cond.store");
+ Builder.SetInsertPoint(CondBlock->getTerminator());
Value *OneElt = Builder.CreateExtractElement(Src, Idx);
Value *Gep = Builder.CreateConstInBoundsGEP1_32(EltTy, FirstEltPtr, Idx);
Builder.CreateAlignedStore(OneElt, Gep, AdjustedAlignVal);
// Create "else" block, fill it in the next iteration
- BasicBlock *NewIfBlock =
- CondBlock->splitBasicBlock(InsertPt->getIterator(), "else");
- Builder.SetInsertPoint(InsertPt);
- Instruction *OldBr = IfBlock->getTerminator();
- BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr);
- OldBr->eraseFromParent();
- IfBlock = NewIfBlock;
+ BasicBlock *NewIfBlock = ThenTerm->getSuccessor(0);
+ NewIfBlock->setName("else");
+
+ Builder.SetInsertPoint(NewIfBlock, NewIfBlock->begin());
}
CI->eraseFromParent();
@@ -396,7 +412,8 @@ static void scalarizeMaskedStore(CallInst *CI, bool &ModifiedDT) {
// . . .
// %Result = select <16 x i1> %Mask, <16 x i32> %res.phi.select, <16 x i32> %Src
// ret <16 x i32> %Result
-static void scalarizeMaskedGather(CallInst *CI, bool &ModifiedDT) {
+static void scalarizeMaskedGather(const DataLayout &DL, CallInst *CI,
+ DomTreeUpdater *DTU, bool &ModifiedDT) {
Value *Ptrs = CI->getArgOperand(0);
Value *Alignment = CI->getArgOperand(1);
Value *Mask = CI->getArgOperand(2);
@@ -451,7 +468,8 @@ static void scalarizeMaskedGather(CallInst *CI, bool &ModifiedDT) {
Value *Predicate;
if (VectorWidth != 1) {
- Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx));
+ Value *Mask = Builder.getInt(APInt::getOneBitSet(
+ VectorWidth, adjustForEndian(DL, VectorWidth, Idx)));
Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask),
Builder.getIntN(VectorWidth, 0));
} else {
@@ -464,9 +482,14 @@ static void scalarizeMaskedGather(CallInst *CI, bool &ModifiedDT) {
// %Elt = load i32* %EltAddr
// VResult = insertelement <16 x i32> VResult, i32 %Elt, i32 Idx
//
- BasicBlock *CondBlock = IfBlock->splitBasicBlock(InsertPt, "cond.load");
- Builder.SetInsertPoint(InsertPt);
+ Instruction *ThenTerm =
+ SplitBlockAndInsertIfThen(Predicate, InsertPt, /*Unreachable=*/false,
+ /*BranchWeights=*/nullptr, DTU);
+ BasicBlock *CondBlock = ThenTerm->getParent();
+ CondBlock->setName("cond.load");
+
+ Builder.SetInsertPoint(CondBlock->getTerminator());
Value *Ptr = Builder.CreateExtractElement(Ptrs, Idx, "Ptr" + Twine(Idx));
LoadInst *Load =
Builder.CreateAlignedLoad(EltTy, Ptr, AlignVal, "Load" + Twine(Idx));
@@ -474,14 +497,13 @@ static void scalarizeMaskedGather(CallInst *CI, bool &ModifiedDT) {
Builder.CreateInsertElement(VResult, Load, Idx, "Res" + Twine(Idx));
// Create "else" block, fill it in the next iteration
- BasicBlock *NewIfBlock = CondBlock->splitBasicBlock(InsertPt, "else");
- Builder.SetInsertPoint(InsertPt);
- Instruction *OldBr = IfBlock->getTerminator();
- BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr);
- OldBr->eraseFromParent();
+ BasicBlock *NewIfBlock = ThenTerm->getSuccessor(0);
+ NewIfBlock->setName("else");
BasicBlock *PrevIfBlock = IfBlock;
IfBlock = NewIfBlock;
+ // Create the phi to join the new and previous value.
+ Builder.SetInsertPoint(NewIfBlock, NewIfBlock->begin());
PHINode *Phi = Builder.CreatePHI(VecType, 2, "res.phi.else");
Phi->addIncoming(NewVResult, CondBlock);
Phi->addIncoming(VResult, PrevIfBlock);
@@ -520,7 +542,8 @@ static void scalarizeMaskedGather(CallInst *CI, bool &ModifiedDT) {
// store i32 %Elt1, i32* %Ptr1, align 4
// br label %else2
// . . .
-static void scalarizeMaskedScatter(CallInst *CI, bool &ModifiedDT) {
+static void scalarizeMaskedScatter(const DataLayout &DL, CallInst *CI,
+ DomTreeUpdater *DTU, bool &ModifiedDT) {
Value *Src = CI->getArgOperand(0);
Value *Ptrs = CI->getArgOperand(1);
Value *Alignment = CI->getArgOperand(2);
@@ -535,7 +558,6 @@ static void scalarizeMaskedScatter(CallInst *CI, bool &ModifiedDT) {
IRBuilder<> Builder(CI->getContext());
Instruction *InsertPt = CI;
- BasicBlock *IfBlock = CI->getParent();
Builder.SetInsertPoint(InsertPt);
Builder.SetCurrentDebugLocation(CI->getDebugLoc());
@@ -573,7 +595,8 @@ static void scalarizeMaskedScatter(CallInst *CI, bool &ModifiedDT) {
//
Value *Predicate;
if (VectorWidth != 1) {
- Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx));
+ Value *Mask = Builder.getInt(APInt::getOneBitSet(
+ VectorWidth, adjustForEndian(DL, VectorWidth, Idx)));
Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask),
Builder.getIntN(VectorWidth, 0));
} else {
@@ -586,27 +609,31 @@ static void scalarizeMaskedScatter(CallInst *CI, bool &ModifiedDT) {
// %Ptr1 = extractelement <16 x i32*> %Ptrs, i32 1
// %store i32 %Elt1, i32* %Ptr1
//
- BasicBlock *CondBlock = IfBlock->splitBasicBlock(InsertPt, "cond.store");
- Builder.SetInsertPoint(InsertPt);
+ Instruction *ThenTerm =
+ SplitBlockAndInsertIfThen(Predicate, InsertPt, /*Unreachable=*/false,
+ /*BranchWeights=*/nullptr, DTU);
+
+ BasicBlock *CondBlock = ThenTerm->getParent();
+ CondBlock->setName("cond.store");
+ Builder.SetInsertPoint(CondBlock->getTerminator());
Value *OneElt = Builder.CreateExtractElement(Src, Idx, "Elt" + Twine(Idx));
Value *Ptr = Builder.CreateExtractElement(Ptrs, Idx, "Ptr" + Twine(Idx));
Builder.CreateAlignedStore(OneElt, Ptr, AlignVal);
// Create "else" block, fill it in the next iteration
- BasicBlock *NewIfBlock = CondBlock->splitBasicBlock(InsertPt, "else");
- Builder.SetInsertPoint(InsertPt);
- Instruction *OldBr = IfBlock->getTerminator();
- BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr);
- OldBr->eraseFromParent();
- IfBlock = NewIfBlock;
+ BasicBlock *NewIfBlock = ThenTerm->getSuccessor(0);
+ NewIfBlock->setName("else");
+
+ Builder.SetInsertPoint(NewIfBlock, NewIfBlock->begin());
}
CI->eraseFromParent();
ModifiedDT = true;
}
-static void scalarizeMaskedExpandLoad(CallInst *CI, bool &ModifiedDT) {
+static void scalarizeMaskedExpandLoad(const DataLayout &DL, CallInst *CI,
+ DomTreeUpdater *DTU, bool &ModifiedDT) {
Value *Ptr = CI->getArgOperand(0);
Value *Mask = CI->getArgOperand(1);
Value *PassThru = CI->getArgOperand(2);
@@ -674,7 +701,8 @@ static void scalarizeMaskedExpandLoad(CallInst *CI, bool &ModifiedDT) {
Value *Predicate;
if (VectorWidth != 1) {
- Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx));
+ Value *Mask = Builder.getInt(APInt::getOneBitSet(
+ VectorWidth, adjustForEndian(DL, VectorWidth, Idx)));
Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask),
Builder.getIntN(VectorWidth, 0));
} else {
@@ -687,10 +715,14 @@ static void scalarizeMaskedExpandLoad(CallInst *CI, bool &ModifiedDT) {
// %Elt = load i32* %EltAddr
// VResult = insertelement <16 x i32> VResult, i32 %Elt, i32 Idx
//
- BasicBlock *CondBlock = IfBlock->splitBasicBlock(InsertPt->getIterator(),
- "cond.load");
- Builder.SetInsertPoint(InsertPt);
+ Instruction *ThenTerm =
+ SplitBlockAndInsertIfThen(Predicate, InsertPt, /*Unreachable=*/false,
+ /*BranchWeights=*/nullptr, DTU);
+
+ BasicBlock *CondBlock = ThenTerm->getParent();
+ CondBlock->setName("cond.load");
+ Builder.SetInsertPoint(CondBlock->getTerminator());
LoadInst *Load = Builder.CreateAlignedLoad(EltTy, Ptr, Align(1));
Value *NewVResult = Builder.CreateInsertElement(VResult, Load, Idx);
@@ -700,16 +732,13 @@ static void scalarizeMaskedExpandLoad(CallInst *CI, bool &ModifiedDT) {
NewPtr = Builder.CreateConstInBoundsGEP1_32(EltTy, Ptr, 1);
// Create "else" block, fill it in the next iteration
- BasicBlock *NewIfBlock =
- CondBlock->splitBasicBlock(InsertPt->getIterator(), "else");
- Builder.SetInsertPoint(InsertPt);
- Instruction *OldBr = IfBlock->getTerminator();
- BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr);
- OldBr->eraseFromParent();
+ BasicBlock *NewIfBlock = ThenTerm->getSuccessor(0);
+ NewIfBlock->setName("else");
BasicBlock *PrevIfBlock = IfBlock;
IfBlock = NewIfBlock;
// Create the phi to join the new and previous value.
+ Builder.SetInsertPoint(NewIfBlock, NewIfBlock->begin());
PHINode *ResultPhi = Builder.CreatePHI(VecType, 2, "res.phi.else");
ResultPhi->addIncoming(NewVResult, CondBlock);
ResultPhi->addIncoming(VResult, PrevIfBlock);
@@ -730,7 +759,9 @@ static void scalarizeMaskedExpandLoad(CallInst *CI, bool &ModifiedDT) {
ModifiedDT = true;
}
-static void scalarizeMaskedCompressStore(CallInst *CI, bool &ModifiedDT) {
+static void scalarizeMaskedCompressStore(const DataLayout &DL, CallInst *CI,
+ DomTreeUpdater *DTU,
+ bool &ModifiedDT) {
Value *Src = CI->getArgOperand(0);
Value *Ptr = CI->getArgOperand(1);
Value *Mask = CI->getArgOperand(2);
@@ -780,7 +811,8 @@ static void scalarizeMaskedCompressStore(CallInst *CI, bool &ModifiedDT) {
//
Value *Predicate;
if (VectorWidth != 1) {
- Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx));
+ Value *Mask = Builder.getInt(APInt::getOneBitSet(
+ VectorWidth, adjustForEndian(DL, VectorWidth, Idx)));
Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask),
Builder.getIntN(VectorWidth, 0));
} else {
@@ -793,10 +825,14 @@ static void scalarizeMaskedCompressStore(CallInst *CI, bool &ModifiedDT) {
// %EltAddr = getelementptr i32* %1, i32 0
// %store i32 %OneElt, i32* %EltAddr
//
- BasicBlock *CondBlock =
- IfBlock->splitBasicBlock(InsertPt->getIterator(), "cond.store");
- Builder.SetInsertPoint(InsertPt);
+ Instruction *ThenTerm =
+ SplitBlockAndInsertIfThen(Predicate, InsertPt, /*Unreachable=*/false,
+ /*BranchWeights=*/nullptr, DTU);
+ BasicBlock *CondBlock = ThenTerm->getParent();
+ CondBlock->setName("cond.store");
+
+ Builder.SetInsertPoint(CondBlock->getTerminator());
Value *OneElt = Builder.CreateExtractElement(Src, Idx);
Builder.CreateAlignedStore(OneElt, Ptr, Align(1));
@@ -806,15 +842,13 @@ static void scalarizeMaskedCompressStore(CallInst *CI, bool &ModifiedDT) {
NewPtr = Builder.CreateConstInBoundsGEP1_32(EltTy, Ptr, 1);
// Create "else" block, fill it in the next iteration
- BasicBlock *NewIfBlock =
- CondBlock->splitBasicBlock(InsertPt->getIterator(), "else");
- Builder.SetInsertPoint(InsertPt);
- Instruction *OldBr = IfBlock->getTerminator();
- BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr);
- OldBr->eraseFromParent();
+ BasicBlock *NewIfBlock = ThenTerm->getSuccessor(0);
+ NewIfBlock->setName("else");
BasicBlock *PrevIfBlock = IfBlock;
IfBlock = NewIfBlock;
+ Builder.SetInsertPoint(NewIfBlock, NewIfBlock->begin());
+
// Add a PHI for the pointer if this isn't the last iteration.
if ((Idx + 1) != VectorWidth) {
PHINode *PtrPhi = Builder.CreatePHI(Ptr->getType(), 2, "ptr.phi.else");
@@ -828,7 +862,12 @@ static void scalarizeMaskedCompressStore(CallInst *CI, bool &ModifiedDT) {
ModifiedDT = true;
}
-static bool runImpl(Function &F, const TargetTransformInfo &TTI) {
+static bool runImpl(Function &F, const TargetTransformInfo &TTI,
+ DominatorTree *DT) {
+ Optional<DomTreeUpdater> DTU;
+ if (DT)
+ DTU.emplace(DT, DomTreeUpdater::UpdateStrategy::Lazy);
+
bool EverMadeChange = false;
bool MadeChange = true;
auto &DL = F.getParent()->getDataLayout();
@@ -837,7 +876,9 @@ static bool runImpl(Function &F, const TargetTransformInfo &TTI) {
for (Function::iterator I = F.begin(); I != F.end();) {
BasicBlock *BB = &*I++;
bool ModifiedDTOnIteration = false;
- MadeChange |= optimizeBlock(*BB, ModifiedDTOnIteration, TTI, DL);
+ MadeChange |= optimizeBlock(*BB, ModifiedDTOnIteration, TTI, DL,
+ DTU.hasValue() ? DTU.getPointer() : nullptr);
+
// Restart BB iteration if the dominator tree of the Function was changed
if (ModifiedDTOnIteration)
@@ -851,28 +892,33 @@ static bool runImpl(Function &F, const TargetTransformInfo &TTI) {
bool ScalarizeMaskedMemIntrinLegacyPass::runOnFunction(Function &F) {
auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
- return runImpl(F, TTI);
+ DominatorTree *DT = nullptr;
+ if (auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>())
+ DT = &DTWP->getDomTree();
+ return runImpl(F, TTI, DT);
}
PreservedAnalyses
ScalarizeMaskedMemIntrinPass::run(Function &F, FunctionAnalysisManager &AM) {
auto &TTI = AM.getResult<TargetIRAnalysis>(F);
- if (!runImpl(F, TTI))
+ auto *DT = AM.getCachedResult<DominatorTreeAnalysis>(F);
+ if (!runImpl(F, TTI, DT))
return PreservedAnalyses::all();
PreservedAnalyses PA;
PA.preserve<TargetIRAnalysis>();
+ PA.preserve<DominatorTreeAnalysis>();
return PA;
}
static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT,
- const TargetTransformInfo &TTI,
- const DataLayout &DL) {
+ const TargetTransformInfo &TTI, const DataLayout &DL,
+ DomTreeUpdater *DTU) {
bool MadeChange = false;
BasicBlock::iterator CurInstIterator = BB.begin();
while (CurInstIterator != BB.end()) {
if (CallInst *CI = dyn_cast<CallInst>(&*CurInstIterator++))
- MadeChange |= optimizeCallInst(CI, ModifiedDT, TTI, DL);
+ MadeChange |= optimizeCallInst(CI, ModifiedDT, TTI, DL, DTU);
if (ModifiedDT)
return true;
}
@@ -882,7 +928,7 @@ static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT,
static bool optimizeCallInst(CallInst *CI, bool &ModifiedDT,
const TargetTransformInfo &TTI,
- const DataLayout &DL) {
+ const DataLayout &DL, DomTreeUpdater *DTU) {
IntrinsicInst *II = dyn_cast<IntrinsicInst>(CI);
if (II) {
// The scalarization code below does not work for scalable vectors.
@@ -900,46 +946,46 @@ static bool optimizeCallInst(CallInst *CI, bool &ModifiedDT,
CI->getType(),
cast<ConstantInt>(CI->getArgOperand(1))->getAlignValue()))
return false;
- scalarizeMaskedLoad(CI, ModifiedDT);
+ scalarizeMaskedLoad(DL, CI, DTU, ModifiedDT);
return true;
case Intrinsic::masked_store:
if (TTI.isLegalMaskedStore(
CI->getArgOperand(0)->getType(),
cast<ConstantInt>(CI->getArgOperand(2))->getAlignValue()))
return false;
- scalarizeMaskedStore(CI, ModifiedDT);
+ scalarizeMaskedStore(DL, CI, DTU, ModifiedDT);
return true;
case Intrinsic::masked_gather: {
- unsigned AlignmentInt =
- cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue();
+ MaybeAlign MA =
+ cast<ConstantInt>(CI->getArgOperand(1))->getMaybeAlignValue();
Type *LoadTy = CI->getType();
- Align Alignment =
- DL.getValueOrABITypeAlignment(MaybeAlign(AlignmentInt), LoadTy);
+ Align Alignment = DL.getValueOrABITypeAlignment(MA,
+ LoadTy->getScalarType());
if (TTI.isLegalMaskedGather(LoadTy, Alignment))
return false;
- scalarizeMaskedGather(CI, ModifiedDT);
+ scalarizeMaskedGather(DL, CI, DTU, ModifiedDT);
return true;
}
case Intrinsic::masked_scatter: {
- unsigned AlignmentInt =
- cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
+ MaybeAlign MA =
+ cast<ConstantInt>(CI->getArgOperand(2))->getMaybeAlignValue();
Type *StoreTy = CI->getArgOperand(0)->getType();
- Align Alignment =
- DL.getValueOrABITypeAlignment(MaybeAlign(AlignmentInt), StoreTy);
+ Align Alignment = DL.getValueOrABITypeAlignment(MA,
+ StoreTy->getScalarType());
if (TTI.isLegalMaskedScatter(StoreTy, Alignment))
return false;
- scalarizeMaskedScatter(CI, ModifiedDT);
+ scalarizeMaskedScatter(DL, CI, DTU, ModifiedDT);
return true;
}
case Intrinsic::masked_expandload:
if (TTI.isLegalMaskedExpandLoad(CI->getType()))
return false;
- scalarizeMaskedExpandLoad(CI, ModifiedDT);
+ scalarizeMaskedExpandLoad(DL, CI, DTU, ModifiedDT);
return true;
case Intrinsic::masked_compressstore:
if (TTI.isLegalMaskedCompressStore(CI->getArgOperand(0)->getType()))
return false;
- scalarizeMaskedCompressStore(CI, ModifiedDT);
+ scalarizeMaskedCompressStore(DL, CI, DTU, ModifiedDT);
return true;
}
}
diff --git a/llvm/lib/Transforms/Scalar/Scalarizer.cpp b/llvm/lib/Transforms/Scalar/Scalarizer.cpp
index c95984fe198f..8ef6b69673be 100644
--- a/llvm/lib/Transforms/Scalar/Scalarizer.cpp
+++ b/llvm/lib/Transforms/Scalar/Scalarizer.cpp
@@ -510,8 +510,8 @@ static bool isTriviallyScalariable(Intrinsic::ID ID) {
// All of the current scalarizable intrinsics only have one mangled type.
static Function *getScalarIntrinsicDeclaration(Module *M,
Intrinsic::ID ID,
- VectorType *Ty) {
- return Intrinsic::getDeclaration(M, ID, { Ty->getScalarType() });
+ ArrayRef<Type*> Tys) {
+ return Intrinsic::getDeclaration(M, ID, Tys);
}
/// If a call to a vector typed intrinsic function, split into a scalar call per
@@ -537,6 +537,9 @@ bool ScalarizerVisitor::splitCall(CallInst &CI) {
Scattered.resize(NumArgs);
+ SmallVector<llvm::Type *, 3> Tys;
+ Tys.push_back(VT->getScalarType());
+
// Assumes that any vector type has the same number of elements as the return
// vector type, which is true for all current intrinsics.
for (unsigned I = 0; I != NumArgs; ++I) {
@@ -546,13 +549,15 @@ bool ScalarizerVisitor::splitCall(CallInst &CI) {
assert(Scattered[I].size() == NumElems && "mismatched call operands");
} else {
ScalarOperands[I] = OpI;
+ if (hasVectorInstrinsicOverloadedScalarOpd(ID, I))
+ Tys.push_back(OpI->getType());
}
}
ValueVector Res(NumElems);
ValueVector ScalarCallOps(NumArgs);
- Function *NewIntrin = getScalarIntrinsicDeclaration(F->getParent(), ID, VT);
+ Function *NewIntrin = getScalarIntrinsicDeclaration(F->getParent(), ID, Tys);
IRBuilder<> Builder(&CI);
// Perform actual scalarization, taking care to preserve any scalar operands.
diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index 9d3c8d0f3739..b9cccc2af309 100644
--- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -38,6 +38,7 @@
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/Value.h"
#include "llvm/InitializePasses.h"
@@ -63,6 +64,7 @@
#define DEBUG_TYPE "simple-loop-unswitch"
using namespace llvm;
+using namespace llvm::PatternMatch;
STATISTIC(NumBranches, "Number of branches unswitched");
STATISTIC(NumSwitches, "Number of switches unswitched");
@@ -101,6 +103,11 @@ static cl::opt<bool> DropNonTrivialImplicitNullChecks(
cl::init(false), cl::Hidden,
cl::desc("If enabled, drop make.implicit metadata in unswitched implicit "
"null checks to save time analyzing if we can keep it."));
+static cl::opt<unsigned>
+ MSSAThreshold("simple-loop-unswitch-memoryssa-threshold",
+ cl::desc("Max number of memory uses to explore during "
+ "partial unswitching analysis"),
+ cl::init(100), cl::Hidden);
/// Collect all of the loop invariant input values transitively used by the
/// homogeneous instruction graph from a given root.
@@ -116,6 +123,9 @@ collectHomogenousInstGraphLoopInvariants(Loop &L, Instruction &Root,
"Only need to walk the graph if root itself is not invariant.");
TinyPtrVector<Value *> Invariants;
+ bool IsRootAnd = match(&Root, m_LogicalAnd());
+ bool IsRootOr = match(&Root, m_LogicalOr());
+
// Build a worklist and recurse through operators collecting invariants.
SmallVector<Instruction *, 4> Worklist;
SmallPtrSet<Instruction *, 8> Visited;
@@ -136,12 +146,13 @@ collectHomogenousInstGraphLoopInvariants(Loop &L, Instruction &Root,
// If not an instruction with the same opcode, nothing we can do.
Instruction *OpI = dyn_cast<Instruction>(OpV);
- if (!OpI || OpI->getOpcode() != Root.getOpcode())
- continue;
- // Visit this operand.
- if (Visited.insert(OpI).second)
- Worklist.push_back(OpI);
+ if (OpI && ((IsRootAnd && match(OpI, m_LogicalAnd())) ||
+ (IsRootOr && match(OpI, m_LogicalOr())))) {
+ // Visit this operand.
+ if (Visited.insert(OpI).second)
+ Worklist.push_back(OpI);
+ }
}
} while (!Worklist.empty());
@@ -153,14 +164,13 @@ static void replaceLoopInvariantUses(Loop &L, Value *Invariant,
assert(!isa<Constant>(Invariant) && "Why are we unswitching on a constant?");
// Replace uses of LIC in the loop with the given constant.
- for (auto UI = Invariant->use_begin(), UE = Invariant->use_end(); UI != UE;) {
- // Grab the use and walk past it so we can clobber it in the use list.
- Use *U = &*UI++;
- Instruction *UserI = dyn_cast<Instruction>(U->getUser());
+ // We use make_early_inc_range as set invalidates the iterator.
+ for (Use &U : llvm::make_early_inc_range(Invariant->uses())) {
+ Instruction *UserI = dyn_cast<Instruction>(U.getUser());
// Replace this use within the loop body.
if (UserI && L.contains(UserI))
- U->set(&Replacement);
+ U.set(&Replacement);
}
}
@@ -182,8 +192,9 @@ static bool areLoopExitPHIsLoopInvariant(Loop &L, BasicBlock &ExitingBB,
llvm_unreachable("Basic blocks should never be empty!");
}
-/// Insert code to test a set of loop invariant values, and conditionally branch
-/// on them.
+/// Copy a set of loop invariant values \p ToDuplicate and insert them at the
+/// end of \p BB and conditionally branch on the copied condition. We only
+/// branch on a single value.
static void buildPartialUnswitchConditionalBranch(BasicBlock &BB,
ArrayRef<Value *> Invariants,
bool Direction,
@@ -197,6 +208,49 @@ static void buildPartialUnswitchConditionalBranch(BasicBlock &BB,
Direction ? &NormalSucc : &UnswitchedSucc);
}
+/// Copy a set of loop invariant values, and conditionally branch on them.
+static void buildPartialInvariantUnswitchConditionalBranch(
+ BasicBlock &BB, ArrayRef<Value *> ToDuplicate, bool Direction,
+ BasicBlock &UnswitchedSucc, BasicBlock &NormalSucc, Loop &L,
+ MemorySSAUpdater *MSSAU) {
+ ValueToValueMapTy VMap;
+ for (auto *Val : reverse(ToDuplicate)) {
+ Instruction *Inst = cast<Instruction>(Val);
+ Instruction *NewInst = Inst->clone();
+ BB.getInstList().insert(BB.end(), NewInst);
+ RemapInstruction(NewInst, VMap,
+ RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
+ VMap[Val] = NewInst;
+
+ if (!MSSAU)
+ continue;
+
+ MemorySSA *MSSA = MSSAU->getMemorySSA();
+ if (auto *MemUse =
+ dyn_cast_or_null<MemoryUse>(MSSA->getMemoryAccess(Inst))) {
+ auto *DefiningAccess = MemUse->getDefiningAccess();
+ // Get the first defining access before the loop.
+ while (L.contains(DefiningAccess->getBlock())) {
+ // If the defining access is a MemoryPhi, get the incoming
+ // value for the pre-header as defining access.
+ if (auto *MemPhi = dyn_cast<MemoryPhi>(DefiningAccess))
+ DefiningAccess =
+ MemPhi->getIncomingValueForBlock(L.getLoopPreheader());
+ else
+ DefiningAccess = cast<MemoryDef>(DefiningAccess)->getDefiningAccess();
+ }
+ MSSAU->createMemoryAccessInBB(NewInst, DefiningAccess,
+ NewInst->getParent(),
+ MemorySSA::BeforeTerminator);
+ }
+ }
+
+ IRBuilder<> IRB(&BB);
+ Value *Cond = VMap[ToDuplicate[0]];
+ IRB.CreateCondBr(Cond, Direction ? &UnswitchedSucc : &NormalSucc,
+ Direction ? &NormalSucc : &UnswitchedSucc);
+}
+
/// Rewrite the PHI nodes in an unswitched loop exit basic block.
///
/// Requires that the loop exit and unswitched basic block are the same, and
@@ -366,7 +420,7 @@ static Loop *getTopMostExitingLoop(BasicBlock *ExitBB, LoopInfo &LI) {
/// hoists the branch above that split. Preserves loop simplified form
/// (splitting the exit block as necessary). It simplifies the branch within
/// the loop to an unconditional branch but doesn't remove it entirely. Further
-/// cleanup can be done with some simplify-cfg like pass.
+/// cleanup can be done with some simplifycfg like pass.
///
/// If `SE` is not null, it will be updated based on the potential loop SCEVs
/// invalidated by this.
@@ -389,9 +443,10 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
} else {
if (auto *CondInst = dyn_cast<Instruction>(BI.getCondition()))
Invariants = collectHomogenousInstGraphLoopInvariants(L, *CondInst, LI);
- if (Invariants.empty())
- // Couldn't find invariant inputs!
+ if (Invariants.empty()) {
+ LLVM_DEBUG(dbgs() << " Couldn't find invariant inputs!\n");
return false;
+ }
}
// Check that one of the branch's successors exits, and which one.
@@ -402,13 +457,17 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
ExitDirection = false;
LoopExitSuccIdx = 1;
LoopExitBB = BI.getSuccessor(1);
- if (L.contains(LoopExitBB))
+ if (L.contains(LoopExitBB)) {
+ LLVM_DEBUG(dbgs() << " Branch doesn't exit the loop!\n");
return false;
+ }
}
auto *ContinueBB = BI.getSuccessor(1 - LoopExitSuccIdx);
auto *ParentBB = BI.getParent();
- if (!areLoopExitPHIsLoopInvariant(L, *ParentBB, *LoopExitBB))
+ if (!areLoopExitPHIsLoopInvariant(L, *ParentBB, *LoopExitBB)) {
+ LLVM_DEBUG(dbgs() << " Loop exit PHI's aren't loop-invariant!\n");
return false;
+ }
// When unswitching only part of the branch's condition, we need the exit
// block to be reached directly from the partially unswitched input. This can
@@ -416,12 +475,11 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
// is a graph of `or` operations, or the exit block is along the false edge
// and the condition is a graph of `and` operations.
if (!FullUnswitch) {
- if (ExitDirection) {
- if (cast<Instruction>(BI.getCondition())->getOpcode() != Instruction::Or)
- return false;
- } else {
- if (cast<Instruction>(BI.getCondition())->getOpcode() != Instruction::And)
- return false;
+ if (ExitDirection ? !match(BI.getCondition(), m_LogicalOr())
+ : !match(BI.getCondition(), m_LogicalAnd())) {
+ LLVM_DEBUG(dbgs() << " Branch condition is in improper form for "
+ "non-full unswitch!\n");
+ return false;
}
}
@@ -498,13 +556,13 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
// Only unswitching a subset of inputs to the condition, so we will need to
// build a new branch that merges the invariant inputs.
if (ExitDirection)
- assert(cast<Instruction>(BI.getCondition())->getOpcode() ==
- Instruction::Or &&
- "Must have an `or` of `i1`s for the condition!");
+ assert(match(BI.getCondition(), m_LogicalOr()) &&
+ "Must have an `or` of `i1`s or `select i1 X, true, Y`s for the "
+ "condition!");
else
- assert(cast<Instruction>(BI.getCondition())->getOpcode() ==
- Instruction::And &&
- "Must have an `and` of `i1`s for the condition!");
+ assert(match(BI.getCondition(), m_LogicalAnd()) &&
+ "Must have an `and` of `i1`s or `select i1 X, Y, false`s for the"
+ " condition!");
buildPartialUnswitchConditionalBranch(*OldPH, Invariants, ExitDirection,
*UnswitchedBB, *NewPH);
}
@@ -590,7 +648,7 @@ static bool unswitchTrivialBranch(Loop &L, BranchInst &BI, DominatorTree &DT,
/// considered for unswitching so this is a stable transform and the same
/// switch will not be revisited. If after unswitching there is only a single
/// in-loop successor, the switch is further simplified to an unconditional
-/// branch. Still more cleanup can be done with some simplify-cfg like pass.
+/// branch. Still more cleanup can be done with some simplifycfg like pass.
///
/// If `SE` is not null, it will be updated based on the potential loop SCEVs
/// invalidated by this.
@@ -925,7 +983,7 @@ static bool unswitchAllTrivialConditions(Loop &L, DominatorTree &DT,
if (auto *SI = dyn_cast<SwitchInst>(CurrentTerm)) {
// Don't bother trying to unswitch past a switch with a constant
// condition. This should be removed prior to running this pass by
- // simplify-cfg.
+ // simplifycfg.
if (isa<Constant>(SI->getCondition()))
return Changed;
@@ -954,7 +1012,7 @@ static bool unswitchAllTrivialConditions(Loop &L, DominatorTree &DT,
return Changed;
// Don't bother trying to unswitch past an unconditional branch or a branch
- // with a constant value. These should be removed by simplify-cfg prior to
+ // with a constant value. These should be removed by simplifycfg prior to
// running this pass.
if (!BI->isConditional() || isa<Constant>(BI->getCondition()))
return Changed;
@@ -1108,9 +1166,8 @@ static BasicBlock *buildClonedLoopBlocks(
for (Instruction &I : *ClonedBB) {
RemapInstruction(&I, VMap,
RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
- if (auto *II = dyn_cast<IntrinsicInst>(&I))
- if (II->getIntrinsicID() == Intrinsic::assume)
- AC.registerAssumption(II);
+ if (auto *II = dyn_cast<AssumeInst>(&I))
+ AC.registerAssumption(II);
}
// Update any PHI nodes in the cloned successors of the skipped blocks to not
@@ -1959,18 +2016,22 @@ void visitDomSubTree(DominatorTree &DT, BasicBlock *BB, CallableT Callable) {
static void unswitchNontrivialInvariants(
Loop &L, Instruction &TI, ArrayRef<Value *> Invariants,
- SmallVectorImpl<BasicBlock *> &ExitBlocks, DominatorTree &DT, LoopInfo &LI,
- AssumptionCache &AC, function_ref<void(bool, ArrayRef<Loop *>)> UnswitchCB,
+ SmallVectorImpl<BasicBlock *> &ExitBlocks, IVConditionInfo &PartialIVInfo,
+ DominatorTree &DT, LoopInfo &LI, AssumptionCache &AC,
+ function_ref<void(bool, bool, ArrayRef<Loop *>)> UnswitchCB,
ScalarEvolution *SE, MemorySSAUpdater *MSSAU) {
auto *ParentBB = TI.getParent();
BranchInst *BI = dyn_cast<BranchInst>(&TI);
SwitchInst *SI = BI ? nullptr : cast<SwitchInst>(&TI);
// We can only unswitch switches, conditional branches with an invariant
- // condition, or combining invariant conditions with an instruction.
+ // condition, or combining invariant conditions with an instruction or
+ // partially invariant instructions.
assert((SI || (BI && BI->isConditional())) &&
"Can only unswitch switches and conditional branch!");
- bool FullUnswitch = SI || BI->getCondition() == Invariants[0];
+ bool PartiallyInvariant = !PartialIVInfo.InstToDuplicate.empty();
+ bool FullUnswitch =
+ SI || (BI->getCondition() == Invariants[0] && !PartiallyInvariant);
if (FullUnswitch)
assert(Invariants.size() == 1 &&
"Cannot have other invariants with full unswitching!");
@@ -1984,19 +2045,24 @@ static void unswitchNontrivialInvariants(
// Constant and BBs tracking the cloned and continuing successor. When we are
// unswitching the entire condition, this can just be trivially chosen to
// unswitch towards `true`. However, when we are unswitching a set of
- // invariants combined with `and` or `or`, the combining operation determines
- // the best direction to unswitch: we want to unswitch the direction that will
- // collapse the branch.
+ // invariants combined with `and` or `or` or partially invariant instructions,
+ // the combining operation determines the best direction to unswitch: we want
+ // to unswitch the direction that will collapse the branch.
bool Direction = true;
int ClonedSucc = 0;
if (!FullUnswitch) {
- if (cast<Instruction>(BI->getCondition())->getOpcode() != Instruction::Or) {
- assert(cast<Instruction>(BI->getCondition())->getOpcode() ==
- Instruction::And &&
- "Only `or` and `and` instructions can combine invariants being "
- "unswitched.");
- Direction = false;
- ClonedSucc = 1;
+ Value *Cond = BI->getCondition();
+ (void)Cond;
+ assert(((match(Cond, m_LogicalAnd()) ^ match(Cond, m_LogicalOr())) ||
+ PartiallyInvariant) &&
+ "Only `or`, `and`, an `select`, partially invariant instructions "
+ "can combine invariants being unswitched.");
+ if (!match(BI->getCondition(), m_LogicalOr())) {
+ if (match(BI->getCondition(), m_LogicalAnd()) ||
+ (PartiallyInvariant && !PartialIVInfo.KnownValue->isOneValue())) {
+ Direction = false;
+ ClonedSucc = 1;
+ }
}
}
@@ -2214,8 +2280,12 @@ static void unswitchNontrivialInvariants(
BasicBlock *ClonedPH = ClonedPHs.begin()->second;
// When doing a partial unswitch, we have to do a bit more work to build up
// the branch in the split block.
- buildPartialUnswitchConditionalBranch(*SplitBB, Invariants, Direction,
- *ClonedPH, *LoopPH);
+ if (PartiallyInvariant)
+ buildPartialInvariantUnswitchConditionalBranch(
+ *SplitBB, Invariants, Direction, *ClonedPH, *LoopPH, L, MSSAU);
+ else
+ buildPartialUnswitchConditionalBranch(*SplitBB, Invariants, Direction,
+ *ClonedPH, *LoopPH);
DTUpdates.push_back({DominatorTree::Insert, SplitBB, ClonedPH});
if (MSSAU) {
@@ -2267,7 +2337,7 @@ static void unswitchNontrivialInvariants(
// verification steps.
assert(DT.verify(DominatorTree::VerificationLevel::Fast));
- if (BI) {
+ if (BI && !PartiallyInvariant) {
// If we unswitched a branch which collapses the condition to a known
// constant we want to replace all the uses of the invariants within both
// the original and cloned blocks. We do this here so that we can use the
@@ -2285,7 +2355,8 @@ static void unswitchNontrivialInvariants(
// for each invariant operand.
// So it happens that for multiple-partial case we dont replace
// in the unswitched branch.
- bool ReplaceUnswitched = FullUnswitch || (Invariants.size() == 1);
+ bool ReplaceUnswitched =
+ FullUnswitch || (Invariants.size() == 1) || PartiallyInvariant;
ConstantInt *UnswitchedReplacement =
Direction ? ConstantInt::getTrue(BI->getContext())
@@ -2294,21 +2365,19 @@ static void unswitchNontrivialInvariants(
Direction ? ConstantInt::getFalse(BI->getContext())
: ConstantInt::getTrue(BI->getContext());
for (Value *Invariant : Invariants)
- for (auto UI = Invariant->use_begin(), UE = Invariant->use_end();
- UI != UE;) {
- // Grab the use and walk past it so we can clobber it in the use list.
- Use *U = &*UI++;
- Instruction *UserI = dyn_cast<Instruction>(U->getUser());
+ // Use make_early_inc_range here as set invalidates the iterator.
+ for (Use &U : llvm::make_early_inc_range(Invariant->uses())) {
+ Instruction *UserI = dyn_cast<Instruction>(U.getUser());
if (!UserI)
continue;
// Replace it with the 'continue' side if in the main loop body, and the
// unswitched if in the cloned blocks.
if (DT.dominates(LoopPH, UserI->getParent()))
- U->set(ContinueReplacement);
+ U.set(ContinueReplacement);
else if (ReplaceUnswitched &&
DT.dominates(ClonedPH, UserI->getParent()))
- U->set(UnswitchedReplacement);
+ U.set(UnswitchedReplacement);
}
}
@@ -2382,7 +2451,7 @@ static void unswitchNontrivialInvariants(
for (Loop *UpdatedL : llvm::concat<Loop *>(NonChildClonedLoops, HoistedLoops))
if (UpdatedL->getParentLoop() == ParentL)
SibLoops.push_back(UpdatedL);
- UnswitchCB(IsStillLoop, SibLoops);
+ UnswitchCB(IsStillLoop, PartiallyInvariant, SibLoops);
if (MSSAU && VerifyMemorySSA)
MSSAU->getMemorySSA()->verifyMemorySSA();
@@ -2399,10 +2468,10 @@ static void unswitchNontrivialInvariants(
/// The recursive computation is memozied into the provided DT-indexed cost map
/// to allow querying it for most nodes in the domtree without it becoming
/// quadratic.
-static int
-computeDomSubtreeCost(DomTreeNode &N,
- const SmallDenseMap<BasicBlock *, int, 4> &BBCostMap,
- SmallDenseMap<DomTreeNode *, int, 4> &DTCostMap) {
+static InstructionCost computeDomSubtreeCost(
+ DomTreeNode &N,
+ const SmallDenseMap<BasicBlock *, InstructionCost, 4> &BBCostMap,
+ SmallDenseMap<DomTreeNode *, InstructionCost, 4> &DTCostMap) {
// Don't accumulate cost (or recurse through) blocks not in our block cost
// map and thus not part of the duplication cost being considered.
auto BBCostIt = BBCostMap.find(N.getBlock());
@@ -2416,8 +2485,9 @@ computeDomSubtreeCost(DomTreeNode &N,
// If not, we have to compute it. We can't use insert above and update
// because computing the cost may insert more things into the map.
- int Cost = std::accumulate(
- N.begin(), N.end(), BBCostIt->second, [&](int Sum, DomTreeNode *ChildN) {
+ InstructionCost Cost = std::accumulate(
+ N.begin(), N.end(), BBCostIt->second,
+ [&](InstructionCost Sum, DomTreeNode *ChildN) -> InstructionCost {
return Sum + computeDomSubtreeCost(*ChildN, BBCostMap, DTCostMap);
});
bool Inserted = DTCostMap.insert({&N, Cost}).second;
@@ -2596,11 +2666,11 @@ static int CalculateUnswitchCostMultiplier(
return CostMultiplier;
}
-static bool
-unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
- AssumptionCache &AC, TargetTransformInfo &TTI,
- function_ref<void(bool, ArrayRef<Loop *>)> UnswitchCB,
- ScalarEvolution *SE, MemorySSAUpdater *MSSAU) {
+static bool unswitchBestCondition(
+ Loop &L, DominatorTree &DT, LoopInfo &LI, AssumptionCache &AC,
+ AAResults &AA, TargetTransformInfo &TTI,
+ function_ref<void(bool, bool, ArrayRef<Loop *>)> UnswitchCB,
+ ScalarEvolution *SE, MemorySSAUpdater *MSSAU) {
// Collect all invariant conditions within this loop (as opposed to an inner
// loop which would be handled when visiting that inner loop).
SmallVector<std::pair<Instruction *, TinyPtrVector<Value *>>, 4>
@@ -2615,6 +2685,7 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
CollectGuards = true;
}
+ IVConditionInfo PartialIVInfo;
for (auto *BB : L.blocks()) {
if (LI.getLoopFor(BB) != &L)
continue;
@@ -2642,22 +2713,48 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
BI->getSuccessor(0) == BI->getSuccessor(1))
continue;
+ // If BI's condition is 'select _, true, false', simplify it to confuse
+ // matchers
+ Value *Cond = BI->getCondition(), *CondNext;
+ while (match(Cond, m_Select(m_Value(CondNext), m_One(), m_Zero())))
+ Cond = CondNext;
+ BI->setCondition(Cond);
+
if (L.isLoopInvariant(BI->getCondition())) {
UnswitchCandidates.push_back({BI, {BI->getCondition()}});
continue;
}
Instruction &CondI = *cast<Instruction>(BI->getCondition());
- if (CondI.getOpcode() != Instruction::And &&
- CondI.getOpcode() != Instruction::Or)
- continue;
+ if (match(&CondI, m_CombineOr(m_LogicalAnd(), m_LogicalOr()))) {
+ TinyPtrVector<Value *> Invariants =
+ collectHomogenousInstGraphLoopInvariants(L, CondI, LI);
+ if (Invariants.empty())
+ continue;
- TinyPtrVector<Value *> Invariants =
- collectHomogenousInstGraphLoopInvariants(L, CondI, LI);
- if (Invariants.empty())
+ UnswitchCandidates.push_back({BI, std::move(Invariants)});
continue;
+ }
+ }
- UnswitchCandidates.push_back({BI, std::move(Invariants)});
+ Instruction *PartialIVCondBranch = nullptr;
+ if (MSSAU && !findOptionMDForLoop(&L, "llvm.loop.unswitch.partial.disable") &&
+ !any_of(UnswitchCandidates, [&L](auto &TerminatorAndInvariants) {
+ return TerminatorAndInvariants.first == L.getHeader()->getTerminator();
+ })) {
+ MemorySSA *MSSA = MSSAU->getMemorySSA();
+ if (auto Info = hasPartialIVCondition(L, MSSAThreshold, *MSSA, AA)) {
+ LLVM_DEBUG(
+ dbgs() << "simple-loop-unswitch: Found partially invariant condition "
+ << *Info->InstToDuplicate[0] << "\n");
+ PartialIVInfo = *Info;
+ PartialIVCondBranch = L.getHeader()->getTerminator();
+ TinyPtrVector<Value *> ValsToDuplicate;
+ for (auto *Inst : Info->InstToDuplicate)
+ ValsToDuplicate.push_back(Inst);
+ UnswitchCandidates.push_back(
+ {L.getHeader()->getTerminator(), std::move(ValsToDuplicate)});
+ }
}
// If we didn't find any candidates, we're done.
@@ -2678,15 +2775,18 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
SmallVector<BasicBlock *, 4> ExitBlocks;
L.getUniqueExitBlocks(ExitBlocks);
- // We cannot unswitch if exit blocks contain a cleanuppad instruction as we
- // don't know how to split those exit blocks.
+ // We cannot unswitch if exit blocks contain a cleanuppad/catchswitch
+ // instruction as we don't know how to split those exit blocks.
// FIXME: We should teach SplitBlock to handle this and remove this
// restriction.
- for (auto *ExitBB : ExitBlocks)
- if (isa<CleanupPadInst>(ExitBB->getFirstNonPHI())) {
- dbgs() << "Cannot unswitch because of cleanuppad in exit block\n";
+ for (auto *ExitBB : ExitBlocks) {
+ auto *I = ExitBB->getFirstNonPHI();
+ if (isa<CleanupPadInst>(I) || isa<CatchSwitchInst>(I)) {
+ LLVM_DEBUG(dbgs() << "Cannot unswitch because of cleanuppad/catchswitch "
+ "in exit block\n");
return false;
}
+ }
LLVM_DEBUG(
dbgs() << "Considering " << UnswitchCandidates.size()
@@ -2699,7 +2799,7 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
// subsets of the loop for duplication during unswitching.
SmallPtrSet<const Value *, 4> EphValues;
CodeMetrics::collectEphemeralValues(&L, &AC, EphValues);
- SmallDenseMap<BasicBlock *, int, 4> BBCostMap;
+ SmallDenseMap<BasicBlock *, InstructionCost, 4> BBCostMap;
// Compute the cost of each block, as well as the total loop cost. Also, bail
// out if we see instructions which are incompatible with loop unswitching
@@ -2710,9 +2810,9 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
L.getHeader()->getParent()->hasMinSize()
? TargetTransformInfo::TCK_CodeSize
: TargetTransformInfo::TCK_SizeAndLatency;
- int LoopCost = 0;
+ InstructionCost LoopCost = 0;
for (auto *BB : L.blocks()) {
- int Cost = 0;
+ InstructionCost Cost = 0;
for (auto &I : *BB) {
if (EphValues.count(&I))
continue;
@@ -2746,37 +2846,38 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
// This requires memoizing each dominator subtree to avoid redundant work.
//
// FIXME: Need to actually do the number of candidates part above.
- SmallDenseMap<DomTreeNode *, int, 4> DTCostMap;
+ SmallDenseMap<DomTreeNode *, InstructionCost, 4> DTCostMap;
// Given a terminator which might be unswitched, computes the non-duplicated
// cost for that terminator.
- auto ComputeUnswitchedCost = [&](Instruction &TI, bool FullUnswitch) {
+ auto ComputeUnswitchedCost = [&](Instruction &TI,
+ bool FullUnswitch) -> InstructionCost {
BasicBlock &BB = *TI.getParent();
SmallPtrSet<BasicBlock *, 4> Visited;
- int Cost = LoopCost;
+ InstructionCost Cost = 0;
for (BasicBlock *SuccBB : successors(&BB)) {
// Don't count successors more than once.
if (!Visited.insert(SuccBB).second)
continue;
// If this is a partial unswitch candidate, then it must be a conditional
- // branch with a condition of either `or` or `and`. In that case, one of
+ // branch with a condition of either `or`, `and`, their corresponding
+ // select forms or partially invariant instructions. In that case, one of
// the successors is necessarily duplicated, so don't even try to remove
// its cost.
if (!FullUnswitch) {
auto &BI = cast<BranchInst>(TI);
- if (cast<Instruction>(BI.getCondition())->getOpcode() ==
- Instruction::And) {
+ if (match(BI.getCondition(), m_LogicalAnd())) {
if (SuccBB == BI.getSuccessor(1))
continue;
- } else {
- assert(cast<Instruction>(BI.getCondition())->getOpcode() ==
- Instruction::Or &&
- "Only `and` and `or` conditions can result in a partial "
- "unswitch!");
+ } else if (match(BI.getCondition(), m_LogicalOr())) {
if (SuccBB == BI.getSuccessor(0))
continue;
- }
+ } else if ((PartialIVInfo.KnownValue->isOneValue() &&
+ SuccBB == BI.getSuccessor(0)) ||
+ (!PartialIVInfo.KnownValue->isOneValue() &&
+ SuccBB == BI.getSuccessor(1)))
+ continue;
}
// This successor's domtree will not need to be duplicated after
@@ -2787,8 +2888,8 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
llvm::all_of(predecessors(SuccBB), [&](BasicBlock *PredBB) {
return PredBB == &BB || DT.dominates(SuccBB, PredBB);
})) {
- Cost -= computeDomSubtreeCost(*DT[SuccBB], BBCostMap, DTCostMap);
- assert(Cost >= 0 &&
+ Cost += computeDomSubtreeCost(*DT[SuccBB], BBCostMap, DTCostMap);
+ assert(Cost <= LoopCost &&
"Non-duplicated cost should never exceed total loop cost!");
}
}
@@ -2801,16 +2902,16 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
int SuccessorsCount = isGuard(&TI) ? 2 : Visited.size();
assert(SuccessorsCount > 1 &&
"Cannot unswitch a condition without multiple distinct successors!");
- return Cost * (SuccessorsCount - 1);
+ return (LoopCost - Cost) * (SuccessorsCount - 1);
};
Instruction *BestUnswitchTI = nullptr;
- int BestUnswitchCost = 0;
+ InstructionCost BestUnswitchCost = 0;
ArrayRef<Value *> BestUnswitchInvariants;
for (auto &TerminatorAndInvariants : UnswitchCandidates) {
Instruction &TI = *TerminatorAndInvariants.first;
ArrayRef<Value *> Invariants = TerminatorAndInvariants.second;
BranchInst *BI = dyn_cast<BranchInst>(&TI);
- int CandidateCost = ComputeUnswitchedCost(
+ InstructionCost CandidateCost = ComputeUnswitchedCost(
TI, /*FullUnswitch*/ !BI || (Invariants.size() == 1 &&
Invariants[0] == BI->getCondition()));
// Calculate cost multiplier which is a tool to limit potentially
@@ -2844,6 +2945,9 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
return false;
}
+ if (BestUnswitchTI != PartialIVCondBranch)
+ PartialIVInfo.InstToDuplicate.clear();
+
// If the best candidate is a guard, turn it into a branch.
if (isGuard(BestUnswitchTI))
BestUnswitchTI = turnGuardIntoBranch(cast<IntrinsicInst>(BestUnswitchTI), L,
@@ -2853,7 +2957,8 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
<< BestUnswitchCost << ") terminator: " << *BestUnswitchTI
<< "\n");
unswitchNontrivialInvariants(L, *BestUnswitchTI, BestUnswitchInvariants,
- ExitBlocks, DT, LI, AC, UnswitchCB, SE, MSSAU);
+ ExitBlocks, PartialIVInfo, DT, LI, AC,
+ UnswitchCB, SE, MSSAU);
return true;
}
@@ -2864,9 +2969,9 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
/// looks at other loop invariant control flows and tries to unswitch those as
/// well by cloning the loop if the result is small enough.
///
-/// The `DT`, `LI`, `AC`, `TTI` parameters are required analyses that are also
-/// updated based on the unswitch.
-/// The `MSSA` analysis is also updated if valid (i.e. its use is enabled).
+/// The `DT`, `LI`, `AC`, `AA`, `TTI` parameters are required analyses that are
+/// also updated based on the unswitch. The `MSSA` analysis is also updated if
+/// valid (i.e. its use is enabled).
///
/// If either `NonTrivial` is true or the flag `EnableNonTrivialUnswitch` is
/// true, we will attempt to do non-trivial unswitching as well as trivial
@@ -2878,11 +2983,12 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI,
///
/// If `SE` is non-null, we will update that analysis based on the unswitching
/// done.
-static bool unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI,
- AssumptionCache &AC, TargetTransformInfo &TTI,
- bool NonTrivial,
- function_ref<void(bool, ArrayRef<Loop *>)> UnswitchCB,
- ScalarEvolution *SE, MemorySSAUpdater *MSSAU) {
+static bool
+unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI, AssumptionCache &AC,
+ AAResults &AA, TargetTransformInfo &TTI, bool Trivial,
+ bool NonTrivial,
+ function_ref<void(bool, bool, ArrayRef<Loop *>)> UnswitchCB,
+ ScalarEvolution *SE, MemorySSAUpdater *MSSAU) {
assert(L.isRecursivelyLCSSAForm(DT, LI) &&
"Loops must be in LCSSA form before unswitching.");
@@ -2891,23 +2997,37 @@ static bool unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI,
return false;
// Try trivial unswitch first before loop over other basic blocks in the loop.
- if (unswitchAllTrivialConditions(L, DT, LI, SE, MSSAU)) {
+ if (Trivial && unswitchAllTrivialConditions(L, DT, LI, SE, MSSAU)) {
// If we unswitched successfully we will want to clean up the loop before
// processing it further so just mark it as unswitched and return.
- UnswitchCB(/*CurrentLoopValid*/ true, {});
+ UnswitchCB(/*CurrentLoopValid*/ true, false, {});
return true;
}
- // If we're not doing non-trivial unswitching, we're done. We both accept
- // a parameter but also check a local flag that can be used for testing
- // a debugging.
- if (!NonTrivial && !EnableNonTrivialUnswitch)
+ // Check whether we should continue with non-trivial conditions.
+ // EnableNonTrivialUnswitch: Global variable that forces non-trivial
+ // unswitching for testing and debugging.
+ // NonTrivial: Parameter that enables non-trivial unswitching for this
+ // invocation of the transform. But this should be allowed only
+ // for targets without branch divergence.
+ //
+ // FIXME: If divergence analysis becomes available to a loop
+ // transform, we should allow unswitching for non-trivial uniform
+ // branches even on targets that have divergence.
+ // https://bugs.llvm.org/show_bug.cgi?id=48819
+ bool ContinueWithNonTrivial =
+ EnableNonTrivialUnswitch || (NonTrivial && !TTI.hasBranchDivergence());
+ if (!ContinueWithNonTrivial)
return false;
// Skip non-trivial unswitching for optsize functions.
if (L.getHeader()->getParent()->hasOptSize())
return false;
+ // Skip non-trivial unswitching for loops that cannot be cloned.
+ if (!L.isSafeToClone())
+ return false;
+
// For non-trivial unswitching, because it often creates new loops, we rely on
// the pass manager to iterate on the loops rather than trying to immediately
// reach a fixed point. There is no substantial advantage to iterating
@@ -2916,7 +3036,7 @@ static bool unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI,
// Try to unswitch the best invariant condition. We prefer this full unswitch to
// a partial unswitch when possible below the threshold.
- if (unswitchBestCondition(L, DT, LI, AC, TTI, UnswitchCB, SE, MSSAU))
+ if (unswitchBestCondition(L, DT, LI, AC, AA, TTI, UnswitchCB, SE, MSSAU))
return true;
// No other opportunities to unswitch.
@@ -2937,6 +3057,7 @@ PreservedAnalyses SimpleLoopUnswitchPass::run(Loop &L, LoopAnalysisManager &AM,
std::string LoopName = std::string(L.getName());
auto UnswitchCB = [&L, &U, &LoopName](bool CurrentLoopValid,
+ bool PartiallyInvariant,
ArrayRef<Loop *> NewLoops) {
// If we did a non-trivial unswitch, we have added new (cloned) loops.
if (!NewLoops.empty())
@@ -2944,9 +3065,21 @@ PreservedAnalyses SimpleLoopUnswitchPass::run(Loop &L, LoopAnalysisManager &AM,
// If the current loop remains valid, we should revisit it to catch any
// other unswitch opportunities. Otherwise, we need to mark it as deleted.
- if (CurrentLoopValid)
- U.revisitCurrentLoop();
- else
+ if (CurrentLoopValid) {
+ if (PartiallyInvariant) {
+ // Mark the new loop as partially unswitched, to avoid unswitching on
+ // the same condition again.
+ auto &Context = L.getHeader()->getContext();
+ MDNode *DisableUnswitchMD = MDNode::get(
+ Context,
+ MDString::get(Context, "llvm.loop.unswitch.partial.disable"));
+ MDNode *NewLoopID = makePostTransformationMetadata(
+ Context, L.getLoopID(), {"llvm.loop.unswitch.partial"},
+ {DisableUnswitchMD});
+ L.setLoopID(NewLoopID);
+ } else
+ U.revisitCurrentLoop();
+ } else
U.markLoopAsDeleted(L, LoopName);
};
@@ -2956,8 +3089,9 @@ PreservedAnalyses SimpleLoopUnswitchPass::run(Loop &L, LoopAnalysisManager &AM,
if (VerifyMemorySSA)
AR.MSSA->verifyMemorySSA();
}
- if (!unswitchLoop(L, AR.DT, AR.LI, AR.AC, AR.TTI, NonTrivial, UnswitchCB,
- &AR.SE, MSSAU.hasValue() ? MSSAU.getPointer() : nullptr))
+ if (!unswitchLoop(L, AR.DT, AR.LI, AR.AC, AR.AA, AR.TTI, Trivial, NonTrivial,
+ UnswitchCB, &AR.SE,
+ MSSAU.hasValue() ? MSSAU.getPointer() : nullptr))
return PreservedAnalyses::all();
if (AR.MSSA && VerifyMemorySSA)
@@ -3014,6 +3148,7 @@ bool SimpleLoopUnswitchLegacyPass::runOnLoop(Loop *L, LPPassManager &LPM) {
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
+ auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
MemorySSA *MSSA = nullptr;
Optional<MemorySSAUpdater> MSSAU;
@@ -3025,7 +3160,7 @@ bool SimpleLoopUnswitchLegacyPass::runOnLoop(Loop *L, LPPassManager &LPM) {
auto *SEWP = getAnalysisIfAvailable<ScalarEvolutionWrapperPass>();
auto *SE = SEWP ? &SEWP->getSE() : nullptr;
- auto UnswitchCB = [&L, &LPM](bool CurrentLoopValid,
+ auto UnswitchCB = [&L, &LPM](bool CurrentLoopValid, bool PartiallyInvariant,
ArrayRef<Loop *> NewLoops) {
// If we did a non-trivial unswitch, we have added new (cloned) loops.
for (auto *NewL : NewLoops)
@@ -3034,17 +3169,22 @@ bool SimpleLoopUnswitchLegacyPass::runOnLoop(Loop *L, LPPassManager &LPM) {
// If the current loop remains valid, re-add it to the queue. This is
// a little wasteful as we'll finish processing the current loop as well,
// but it is the best we can do in the old PM.
- if (CurrentLoopValid)
- LPM.addLoop(*L);
- else
+ if (CurrentLoopValid) {
+ // If the current loop has been unswitched using a partially invariant
+ // condition, we should not re-add the current loop to avoid unswitching
+ // on the same condition again.
+ if (!PartiallyInvariant)
+ LPM.addLoop(*L);
+ } else
LPM.markLoopAsDeleted(*L);
};
if (MSSA && VerifyMemorySSA)
MSSA->verifyMemorySSA();
- bool Changed = unswitchLoop(*L, DT, LI, AC, TTI, NonTrivial, UnswitchCB, SE,
- MSSAU.hasValue() ? MSSAU.getPointer() : nullptr);
+ bool Changed =
+ unswitchLoop(*L, DT, LI, AC, AA, TTI, true, NonTrivial, UnswitchCB, SE,
+ MSSAU.hasValue() ? MSSAU.getPointer() : nullptr);
if (MSSA && VerifyMemorySSA)
MSSA->verifyMemorySSA();
diff --git a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
index 38e7109ead57..09d59b0e884a 100644
--- a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
+++ b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
@@ -20,6 +20,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
@@ -42,6 +43,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/SimplifyCFGOptions.h"
#include <utility>
@@ -76,117 +78,131 @@ static cl::opt<bool> UserSinkCommonInsts(
STATISTIC(NumSimpl, "Number of blocks simplified");
-/// If we have more than one empty (other than phi node) return blocks,
-/// merge them together to promote recursive block merging.
-static bool mergeEmptyReturnBlocks(Function &F, DomTreeUpdater *DTU) {
- bool Changed = false;
-
- std::vector<DominatorTree::UpdateType> Updates;
- SmallVector<BasicBlock *, 8> DeadBlocks;
-
- BasicBlock *RetBlock = nullptr;
+static bool tailMergeBlocksWithSimilarFunctionTerminators(Function &F,
+ DomTreeUpdater *DTU) {
+ SmallMapVector<unsigned /*TerminatorOpcode*/, SmallVector<BasicBlock *, 2>, 4>
+ Structure;
- // Scan all the blocks in the function, looking for empty return blocks.
- for (BasicBlock &BB : make_early_inc_range(F)) {
+ // Scan all the blocks in the function, record the interesting-ones.
+ for (BasicBlock &BB : F) {
if (DTU && DTU->isBBPendingDeletion(&BB))
continue;
- // Only look at return blocks.
- ReturnInst *Ret = dyn_cast<ReturnInst>(BB.getTerminator());
- if (!Ret) continue;
+ // We are only interested in function-terminating blocks.
+ if (!succ_empty(&BB))
+ continue;
- // Only look at the block if it is empty or the only other thing in it is a
- // single PHI node that is the operand to the return.
- if (Ret != &BB.front()) {
- // Check for something else in the block.
- BasicBlock::iterator I(Ret);
- --I;
- // Skip over debug info.
- while (isa<DbgInfoIntrinsic>(I) && I != BB.begin())
- --I;
- if (!isa<DbgInfoIntrinsic>(I) &&
- (!isa<PHINode>(I) || I != BB.begin() || Ret->getNumOperands() == 0 ||
- Ret->getOperand(0) != &*I))
- continue;
- }
+ auto *Term = BB.getTerminator();
- // If this is the first returning block, remember it and keep going.
- if (!RetBlock) {
- RetBlock = &BB;
+ // Fow now only support `ret`/`resume` function terminators.
+ // FIXME: lift this restriction.
+ switch (Term->getOpcode()) {
+ case Instruction::Ret:
+ case Instruction::Resume:
+ break;
+ default:
continue;
}
- // Skip merging if this would result in a CallBr instruction with a
- // duplicate destination. FIXME: See note in CodeGenPrepare.cpp.
- bool SkipCallBr = false;
- for (pred_iterator PI = pred_begin(&BB), E = pred_end(&BB);
- PI != E && !SkipCallBr; ++PI) {
- if (auto *CBI = dyn_cast<CallBrInst>((*PI)->getTerminator()))
- for (unsigned i = 0, e = CBI->getNumSuccessors(); i != e; ++i)
- if (RetBlock == CBI->getSuccessor(i)) {
- SkipCallBr = true;
- break;
- }
+ // We can't tail-merge block that contains a musttail call.
+ if (BB.getTerminatingMustTailCall())
+ continue;
+
+ // Calls to experimental_deoptimize must be followed by a return
+ // of the value computed by experimental_deoptimize.
+ // I.e., we can not change `ret` to `br` for this block.
+ if (auto *CI =
+ dyn_cast_or_null<CallInst>(Term->getPrevNonDebugInstruction())) {
+ if (Function *F = CI->getCalledFunction())
+ if (Intrinsic::ID ID = F->getIntrinsicID())
+ if (ID == Intrinsic::experimental_deoptimize)
+ continue;
}
- if (SkipCallBr)
+
+ // PHI nodes cannot have token type, so if the terminator has an operand
+ // with token type, we can not tail-merge this kind of function terminators.
+ if (any_of(Term->operands(),
+ [](Value *Op) { return Op->getType()->isTokenTy(); }))
+ continue;
+
+ // Canonical blocks are uniqued based on the terminator type (opcode).
+ Structure[Term->getOpcode()].emplace_back(&BB);
+ }
+
+ bool Changed = false;
+
+ std::vector<DominatorTree::UpdateType> Updates;
+
+ for (ArrayRef<BasicBlock *> BBs : make_second_range(Structure)) {
+ SmallVector<PHINode *, 1> NewOps;
+
+ // We don't want to change IR just because we can.
+ // Only do that if there are at least two blocks we'll tail-merge.
+ if (BBs.size() < 2)
continue;
- // Otherwise, we found a duplicate return block. Merge the two.
Changed = true;
- // Case when there is no input to the return or when the returned values
- // agree is trivial. Note that they can't agree if there are phis in the
- // blocks.
- if (Ret->getNumOperands() == 0 ||
- Ret->getOperand(0) ==
- cast<ReturnInst>(RetBlock->getTerminator())->getOperand(0)) {
- // All predecessors of BB should now branch to RetBlock instead.
- if (DTU) {
- for (auto *Predecessor : predecessors(&BB)) {
- // But, iff Predecessor already branches to RetBlock,
- // don't (re-)add DomTree edge, because it already exists.
- if (!is_contained(successors(Predecessor), RetBlock))
- Updates.push_back({DominatorTree::Insert, Predecessor, RetBlock});
- Updates.push_back({DominatorTree::Delete, Predecessor, &BB});
- }
+ if (DTU)
+ Updates.reserve(Updates.size() + BBs.size());
+
+ BasicBlock *CanonicalBB;
+ Instruction *CanonicalTerm;
+ {
+ auto *Term = BBs[0]->getTerminator();
+
+ // Create a canonical block for this function terminator type now,
+ // placing it *before* the first block that will branch to it.
+ CanonicalBB = BasicBlock::Create(
+ F.getContext(), Twine("common.") + Term->getOpcodeName(), &F, BBs[0]);
+ // We'll also need a PHI node per each operand of the terminator.
+ NewOps.resize(Term->getNumOperands());
+ for (auto I : zip(Term->operands(), NewOps)) {
+ std::get<1>(I) = PHINode::Create(std::get<0>(I)->getType(),
+ /*NumReservedValues=*/BBs.size(),
+ CanonicalBB->getName() + ".op");
+ CanonicalBB->getInstList().push_back(std::get<1>(I));
}
- BB.replaceAllUsesWith(RetBlock);
- DeadBlocks.emplace_back(&BB);
- continue;
+ // Make it so that this canonical block actually has the right
+ // terminator.
+ CanonicalTerm = Term->clone();
+ CanonicalBB->getInstList().push_back(CanonicalTerm);
+ // If the canonical terminator has operands, rewrite it to take PHI's.
+ for (auto I : zip(NewOps, CanonicalTerm->operands()))
+ std::get<1>(I) = std::get<0>(I);
}
- // If the canonical return block has no PHI node, create one now.
- PHINode *RetBlockPHI = dyn_cast<PHINode>(RetBlock->begin());
- if (!RetBlockPHI) {
- Value *InVal = cast<ReturnInst>(RetBlock->getTerminator())->getOperand(0);
- pred_iterator PB = pred_begin(RetBlock), PE = pred_end(RetBlock);
- RetBlockPHI = PHINode::Create(Ret->getOperand(0)->getType(),
- std::distance(PB, PE), "merge",
- &RetBlock->front());
+ // Now, go through each block (with the current terminator type)
+ // we've recorded, and rewrite it to branch to the new common block.
+ const DILocation *CommonDebugLoc = nullptr;
+ for (BasicBlock *BB : BBs) {
+ auto *Term = BB->getTerminator();
+
+ // Aha, found a new non-canonical function terminator. If it has operands,
+ // forward them to the PHI nodes in the canonical block.
+ for (auto I : zip(Term->operands(), NewOps))
+ std::get<1>(I)->addIncoming(std::get<0>(I), BB);
+
+ // Compute the debug location common to all the original terminators.
+ if (!CommonDebugLoc)
+ CommonDebugLoc = Term->getDebugLoc();
+ else
+ CommonDebugLoc =
+ DILocation::getMergedLocation(CommonDebugLoc, Term->getDebugLoc());
- for (pred_iterator PI = PB; PI != PE; ++PI)
- RetBlockPHI->addIncoming(InVal, *PI);
- RetBlock->getTerminator()->setOperand(0, RetBlockPHI);
+ // And turn BB into a block that just unconditionally branches
+ // to the canonical block.
+ Term->eraseFromParent();
+ BranchInst::Create(CanonicalBB, BB);
+ if (DTU)
+ Updates.push_back({DominatorTree::Insert, BB, CanonicalBB});
}
- // Turn BB into a block that just unconditionally branches to the return
- // block. This handles the case when the two return blocks have a common
- // predecessor but that return different things.
- RetBlockPHI->addIncoming(Ret->getOperand(0), &BB);
- BB.getTerminator()->eraseFromParent();
- BranchInst::Create(RetBlock, &BB);
- if (DTU)
- Updates.push_back({DominatorTree::Insert, &BB, RetBlock});
+ CanonicalTerm->setDebugLoc(CommonDebugLoc);
}
- if (DTU) {
+ if (DTU)
DTU->applyUpdates(Updates);
- for (auto *BB : DeadBlocks)
- DTU->deleteBB(BB);
- } else {
- for (auto *BB : DeadBlocks)
- BB->eraseFromParent();
- }
return Changed;
}
@@ -239,7 +255,8 @@ static bool simplifyFunctionCFGImpl(Function &F, const TargetTransformInfo &TTI,
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
bool EverChanged = removeUnreachableBlocks(F, DT ? &DTU : nullptr);
- EverChanged |= mergeEmptyReturnBlocks(F, DT ? &DTU : nullptr);
+ EverChanged |=
+ tailMergeBlocksWithSimilarFunctionTerminators(F, DT ? &DTU : nullptr);
EverChanged |= iterativelySimplifyCFG(F, TTI, DT ? &DTU : nullptr, Options);
// If neither pass changed anything, we're done.
@@ -319,7 +336,6 @@ PreservedAnalyses SimplifyCFGPass::run(Function &F,
PreservedAnalyses PA;
if (RequireAndPreserveDomTree)
PA.preserve<DominatorTreeAnalysis>();
- PA.preserve<GlobalsAA>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/Sink.cpp b/llvm/lib/Transforms/Scalar/Sink.cpp
index 89cfbe384be4..8600aacdb056 100644
--- a/llvm/lib/Transforms/Scalar/Sink.cpp
+++ b/llvm/lib/Transforms/Scalar/Sink.cpp
@@ -202,7 +202,7 @@ static bool ProcessBlock(BasicBlock &BB, DominatorTree &DT, LoopInfo &LI,
if (!ProcessedBegin)
--I;
- if (isa<DbgInfoIntrinsic>(Inst))
+ if (Inst->isDebugOrPseudoInst())
continue;
if (SinkInstruction(Inst, Stores, DT, LI, AA)) {
diff --git a/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp b/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp
deleted file mode 100644
index 9b18c945d950..000000000000
--- a/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp
+++ /dev/null
@@ -1,830 +0,0 @@
-//===- SpeculateAroundPHIs.cpp --------------------------------------------===//
-//
-// 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/Transforms/Scalar/SpeculateAroundPHIs.h"
-#include "llvm/ADT/PostOrderIterator.h"
-#include "llvm/ADT/Sequence.h"
-#include "llvm/ADT/SetVector.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/Analysis/TargetTransformInfo.h"
-#include "llvm/Analysis/ValueTracking.h"
-#include "llvm/IR/BasicBlock.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Transforms/Utils/BasicBlockUtils.h"
-
-using namespace llvm;
-
-#define DEBUG_TYPE "spec-phis"
-
-STATISTIC(NumPHIsSpeculated, "Number of PHI nodes we speculated around");
-STATISTIC(NumEdgesSplit,
- "Number of critical edges which were split for speculation");
-STATISTIC(NumSpeculatedInstructions,
- "Number of instructions we speculated around the PHI nodes");
-STATISTIC(NumNewRedundantInstructions,
- "Number of new, redundant instructions inserted");
-
-/// Check whether speculating the users of a PHI node around the PHI
-/// will be safe.
-///
-/// This checks both that all of the users are safe and also that all of their
-/// operands are either recursively safe or already available along an incoming
-/// edge to the PHI.
-///
-/// This routine caches both all the safe nodes explored in `PotentialSpecSet`
-/// and the chain of nodes that definitively reach any unsafe node in
-/// `UnsafeSet`. By preserving these between repeated calls to this routine for
-/// PHIs in the same basic block, the exploration here can be reused. However,
-/// these caches must no be reused for PHIs in a different basic block as they
-/// reflect what is available along incoming edges.
-static bool
-isSafeToSpeculatePHIUsers(PHINode &PN, DominatorTree &DT,
- SmallPtrSetImpl<Instruction *> &PotentialSpecSet,
- SmallPtrSetImpl<Instruction *> &UnsafeSet) {
- auto *PhiBB = PN.getParent();
- SmallPtrSet<Instruction *, 4> Visited;
- SmallVector<std::pair<Instruction *, User::value_op_iterator>, 16> DFSStack;
-
- // Walk each user of the PHI node.
- for (Use &U : PN.uses()) {
- auto *UI = cast<Instruction>(U.getUser());
-
- // Ensure the use post-dominates the PHI node. This ensures that, in the
- // absence of unwinding, the use will actually be reached.
- // FIXME: We use a blunt hammer of requiring them to be in the same basic
- // block. We should consider using actual post-dominance here in the
- // future.
- if (UI->getParent() != PhiBB) {
- LLVM_DEBUG(dbgs() << " Unsafe: use in a different BB: " << *UI << "\n");
- return false;
- }
-
- if (const auto *CS = dyn_cast<CallBase>(UI)) {
- if (CS->isConvergent() || CS->cannotDuplicate()) {
- LLVM_DEBUG(dbgs() << " Unsafe: convergent "
- "callsite cannot de duplicated: " << *UI << '\n');
- return false;
- }
- }
-
- // FIXME: This check is much too conservative. We're not going to move these
- // instructions onto new dynamic paths through the program unless there is
- // a call instruction between the use and the PHI node. And memory isn't
- // changing unless there is a store in that same sequence. We should
- // probably change this to do at least a limited scan of the intervening
- // instructions and allow handling stores in easily proven safe cases.
- if (mayBeMemoryDependent(*UI)) {
- LLVM_DEBUG(dbgs() << " Unsafe: can't speculate use: " << *UI << "\n");
- return false;
- }
-
- // Now do a depth-first search of everything these users depend on to make
- // sure they are transitively safe. This is a depth-first search, but we
- // check nodes in preorder to minimize the amount of checking.
- Visited.insert(UI);
- DFSStack.push_back({UI, UI->value_op_begin()});
- do {
- User::value_op_iterator OpIt;
- std::tie(UI, OpIt) = DFSStack.pop_back_val();
-
- while (OpIt != UI->value_op_end()) {
- auto *OpI = dyn_cast<Instruction>(*OpIt);
- // Increment to the next operand for whenever we continue.
- ++OpIt;
- // No need to visit non-instructions, which can't form dependencies.
- if (!OpI)
- continue;
-
- // Now do the main pre-order checks that this operand is a viable
- // dependency of something we want to speculate.
-
- // First do a few checks for instructions that won't require
- // speculation at all because they are trivially available on the
- // incoming edge (either through dominance or through an incoming value
- // to a PHI).
- //
- // The cases in the current block will be trivially dominated by the
- // edge.
- auto *ParentBB = OpI->getParent();
- if (ParentBB == PhiBB) {
- if (isa<PHINode>(OpI)) {
- // We can trivially map through phi nodes in the same block.
- continue;
- }
- } else if (DT.dominates(ParentBB, PhiBB)) {
- // Instructions from dominating blocks are already available.
- continue;
- }
-
- // Once we know that we're considering speculating the operand, check
- // if we've already explored this subgraph and found it to be safe.
- if (PotentialSpecSet.count(OpI))
- continue;
-
- // If we've already explored this subgraph and found it unsafe, bail.
- // If when we directly test whether this is safe it fails, bail.
- if (UnsafeSet.count(OpI) || ParentBB != PhiBB ||
- mayBeMemoryDependent(*OpI)) {
- LLVM_DEBUG(dbgs() << " Unsafe: can't speculate transitive use: "
- << *OpI << "\n");
- // Record the stack of instructions which reach this node as unsafe
- // so we prune subsequent searches.
- UnsafeSet.insert(OpI);
- for (auto &StackPair : DFSStack) {
- Instruction *I = StackPair.first;
- UnsafeSet.insert(I);
- }
- return false;
- }
-
- // Skip any operands we're already recursively checking.
- if (!Visited.insert(OpI).second)
- continue;
-
- // Push onto the stack and descend. We can directly continue this
- // loop when ascending.
- DFSStack.push_back({UI, OpIt});
- UI = OpI;
- OpIt = OpI->value_op_begin();
- }
-
- // This node and all its operands are safe. Go ahead and cache that for
- // reuse later.
- PotentialSpecSet.insert(UI);
-
- // Continue with the next node on the stack.
- } while (!DFSStack.empty());
- }
-
-#ifndef NDEBUG
- // Every visited operand should have been marked as safe for speculation at
- // this point. Verify this and return success.
- for (auto *I : Visited)
- assert(PotentialSpecSet.count(I) &&
- "Failed to mark a visited instruction as safe!");
-#endif
- return true;
-}
-
-/// Check whether, in isolation, a given PHI node is both safe and profitable
-/// to speculate users around.
-///
-/// This handles checking whether there are any constant operands to a PHI
-/// which could represent a useful speculation candidate, whether the users of
-/// the PHI are safe to speculate including all their transitive dependencies,
-/// and whether after speculation there will be some cost savings (profit) to
-/// folding the operands into the users of the PHI node. Returns true if both
-/// safe and profitable with relevant cost savings updated in the map and with
-/// an update to the `PotentialSpecSet`. Returns false if either safety or
-/// profitability are absent. Some new entries may be made to the
-/// `PotentialSpecSet` even when this routine returns false, but they remain
-/// conservatively correct.
-///
-/// The profitability check here is a local one, but it checks this in an
-/// interesting way. Beyond checking that the total cost of materializing the
-/// constants will be less than the cost of folding them into their users, it
-/// also checks that no one incoming constant will have a higher cost when
-/// folded into its users rather than materialized. This higher cost could
-/// result in a dynamic *path* that is more expensive even when the total cost
-/// is lower. Currently, all of the interesting cases where this optimization
-/// should fire are ones where it is a no-loss operation in this sense. If we
-/// ever want to be more aggressive here, we would need to balance the
-/// different incoming edges' cost by looking at their respective
-/// probabilities.
-static bool isSafeAndProfitableToSpeculateAroundPHI(
- PHINode &PN, SmallDenseMap<PHINode *, int, 16> &CostSavingsMap,
- SmallPtrSetImpl<Instruction *> &PotentialSpecSet,
- SmallPtrSetImpl<Instruction *> &UnsafeSet, DominatorTree &DT,
- TargetTransformInfo &TTI) {
- // First see whether there is any cost savings to speculating around this
- // PHI, and build up a map of the constant inputs to how many times they
- // occur.
- bool NonFreeMat = false;
- struct CostsAndCount {
- int MatCost = TargetTransformInfo::TCC_Free;
- int FoldedCost = TargetTransformInfo::TCC_Free;
- int Count = 0;
- };
- SmallDenseMap<ConstantInt *, CostsAndCount, 16> CostsAndCounts;
- SmallPtrSet<BasicBlock *, 16> IncomingConstantBlocks;
- for (int i : llvm::seq<int>(0, PN.getNumIncomingValues())) {
- auto *IncomingC = dyn_cast<ConstantInt>(PN.getIncomingValue(i));
- if (!IncomingC)
- continue;
-
- // Only visit each incoming edge with a constant input once.
- if (!IncomingConstantBlocks.insert(PN.getIncomingBlock(i)).second)
- continue;
-
- auto InsertResult = CostsAndCounts.insert({IncomingC, {}});
- // Count how many edges share a given incoming costant.
- ++InsertResult.first->second.Count;
- // Only compute the cost the first time we see a particular constant.
- if (!InsertResult.second)
- continue;
-
- int &MatCost = InsertResult.first->second.MatCost;
- MatCost = TTI.getIntImmCost(IncomingC->getValue(), IncomingC->getType(),
- TargetTransformInfo::TCK_SizeAndLatency);
- NonFreeMat |= MatCost != TTI.TCC_Free;
- }
- if (!NonFreeMat) {
- LLVM_DEBUG(dbgs() << " Free: " << PN << "\n");
- // No profit in free materialization.
- return false;
- }
-
- // Now check that the uses of this PHI can actually be speculated,
- // otherwise we'll still have to materialize the PHI value.
- if (!isSafeToSpeculatePHIUsers(PN, DT, PotentialSpecSet, UnsafeSet)) {
- LLVM_DEBUG(dbgs() << " Unsafe PHI: " << PN << "\n");
- return false;
- }
-
- // Compute how much (if any) savings are available by speculating around this
- // PHI.
- for (Use &U : PN.uses()) {
- auto *UserI = cast<Instruction>(U.getUser());
- // Now check whether there is any savings to folding the incoming constants
- // into this use.
- unsigned Idx = U.getOperandNo();
-
- // If we have a binary operator that is commutative, an actual constant
- // operand would end up on the RHS, so pretend the use of the PHI is on the
- // RHS.
- //
- // Technically, this is a bit weird if *both* operands are PHIs we're
- // speculating. But if that is the case, giving an "optimistic" cost isn't
- // a bad thing because after speculation it will constant fold. And
- // moreover, such cases should likely have been constant folded already by
- // some other pass, so we shouldn't worry about "modeling" them terribly
- // accurately here. Similarly, if the other operand is a constant, it still
- // seems fine to be "optimistic" in our cost modeling, because when the
- // incoming operand from the PHI node is also a constant, we will end up
- // constant folding.
- if (UserI->isBinaryOp() && UserI->isCommutative() && Idx != 1)
- // Assume we will commute the constant to the RHS to be canonical.
- Idx = 1;
-
- // Get the intrinsic ID if this user is an intrinsic.
- Intrinsic::ID IID = Intrinsic::not_intrinsic;
- if (auto *UserII = dyn_cast<IntrinsicInst>(UserI))
- IID = UserII->getIntrinsicID();
-
- for (auto &IncomingConstantAndCostsAndCount : CostsAndCounts) {
- ConstantInt *IncomingC = IncomingConstantAndCostsAndCount.first;
- int MatCost = IncomingConstantAndCostsAndCount.second.MatCost;
- int &FoldedCost = IncomingConstantAndCostsAndCount.second.FoldedCost;
- if (IID)
- FoldedCost +=
- TTI.getIntImmCostIntrin(IID, Idx, IncomingC->getValue(),
- IncomingC->getType(),
- TargetTransformInfo::TCK_SizeAndLatency);
- else
- FoldedCost +=
- TTI.getIntImmCostInst(UserI->getOpcode(), Idx,
- IncomingC->getValue(), IncomingC->getType(),
- TargetTransformInfo::TCK_SizeAndLatency);
-
- // If we accumulate more folded cost for this incoming constant than
- // materialized cost, then we'll regress any edge with this constant so
- // just bail. We're only interested in cases where folding the incoming
- // constants is at least break-even on all paths.
- if (FoldedCost > MatCost) {
- LLVM_DEBUG(dbgs() << " Not profitable to fold imm: " << *IncomingC
- << "\n"
- " Materializing cost: "
- << MatCost
- << "\n"
- " Accumulated folded cost: "
- << FoldedCost << "\n");
- return false;
- }
- }
- }
-
- // Compute the total cost savings afforded by this PHI node.
- int TotalMatCost = TTI.TCC_Free, TotalFoldedCost = TTI.TCC_Free;
- for (auto IncomingConstantAndCostsAndCount : CostsAndCounts) {
- int MatCost = IncomingConstantAndCostsAndCount.second.MatCost;
- int FoldedCost = IncomingConstantAndCostsAndCount.second.FoldedCost;
- int Count = IncomingConstantAndCostsAndCount.second.Count;
-
- TotalMatCost += MatCost * Count;
- TotalFoldedCost += FoldedCost * Count;
- }
- assert(TotalFoldedCost <= TotalMatCost && "If each constant's folded cost is "
- "less that its materialized cost, "
- "the sum must be as well.");
-
- LLVM_DEBUG(dbgs() << " Cost savings " << (TotalMatCost - TotalFoldedCost)
- << ": " << PN << "\n");
- CostSavingsMap[&PN] = TotalMatCost - TotalFoldedCost;
- return true;
-}
-
-/// Simple helper to walk all the users of a list of phis depth first, and call
-/// a visit function on each one in post-order.
-///
-/// All of the PHIs should be in the same basic block, and this is primarily
-/// used to make a single depth-first walk across their collective users
-/// without revisiting any subgraphs. Callers should provide a fast, idempotent
-/// callable to test whether a node has been visited and the more important
-/// callable to actually visit a particular node.
-///
-/// Depth-first and postorder here refer to the *operand* graph -- we start
-/// from a collection of users of PHI nodes and walk "up" the operands
-/// depth-first.
-template <typename IsVisitedT, typename VisitT>
-static void visitPHIUsersAndDepsInPostOrder(ArrayRef<PHINode *> PNs,
- IsVisitedT IsVisited,
- VisitT Visit) {
- SmallVector<std::pair<Instruction *, User::value_op_iterator>, 16> DFSStack;
- for (auto *PN : PNs)
- for (Use &U : PN->uses()) {
- auto *UI = cast<Instruction>(U.getUser());
- if (IsVisited(UI))
- // Already visited this user, continue across the roots.
- continue;
-
- // Otherwise, walk the operand graph depth-first and visit each
- // dependency in postorder.
- DFSStack.push_back({UI, UI->value_op_begin()});
- do {
- User::value_op_iterator OpIt;
- std::tie(UI, OpIt) = DFSStack.pop_back_val();
- while (OpIt != UI->value_op_end()) {
- auto *OpI = dyn_cast<Instruction>(*OpIt);
- // Increment to the next operand for whenever we continue.
- ++OpIt;
- // No need to visit non-instructions, which can't form dependencies,
- // or instructions outside of our potential dependency set that we
- // were given. Finally, if we've already visited the node, continue
- // to the next.
- if (!OpI || IsVisited(OpI))
- continue;
-
- // Push onto the stack and descend. We can directly continue this
- // loop when ascending.
- DFSStack.push_back({UI, OpIt});
- UI = OpI;
- OpIt = OpI->value_op_begin();
- }
-
- // Finished visiting children, visit this node.
- assert(!IsVisited(UI) && "Should not have already visited a node!");
- Visit(UI);
- } while (!DFSStack.empty());
- }
-}
-
-/// Find profitable PHIs to speculate.
-///
-/// For a PHI node to be profitable, we need the cost of speculating its users
-/// (and their dependencies) to not exceed the savings of folding the PHI's
-/// constant operands into the speculated users.
-///
-/// Computing this is surprisingly challenging. Because users of two different
-/// PHI nodes can depend on each other or on common other instructions, it may
-/// be profitable to speculate two PHI nodes together even though neither one
-/// in isolation is profitable. The straightforward way to find all the
-/// profitable PHIs would be to check each combination of PHIs' cost, but this
-/// is exponential in complexity.
-///
-/// Even if we assume that we only care about cases where we can consider each
-/// PHI node in isolation (rather than considering cases where none are
-/// profitable in isolation but some subset are profitable as a set), we still
-/// have a challenge. The obvious way to find all individually profitable PHIs
-/// is to iterate until reaching a fixed point, but this will be quadratic in
-/// complexity. =/
-///
-/// This code currently uses a linear-to-compute order for a greedy approach.
-/// It won't find cases where a set of PHIs must be considered together, but it
-/// handles most cases of order dependence without quadratic iteration. The
-/// specific order used is the post-order across the operand DAG. When the last
-/// user of a PHI is visited in this postorder walk, we check it for
-/// profitability.
-///
-/// There is an orthogonal extra complexity to all of this: computing the cost
-/// itself can easily become a linear computation making everything again (at
-/// best) quadratic. Using a postorder over the operand graph makes it
-/// particularly easy to avoid this through dynamic programming. As we do the
-/// postorder walk, we build the transitive cost of that subgraph. It is also
-/// straightforward to then update these costs when we mark a PHI for
-/// speculation so that subsequent PHIs don't re-pay the cost of already
-/// speculated instructions.
-static SmallVector<PHINode *, 16>
-findProfitablePHIs(ArrayRef<PHINode *> PNs,
- const SmallDenseMap<PHINode *, int, 16> &CostSavingsMap,
- const SmallPtrSetImpl<Instruction *> &PotentialSpecSet,
- int NumPreds, DominatorTree &DT, TargetTransformInfo &TTI) {
- SmallVector<PHINode *, 16> SpecPNs;
-
- // First, establish a reverse mapping from immediate users of the PHI nodes
- // to the nodes themselves, and count how many users each PHI node has in
- // a way we can update while processing them.
- SmallDenseMap<Instruction *, TinyPtrVector<PHINode *>, 16> UserToPNMap;
- SmallDenseMap<PHINode *, int, 16> PNUserCountMap;
- SmallPtrSet<Instruction *, 16> UserSet;
- for (auto *PN : PNs) {
- assert(UserSet.empty() && "Must start with an empty user set!");
- for (Use &U : PN->uses())
- UserSet.insert(cast<Instruction>(U.getUser()));
- PNUserCountMap[PN] = UserSet.size();
- for (auto *UI : UserSet)
- UserToPNMap.insert({UI, {}}).first->second.push_back(PN);
- UserSet.clear();
- }
-
- // Now do a DFS across the operand graph of the users, computing cost as we
- // go and when all costs for a given PHI are known, checking that PHI for
- // profitability.
- SmallDenseMap<Instruction *, int, 16> SpecCostMap;
- visitPHIUsersAndDepsInPostOrder(
- PNs,
- /*IsVisited*/
- [&](Instruction *I) {
- // We consider anything that isn't potentially speculated to be
- // "visited" as it is already handled. Similarly, anything that *is*
- // potentially speculated but for which we have an entry in our cost
- // map, we're done.
- return !PotentialSpecSet.count(I) || SpecCostMap.count(I);
- },
- /*Visit*/
- [&](Instruction *I) {
- // We've fully visited the operands, so sum their cost with this node
- // and update the cost map.
- int Cost = TTI.TCC_Free;
- for (Value *OpV : I->operand_values())
- if (auto *OpI = dyn_cast<Instruction>(OpV)) {
- auto CostMapIt = SpecCostMap.find(OpI);
- if (CostMapIt != SpecCostMap.end())
- Cost += CostMapIt->second;
- }
- Cost += TTI.getUserCost(I, TargetTransformInfo::TCK_SizeAndLatency);
- bool Inserted = SpecCostMap.insert({I, Cost}).second;
- (void)Inserted;
- assert(Inserted && "Must not re-insert a cost during the DFS!");
-
- // Now check if this node had a corresponding PHI node using it. If so,
- // we need to decrement the outstanding user count for it.
- auto UserPNsIt = UserToPNMap.find(I);
- if (UserPNsIt == UserToPNMap.end())
- return;
- auto &UserPNs = UserPNsIt->second;
- auto UserPNsSplitIt = std::stable_partition(
- UserPNs.begin(), UserPNs.end(), [&](PHINode *UserPN) {
- int &PNUserCount = PNUserCountMap.find(UserPN)->second;
- assert(
- PNUserCount > 0 &&
- "Should never re-visit a PN after its user count hits zero!");
- --PNUserCount;
- return PNUserCount != 0;
- });
-
- // FIXME: Rather than one at a time, we should sum the savings as the
- // cost will be completely shared.
- SmallVector<Instruction *, 16> SpecWorklist;
- for (auto *PN : llvm::make_range(UserPNsSplitIt, UserPNs.end())) {
- int SpecCost = TTI.TCC_Free;
- for (Use &U : PN->uses())
- SpecCost +=
- SpecCostMap.find(cast<Instruction>(U.getUser()))->second;
- SpecCost *= (NumPreds - 1);
- // When the user count of a PHI node hits zero, we should check its
- // profitability. If profitable, we should mark it for speculation
- // and zero out the cost of everything it depends on.
- int CostSavings = CostSavingsMap.find(PN)->second;
- if (SpecCost > CostSavings) {
- LLVM_DEBUG(dbgs() << " Not profitable, speculation cost: " << *PN
- << "\n"
- " Cost savings: "
- << CostSavings
- << "\n"
- " Speculation cost: "
- << SpecCost << "\n");
- continue;
- }
-
- // We're going to speculate this user-associated PHI. Copy it out and
- // add its users to the worklist to update their cost.
- SpecPNs.push_back(PN);
- for (Use &U : PN->uses()) {
- auto *UI = cast<Instruction>(U.getUser());
- auto CostMapIt = SpecCostMap.find(UI);
- if (CostMapIt->second == 0)
- continue;
- // Zero out this cost entry to avoid duplicates.
- CostMapIt->second = 0;
- SpecWorklist.push_back(UI);
- }
- }
-
- // Now walk all the operands of the users in the worklist transitively
- // to zero out all the memoized costs.
- while (!SpecWorklist.empty()) {
- Instruction *SpecI = SpecWorklist.pop_back_val();
- assert(SpecCostMap.find(SpecI)->second == 0 &&
- "Didn't zero out a cost!");
-
- // Walk the operands recursively to zero out their cost as well.
- for (auto *OpV : SpecI->operand_values()) {
- auto *OpI = dyn_cast<Instruction>(OpV);
- if (!OpI)
- continue;
- auto CostMapIt = SpecCostMap.find(OpI);
- if (CostMapIt == SpecCostMap.end() || CostMapIt->second == 0)
- continue;
- CostMapIt->second = 0;
- SpecWorklist.push_back(OpI);
- }
- }
- });
-
- return SpecPNs;
-}
-
-/// Speculate users around a set of PHI nodes.
-///
-/// This routine does the actual speculation around a set of PHI nodes where we
-/// have determined this to be both safe and profitable.
-///
-/// This routine handles any spliting of critical edges necessary to create
-/// a safe block to speculate into as well as cloning the instructions and
-/// rewriting all uses.
-static void speculatePHIs(ArrayRef<PHINode *> SpecPNs,
- SmallPtrSetImpl<Instruction *> &PotentialSpecSet,
- SmallSetVector<BasicBlock *, 16> &PredSet,
- DominatorTree &DT) {
- LLVM_DEBUG(dbgs() << " Speculating around " << SpecPNs.size() << " PHIs!\n");
- NumPHIsSpeculated += SpecPNs.size();
-
- // Split any critical edges so that we have a block to hoist into.
- auto *ParentBB = SpecPNs[0]->getParent();
- SmallVector<BasicBlock *, 16> SpecPreds;
- SpecPreds.reserve(PredSet.size());
- for (auto *PredBB : PredSet) {
- auto *NewPredBB = SplitCriticalEdge(
- PredBB, ParentBB,
- CriticalEdgeSplittingOptions(&DT).setMergeIdenticalEdges());
- if (NewPredBB) {
- ++NumEdgesSplit;
- LLVM_DEBUG(dbgs() << " Split critical edge from: " << PredBB->getName()
- << "\n");
- SpecPreds.push_back(NewPredBB);
- } else {
- assert(PredBB->getSingleSuccessor() == ParentBB &&
- "We need a non-critical predecessor to speculate into.");
- assert(!isa<InvokeInst>(PredBB->getTerminator()) &&
- "Cannot have a non-critical invoke!");
-
- // Already non-critical, use existing pred.
- SpecPreds.push_back(PredBB);
- }
- }
-
- SmallPtrSet<Instruction *, 16> SpecSet;
- SmallVector<Instruction *, 16> SpecList;
- visitPHIUsersAndDepsInPostOrder(SpecPNs,
- /*IsVisited*/
- [&](Instruction *I) {
- // This is visited if we don't need to
- // speculate it or we already have
- // speculated it.
- return !PotentialSpecSet.count(I) ||
- SpecSet.count(I);
- },
- /*Visit*/
- [&](Instruction *I) {
- // All operands scheduled, schedule this
- // node.
- SpecSet.insert(I);
- SpecList.push_back(I);
- });
-
- int NumSpecInsts = SpecList.size() * SpecPreds.size();
- int NumRedundantInsts = NumSpecInsts - SpecList.size();
- LLVM_DEBUG(dbgs() << " Inserting " << NumSpecInsts
- << " speculated instructions, " << NumRedundantInsts
- << " redundancies\n");
- NumSpeculatedInstructions += NumSpecInsts;
- NumNewRedundantInstructions += NumRedundantInsts;
-
- // Each predecessor is numbered by its index in `SpecPreds`, so for each
- // instruction we speculate, the speculated instruction is stored in that
- // index of the vector associated with the original instruction. We also
- // store the incoming values for each predecessor from any PHIs used.
- SmallDenseMap<Instruction *, SmallVector<Value *, 2>, 16> SpeculatedValueMap;
-
- // Inject the synthetic mappings to rewrite PHIs to the appropriate incoming
- // value. This handles both the PHIs we are speculating around and any other
- // PHIs that happen to be used.
- for (auto *OrigI : SpecList)
- for (auto *OpV : OrigI->operand_values()) {
- auto *OpPN = dyn_cast<PHINode>(OpV);
- if (!OpPN || OpPN->getParent() != ParentBB)
- continue;
-
- auto InsertResult = SpeculatedValueMap.insert({OpPN, {}});
- if (!InsertResult.second)
- continue;
-
- auto &SpeculatedVals = InsertResult.first->second;
-
- // Populating our structure for mapping is particularly annoying because
- // finding an incoming value for a particular predecessor block in a PHI
- // node is a linear time operation! To avoid quadratic behavior, we build
- // a map for this PHI node's incoming values and then translate it into
- // the more compact representation used below.
- SmallDenseMap<BasicBlock *, Value *, 16> IncomingValueMap;
- for (int i : llvm::seq<int>(0, OpPN->getNumIncomingValues()))
- IncomingValueMap[OpPN->getIncomingBlock(i)] = OpPN->getIncomingValue(i);
-
- for (auto *PredBB : SpecPreds)
- SpeculatedVals.push_back(IncomingValueMap.find(PredBB)->second);
- }
-
- // Speculate into each predecessor.
- for (int PredIdx : llvm::seq<int>(0, SpecPreds.size())) {
- auto *PredBB = SpecPreds[PredIdx];
- assert(PredBB->getSingleSuccessor() == ParentBB &&
- "We need a non-critical predecessor to speculate into.");
-
- for (auto *OrigI : SpecList) {
- auto *NewI = OrigI->clone();
- NewI->setName(Twine(OrigI->getName()) + "." + Twine(PredIdx));
- NewI->insertBefore(PredBB->getTerminator());
-
- // Rewrite all the operands to the previously speculated instructions.
- // Because we're walking in-order, the defs must precede the uses and we
- // should already have these mappings.
- for (Use &U : NewI->operands()) {
- auto *OpI = dyn_cast<Instruction>(U.get());
- if (!OpI)
- continue;
- auto MapIt = SpeculatedValueMap.find(OpI);
- if (MapIt == SpeculatedValueMap.end())
- continue;
- const auto &SpeculatedVals = MapIt->second;
- assert(SpeculatedVals[PredIdx] &&
- "Must have a speculated value for this predecessor!");
- assert(SpeculatedVals[PredIdx]->getType() == OpI->getType() &&
- "Speculated value has the wrong type!");
-
- // Rewrite the use to this predecessor's speculated instruction.
- U.set(SpeculatedVals[PredIdx]);
- }
-
- // Commute instructions which now have a constant in the LHS but not the
- // RHS.
- if (NewI->isBinaryOp() && NewI->isCommutative() &&
- isa<Constant>(NewI->getOperand(0)) &&
- !isa<Constant>(NewI->getOperand(1)))
- NewI->getOperandUse(0).swap(NewI->getOperandUse(1));
-
- SpeculatedValueMap[OrigI].push_back(NewI);
- assert(SpeculatedValueMap[OrigI][PredIdx] == NewI &&
- "Mismatched speculated instruction index!");
- }
- }
-
- // Walk the speculated instruction list and if they have uses, insert a PHI
- // for them from the speculated versions, and replace the uses with the PHI.
- // Then erase the instructions as they have been fully speculated. The walk
- // needs to be in reverse so that we don't think there are users when we'll
- // actually eventually remove them later.
- IRBuilder<> IRB(SpecPNs[0]);
- for (auto *OrigI : llvm::reverse(SpecList)) {
- // Check if we need a PHI for any remaining users and if so, insert it.
- if (!OrigI->use_empty()) {
- auto *SpecIPN = IRB.CreatePHI(OrigI->getType(), SpecPreds.size(),
- Twine(OrigI->getName()) + ".phi");
- // Add the incoming values we speculated.
- auto &SpeculatedVals = SpeculatedValueMap.find(OrigI)->second;
- for (int PredIdx : llvm::seq<int>(0, SpecPreds.size()))
- SpecIPN->addIncoming(SpeculatedVals[PredIdx], SpecPreds[PredIdx]);
-
- // And replace the uses with the PHI node.
- OrigI->replaceAllUsesWith(SpecIPN);
- }
-
- // It is important to immediately erase this so that it stops using other
- // instructions. This avoids inserting needless PHIs of them.
- OrigI->eraseFromParent();
- }
-
- // All of the uses of the speculated phi nodes should be removed at this
- // point, so erase them.
- for (auto *SpecPN : SpecPNs) {
- assert(SpecPN->use_empty() && "All users should have been speculated!");
- SpecPN->eraseFromParent();
- }
-}
-
-/// Try to speculate around a series of PHIs from a single basic block.
-///
-/// This routine checks whether any of these PHIs are profitable to speculate
-/// users around. If safe and profitable, it does the speculation. It returns
-/// true when at least some speculation occurs.
-static bool tryToSpeculatePHIs(SmallVectorImpl<PHINode *> &PNs,
- DominatorTree &DT, TargetTransformInfo &TTI) {
- LLVM_DEBUG(dbgs() << "Evaluating phi nodes for speculation:\n");
-
- // Savings in cost from speculating around a PHI node.
- SmallDenseMap<PHINode *, int, 16> CostSavingsMap;
-
- // Remember the set of instructions that are candidates for speculation so
- // that we can quickly walk things within that space. This prunes out
- // instructions already available along edges, etc.
- SmallPtrSet<Instruction *, 16> PotentialSpecSet;
-
- // Remember the set of instructions that are (transitively) unsafe to
- // speculate into the incoming edges of this basic block. This avoids
- // recomputing them for each PHI node we check. This set is specific to this
- // block though as things are pruned out of it based on what is available
- // along incoming edges.
- SmallPtrSet<Instruction *, 16> UnsafeSet;
-
- // For each PHI node in this block, check whether there are immediate folding
- // opportunities from speculation, and whether that speculation will be
- // valid. This determise the set of safe PHIs to speculate.
- llvm::erase_if(PNs, [&](PHINode *PN) {
- return !isSafeAndProfitableToSpeculateAroundPHI(
- *PN, CostSavingsMap, PotentialSpecSet, UnsafeSet, DT, TTI);
- });
- // If no PHIs were profitable, skip.
- if (PNs.empty()) {
- LLVM_DEBUG(dbgs() << " No safe and profitable PHIs found!\n");
- return false;
- }
-
- // We need to know how much speculation will cost which is determined by how
- // many incoming edges will need a copy of each speculated instruction.
- SmallSetVector<BasicBlock *, 16> PredSet;
- for (auto *PredBB : PNs[0]->blocks()) {
- if (!PredSet.insert(PredBB))
- continue;
-
- // We cannot speculate when a predecessor is an indirect branch.
- // FIXME: We also can't reliably create a non-critical edge block for
- // speculation if the predecessor is an invoke. This doesn't seem
- // fundamental and we should probably be splitting critical edges
- // differently.
- const auto *TermInst = PredBB->getTerminator();
- if (isa<IndirectBrInst>(TermInst) ||
- isa<InvokeInst>(TermInst) ||
- isa<CallBrInst>(TermInst)) {
- LLVM_DEBUG(dbgs() << " Invalid: predecessor terminator: "
- << PredBB->getName() << "\n");
- return false;
- }
- }
- if (PredSet.size() < 2) {
- LLVM_DEBUG(dbgs() << " Unimportant: phi with only one predecessor\n");
- return false;
- }
-
- SmallVector<PHINode *, 16> SpecPNs = findProfitablePHIs(
- PNs, CostSavingsMap, PotentialSpecSet, PredSet.size(), DT, TTI);
- if (SpecPNs.empty())
- // Nothing to do.
- return false;
-
- speculatePHIs(SpecPNs, PotentialSpecSet, PredSet, DT);
- return true;
-}
-
-PreservedAnalyses SpeculateAroundPHIsPass::run(Function &F,
- FunctionAnalysisManager &AM) {
- auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
- auto &TTI = AM.getResult<TargetIRAnalysis>(F);
-
- bool Changed = false;
- for (auto *BB : ReversePostOrderTraversal<Function *>(&F)) {
- SmallVector<PHINode *, 16> PNs;
- auto BBI = BB->begin();
- while (auto *PN = dyn_cast<PHINode>(&*BBI)) {
- PNs.push_back(PN);
- ++BBI;
- }
-
- if (PNs.empty())
- continue;
-
- Changed |= tryToSpeculatePHIs(PNs, DT, TTI);
- }
-
- if (!Changed)
- return PreservedAnalyses::all();
-
- PreservedAnalyses PA;
- return PA;
-}
diff --git a/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp b/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp
index c78185f2a6ad..dfa30418ea01 100644
--- a/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp
+++ b/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp
@@ -210,8 +210,8 @@ bool SpeculativeExecutionPass::runOnBasicBlock(BasicBlock &B) {
return false;
}
-static unsigned ComputeSpeculationCost(const Instruction *I,
- const TargetTransformInfo &TTI) {
+static InstructionCost ComputeSpeculationCost(const Instruction *I,
+ const TargetTransformInfo &TTI) {
switch (Operator::getOpcode(I)) {
case Instruction::GetElementPtr:
case Instruction::Add:
@@ -255,7 +255,8 @@ static unsigned ComputeSpeculationCost(const Instruction *I,
return TTI.getUserCost(I, TargetTransformInfo::TCK_SizeAndLatency);
default:
- return UINT_MAX; // Disallow anything not explicitly listed.
+ return InstructionCost::getInvalid(); // Disallow anything not explicitly
+ // listed.
}
}
@@ -265,11 +266,13 @@ bool SpeculativeExecutionPass::considerHoistingFromTo(
const auto AllPrecedingUsesFromBlockHoisted = [&NotHoisted](const User *U) {
// Debug variable has special operand to check it's not hoisted.
if (const auto *DVI = dyn_cast<DbgVariableIntrinsic>(U)) {
- if (const auto *I =
- dyn_cast_or_null<Instruction>(DVI->getVariableLocation()))
- if (NotHoisted.count(I) == 0)
- return true;
- return false;
+ return all_of(DVI->location_ops(), [&NotHoisted](Value *V) {
+ if (const auto *I = dyn_cast_or_null<Instruction>(V)) {
+ if (NotHoisted.count(I) == 0)
+ return true;
+ }
+ return false;
+ });
}
// Usially debug label instrinsic corresponds to label in LLVM IR. In these
@@ -288,11 +291,11 @@ bool SpeculativeExecutionPass::considerHoistingFromTo(
return true;
};
- unsigned TotalSpeculationCost = 0;
+ InstructionCost TotalSpeculationCost = 0;
unsigned NotHoistedInstCount = 0;
for (const auto &I : FromBlock) {
- const unsigned Cost = ComputeSpeculationCost(&I, *TTI);
- if (Cost != UINT_MAX && isSafeToSpeculativelyExecute(&I) &&
+ const InstructionCost Cost = ComputeSpeculationCost(&I, *TTI);
+ if (Cost.isValid() && isSafeToSpeculativelyExecute(&I) &&
AllPrecedingUsesFromBlockHoisted(&I)) {
TotalSpeculationCost += Cost;
if (TotalSpeculationCost > SpecExecMaxSpeculationCost)
@@ -340,7 +343,6 @@ PreservedAnalyses SpeculativeExecutionPass::run(Function &F,
if (!Changed)
return PreservedAnalyses::all();
PreservedAnalyses PA;
- PA.preserve<GlobalsAA>();
PA.preserveSet<CFGAnalyses>();
return PA;
}
diff --git a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
index 577992ccb5f4..20b8b982e14b 100644
--- a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
+++ b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp
@@ -312,8 +312,8 @@ bool StraightLineStrengthReduce::isFoldable(const Candidate &C,
// Returns true if GEP has zero or one non-zero index.
static bool hasOnlyOneNonZeroIndex(GetElementPtrInst *GEP) {
unsigned NumNonZeroIndices = 0;
- for (auto I = GEP->idx_begin(); I != GEP->idx_end(); ++I) {
- ConstantInt *ConstIdx = dyn_cast<ConstantInt>(*I);
+ for (Use &Idx : GEP->indices()) {
+ ConstantInt *ConstIdx = dyn_cast<ConstantInt>(Idx);
if (ConstIdx == nullptr || !ConstIdx->isZero())
++NumNonZeroIndices;
}
@@ -533,8 +533,8 @@ void StraightLineStrengthReduce::allocateCandidatesAndFindBasisForGEP(
return;
SmallVector<const SCEV *, 4> IndexExprs;
- for (auto I = GEP->idx_begin(); I != GEP->idx_end(); ++I)
- IndexExprs.push_back(SE->getSCEV(*I));
+ for (Use &Idx : GEP->indices())
+ IndexExprs.push_back(SE->getSCEV(Idx));
gep_type_iterator GTI = gep_type_begin(GEP);
for (unsigned I = 1, E = GEP->getNumOperands(); I != E; ++I, ++GTI) {
diff --git a/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp b/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp
index 3e15cad5f3f3..ac580b4161f4 100644
--- a/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp
+++ b/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp
@@ -677,9 +677,8 @@ void StructurizeCFG::killTerminator(BasicBlock *BB) {
if (!Term)
return;
- for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB);
- SI != SE; ++SI)
- delPhiValues(BB, *SI);
+ for (BasicBlock *Succ : successors(BB))
+ delPhiValues(BB, Succ);
if (DA)
DA->removeValue(Term);
@@ -694,11 +693,9 @@ void StructurizeCFG::changeExit(RegionNode *Node, BasicBlock *NewExit,
BasicBlock *OldExit = SubRegion->getExit();
BasicBlock *Dominator = nullptr;
- // Find all the edges from the sub region to the exit
- for (auto BBI = pred_begin(OldExit), E = pred_end(OldExit); BBI != E;) {
- // Incrememt BBI before mucking with BB's terminator.
- BasicBlock *BB = *BBI++;
-
+ // Find all the edges from the sub region to the exit.
+ // We use make_early_inc_range here because we modify BB's terminator.
+ for (BasicBlock *BB : llvm::make_early_inc_range(predecessors(OldExit))) {
if (!SubRegion->contains(BB))
continue;
@@ -924,10 +921,9 @@ void StructurizeCFG::rebuildSSA() {
for (BasicBlock *BB : ParentRegion->blocks())
for (Instruction &I : *BB) {
bool Initialized = false;
- // We may modify the use list as we iterate over it, so be careful to
- // compute the next element in the use list at the top of the loop.
- for (auto UI = I.use_begin(), E = I.use_end(); UI != E;) {
- Use &U = *UI++;
+ // We may modify the use list as we iterate over it, so we use
+ // make_early_inc_range.
+ for (Use &U : llvm::make_early_inc_range(I.uses())) {
Instruction *User = cast<Instruction>(U.getUser());
if (User->getParent() == BB) {
continue;
diff --git a/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp b/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
index 9e7cccc88412..846a9321f53e 100644
--- a/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp
@@ -63,6 +63,7 @@
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
@@ -70,6 +71,7 @@
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
@@ -81,6 +83,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Local.h"
using namespace llvm;
#define DEBUG_TYPE "tailcallelim"
@@ -92,10 +95,10 @@ STATISTIC(NumAccumAdded, "Number of accumulators introduced");
/// Scan the specified function for alloca instructions.
/// If it contains any dynamic allocas, returns false.
static bool canTRE(Function &F) {
- // FIXME: The code generator produces really bad code when an 'escaping
- // alloca' is changed from being a static alloca to being a dynamic alloca.
- // Until this is resolved, disable this transformation if that would ever
- // happen. This bug is PR962.
+ // TODO: We don't do TRE if dynamic allocas are used.
+ // Dynamic allocas allocate stack space which should be
+ // deallocated before new iteration started. That is
+ // currently not implemented.
return llvm::all_of(instructions(F), [](Instruction &I) {
auto *AI = dyn_cast<AllocaInst>(&I);
return !AI || AI->isStaticAlloca();
@@ -188,11 +191,9 @@ struct AllocaDerivedValueTracker {
};
}
-static bool markTails(Function &F, bool &AllCallsAreTailCalls,
- OptimizationRemarkEmitter *ORE) {
+static bool markTails(Function &F, OptimizationRemarkEmitter *ORE) {
if (F.callsFunctionThatReturnsTwice())
return false;
- AllCallsAreTailCalls = true;
// The local stack holds all alloca instructions and all byval arguments.
AllocaDerivedValueTracker Tracker;
@@ -247,7 +248,10 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls,
isa<PseudoProbeInst>(&I))
continue;
- bool IsNoTail = CI->isNoTailCall() || CI->hasOperandBundles();
+ // Special-case operand bundle "clang.arc.attachedcall".
+ bool IsNoTail =
+ CI->isNoTailCall() || CI->hasOperandBundlesOtherThan(
+ LLVMContext::OB_clang_arc_attachedcall);
if (!IsNoTail && CI->doesNotAccessMemory()) {
// A call to a readnone function whose arguments are all things computed
@@ -279,11 +283,8 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls,
}
}
- if (!IsNoTail && Escaped == UNESCAPED && !Tracker.AllocaUsers.count(CI)) {
+ if (!IsNoTail && Escaped == UNESCAPED && !Tracker.AllocaUsers.count(CI))
DeferredTails.push_back(CI);
- } else {
- AllCallsAreTailCalls = false;
- }
}
for (auto *SuccBB : successors(BB)) {
@@ -320,8 +321,6 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls,
LLVM_DEBUG(dbgs() << "Marked as tail call candidate: " << *CI << "\n");
CI->setTailCall();
Modified = true;
- } else {
- AllCallsAreTailCalls = false;
}
}
@@ -333,6 +332,14 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls,
/// instructions between the call and this instruction are movable.
///
static bool canMoveAboveCall(Instruction *I, CallInst *CI, AliasAnalysis *AA) {
+ if (isa<DbgInfoIntrinsic>(I))
+ return true;
+
+ if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
+ if (II->getIntrinsicID() == Intrinsic::lifetime_end &&
+ llvm::findAllocaForValue(II->getArgOperand(1)))
+ return true;
+
// FIXME: We can move load/store/call/free instructions above the call if the
// call does not mod/ref the memory location being processed.
if (I->mayHaveSideEffects()) // This also handles volatile loads.
@@ -399,7 +406,6 @@ class TailRecursionEliminator {
// createTailRecurseLoopHeader the first time we find a call we can eliminate.
BasicBlock *HeaderBB = nullptr;
SmallVector<PHINode *, 8> ArgumentPHIs;
- bool RemovableCallsMustBeMarkedTail = false;
// PHI node to store our return value.
PHINode *RetPN = nullptr;
@@ -426,8 +432,7 @@ class TailRecursionEliminator {
DomTreeUpdater &DTU)
: F(F), TTI(TTI), AA(AA), ORE(ORE), DTU(DTU) {}
- CallInst *findTRECandidate(BasicBlock *BB,
- bool CannotTailCallElimCallsMarkedTail);
+ CallInst *findTRECandidate(BasicBlock *BB);
void createTailRecurseLoopHeader(CallInst *CI);
@@ -437,7 +442,11 @@ class TailRecursionEliminator {
void cleanupAndFinalize();
- bool processBlock(BasicBlock &BB, bool CannotTailCallElimCallsMarkedTail);
+ bool processBlock(BasicBlock &BB);
+
+ void copyByValueOperandIntoLocalTemp(CallInst *CI, int OpndIdx);
+
+ void copyLocalTempOfByValueOperandIntoArguments(CallInst *CI, int OpndIdx);
public:
static bool eliminate(Function &F, const TargetTransformInfo *TTI,
@@ -446,8 +455,7 @@ public:
};
} // namespace
-CallInst *TailRecursionEliminator::findTRECandidate(
- BasicBlock *BB, bool CannotTailCallElimCallsMarkedTail) {
+CallInst *TailRecursionEliminator::findTRECandidate(BasicBlock *BB) {
Instruction *TI = BB->getTerminator();
if (&BB->front() == TI) // Make sure there is something before the terminator.
@@ -467,9 +475,9 @@ CallInst *TailRecursionEliminator::findTRECandidate(
--BBI;
}
- // If this call is marked as a tail call, and if there are dynamic allocas in
- // the function, we cannot perform this optimization.
- if (CI->isTailCall() && CannotTailCallElimCallsMarkedTail)
+ assert((!CI->isTailCall() || !CI->isNoTailCall()) &&
+ "Incompatible call site attributes(Tail,NoTail)");
+ if (!CI->isTailCall())
return nullptr;
// As a special case, detect code like this:
@@ -501,26 +509,13 @@ void TailRecursionEliminator::createTailRecurseLoopHeader(CallInst *CI) {
BranchInst *BI = BranchInst::Create(HeaderBB, NewEntry);
BI->setDebugLoc(CI->getDebugLoc());
- // If this function has self recursive calls in the tail position where some
- // are marked tail and some are not, only transform one flavor or another.
- // We have to choose whether we move allocas in the entry block to the new
- // entry block or not, so we can't make a good choice for both. We make this
- // decision here based on whether the first call we found to remove is
- // marked tail.
- // NOTE: We could do slightly better here in the case that the function has
- // no entry block allocas.
- RemovableCallsMustBeMarkedTail = CI->isTailCall();
-
- // If this tail call is marked 'tail' and if there are any allocas in the
- // entry block, move them up to the new entry block.
- if (RemovableCallsMustBeMarkedTail)
- // Move all fixed sized allocas from HeaderBB to NewEntry.
- for (BasicBlock::iterator OEBI = HeaderBB->begin(), E = HeaderBB->end(),
- NEBI = NewEntry->begin();
- OEBI != E;)
- if (AllocaInst *AI = dyn_cast<AllocaInst>(OEBI++))
- if (isa<ConstantInt>(AI->getArraySize()))
- AI->moveBefore(&*NEBI);
+ // Move all fixed sized allocas from HeaderBB to NewEntry.
+ for (BasicBlock::iterator OEBI = HeaderBB->begin(), E = HeaderBB->end(),
+ NEBI = NewEntry->begin();
+ OEBI != E;)
+ if (AllocaInst *AI = dyn_cast<AllocaInst>(OEBI++))
+ if (isa<ConstantInt>(AI->getArraySize()))
+ AI->moveBefore(&*NEBI);
// Now that we have created a new block, which jumps to the entry
// block, insert a PHI node for each argument of the function.
@@ -585,6 +580,54 @@ void TailRecursionEliminator::insertAccumulator(Instruction *AccRecInstr) {
++NumAccumAdded;
}
+// Creates a copy of contents of ByValue operand of the specified
+// call instruction into the newly created temporarily variable.
+void TailRecursionEliminator::copyByValueOperandIntoLocalTemp(CallInst *CI,
+ int OpndIdx) {
+ PointerType *ArgTy = cast<PointerType>(CI->getArgOperand(OpndIdx)->getType());
+ Type *AggTy = ArgTy->getElementType();
+ const DataLayout &DL = F.getParent()->getDataLayout();
+
+ // Get alignment of byVal operand.
+ Align Alignment(CI->getParamAlign(OpndIdx).valueOrOne());
+
+ // Create alloca for temporarily byval operands.
+ // Put alloca into the entry block.
+ Value *NewAlloca = new AllocaInst(
+ AggTy, DL.getAllocaAddrSpace(), nullptr, Alignment,
+ CI->getArgOperand(OpndIdx)->getName(), &*F.getEntryBlock().begin());
+
+ IRBuilder<> Builder(CI);
+ Value *Size = Builder.getInt64(DL.getTypeAllocSize(AggTy));
+
+ // Copy data from byvalue operand into the temporarily variable.
+ Builder.CreateMemCpy(NewAlloca, /*DstAlign*/ Alignment,
+ CI->getArgOperand(OpndIdx),
+ /*SrcAlign*/ Alignment, Size);
+ CI->setArgOperand(OpndIdx, NewAlloca);
+}
+
+// Creates a copy from temporarily variable(keeping value of ByVal argument)
+// into the corresponding function argument location.
+void TailRecursionEliminator::copyLocalTempOfByValueOperandIntoArguments(
+ CallInst *CI, int OpndIdx) {
+ PointerType *ArgTy = cast<PointerType>(CI->getArgOperand(OpndIdx)->getType());
+ Type *AggTy = ArgTy->getElementType();
+ const DataLayout &DL = F.getParent()->getDataLayout();
+
+ // Get alignment of byVal operand.
+ Align Alignment(CI->getParamAlign(OpndIdx).valueOrOne());
+
+ IRBuilder<> Builder(CI);
+ Value *Size = Builder.getInt64(DL.getTypeAllocSize(AggTy));
+
+ // Copy data from the temporarily variable into corresponding
+ // function argument location.
+ Builder.CreateMemCpy(F.getArg(OpndIdx), /*DstAlign*/ Alignment,
+ CI->getArgOperand(OpndIdx),
+ /*SrcAlign*/ Alignment, Size);
+}
+
bool TailRecursionEliminator::eliminateCall(CallInst *CI) {
ReturnInst *Ret = cast<ReturnInst>(CI->getParent()->getTerminator());
@@ -623,14 +666,22 @@ bool TailRecursionEliminator::eliminateCall(CallInst *CI) {
if (!HeaderBB)
createTailRecurseLoopHeader(CI);
- if (RemovableCallsMustBeMarkedTail && !CI->isTailCall())
- return false;
+ // Copy values of ByVal operands into local temporarily variables.
+ for (unsigned I = 0, E = CI->getNumArgOperands(); I != E; ++I) {
+ if (CI->isByValArgument(I))
+ copyByValueOperandIntoLocalTemp(CI, I);
+ }
// Ok, now that we know we have a pseudo-entry block WITH all of the
// required PHI nodes, add entries into the PHI node for the actual
// parameters passed into the tail-recursive call.
- for (unsigned i = 0, e = CI->getNumArgOperands(); i != e; ++i)
- ArgumentPHIs[i]->addIncoming(CI->getArgOperand(i), BB);
+ for (unsigned I = 0, E = CI->getNumArgOperands(); I != E; ++I) {
+ if (CI->isByValArgument(I)) {
+ copyLocalTempOfByValueOperandIntoArguments(CI, I);
+ ArgumentPHIs[I]->addIncoming(F.getArg(I), BB);
+ } else
+ ArgumentPHIs[I]->addIncoming(CI->getArgOperand(I), BB);
+ }
if (AccRecInstr) {
insertAccumulator(AccRecInstr);
@@ -747,8 +798,7 @@ void TailRecursionEliminator::cleanupAndFinalize() {
}
}
-bool TailRecursionEliminator::processBlock(
- BasicBlock &BB, bool CannotTailCallElimCallsMarkedTail) {
+bool TailRecursionEliminator::processBlock(BasicBlock &BB) {
Instruction *TI = BB.getTerminator();
if (BranchInst *BI = dyn_cast<BranchInst>(TI)) {
@@ -761,7 +811,7 @@ bool TailRecursionEliminator::processBlock(
if (!Ret)
return false;
- CallInst *CI = findTRECandidate(&BB, CannotTailCallElimCallsMarkedTail);
+ CallInst *CI = findTRECandidate(&BB);
if (!CI)
return false;
@@ -782,7 +832,7 @@ bool TailRecursionEliminator::processBlock(
eliminateCall(CI);
return true;
} else if (isa<ReturnInst>(TI)) {
- CallInst *CI = findTRECandidate(&BB, CannotTailCallElimCallsMarkedTail);
+ CallInst *CI = findTRECandidate(&BB);
if (CI)
return eliminateCall(CI);
@@ -796,30 +846,25 @@ bool TailRecursionEliminator::eliminate(Function &F,
AliasAnalysis *AA,
OptimizationRemarkEmitter *ORE,
DomTreeUpdater &DTU) {
- if (F.getFnAttribute("disable-tail-calls").getValueAsString() == "true")
+ if (F.getFnAttribute("disable-tail-calls").getValueAsBool())
return false;
bool MadeChange = false;
- bool AllCallsAreTailCalls = false;
- MadeChange |= markTails(F, AllCallsAreTailCalls, ORE);
- if (!AllCallsAreTailCalls)
- return MadeChange;
+ MadeChange |= markTails(F, ORE);
// If this function is a varargs function, we won't be able to PHI the args
// right, so don't even try to convert it...
if (F.getFunctionType()->isVarArg())
return MadeChange;
- // If false, we cannot perform TRE on tail calls marked with the 'tail'
- // attribute, because doing so would cause the stack size to increase (real
- // TRE would deallocate variable sized allocas, TRE doesn't).
- bool CanTRETailMarkedCall = canTRE(F);
+ if (!canTRE(F))
+ return MadeChange;
// Change any tail recursive calls to loops.
TailRecursionEliminator TRE(F, TTI, AA, ORE, DTU);
for (BasicBlock &BB : F)
- MadeChange |= TRE.processBlock(BB, !CanTRETailMarkedCall);
+ MadeChange |= TRE.processBlock(BB);
TRE.cleanupAndFinalize();
@@ -893,7 +938,6 @@ PreservedAnalyses TailCallElimPass::run(Function &F,
if (!Changed)
return PreservedAnalyses::all();
PreservedAnalyses PA;
- PA.preserve<GlobalsAA>();
PA.preserve<DominatorTreeAnalysis>();
PA.preserve<PostDominatorTreeAnalysis>();
return PA;