149 using namespace llvm;
151 #define DEBUG_TYPE "hexagon-vlcr" 153 STATISTIC(HexagonNumVectorLoopCarriedReuse,
154 "Number of values that were reused from a previous iteration.");
158 cl::desc(
"Maximum distance of loop carried dependences that are handled"),
174 ChainOfDependences Chain;
177 bool isIdentical(DepChain &Other)
const {
178 if (Other.size() !=
size())
180 ChainOfDependences &OtherChain = Other.getChain();
181 for (
int i = 0; i <
size(); ++i) {
182 if (Chain[i] != OtherChain[i])
188 ChainOfDependences &getChain() {
204 int iterations()
const {
209 return Chain.front();
225 const ChainOfDependences &CD = D.Chain;
226 int ChainSize = CD.size();
227 OS <<
"**DepChain Start::**\n";
228 for (
int i = 0; i < ChainSize -1; ++i) {
229 OS << *(CD[i]) <<
" -->\n";
231 OS << *CD[ChainSize-1] <<
"\n";
243 ReuseValue() =
default;
245 void reset() { Inst2Replace =
nullptr; BackedgeInst =
nullptr; }
246 bool isDefined() {
return Inst2Replace !=
nullptr; }
251 OS <<
"** ReuseValue ***\n";
252 OS <<
"Instruction to Replace: " << *(RU.Inst2Replace) <<
"\n";
253 OS <<
"Backedge Instruction: " << *(RU.BackedgeInst) <<
"\n";
257 class HexagonVectorLoopCarriedReuse :
public LoopPass {
261 explicit HexagonVectorLoopCarriedReuse() :
LoopPass(ID) {
267 return "Hexagon-specific loop carried reuse for HVX vectors";
282 std::set<Instruction *> ReplacedInsts;
284 ReuseValue ReuseCandidate;
287 void findLoopCarriedDeps();
288 void findValueToReuse();
289 void findDepChainFromPHI(
Instruction *I, DepChain &D);
303 "Hexagon-specific predictive commoning for HVX vectors",
false,
false)
314 if (!L->getLoopPreheader())
318 if (!L->getSubLoops().empty())
322 if (L->getNumBlocks() != 1)
330 bool HexagonVectorLoopCarriedReuse::isEquivalentOperation(
Instruction *I1,
338 if (
CallInst *C1 = dyn_cast<CallInst>(I1)) {
339 if (
CallInst *C2 = dyn_cast<CallInst>(I2)) {
340 if (C1->getCalledFunction() != C2->getCalledFunction())
349 for (
unsigned i = 0; i < NumOperands; ++i) {
362 bool HexagonVectorLoopCarriedReuse::canReplace(
Instruction *I) {
367 LLVM_DEBUG(
dbgs() <<
"Not considering for reuse: " << *II <<
"\n");
372 void HexagonVectorLoopCarriedReuse::findValueToReuse() {
373 for (
auto *D : Dependences) {
374 LLVM_DEBUG(
dbgs() <<
"Processing dependence " << *(D->front()) <<
"\n");
378 <<
".. Skipping because number of iterations > than the limit\n");
382 PHINode *PN = cast<PHINode>(D->front());
384 int Iters = D->iterations();
387 <<
" can be reused\n");
396 if (ReplacedInsts.count(User)) {
398 <<
" has already been replaced. Skipping...\n");
401 if (isa<PHINode>(User))
405 if (!canReplace(User))
419 for (
auto UI = BEInst->use_begin(),
E = BEInst->use_end(); UI !=
E;
426 if (!isEquivalentOperation(I, BEUser))
431 for (
int OpNo = 0; OpNo < NumOperands; ++OpNo) {
440 if (!isDepChainBtwn(OpInst, BEOpInst, Iters)) {
447 ReuseCandidate.Inst2Replace =
I;
448 ReuseCandidate.BackedgeInst = BEUser;
451 ReuseCandidate.reset();
455 ReuseCandidate.reset();
458 Value *HexagonVectorLoopCarriedReuse::findValueInBlock(
Value *
Op,
466 void HexagonVectorLoopCarriedReuse::reuseValue() {
468 Instruction *Inst2Replace = ReuseCandidate.Inst2Replace;
471 std::map<Instruction *, DepChain *> DepChains;
473 BasicBlock *LoopPH = CurLoop->getLoopPreheader();
475 for (
int i = 0; i < NumOperands; ++i) {
481 DepChain *D = getDepChainBtwn(I, J);
484 "No DepChain between corresponding operands in ReuseCandidate\n");
485 if (Iterations == -1)
486 Iterations = D->iterations();
487 assert(Iterations == D->iterations() &&
"Iterations mismatch");
492 LLVM_DEBUG(
dbgs() <<
"reuseValue is making the following changes\n");
495 for (
int i = 0; i < Iterations; ++i) {
498 for (
int j = 0; j < NumOperands; ++j) {
503 DepChain &D = *DepChains[
I];
507 Value *ValInPreheader = findValueInBlock(D[i], LoopPH);
508 InstInPreheader->
setOperand(j, ValInPreheader);
510 InstsInPreheader.
push_back(InstInPreheader);
511 InstInPreheader->
setName(Inst2Replace->
getName() +
".hexagon.vlcr");
519 Value *BEVal = BEInst;
521 for (
int i = Iterations-1; i >=0 ; --i) {
522 Instruction *InstInPreheader = InstsInPreheader[i];
533 ReplacedInsts.insert(Inst2Replace);
534 ++HexagonNumVectorLoopCarriedReuse;
537 bool HexagonVectorLoopCarriedReuse::doVLCR() {
538 assert(CurLoop->getSubLoops().empty() &&
539 "Can do VLCR on the innermost loop only");
540 assert((CurLoop->getNumBlocks() == 1) &&
541 "Can do VLCR only on single block loops");
543 bool Changed =
false;
546 LLVM_DEBUG(
dbgs() <<
"Working on Loop: " << *CurLoop->getHeader() <<
"\n");
552 findLoopCarriedDeps();
554 if (ReuseCandidate.isDefined()) {
564 void HexagonVectorLoopCarriedReuse::findDepChainFromPHI(
Instruction *I,
572 if (NumIncomingValues != 2) {
578 if (BB != CurLoop->getHeader()) {
587 assert(BEInst &&
"There should be a value over the backedge");
591 if(!PreHdrVal || !isa<Instruction>(PreHdrVal)) {
596 findDepChainFromPHI(BEInst, D);
600 bool HexagonVectorLoopCarriedReuse::isDepChainBtwn(
Instruction *I1,
603 for (
auto *D : Dependences) {
604 if (D->front() == I1 && D->back() == I2 && D->iterations() == Iters)
610 DepChain *HexagonVectorLoopCarriedReuse::getDepChainBtwn(
Instruction *I1,
612 for (
auto *D : Dependences) {
613 if (D->front() == I1 && D->back() == I2)
619 void HexagonVectorLoopCarriedReuse::findLoopCarriedDeps() {
621 for (
auto I = BB->
begin(),
E = BB->
end(); I !=
E && isa<PHINode>(
I); ++
I) {
622 auto *PN = cast<PHINode>(
I);
623 if (!isa<VectorType>(PN->getType()))
626 DepChain *D =
new DepChain();
627 findDepChainFromPHI(PN, *D);
629 Dependences.insert(D);
633 LLVM_DEBUG(
dbgs() <<
"Found " << Dependences.size() <<
" dependences\n");
634 LLVM_DEBUG(
for (
size_t i = 0; i < Dependences.size();
635 ++i) {
dbgs() << *Dependences[i] <<
"\n"; });
639 return new HexagonVectorLoopCarriedReuse();
Pass interface - Implemented by all 'passes'.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
bool isSameOperationAs(const Instruction *I, unsigned flags=0) const
This function determines if the specified instruction executes the same operation as the current one...
This class represents lattice values for constants.
void push_back(const T &Elt)
This class represents a function call, abstracting a target machine's calling convention.
static cl::opt< int > HexagonVLCRIterationLim("hexagon-vlcr-iteration-lim", cl::Hidden, cl::desc("Maximum distance of loop carried dependences that are handled"), cl::init(2), cl::ZeroOrMore)
STATISTIC(NumFunctions, "Total number of functions")
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
bool isVectorTy() const
True if this is an instance of VectorType.
This defines the Use class.
iterator begin()
Instruction iterator methods.
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
hexagon Hexagon specific predictive commoning for HVX vectors
A Use represents the edge between a Value definition and its users.
INITIALIZE_PASS_BEGIN(HexagonVectorLoopCarriedReuse, "hexagon-vlcr", "Hexagon-specific predictive commoning for HVX vectors", false, false) INITIALIZE_PASS_END(HexagonVectorLoopCarriedReuse
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
void setName(const Twine &Name)
Change the name of the value.
Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following: ...
User * getUser() const LLVM_READONLY
Returns the User that contains this Use.
Type * getType() const
All values are typed, get the type of this value.
AnalysisUsage & addPreservedID(const void *ID)
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block...
Value * getOperand(unsigned i) const
void initializeHexagonVectorLoopCarriedReusePass(PassRegistry &)
initializer< Ty > init(const Ty &Val)
void insertBefore(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified instruction...
LLVM Basic Block Representation.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Value * getIncomingValueForBlock(const BasicBlock *BB) const
bool mayHaveSideEffects() const
Return true if the instruction may have side effects.
Represent the analysis usage information of a pass.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
unsigned getNumOperands() const
This is the shared class of boolean and integer constants.
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
AnalysisUsage & addRequiredID(const void *ID)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
void setPreservesCFG()
This function should be called by the pass, iff they do not:
unsigned getNumIncomingValues() const
Return the number of incoming edges.
void setOperand(unsigned i, Value *Val)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
static void clear(coro::Shape &Shape)
Pass * createHexagonVectorLoopCarriedReusePass()
Represents a single loop in the control flow graph.
StringRef getName() const
Return a constant reference to the value's name.
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
raw_ostream & operator<<(raw_ostream &OS, const APInt &I)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
LLVM Value Representation.
A vector that has set insertion semantics.
This class implements an extremely fast bulk output stream that can only output to a stream...
The legacy pass manager's analysis pass to compute loop information.
StringRef - Represent a constant reference to a string, i.e.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
#define LLVM_ATTRIBUTE_UNUSED
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
UnaryPredicate for_each(R &&Range, UnaryPredicate P)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly...
for(unsigned i=Desc.getNumOperands(), e=OldMI.getNumOperands();i !=e;++i)
A wrapper class for inspecting calls to intrinsic functions.
const BasicBlock * getParent() const