#include "llvm/Transforms/Scalar/LoopInstSimplify.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/InstructionSimplify.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/TargetLibraryInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/LoopUtils.h"
#include <utility>
using namespace llvm;
#define DEBUG_TYPE "loop-instsimplify"
STATISTIC(NumSimplified, "Number of redundant instructions simplified");
static bool simplifyLoopInst(Loop &L, DominatorTree &DT, LoopInfo &LI,
AssumptionCache &AC, const TargetLibraryInfo &TLI,
MemorySSAUpdater *MSSAU) {
const DataLayout &DL = L.getHeader()->getModule()->getDataLayout();
SimplifyQuery SQ(DL, &TLI, &DT, &AC);
SmallPtrSet<const Instruction *, 8> S1, S2, *ToSimplify = &S1, *Next = &S2;
SmallPtrSet<PHINode *, 4> VisitedPHIs;
SmallVector<WeakTrackingVH, 8> DeadInsts;
LoopBlocksRPO RPOT(&L);
RPOT.perform(&LI);
MemorySSA *MSSA = MSSAU ? MSSAU->getMemorySSA() : nullptr;
bool Changed = false;
for (;;) {
if (MSSAU && VerifyMemorySSA)
MSSA->verifyMemorySSA();
for (BasicBlock *BB : RPOT) {
for (Instruction &I : *BB) {
if (auto *PI = dyn_cast<PHINode>(&I))
VisitedPHIs.insert(PI);
if (I.use_empty()) {
if (isInstructionTriviallyDead(&I, &TLI))
DeadInsts.push_back(&I);
continue;
}
bool IsFirstIteration = ToSimplify->empty();
if (!IsFirstIteration && !ToSimplify->count(&I))
continue;
Value *V = simplifyInstruction(&I, SQ.getWithInstruction(&I));
if (!V || !LI.replacementPreservesLCSSAForm(&I, V))
continue;
for (Use &U : llvm::make_early_inc_range(I.uses())) {
auto *UserI = cast<Instruction>(U.getUser());
U.set(V);
if (!DT.isReachableFromEntry(UserI->getParent()))
continue;
if (auto *UserPI = dyn_cast<PHINode>(UserI))
if (VisitedPHIs.count(UserPI)) {
Next->insert(UserPI);
continue;
}
assert((L.contains(UserI) || isa<PHINode>(UserI)) &&
"Uses outside the loop should be PHI nodes due to LCSSA!");
if (!IsFirstIteration && L.contains(UserI))
ToSimplify->insert(UserI);
}
if (MSSAU)
if (Instruction *SimpleI = dyn_cast_or_null<Instruction>(V))
if (MemoryAccess *MA = MSSA->getMemoryAccess(&I))
if (MemoryAccess *ReplacementMA = MSSA->getMemoryAccess(SimpleI))
MA->replaceAllUsesWith(ReplacementMA);
assert(I.use_empty() && "Should always have replaced all uses!");
if (isInstructionTriviallyDead(&I, &TLI))
DeadInsts.push_back(&I);
++NumSimplified;
Changed = true;
}
}
if (!DeadInsts.empty()) {
Changed = true;
RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, &TLI, MSSAU);
}
if (MSSAU && VerifyMemorySSA)
MSSA->verifyMemorySSA();
if (Next->empty())
break;
std::swap(Next, ToSimplify);
Next->clear();
VisitedPHIs.clear();
DeadInsts.clear();
}
return Changed;
}
namespace {
class LoopInstSimplifyLegacyPass : public LoopPass {
public:
static char ID;
LoopInstSimplifyLegacyPass() : LoopPass(ID) {
initializeLoopInstSimplifyLegacyPassPass(*PassRegistry::getPassRegistry());
}
bool runOnLoop(Loop *L, LPPassManager &LPM) override {
if (skipLoop(L))
return false;
DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
AssumptionCache &AC =
getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
*L->getHeader()->getParent());
const TargetLibraryInfo &TLI =
getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
*L->getHeader()->getParent());
MemorySSA *MSSA = &getAnalysis<MemorySSAWrapperPass>().getMSSA();
MemorySSAUpdater MSSAU(MSSA);
return simplifyLoopInst(*L, DT, LI, AC, TLI, &MSSAU);
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
AU.setPreservesCFG();
AU.addRequired<MemorySSAWrapperPass>();
AU.addPreserved<MemorySSAWrapperPass>();
getLoopAnalysisUsage(AU);
}
};
}
PreservedAnalyses LoopInstSimplifyPass::run(Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &) {
Optional<MemorySSAUpdater> MSSAU;
if (AR.MSSA) {
MSSAU = MemorySSAUpdater(AR.MSSA);
if (VerifyMemorySSA)
AR.MSSA->verifyMemorySSA();
}
if (!simplifyLoopInst(L, AR.DT, AR.LI, AR.AC, AR.TLI,
MSSAU ? MSSAU.getPointer() : nullptr))
return PreservedAnalyses::all();
auto PA = getLoopPassPreservedAnalyses();
PA.preserveSet<CFGAnalyses>();
if (AR.MSSA)
PA.preserve<MemorySSAAnalysis>();
return PA;
}
char LoopInstSimplifyLegacyPass::ID = 0;
INITIALIZE_PASS_BEGIN(LoopInstSimplifyLegacyPass, "loop-instsimplify",
"Simplify instructions in loops", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(LoopPass)
INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(LoopInstSimplifyLegacyPass, "loop-instsimplify",
"Simplify instructions in loops", false, false)
Pass *llvm::createLoopInstSimplifyPass() {
return new LoopInstSimplifyLegacyPass();
}