diff --git a/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.h b/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.h @@ -0,0 +1,24 @@ +//===- HexagonLoopIdiomRecognition.h --------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_HEXAGON_HEXAGONLOOPIDIOMRECOGNITION_H +#define LLVM_LIB_TARGET_HEXAGON_HEXAGONLOOPIDIOMRECOGNITION_H + +#include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Scalar/LoopPassManager.h" + +namespace llvm { + +struct HexagonLoopIdiomRecognitionPass + : PassInfoMixin { + PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, LPMUpdater &U); +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONLOOPIDIOMRECOGNITION_H diff --git a/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp b/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp --- a/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp +++ b/llvm/lib/Target/Hexagon/HexagonLoopIdiomRecognition.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "HexagonLoopIdiomRecognition.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SetVector.h" @@ -16,6 +17,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/InstructionSimplify.h" +#include "llvm/Analysis/LoopAnalysisManager.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/MemoryLocation.h" @@ -40,6 +42,7 @@ #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicsHexagon.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Type.h" #include "llvm/IR/User.h" @@ -108,136 +111,152 @@ namespace llvm { - void initializeHexagonLoopIdiomRecognizePass(PassRegistry&); - Pass *createHexagonLoopIdiomPass(); +void initializeHexagonLoopIdiomRecognizeLegacyPassPass(PassRegistry &); +Pass *createHexagonLoopIdiomPass(); } // end namespace llvm namespace { - class HexagonLoopIdiomRecognize : public LoopPass { - public: - static char ID; - - explicit HexagonLoopIdiomRecognize() : LoopPass(ID) { - initializeHexagonLoopIdiomRecognizePass(*PassRegistry::getPassRegistry()); - } +class HexagonLoopIdiomRecognize { +public: + explicit HexagonLoopIdiomRecognize(AliasAnalysis *AA, DominatorTree *DT, + LoopInfo *LF, const TargetLibraryInfo *TLI, + ScalarEvolution *SE) + : AA(AA), DT(DT), LF(LF), TLI(TLI), SE(SE) {} + + bool run(Loop *L); + +private: + int getSCEVStride(const SCEVAddRecExpr *StoreEv); + bool isLegalStore(Loop *CurLoop, StoreInst *SI); + void collectStores(Loop *CurLoop, BasicBlock *BB, + SmallVectorImpl &Stores); + bool processCopyingStore(Loop *CurLoop, StoreInst *SI, const SCEV *BECount); + bool coverLoop(Loop *L, SmallVectorImpl &Insts) const; + bool runOnLoopBlock(Loop *CurLoop, BasicBlock *BB, const SCEV *BECount, + SmallVectorImpl &ExitBlocks); + bool runOnCountableLoop(Loop *L); + + AliasAnalysis *AA; + const DataLayout *DL; + DominatorTree *DT; + LoopInfo *LF; + const TargetLibraryInfo *TLI; + ScalarEvolution *SE; + bool HasMemcpy, HasMemmove; +}; + +class HexagonLoopIdiomRecognizeLegacyPass : public LoopPass { +public: + static char ID; + + explicit HexagonLoopIdiomRecognizeLegacyPass() : LoopPass(ID) { + initializeHexagonLoopIdiomRecognizeLegacyPassPass( + *PassRegistry::getPassRegistry()); + } - StringRef getPassName() const override { - return "Recognize Hexagon-specific loop idioms"; - } + StringRef getPassName() const override { + return "Recognize Hexagon-specific loop idioms"; + } - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired(); - AU.addRequiredID(LoopSimplifyID); - AU.addRequiredID(LCSSAID); - AU.addRequired(); - AU.addPreserved(); - AU.addRequired(); - AU.addRequired(); - AU.addRequired(); - AU.addPreserved(); - } + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addRequiredID(LoopSimplifyID); + AU.addRequiredID(LCSSAID); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); + } - bool runOnLoop(Loop *L, LPPassManager &LPM) override; + bool runOnLoop(Loop *L, LPPassManager &LPM) override; +}; - private: - int getSCEVStride(const SCEVAddRecExpr *StoreEv); - bool isLegalStore(Loop *CurLoop, StoreInst *SI); - void collectStores(Loop *CurLoop, BasicBlock *BB, - SmallVectorImpl &Stores); - bool processCopyingStore(Loop *CurLoop, StoreInst *SI, const SCEV *BECount); - bool coverLoop(Loop *L, SmallVectorImpl &Insts) const; - bool runOnLoopBlock(Loop *CurLoop, BasicBlock *BB, const SCEV *BECount, - SmallVectorImpl &ExitBlocks); - bool runOnCountableLoop(Loop *L); - - AliasAnalysis *AA; - const DataLayout *DL; - DominatorTree *DT; - LoopInfo *LF; - const TargetLibraryInfo *TLI; - ScalarEvolution *SE; - bool HasMemcpy, HasMemmove; +struct Simplifier { + struct Rule { + using FuncType = std::function; + Rule(StringRef N, FuncType F) : Name(N), Fn(F) {} + StringRef Name; // For debugging. + FuncType Fn; }; - struct Simplifier { - struct Rule { - using FuncType = std::function; - Rule(StringRef N, FuncType F) : Name(N), Fn(F) {} - StringRef Name; // For debugging. - FuncType Fn; - }; - - void addRule(StringRef N, const Rule::FuncType &F) { - Rules.push_back(Rule(N, F)); - } + void addRule(StringRef N, const Rule::FuncType &F) { + Rules.push_back(Rule(N, F)); + } - private: - struct WorkListType { - WorkListType() = default; +private: + struct WorkListType { + WorkListType() = default; - void push_back(Value* V) { - // Do not push back duplicates. - if (!S.count(V)) { Q.push_back(V); S.insert(V); } + void push_back(Value *V) { + // Do not push back duplicates. + if (!S.count(V)) { + Q.push_back(V); + S.insert(V); } + } - Value *pop_front_val() { - Value *V = Q.front(); Q.pop_front(); S.erase(V); - return V; - } + Value *pop_front_val() { + Value *V = Q.front(); + Q.pop_front(); + S.erase(V); + return V; + } - bool empty() const { return Q.empty(); } + bool empty() const { return Q.empty(); } - private: - std::deque Q; - std::set S; - }; + private: + std::deque Q; + std::set S; + }; - using ValueSetType = std::set; + using ValueSetType = std::set; - std::vector Rules; + std::vector Rules; - public: - struct Context { - using ValueMapType = DenseMap; +public: + struct Context { + using ValueMapType = DenseMap; - Value *Root; - ValueSetType Used; // The set of all cloned values used by Root. - ValueSetType Clones; // The set of all cloned values. - LLVMContext &Ctx; + Value *Root; + ValueSetType Used; // The set of all cloned values used by Root. + ValueSetType Clones; // The set of all cloned values. + LLVMContext &Ctx; - Context(Instruction *Exp) + Context(Instruction *Exp) : Ctx(Exp->getParent()->getParent()->getContext()) { - initialize(Exp); - } - - ~Context() { cleanup(); } + initialize(Exp); + } - void print(raw_ostream &OS, const Value *V) const; - Value *materialize(BasicBlock *B, BasicBlock::iterator At); + ~Context() { cleanup(); } - private: - friend struct Simplifier; + void print(raw_ostream &OS, const Value *V) const; + Value *materialize(BasicBlock *B, BasicBlock::iterator At); - void initialize(Instruction *Exp); - void cleanup(); + private: + friend struct Simplifier; - template void traverse(Value *V, FuncT F); - void record(Value *V); - void use(Value *V); - void unuse(Value *V); + void initialize(Instruction *Exp); + void cleanup(); - bool equal(const Instruction *I, const Instruction *J) const; - Value *find(Value *Tree, Value *Sub) const; - Value *subst(Value *Tree, Value *OldV, Value *NewV); - void replace(Value *OldV, Value *NewV); - void link(Instruction *I, BasicBlock *B, BasicBlock::iterator At); - }; + template void traverse(Value *V, FuncT F); + void record(Value *V); + void use(Value *V); + void unuse(Value *V); - Value *simplify(Context &C); + bool equal(const Instruction *I, const Instruction *J) const; + Value *find(Value *Tree, Value *Sub) const; + Value *subst(Value *Tree, Value *OldV, Value *NewV); + void replace(Value *OldV, Value *NewV); + void link(Instruction *I, BasicBlock *B, BasicBlock::iterator At); }; + Value *simplify(Context &C); +}; + struct PE { PE(const Simplifier::Context &c, Value *v = nullptr) : C(c), V(v) {} @@ -253,10 +272,10 @@ } // end anonymous namespace -char HexagonLoopIdiomRecognize::ID = 0; +char HexagonLoopIdiomRecognizeLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(HexagonLoopIdiomRecognize, "hexagon-loop-idiom", - "Recognize Hexagon-specific loop idioms", false, false) +INITIALIZE_PASS_BEGIN(HexagonLoopIdiomRecognizeLegacyPass, "hexagon-loop-idiom", + "Recognize Hexagon-specific loop idioms", false, false) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopSimplify) INITIALIZE_PASS_DEPENDENCY(LCSSAWrapperPass) @@ -264,8 +283,8 @@ INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) -INITIALIZE_PASS_END(HexagonLoopIdiomRecognize, "hexagon-loop-idiom", - "Recognize Hexagon-specific loop idioms", false, false) +INITIALIZE_PASS_END(HexagonLoopIdiomRecognizeLegacyPass, "hexagon-loop-idiom", + "Recognize Hexagon-specific loop idioms", false, false) template void Simplifier::Context::traverse(Value *V, FuncT F) { @@ -2404,14 +2423,11 @@ return Changed; } -bool HexagonLoopIdiomRecognize::runOnLoop(Loop *L, LPPassManager &LPM) { +bool HexagonLoopIdiomRecognize::run(Loop *L) { const Module &M = *L->getHeader()->getParent()->getParent(); if (Triple(M.getTargetTriple()).getArch() != Triple::hexagon) return false; - if (skipLoop(L)) - return false; - // If the loop could not be converted to canonical form, it must have an // indirectbr in it, just give up. if (!L->getLoopPreheader()) @@ -2422,13 +2438,7 @@ if (Name == "memset" || Name == "memcpy" || Name == "memmove") return false; - AA = &getAnalysis().getAAResults(); DL = &L->getHeader()->getModule()->getDataLayout(); - DT = &getAnalysis().getDomTree(); - LF = &getAnalysis().getLoopInfo(); - TLI = &getAnalysis().getTLI( - *L->getHeader()->getParent()); - SE = &getAnalysis().getSE(); HasMemcpy = TLI->has(LibFunc_memcpy); HasMemmove = TLI->has(LibFunc_memmove); @@ -2438,6 +2448,30 @@ return false; } +bool HexagonLoopIdiomRecognizeLegacyPass::runOnLoop(Loop *L, + LPPassManager &LPM) { + if (skipLoop(L)) + return false; + + auto *AA = &getAnalysis().getAAResults(); + auto *DT = &getAnalysis().getDomTree(); + auto *LF = &getAnalysis().getLoopInfo(); + auto *TLI = &getAnalysis().getTLI( + *L->getHeader()->getParent()); + auto *SE = &getAnalysis().getSE(); + return HexagonLoopIdiomRecognize(AA, DT, LF, TLI, SE).run(L); +} + Pass *llvm::createHexagonLoopIdiomPass() { - return new HexagonLoopIdiomRecognize(); + return new HexagonLoopIdiomRecognizeLegacyPass(); +} + +PreservedAnalyses +HexagonLoopIdiomRecognitionPass::run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, + LPMUpdater &U) { + return HexagonLoopIdiomRecognize(&AR.AA, &AR.DT, &AR.LI, &AR.TLI, &AR.SE) + .run(&L) + ? getLoopPassPreservedAnalyses() + : PreservedAnalyses::all(); } diff --git a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp --- a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp +++ b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp @@ -13,6 +13,7 @@ #include "HexagonTargetMachine.h" #include "Hexagon.h" #include "HexagonISelLowering.h" +#include "HexagonLoopIdiomRecognition.h" #include "HexagonMachineScheduler.h" #include "HexagonTargetObjectFile.h" #include "HexagonTargetTransformInfo.h" @@ -138,7 +139,7 @@ void initializeHexagonExpandCondsetsPass(PassRegistry&); void initializeHexagonGenMuxPass(PassRegistry&); void initializeHexagonHardwareLoopsPass(PassRegistry&); - void initializeHexagonLoopIdiomRecognizePass(PassRegistry&); + void initializeHexagonLoopIdiomRecognizeLegacyPassPass(PassRegistry &); void initializeHexagonVectorLoopCarriedReuseLegacyPassPass(PassRegistry &); void initializeHexagonNewValueJumpPass(PassRegistry&); void initializeHexagonOptAddrModePass(PassRegistry&); @@ -197,7 +198,7 @@ initializeHexagonEarlyIfConversionPass(PR); initializeHexagonGenMuxPass(PR); initializeHexagonHardwareLoopsPass(PR); - initializeHexagonLoopIdiomRecognizePass(PR); + initializeHexagonLoopIdiomRecognizeLegacyPassPass(PR); initializeHexagonVectorLoopCarriedReuseLegacyPassPass(PR); initializeHexagonNewValueJumpPass(PR); initializeHexagonOptAddrModePass(PR); @@ -276,6 +277,10 @@ void HexagonTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB, bool DebugPassManager) { + PB.registerLateLoopOptimizationsEPCallback( + [=](LoopPassManager &LPM, PassBuilder::OptimizationLevel Level) { + LPM.addPass(HexagonLoopIdiomRecognitionPass()); + }); PB.registerOptimizerLastEPCallback( [=](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { LoopPassManager LPM(DebugPassManager); diff --git a/llvm/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll b/llvm/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll --- a/llvm/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll +++ b/llvm/test/CodeGen/Hexagon/loop-idiom/pmpy-mod.ll @@ -3,6 +3,7 @@ ; get this opportunity regardless of what happens before. ; RUN: opt -O2 -march=hexagon -S < %s | FileCheck %s +; RUN: opt -aa-pipeline=default -passes='default' -march=hexagon -S < %s | FileCheck %s target triple = "hexagon" target datalayout = "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048"