LLVM: lib/Target/Hexagon/HexagonOptShuffleVector.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
23#include "llvm/IR/IntrinsicsHexagon.h"
29
30using namespace llvm;
32
33#define DEBUG_TYPE "hex-shuff-vec"
34
36 "shuffvec-max-search-count",
37 cl::desc("Maximum number of instructions traversed along def chain."),
39
40#ifndef NDEBUG
43 cl::desc("Maximum number of shuffles to be relocated."),
45#endif
46
47namespace llvm {
50}
51
52namespace {
53
54class HexagonOptShuffleVector : public FunctionPass {
55public:
56 static char ID;
57#ifndef NDEBUG
58 static int NumRelocated;
59#endif
62 }
63
64 HexagonOptShuffleVector(const HexagonTargetMachine *TM)
65 : FunctionPass(ID), TM(TM) {
67 }
68
69 StringRef getPassName() const override {
70 return "Hexagon Optimize Vector Shuffles";
71 }
72
74
75 void getAnalysisUsage(AnalysisUsage &AU) const override {
76 FunctionPass::getAnalysisUsage(AU);
77 }
78
79private:
80 using ValueVector = SmallVector<Value *, 8>;
81 const HexagonTargetMachine *TM = nullptr;
82 const HexagonSubtarget *HST = nullptr;
83 SmallPtrSet<Instruction *, 8> Visited;
84 using ShuffUseList =
85 SmallDenseMap<Instruction *, SmallVector<Instruction *, 2>>;
86 ShuffUseList ShuffUses;
87 int DefSearchCount;
88
89 bool visitBlock(BasicBlock *B);
90 bool findNewShuffLoc(Instruction *I, ArrayRef &ShuffMask,
92 bool isValidIntrinsic(IntrinsicInst *I);
93 bool relocateShuffVec(Instruction *I, ArrayRef &M, Value *NewLoc,
94 std::list<Instruction *> &WorkList);
95 bool getUseList(Instruction *I, ValueVector &UseList);
96 bool analyzeHiLoUse(Instruction *HI, Instruction *LO,
97 ArrayRef &ShuffMask, Value *&NewLoc,
98 ShuffUseList &CurShuffUses);
99 bool isHILo(Value *V, bool IsHI);
100 bool hasDefWithSameShuffMask(Value *V, SmallVector<Instruction *, 2> &ImmUse,
101 ArrayRef &ShuffMask,
102 ShuffUseList &CurShuffUses);
103 void FindHiLoUse(ValueVector &UseList, Instruction *&HI, Instruction *&LO);
104 bool isConcatMask(ArrayRef &Mask, Instruction *ShuffInst);
105 bool isValidUseInstr(ValueVector &UseList, Instruction *&UI);
106 bool areAllOperandsValid(Instruction *I, Instruction *UI,
107 ArrayRef &ShuffMask,
108 ShuffUseList &CurShuffUses);
109 Value *getOperand(Instruction *I, unsigned i);
111 static std::pair<Value *, Value *> stripCasts(Value *V);
112 static bool isConstantVectorSplat(Value *V);
113};
114
115}
116
117#ifndef NDEBUG
118int HexagonOptShuffleVector::NumRelocated = 0;
119#endif
120char HexagonOptShuffleVector::ID = 0;
121
123 "Hexagon Optimize Shuffle Vector", false, false)
127
130 Type *ShuffTy = ShuffInst->getType();
132 for (int i = 0; i < NumElts; i++) {
133 if (Mask[i] != i)
134 return false;
135 }
136 return true;
137}
138
139bool HexagonOptShuffleVector::isValidIntrinsic(IntrinsicInst *I) {
140 switch (I->getIntrinsicID()) {
141 default:
142 return false;
143 case Intrinsic::hexagon_V6_vaddubh_128B:
144 case Intrinsic::hexagon_V6_vadduhw_128B:
145 case Intrinsic::hexagon_V6_vaddhw_128B:
146 case Intrinsic::hexagon_V6_vaddh_dv_128B:
147 case Intrinsic::hexagon_V6_vsububh_128B:
148 case Intrinsic::hexagon_V6_vsubuhw_128B:
149 case Intrinsic::hexagon_V6_vsubhw_128B:
150 case Intrinsic::hexagon_V6_vsubh_dv_128B:
151 case Intrinsic::hexagon_V6_vmpyubv_128B:
152 case Intrinsic::hexagon_V6_vmpybv_128B:
153 case Intrinsic::hexagon_V6_vmpyuhv_128B:
154 case Intrinsic::hexagon_V6_vmpyhv_128B:
155 case Intrinsic::hexagon_V6_vmpybusv_128B:
156 case Intrinsic::hexagon_V6_vmpyhus_128B:
157 case Intrinsic::hexagon_V6_vavgb_128B:
158 case Intrinsic::hexagon_V6_vavgub_128B:
159 case Intrinsic::hexagon_V6_vavgh_128B:
160 case Intrinsic::hexagon_V6_vavguh_128B:
161 case Intrinsic::hexagon_V6_vavgw_128B:
162 case Intrinsic::hexagon_V6_vavguw_128B:
163 case Intrinsic::hexagon_V6_hi_128B:
164 case Intrinsic::hexagon_V6_lo_128B:
165 case Intrinsic::sadd_sat:
166 case Intrinsic::uadd_sat:
167
168 case Intrinsic::hexagon_vadd_su:
169 case Intrinsic::hexagon_vadd_uu:
170 case Intrinsic::hexagon_vadd_ss:
171 case Intrinsic::hexagon_vadd_us:
172 case Intrinsic::hexagon_vsub_su:
173 case Intrinsic::hexagon_vsub_uu:
174 case Intrinsic::hexagon_vsub_ss:
175 case Intrinsic::hexagon_vsub_us:
176 case Intrinsic::hexagon_vmpy_su:
177 case Intrinsic::hexagon_vmpy_uu:
178 case Intrinsic::hexagon_vmpy_ss:
179 case Intrinsic::hexagon_vmpy_us:
180 case Intrinsic::hexagon_vavgu:
181 case Intrinsic::hexagon_vavgs:
182 case Intrinsic::hexagon_vmpy_ub_b:
183 case Intrinsic::hexagon_vmpy_ub_ub:
184 case Intrinsic::hexagon_vmpy_uh_uh:
185 case Intrinsic::hexagon_vmpy_h_h:
186 return true;
187 }
189}
190
191bool HexagonOptShuffleVector::getUseList(Instruction *I, ValueVector &UseList) {
192 for (auto UI = I->user_begin(), UE = I->user_end(); UI != UE;) {
194 if (!J)
195 return false;
197 if (!getUseList(C, UseList))
198 return false;
199 } else
201 ++UI;
202 }
203 return true;
204}
205
206bool HexagonOptShuffleVector::isHILo(Value *V, bool IsHI) {
208 return false;
211 return false;
213 if ()
214 return false;
215 if ((II->getIntrinsicID() == Intrinsic::hexagon_V6_hi_128B && IsHI) ||
216 (II->getIntrinsicID() == Intrinsic::hexagon_V6_lo_128B && !IsHI))
217 return true;
218 return false;
219}
220
221Value *HexagonOptShuffleVector::getOperand(Instruction *I, unsigned i) {
222 Value *V = I->getOperand(i);
224 return C->getOperand(0);
225 return V;
226}
227
229HexagonOptShuffleVector::getArgOperands(User *U) {
231 return CB->args();
232 return U->operands();
233}
234
235
236
237std::pair<Value *, Value *> HexagonOptShuffleVector::stripCasts(Value *V) {
238 Value *LastCast = nullptr;
240 LastCast = V;
242 }
243 return std::make_pair(V, LastCast);
244}
245
246bool HexagonOptShuffleVector::isConstantVectorSplat(Value *V) {
248 return CV->getSplatValue();
250 return CV->isSplat();
251 return false;
252}
253
254
255
256
257bool HexagonOptShuffleVector::analyzeHiLoUse(Instruction *HI, Instruction *LO,
258 ArrayRef &ShuffMask,
260 ShuffUseList &CurShuffUses) {
262 getUseList(HI, HiUseList);
263 getUseList(LO, LoUseList);
264
265
266
267
268 if (HiUseList.size() != 1 || LoUseList.size() != 1)
269 return false;
270
273 if (!HiUse || !LoUse)
274 return false;
275
276 bool IsUseIntrinsic = false;
279 return false;
280
283 if (!HiUseII || !LoUseII ||
285 !isValidIntrinsic(HiUseII))
286 return false;
287 IsUseIntrinsic = true;
288 HiUse = HiUseII;
289 LoUse = LoUseII;
290 }
292 return false;
293
294
295
296 if (HiUse == LoUse) {
297
298 ArrayRef M;
301 NewLoc = HiUse;
302 return true;
303 }
304 }
305 return false;
306 }
307
308
309
310 ArrayRef M1, M2;
313 M1.equals(M2))
314 return analyzeHiLoUse(HiUse, LoUse, ShuffMask, NewLoc, CurShuffUses);
315
316
317
318 if (!HiUse->isBinaryOp() && !IsUseIntrinsic)
319 return false;
320
321 ValueVector HiUseOperands, LoUseOperands;
322 int HiOpNum = -1, LoOpNum = -1;
323 for (unsigned i = 0; i < HiUse->getNumOperands(); i++) {
324 Value *V = getOperand(HiUse, i);
325 if (V == HI)
326 HiOpNum = i;
327 else
329 }
330 for (unsigned i = 0; i < LoUse->getNumOperands(); i++) {
331 Value *V = getOperand(LoUse, i);
332 if (V == LO)
333 LoOpNum = i;
334 else
336 }
337
338
339
340 if (HiOpNum < 0 || HiOpNum != LoOpNum ||
341 LoUseOperands.size() != HiUseOperands.size())
342 return false;
343
344 unsigned NumOperands = HiUseOperands.size();
345 for (unsigned i = 0; i < NumOperands; i++) {
346 if (HiUseOperands[i] == LoUseOperands[i])
347 continue;
348
349
350 if (!isHILo(HiUseOperands[i], true) || !isHILo(LoUseOperands[i], false))
351 return false;
352
355 if (!DefHiUse || DefHiUse != DefLoUse)
356 return false;
357 SmallVector<Instruction *, 2> ImmUseList;
360 else {
363 }
364
365
366 if (!hasDefWithSameShuffMask(DefHiUse, ImmUseList, ShuffMask, CurShuffUses))
367 return false;
368 }
369
370
371 return analyzeHiLoUse(HiUse, LoUse, ShuffMask, NewLoc, CurShuffUses);
372}
373
374bool HexagonOptShuffleVector::hasDefWithSameShuffMask(
375 Value *V, SmallVector<Instruction *, 2> &ImmUses, ArrayRef &ShuffMask,
376 ShuffUseList &CurShuffUses) {
377
378
380 return false;
381
382 ++DefSearchCount;
383 V = stripCasts(V).first;
385 if ()
386 return false;
387 bool Found = true;
388 ArrayRef M;
390 M.equals(ShuffMask)) {
391 CurShuffUses[I] = ImmUses;
392 return true;
393 }
396 return true;
397
399 if (->isBinaryOp() && (
|| !isValidIntrinsic(II)))
400 return false;
401
402 for (Value *OpV : getArgOperands(I)) {
403 std::pair<Value *, Value *> P = stripCasts(OpV);
404 OpV = P.first;
405
406 SmallVector<Instruction *, 2> ImmUseList;
407 if (P.second)
409 else
411
413 continue;
414 if (isConstantVectorSplat(OpV))
415 continue;
417 return false;
420 continue;
421 Found &= hasDefWithSameShuffMask(OpV, ImmUseList, ShuffMask, CurShuffUses);
422 }
423 return Found;
424}
425
426void HexagonOptShuffleVector::FindHiLoUse(ValueVector &UseList,
427 Instruction *&HI, Instruction *&LO) {
428
429 for (unsigned i = 0; i < UseList.size(); i++) {
432 if (CI) {
434 if (II) {
436 if (IntID == Intrinsic::hexagon_V6_hi_128B)
437 HI = J;
438 if (IntID == Intrinsic::hexagon_V6_lo_128B)
439 LO = J;
440 }
441 }
442 }
443}
444
445bool HexagonOptShuffleVector::isValidUseInstr(ValueVector &UseList,
446 Instruction *&UI) {
447
448 if (UseList.size() != 1)
449 return false;
451 if (!UI)
452 return false;
453
456 if ( || !isValidIntrinsic(II))
457 return false;
458 UI = II;
460 return false;
461 return true;
462}
463
464
465
466
467
468
469bool HexagonOptShuffleVector::areAllOperandsValid(Instruction *I,
470 Instruction *Use,
471 ArrayRef &ShuffMask,
472 ShuffUseList &CurShuffUses) {
473 bool AllOperandsOK = true;
474 for (Value *OpV : getArgOperands(Use)) {
475 bool HasOneUse = OpV->hasOneUse();
476 std::pair<Value *, Value *> P = stripCasts(OpV);
477 OpV = P.first;
478
479 SmallVector<Instruction *, 2> ImmUseList;
480 if (P.second)
482 else
484
486 continue;
487 if (isConstantVectorSplat(OpV))
488 continue;
490 return false;
491
494 continue;
495 AllOperandsOK &=
496 hasDefWithSameShuffMask(OpV, ImmUseList, ShuffMask, CurShuffUses);
497 }
498 return AllOperandsOK;
499}
500
501
502bool HexagonOptShuffleVector::findNewShuffLoc(Instruction *I,
503 ArrayRef &ShuffMask,
504 Value *&NewLoc) {
505 DefSearchCount = 0;
507 if (!getUseList(I, UseList))
508 return false;
509
510 using ShuffUseList =
511 SmallDenseMap<Instruction *, SmallVector<Instruction *, 2>>;
512 ShuffUseList CurShuffUses;
513
515 FindHiLoUse(UseList, HI, LO);
516 if (UseList.size() == 2 && HI && LO) {
517
518
519
521 dbgs() << "\tFollowing the Hi/LO pair :\n";
522 dbgs() << "\t\tHI - ";
523 HI->dump();
524 dbgs() << "\t\tLO - ";
525 LO->dump();
526 });
527 if (!analyzeHiLoUse(HI, LO, ShuffMask, NewLoc, CurShuffUses))
528 return false;
529 for (auto &it : CurShuffUses)
530 ShuffUses[it.first] = it.second;
531 return true;
532 } else {
534 if (!isValidUseInstr(UseList, UI))
535 return false;
536 assert(UI && "Expected a valid use, but found none!!");
537
538 if (HI || LO) {
539
540 return false;
541 }
542
543 LLVM_DEBUG(dbgs() << "\tChecking operands in 'use' : \n\t\t"; UI->dump());
544 if (!areAllOperandsValid(I, UI, ShuffMask, CurShuffUses)) {
546 return false;
547 }
548 for (auto &it : CurShuffUses)
549 ShuffUses[it.first] = it.second;
550 NewLoc = UI;
551
552 findNewShuffLoc(UI, ShuffMask, NewLoc);
553 }
554 return true;
555}
556
557
558bool HexagonOptShuffleVector::relocateShuffVec(
559 Instruction *I, ArrayRef &M, Value *NewLoc,
560 std::list<Instruction *> &WorkList) {
561
562
563
564 std::map<Instruction *, Value *> InstrMap;
565 bool CanReplace = true;
566 unsigned ShuffInstCount = ShuffUses.size();
567 for (auto &it : ShuffUses) {
569 Visited.insert(J);
570 Value *ShuffleOP = nullptr;
574 if (JTy->getElementCount() != ShuffTy->getElementCount())
575 CanReplace = false;
576
577
578
579
581 if (ShuffInstCount == 1 &&
582 NewShuffTy->getElementType() > ShuffTy->getElementType())
583 CanReplace = false;
584 InstrMap[J] = ShuffleOP;
585 }
586 if (!CanReplace) {
588 return false;
589 }
590 for (auto IM : InstrMap) {
592 assert(ShuffUses.count(J));
593 SmallVector<Instruction *, 2> Uses = ShuffUses[J];
594 if (Uses.size() > 0) {
595 for (auto *U : Uses)
596 U->replaceUsesOfWith(IM.first, IM.second);
597 } else
598
599
600
601 IM.first->replaceAllUsesWith(IM.second);
602 }
603
608 Value *NewShuffV =
611 if (!NewInst) {
613 return false;
614 }
615 for (auto UI = NewLoc->user_begin(), UE = NewLoc->user_end(); UI != UE;) {
616 Use &TheUse = UI.getUse();
617 ++UI;
619 if (J && TheUse.getUser() != NewShuffV)
621 }
622 WorkList.push_back(NewInst);
623 LLVM_DEBUG(dbgs() << "\tRelocation Successfull!! \n");
625 return true;
626}
627
628bool HexagonOptShuffleVector::visitBlock(BasicBlock *B) {
630 ArrayRef M;
631 std::list<Instruction *> WorkList;
632 LLVM_DEBUG(dbgs() << "Preparing worklist for BB:\n");
636 continue;
638 WorkList.push_back(&I);
640 }
641 }
642
644 while (!WorkList.empty()) {
645#ifndef NDEBUG
647 if (Limit >= 0) {
650 dbgs() << "Reached maximum limit!! \n";
651 dbgs() << "Can't process any more shuffles.... \n";
652 });
654 }
655 }
656#endif
658 WorkList.pop_front();
659 LLVM_DEBUG(dbgs() << "\tProcessing instr - "; I->dump());
660 Value *NewLoc = nullptr;
661
662
663
664
665
666
667
668
669
670
671
672
673 ShuffUses.clear();
674 ShuffUses[I] = SmallVector<Instruction *, 2>();
675
676 if (!Visited.insert(I).second) {
677 LLVM_DEBUG(dbgs() << "\t\tSKIPPING - Already visited ...\n");
678 continue;
679 }
681 LLVM_DEBUG(dbgs() << "\t\tSKIPPING - Not a vector shuffle ...\n");
682 continue;
683 }
684 if (!findNewShuffLoc(I, M, NewLoc) || !NewLoc) {
685 LLVM_DEBUG(dbgs() << "\t\tSKIPPING - NewLoc not found ...\n");
686 continue;
687 }
689 Changed |= relocateShuffVec(I, M, NewLoc, WorkList);
690#ifndef NDEBUG
691 NumRelocated++;
692#endif
693 }
695}
696
697bool HexagonOptShuffleVector::runOnFunction(Function &F) {
699
701 return false;
702
706
708}
709
710FunctionPass *
712 return new HexagonOptShuffleVector(&TM);
713}
static bool isConcatMask(ArrayRef< int > Mask, EVT VT, bool SplitLHS)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
static cl::opt< int > MaxDefSearchCount("shuffvec-max-search-count", cl::desc("Maximum number of instructions traversed along def chain."), cl::Hidden, cl::init(15))
A command line argument to limit the search space along def chain.
static cl::opt< int > ShuffVecLimit("shuff-vec-max", cl::desc("Maximum number of shuffles to be relocated."), cl::Hidden, cl::init(-1))
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Remove Loads Into Fake Uses
SmallVector< Value *, 8 > ValueVector
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Legacy analysis pass which computes a DominatorTree.
FunctionPass class - This class is used to implement most global optimizations.
bool useHVX128BOps() const
const HexagonSubtarget * getSubtargetImpl(const Function &F) const override
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
A wrapper class for inspecting calls to intrinsic functions.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
void push_back(const T &Elt)
The instances of the Type class are immutable: once they are created, they are never changed.
User * getUser() const
Returns the User that contains this Use.
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
unsigned getNumOperands() const
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
LLVM_ABI void dump() const
Support for debugging, callable in GDB: V->dump()
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
class_match< PoisonValue > m_Poison()
Match an arbitrary poison constant.
bool match(Val *V, const Pattern &P)
TwoOps_match< V1_t, V2_t, Instruction::ShuffleVector > m_Shuffle(const V1_t &v1, const V2_t &v2)
Matches ShuffleVectorInst independently of mask value.
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
ThreeOps_match< Val_t, Elt_t, Idx_t, Instruction::InsertElement > m_InsertElt(const Val_t &Val, const Elt_t &Elt, const Idx_t &Idx)
Matches InsertElementInst.
initializer< Ty > init(const Ty &Val)
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
FunctionPass * createHexagonOptShuffleVector(const HexagonTargetMachine &)
Definition HexagonOptShuffleVector.cpp:711
unsigned M1(unsigned Val)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isa(const From &Val)
isa - Return true if the parameter to the template is an instance of one of the template type argu...
iterator_range(Container &&) -> iterator_range< llvm::detail::IterOfRange< Container > >
void initializeHexagonOptShuffleVectorPass(PassRegistry &)
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.