LLVM: lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
15#include "llvm/IR/IntrinsicsHexagon.h"
18
19#include
20#include
21#include
22#include
23#include
24#include
25#include
26#include <unordered_map>
27#include
28#include
29
30#define DEBUG_TYPE "hexagon-isel"
31using namespace llvm;
32
33namespace {
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100enum class ColorKind { None, Red, Black };
101
102
103
104struct Coloring {
105 using Node = int;
106 using MapType = std::map<Node, ColorKind>;
108
110 build();
111 if (!color())
112 Colors.clear();
113 }
114
115 const MapType &colors() const {
116 return Colors;
117 }
118
119 ColorKind other(ColorKind Color) {
120 if (Color == ColorKind::None)
121 return ColorKind::Red;
122 return Color == ColorKind::Red ? ColorKind::Black : ColorKind::Red;
123 }
124
126
127private:
129 MapType Colors;
130 std::set Needed;
131
132 using NodeSet = std::set;
133 std::map<Node,NodeSet> Edges;
134
137 return (Pos < Num/2) ? Pos + Num/2 : Pos - Num/2;
138 }
139
140 ColorKind getColor(Node N) {
142 return F != Colors.end() ? F->second : ColorKind::None;
143 }
144
145 std::pair<bool, ColorKind> getUniqueColor(const NodeSet &Nodes);
146
147 void build();
148 bool color();
149};
150}
151
152std::pair<bool, ColorKind> Coloring::getUniqueColor(const NodeSet &Nodes) {
153 auto Color = ColorKind::None;
154 for (Node N : Nodes) {
155 ColorKind ColorN = getColor(N);
156 if (ColorN == ColorKind::None)
157 continue;
158 if (Color == ColorKind::None)
159 Color = ColorN;
160 else if (Color != ColorKind::None && Color != ColorN)
161 return { false, ColorKind::None };
162 }
163 return { true, Color };
164}
165
166void Coloring::build() {
167
168 for (unsigned P = 0; P != Order.size(); ++P) {
171 Needed.insert(I);
172 Node PC = Order[conj(P)];
173 if (PC != Ignore && PC != I)
174 Edges[I].insert(PC);
175 }
176 }
177
178 for (unsigned I = 0; I != Order.size(); ++I) {
179 if (!Needed.count(I))
180 continue;
182
183
184
185 NodeSet &Is = Edges[I];
186 if (Needed.count(C))
188 }
189}
190
191bool Coloring::color() {
192 SetVector FirstQ;
193 auto Enqueue = [this,&FirstQ] (Node N) {
194 SetVector Q;
196 for (unsigned I = 0; I != Q.size(); ++I) {
197 NodeSet &Ns = Edges[Q[I]];
198 Q.insert_range(Ns);
199 }
201 };
202 for (Node N : Needed)
203 Enqueue(N);
204
205 for (Node N : FirstQ) {
206 if (Colors.count(N))
207 continue;
208 NodeSet &Ns = Edges[N];
209 auto P = getUniqueColor(Ns);
210 if (.first)
211 return false;
212 Colors[N] = other(P.second);
213 }
214
215
216 for (auto E : Edges) {
218 if (!Needed.count(conj(N)) || Colors.count(N))
219 continue;
220 auto P = getUniqueColor(E.second);
221 if (.first)
222 return false;
223 Colors[N] = other(P.second);
224 }
225
226
227
228 std::vector WorkQ;
229 for (auto E : Edges) {
231 if (!Colors.count(N))
232 WorkQ.push_back(N);
233 }
234
235 for (Node N : WorkQ) {
236 NodeSet &Ns = Edges[N];
237 auto P = getUniqueColor(Ns);
238 if (P.first) {
239 Colors[N] = other(P.second);
240 continue;
241 }
242
243
245 ColorKind ColorN = other(ColorKind::None);
246 ColorKind ColorC = other(ColorN);
247 NodeSet &Cs = Edges[C];
248 NodeSet CopyNs = Ns;
249 for (Node M : CopyNs) {
250 ColorKind ColorM = getColor(M);
251 if (ColorM == ColorC) {
252
255 Ns.erase(M);
257 }
258 }
259 Colors[N] = ColorN;
260 Colors[C] = ColorC;
261 }
262
263
264 for (unsigned I = 0; I != Order.size(); ++I)
265 Colors.try_emplace(I, ColorKind::None);
266
267 return true;
268}
269
270#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
271void Coloring::dump() const {
272 dbgs() << "{ Order: {";
273 for (Node P : Order) {
276 else
277 dbgs() << " -";
278 }
279 dbgs() << " }\n";
280 dbgs() << " Needed: {";
281 for (Node N : Needed)
283 dbgs() << " }\n";
284
285 dbgs() << " Edges: {\n";
286 for (auto E : Edges) {
287 dbgs() << " " << E.first << " -> {";
290 dbgs() << " }\n";
291 }
292 dbgs() << " }\n";
293
294 auto ColorKindToName = [](ColorKind C) {
295 switch (C) {
296 case ColorKind::None:
297 return "None";
298 case ColorKind::Red:
299 return "Red";
300 case ColorKind::Black:
301 return "Black";
302 }
303 llvm_unreachable("all ColorKinds should be handled by the switch above");
304 };
305
306 dbgs() << " Colors: {\n";
307 for (auto C : Colors)
308 dbgs() << " " << C.first << " -> " << ColorKindToName(C.second) << "\n";
309 dbgs() << " }\n}\n";
310}
311#endif
312
313namespace {
314
315
316
317struct PermNetwork {
318 using Controls = std::vector<uint8_t>;
319 using ElemType = int;
320 static constexpr ElemType Ignore = ElemType(-1);
321
322 enum : uint8_t {
325 Switch
326 };
327 enum : uint8_t {
328 Forward,
330 };
331
333 Order.assign(Ord.data(), Ord.data()+Ord.size());
334 Log = 0;
335
336 unsigned S = Order.size();
337 while (S >>= 1)
338 ++Log;
339
340 Table.resize(Order.size());
341 for (RowType &Row : Table)
342 Row.resize(Mult*Log, None);
343 }
344
345 void getControls(Controls &V, unsigned StartAt, uint8_t Dir) const {
346 unsigned Size = Order.size();
348 for (unsigned I = 0; I != Size; ++I) {
349 unsigned W = 0;
350 for (unsigned L = 0; L != Log; ++L) {
351 unsigned C = ctl(I, StartAt+L) == Switch;
352 if (Dir == Forward)
354 else
356 }
359 }
360 }
361
362 uint8_t ctl(ElemType Pos, unsigned Step) const {
363 return Table[Pos][Step];
364 }
365 unsigned size() const {
366 return Order.size();
367 }
368 unsigned steps() const {
369 return Log;
370 }
371
372protected:
373 unsigned Log;
374 std::vector Order;
375 using RowType = std::vector<uint8_t>;
376 std::vector Table;
377};
378
379struct ForwardDeltaNetwork : public PermNetwork {
381
382 bool run(Controls &V) {
383 if (!route(Order.data(), Table.data(), size(), 0))
384 return false;
385 getControls(V, 0, Forward);
386 return true;
387 }
388
389private:
390 bool route(ElemType *P, RowType *T, unsigned Size, unsigned Step);
391};
392
393struct ReverseDeltaNetwork : public PermNetwork {
395
396 bool run(Controls &V) {
397 if (!route(Order.data(), Table.data(), size(), 0))
398 return false;
399 getControls(V, 0, Reverse);
400 return true;
401 }
402
403private:
404 bool route(ElemType *P, RowType *T, unsigned Size, unsigned Step);
405};
406
407struct BenesNetwork : public PermNetwork {
409
410 bool run(Controls &F, Controls &R) {
411 if (!route(Order.data(), Table.data(), size(), 0))
412 return false;
413
414 getControls(F, 0, Forward);
415 getControls(R, Log, Reverse);
416 return true;
417 }
418
419private:
420 bool route(ElemType *P, RowType *T, unsigned Size, unsigned Step);
421};
422}
423
424bool ForwardDeltaNetwork::route(ElemType *P, RowType *T, unsigned Size,
425 unsigned Step) {
426 bool UseUp = false, UseDown = false;
427 ElemType Num = Size;
428
429
430
431
432
433 for (ElemType J = 0; J != Num; ++J) {
435
436
438 continue;
439 uint8_t S;
440 if (I < Num/2)
442 else
443 S = (J < Num/2) ? Switch : Pass;
444
445
446 ElemType U = (S == Pass) ? I : (I < Num/2 ? I+Num/2 : I-Num/2);
447 if (U < Num/2)
448 UseUp = true;
449 else
450 UseDown = true;
451 if (T[U][Step] != S && T[U][Step] != None)
452 return false;
454 }
455
456 for (ElemType J = 0; J != Num; ++J)
457 if (P[J] != Ignore && P[J] >= Num/2)
458 P[J] -= Num/2;
459
460 if (Step+1 < Log) {
461 if (UseUp && !route(P, T, Size/2, Step+1))
462 return false;
463 if (UseDown && !route(P+Size/2, T+Size/2, Size/2, Step+1))
464 return false;
465 }
466 return true;
467}
468
469bool ReverseDeltaNetwork::route(ElemType *P, RowType *T, unsigned Size,
470 unsigned Step) {
471 unsigned Pets = Log-1 - Step;
472 bool UseUp = false, UseDown = false;
473 ElemType Num = Size;
474
475
477 const Coloring::MapType &M = G.colors();
478 if (M.empty())
479 return false;
480
481 ColorKind ColorUp = ColorKind::None;
482 for (ElemType J = 0; J != Num; ++J) {
484
485
487 continue;
489 if (C == ColorKind::None)
490 continue;
491
492
493
494 bool InpUp = I < Num/2;
495 if (ColorUp == ColorKind::None)
496 ColorUp = InpUp ? C : G.other(C);
497 if ((C == ColorUp) != InpUp) {
498
499 return false;
500 }
501
502 uint8_t S;
503 if (InpUp) {
505 UseUp = true;
506 } else {
507 S = (J < Num/2) ? Switch : Pass;
508 UseDown = true;
509 }
510 T[J][Pets] = S;
511 }
512
513
514
515 for (ElemType J = 0, E = Size / 2; J != E; ++J) {
516 ElemType PJ = P[J];
517 ElemType PC = P[J+Size/2];
518 ElemType QJ = PJ;
519 ElemType QC = PC;
520 if (T[J][Pets] == Switch)
521 QC = PJ;
522 if (T[J+Size/2][Pets] == Switch)
523 QJ = PC;
524 P[J] = QJ;
526 }
527
528 for (ElemType J = 0; J != Num; ++J)
529 if (P[J] != Ignore && P[J] >= Num/2)
530 P[J] -= Num/2;
531
532 if (Step+1 < Log) {
533 if (UseUp && !route(P, T, Size/2, Step+1))
534 return false;
535 if (UseDown && !route(P+Size/2, T+Size/2, Size/2, Step+1))
536 return false;
537 }
538 return true;
539}
540
541bool BenesNetwork::route(ElemType *P, RowType *T, unsigned Size,
542 unsigned Step) {
544 const Coloring::MapType &M = G.colors();
545 if (M.empty())
546 return false;
547 ElemType Num = Size;
548
549 unsigned Pets = 2*Log-1 - Step;
550 bool UseUp = false, UseDown = false;
551
552
553
554
555 ColorKind ColorUp = ColorKind::None;
556 for (ElemType J = 0; J != Num; ++J) {
559 continue;
561 if (C == ColorKind::None)
562 continue;
563 if (ColorUp == ColorKind::None) {
564 ColorUp = (I < Num / 2) ? ColorKind::Red : ColorKind::Black;
565 }
566 unsigned CI = (I < Num/2) ? I+Num/2 : I-Num/2;
567 if (C == ColorUp) {
568 if (I < Num/2)
570 else
572 T[J][Pets] = (J < Num/2) ? Pass : Switch;
573 UseUp = true;
574 } else {
575 if (I < Num/2)
577 else
579 T[J][Pets] = (J < Num/2) ? Switch : Pass;
580 UseDown = true;
581 }
582 }
583
584
585
586 for (ElemType J = 0; J != Num/2; ++J) {
587 ElemType PJ = P[J];
588 ElemType PC = P[J+Num/2];
589 ElemType QJ = PJ;
590 ElemType QC = PC;
591 if (T[J][Pets] == Switch)
592 QC = PJ;
593 if (T[J+Num/2][Pets] == Switch)
594 QJ = PC;
595 P[J] = QJ;
596 P[J+Num/2] = QC;
597 }
598
599 for (ElemType J = 0; J != Num; ++J)
600 if (P[J] != Ignore && P[J] >= Num/2)
601 P[J] -= Num/2;
602
603 if (Step+1 < Log) {
604 if (UseUp && !route(P, T, Size/2, Step+1))
605 return false;
606 if (UseDown && !route(P+Size/2, T+Size/2, Size/2, Step+1))
607 return false;
608 }
609 return true;
610}
611
612
613
614
615
616namespace {
617struct OpRef {
619 bool isValue() const { return OpV.getNode() != nullptr; }
620 bool isValid() const { return isValue() || !(OpN & Invalid); }
621 bool isUndef() const { return OpN & Undef; }
622 static OpRef res(int N) { return OpRef(Whole | (N & Index)); }
623 static OpRef fail() { return OpRef(Invalid); }
624
625 static OpRef lo(const OpRef &R) {
627 return OpRef(R.OpN & (Undef | Index | LoHalf));
628 }
629 static OpRef hi(const OpRef &R) {
631 return OpRef(R.OpN & (Undef | Index | HiHalf));
632 }
633 static OpRef undef(MVT Ty) { return OpRef(Undef | Ty.SimpleTy); }
634
635
637
638
639
640
641
642
643 unsigned OpN = 0;
644
645 enum : unsigned {
647 LoHalf = 0x20000000,
648 HiHalf = 0x40000000,
649 Whole = LoHalf | HiHalf,
650 Undef = 0x80000000,
651 Index = 0x0FFFFFFF,
652 IndexBits = 28,
653 };
654
656 void print(raw_ostream &OS, const SelectionDAG &G) const;
657
658private:
659 OpRef(unsigned N) : OpN(N) {}
660};
661
662struct NodeTemplate {
663 NodeTemplate() = default;
664 unsigned Opc = 0;
665 MVT Ty = MVT::Other;
666 std::vector Ops;
667
669};
670
671struct ResultStack {
672 ResultStack(SDNode *Inp)
674 SDNode *InpNode;
675 MVT InpTy;
676 unsigned push(const NodeTemplate &Res) {
677 List.push_back(Res);
678 return List.size()-1;
679 }
680 unsigned push(unsigned Opc, MVT Ty, std::vector &&Ops) {
681 NodeTemplate Res;
682 Res.Opc = Opc;
683 Res.Ty = Ty;
684 Res.Ops = Ops;
685 return push(Res);
686 }
687 bool empty() const { return List.empty(); }
688 unsigned size() const { return List.size(); }
689 unsigned top() const { return size()-1; }
690 const NodeTemplate &operator[](unsigned I) const { return List[I]; }
691 unsigned reset(unsigned NewTop) {
692 List.resize(NewTop+1);
693 return NewTop;
694 }
695
696 using BaseType = std::vector;
697 BaseType::iterator begin() { return List.begin(); }
698 BaseType::iterator end() { return List.end(); }
699 BaseType::const_iterator begin() const { return List.begin(); }
700 BaseType::const_iterator end() const { return List.end(); }
701
703
705 void print(raw_ostream &OS, const SelectionDAG &G) const;
706};
707}
708
709#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
710void OpRef::print(raw_ostream &OS, const SelectionDAG &G) const {
711 if (isValue()) {
713 return;
714 }
716 OS << "invalid";
717 return;
718 }
719 if (OpN & Undef) {
720 OS << "undef";
721 return;
722 }
723 if ((OpN & Whole) != Whole) {
724 assert((OpN & Whole) == LoHalf || (OpN & Whole) == HiHalf);
725 if (OpN & LoHalf)
726 OS << "lo ";
727 else
728 OS << "hi ";
729 }
730 OS << '#' << SignExtend32(OpN & Index, IndexBits);
731}
732
733void NodeTemplate::print(raw_ostream &OS, const SelectionDAG &G) const {
734 const TargetInstrInfo &TII = *G.getSubtarget().getInstrInfo();
735 OS << format("%8s", EVT(Ty).getEVTString().c_str()) << " "
737 bool Comma = false;
738 for (const auto &R : Ops) {
739 if (Comma)
740 OS << ',';
742 OS << ' ';
744 }
745}
746
747void ResultStack::print(raw_ostream &OS, const SelectionDAG &G) const {
748 OS << "Input node:\n";
749#ifndef NDEBUG
751#endif
752 OS << "Result templates:\n";
753 for (unsigned I = 0, E = List.size(); I != E; ++I) {
754 OS << '[' << I << "] ";
756 OS << '\n';
757 }
758}
759#endif
760
761namespace {
762struct ShuffleMask {
763 ShuffleMask(ArrayRef M) : Mask(M) {
764 for (int M : Mask) {
765 if (M == -1)
766 continue;
767 MinSrc = (MinSrc == -1) ? M : std::min(MinSrc, M);
768 MaxSrc = (MaxSrc == -1) ? M : std::max(MaxSrc, M);
769 }
770 }
771
772 ArrayRef Mask;
773 int MinSrc = -1, MaxSrc = -1;
774
775 ShuffleMask lo() const {
777 return ShuffleMask(Mask.take_front(H));
778 }
779 ShuffleMask hi() const {
781 return ShuffleMask(Mask.take_back(H));
782 }
783
784 void print(raw_ostream &OS) const {
785 OS << "MinSrc:" << MinSrc << ", MaxSrc:" << MaxSrc << " {";
786 for (int M : Mask)
787 OS << ' ' << M;
788 OS << " }";
789 }
790};
791
792[[maybe_unused]]
793raw_ostream &operator<<(raw_ostream &OS, const ShuffleMask &SM) {
794 SM.print(OS);
795 return OS;
796}
797}
798
801
802
803
804
805
806
807
810
812 int Len = Vu.size();
813 MaskT Vdd(2 * Len);
816
819
821 if ((Rt & Offset) == 0)
822 continue;
823 for (int i = 0; i != Len; ++i) {
824 if ((i & Offset) == 0)
826 }
827 }
828 return Vdd;
829}
830
832 int Len = Vu.size();
833 MaskT Vdd(2 * Len);
836
839
841 if ((Rt & Offset) == 0)
842 continue;
843 for (int i = 0; i != Len; ++i) {
844 if ((i & Offset) == 0)
846 }
847 }
848 return Vdd;
849}
850
852 int Len = Vu.size();
854 auto Odd = static_cast<int>(TakeOdd);
855 for (int i = 0, e = Len / (2 * Size); i != e; ++i) {
856 for (int b = 0; b != static_cast<int>(Size); ++b) {
857
858 Vd[i * Size + b] = Vv[(2 * i + Odd) * Size + b];
859 Vd[i * Size + b + Len / 2] = Vu[(2 * i + Odd) * Size + b];
860
861 }
862 }
863 return Vd;
864}
865
867 int Len = Vu.size();
869 auto Odd = static_cast<int>(TakeOdd);
870 for (int i = 0, e = Len / (2 * Size); i != e; ++i) {
871 for (int b = 0; b != static_cast<int>(Size); ++b) {
872 Vd[(2 * i + 0) * Size + b] = Vv[(2 * i + Odd) * Size + b];
873 Vd[(2 * i + 1) * Size + b] = Vu[(2 * i + Odd) * Size + b];
874 }
875 }
876 return Vd;
877}
878
880 int Len = Vu.size();
883}
884
886 int Len = Vu.size();
888 for (int i = 0, e = Len / 4; i != e; ++i) {
889 Vd[0 * (Len / 4) + i] = Vv[4 * i + 0];
890 Vd[1 * (Len / 4) + i] = Vv[4 * i + 2];
891 Vd[2 * (Len / 4) + i] = Vu[4 * i + 0];
892 Vd[3 * (Len / 4) + i] = Vu[4 * i + 2];
893 }
894 return Vd;
895}
896
897template <typename ShuffFunc, typename... OptArgs>
900 std::iota(Vu.begin(), Vu.end(), Length);
901 std::iota(Vv.begin(), Vv.end(), 0);
902 return S(Vu, Vv, args...);
903}
904
905}
906
907
908
909
916
917namespace llvm {
924
928
930 assert(ElemTy != MVT::i1 && "Use getBoolVT for predicates");
931 unsigned NumElems = HwLen / (ElemTy.getSizeInBits() / 8);
933 }
934
936 assert(ElemTy != MVT::i1);
937 unsigned NumElems = (2 * HwLen) / (ElemTy.getSizeInBits() / 8);
939 }
940
945
946 void selectExtractSubvector(SDNode *N);
947 void selectShuffle(SDNode *N);
948 void selectRor(SDNode *N);
949 void selectVAlign(SDNode *N);
950
952 unsigned Width);
955 static std::optional rotationDistance(ShuffleMask SM, unsigned WrapAt);
956
957 private:
958 void select(SDNode *ISelN);
959 void materialize(const ResultStack &Results);
960
961 SDValue getConst32(unsigned Val, const SDLoc &dl);
962 SDValue getSignedConst32(int Val, const SDLoc &dl);
964
965 enum : unsigned {
967 PackMux,
968 };
969 OpRef concats(OpRef Va, OpRef Vb, ResultStack &Results);
970 OpRef funnels(OpRef Va, OpRef Vb, int Amount, ResultStack &Results);
971
972 OpRef packs(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &Results,
974 OpRef packp(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &Results,
980
981 OpRef shuffs1(ShuffleMask SM, OpRef Va, ResultStack &Results);
982 OpRef shuffs2(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &Results);
983 OpRef shuffp1(ShuffleMask SM, OpRef Va, ResultStack &Results);
984 OpRef shuffp2(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &Results);
985
986 OpRef butterfly(ShuffleMask SM, OpRef Va, ResultStack &Results);
987 OpRef contracting(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &Results);
988 OpRef expanding(ShuffleMask SM, OpRef Va, ResultStack &Results);
989 OpRef perfect(ShuffleMask SM, OpRef Va, ResultStack &Results);
990
991 bool selectVectorConstants(SDNode *N);
994 };
995}
996
999 unsigned VecLen = Mask.size();
1000 assert(MaskL.size() == VecLen && MaskR.size() == VecLen);
1001 for (unsigned I = 0; I != VecLen; ++I) {
1002 int M = Mask[I];
1003 if (M < 0) {
1004 MaskL[I] = MaskR[I] = -1;
1005 } else if (unsigned(M) < VecLen) {
1006 MaskL[I] = M;
1007 MaskR[I] = -1;
1008 } else {
1009 MaskL[I] = -1;
1010 MaskR[I] = M-VecLen;
1011 }
1012 }
1013}
1014
1016 unsigned MaxLen) {
1017 assert(A.size() > 0 && A.size() >= MaxLen);
1020 for (unsigned I = 1; I != MaxLen; ++I) {
1024 }
1025 return { F, MaxLen };
1026}
1027
1029 for (int Idx : Mask)
1030 if (Idx != -1)
1031 return false;
1032 return true;
1033}
1034
1036 for (int I = 0, E = Mask.size(); I != E; ++I) {
1037 int M = Mask[I];
1038 if (M >= 0 && M != I)
1039 return false;
1040 }
1041 return true;
1042}
1043
1045 int L = Mask.size();
1047
1048 return llvm::all_of(Mask.drop_front(L / 2), [](int M) { return M < 0; });
1049}
1050
1052 unsigned SegLen) {
1055 if (SM.MaxSrc == -1)
1056 return SegList;
1057
1058 unsigned Shift = Log2_32(SegLen);
1060
1061 for (int M : SM.Mask) {
1062 if (M >= 0)
1063 Segs.set(M >> Shift);
1064 }
1065
1067 return SegList;
1068}
1069
1071 unsigned SegLen) {
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081 unsigned MaskLen = SM.Mask.size();
1082 assert(MaskLen % SegLen == 0);
1084
1085 for (int S = 0, E = Map.size(); S != E; ++S) {
1086 unsigned Idx = ~0u;
1087 for (int I = 0; I != static_cast<int>(SegLen); ++I) {
1088 int M = SM.Mask[S*SegLen + I];
1089 if (M < 0)
1090 continue;
1091 unsigned G = M / SegLen;
1092 if (Idx == ~0u) {
1093 Idx = G;
1094 } else if (Idx != G) {
1095 Idx = ~1u;
1096 break;
1097 }
1098 }
1099 Map[S] = Idx;
1100 }
1101
1102 return Map;
1103}
1104
1108 for (int I = OutSegMap.size() - 1; I >= 0; --I) {
1109 unsigned S = OutSegMap[I];
1110 assert(S != ~0u && "Unexpected undef");
1111 assert(S != ~1u && "Unexpected multi");
1112 if (InvMap.size() <= S)
1114 InvMap[S] = I;
1115 }
1116
1117 unsigned Shift = Log2_32(SegLen);
1118 for (int I = 0, E = Mask.size(); I != E; ++I) {
1119 int M = Mask[I];
1120 if (M >= 0) {
1121 int OutIdx = InvMap[M >> Shift];
1122 M = (M & (SegLen-1)) + SegLen*OutIdx;
1123 }
1124 PackedMask[I] = M;
1125 }
1126}
1127
1128bool HvxSelector::selectVectorConstants(SDNode *N) {
1129
1130
1131
1132
1134 SetVector<SDNode*> WorkQ;
1135
1136
1137
1139 for (unsigned i = 0; i != WorkQ.size(); ++i) {
1140 SDNode *W = WorkQ[i];
1143 for (unsigned j = 0, f = W->getNumOperands(); j != f; ++j)
1144 WorkQ.insert(W->getOperand(j).getNode());
1145 }
1146
1147 for (SDNode *L : Nodes)
1148 select(L);
1149
1150 return !Nodes.empty();
1151}
1152
1153void HvxSelector::materialize(const ResultStack &Results) {
1155 dbgs() << "Materializing\n";
1157 });
1159 return;
1160 const SDLoc &dl(Results.InpNode);
1161 std::vector Output;
1162
1165 std::vector Ops;
1166 for (const OpRef &R : Node.Ops) {
1168 if (R.isValue()) {
1170 continue;
1171 }
1172 if (R.OpN & OpRef::Undef) {
1174 Ops.push_back(ISel.selectUndef(dl, MVT(SVT)));
1175 continue;
1176 }
1177
1178 unsigned Part = R.OpN & OpRef::Whole;
1179 int Idx = SignExtend32(R.OpN & OpRef::Index, OpRef::IndexBits);
1180 if (Idx < 0)
1181 Idx += I;
1182 assert(Idx >= 0 && unsigned(Idx) < Output.size());
1184 MVT OpTy = Op.getValueType().getSimpleVT();
1185 if (Part != OpRef::Whole) {
1186 assert(Part == OpRef::LoHalf || Part == OpRef::HiHalf);
1189 unsigned Sub = (Part == OpRef::LoHalf) ? Hexagon::vsub_lo
1190 : Hexagon::vsub_hi;
1191 Op = DAG.getTargetExtractSubreg(Sub, dl, HalfTy, Op);
1192 }
1194 }
1195
1197 SDNode *ResN = (Node.Opc == TargetOpcode::COPY)
1198 ? Ops.front().getNode()
1199 : DAG.getMachineNode(Node.Opc, dl, Node.Ty, Ops);
1200 Output.push_back(SDValue(ResN, 0));
1201 }
1202
1203 SDNode *OutN = Output.back().getNode();
1204 SDNode *InpN = Results.InpNode;
1206 dbgs() << "Generated node:\n";
1207 OutN->dumpr(&DAG);
1208 });
1209
1210 ISel.ReplaceNode(InpN, OutN);
1211 selectVectorConstants(OutN);
1212 DAG.RemoveDeadNodes();
1213}
1214
1215OpRef HvxSelector::concats(OpRef Lo, OpRef Hi, ResultStack &Results) {
1217 const SDLoc &dl(Results.InpNode);
1218 Results.push(TargetOpcode::REG_SEQUENCE, getPairVT(MVT::i8), {
1219 getConst32(Hexagon::HvxWRRegClassID, dl),
1220 Lo, getConst32(Hexagon::vsub_lo, dl),
1221 Hi, getConst32(Hexagon::vsub_hi, dl),
1222 });
1223 return OpRef::res(Results.top());
1224}
1225
1226OpRef HvxSelector::funnels(OpRef Va, OpRef Vb, int Amount,
1228
1229
1230
1231 auto VecLen = static_cast<int>(HwLen);
1232
1233 if (Amount == 0)
1234 return Va;
1235 if (Amount == VecLen)
1236 return Vb;
1237
1238 MVT Ty = getSingleVT(MVT::i8);
1239 const SDLoc &dl(Results.InpNode);
1240
1241 if (Amount < 0)
1242 Amount += VecLen;
1243 if (Amount > VecLen) {
1244 Amount -= VecLen;
1246 }
1247
1249 SDValue A = getConst32(Amount, dl);
1250 Results.push(Hexagon::V6_valignbi, Ty, {Vb, Va, A});
1251 } else if (isUInt<3>(VecLen - Amount)) {
1252 SDValue A = getConst32(VecLen - Amount, dl);
1253 Results.push(Hexagon::V6_vlalignbi, Ty, {Vb, Va, A});
1254 } else {
1255 SDValue A = getConst32(Amount, dl);
1256 Results.push(Hexagon::A2_tfrsi, Ty, {A});
1257 Results.push(Hexagon::V6_valignb, Ty, {Vb, Va, OpRef::res(-1)});
1258 }
1259 return OpRef::res(Results.top());
1260}
1261
1262
1263
1264
1265OpRef HvxSelector::packs(ShuffleMask SM, OpRef Va, OpRef Vb,
1269 if (!Va.isValid() || !Vb.isValid())
1270 return OpRef::fail();
1271
1272 if (Vb.isUndef()) {
1274 return Va;
1275 }
1276 if (Va.isUndef()) {
1279 return Vb;
1280 }
1281
1282 MVT Ty = getSingleVT(MVT::i8);
1283 MVT PairTy = getPairVT(MVT::i8);
1284 OpRef Inp[2] = {Va, Vb};
1285 unsigned VecLen = SM.Mask.size();
1286
1287 auto valign = [this](OpRef Lo, OpRef Hi, unsigned Amt, MVT Ty,
1289 if (Amt == 0)
1290 return Lo;
1291 const SDLoc &dl(Results.InpNode);
1293 bool IsRight = isUInt<3>(Amt);
1294 SDValue S = getConst32(IsRight ? Amt : HwLen - Amt, dl);
1295 unsigned Opc = IsRight ? Hexagon::V6_valignbi : Hexagon::V6_vlalignbi;
1297 return OpRef::res(Results.top());
1298 }
1299 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(Amt, dl)});
1300 OpRef A = OpRef::res(Results.top());
1301 Results.push(Hexagon::V6_valignb, Ty, {Hi, Lo, A});
1302 return OpRef::res(Results.top());
1303 };
1304
1305
1306 unsigned SegLen = HwLen / 2;
1307
1308
1309
1311 SmallVector<unsigned, 4> SegList = getInputSegmentList(SM.Mask, SegLen);
1312 unsigned SegCount = SegList.size();
1314
1315 if (SegList.empty())
1316 return OpRef::undef(Ty);
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334 unsigned Seg0 = ~0u, Seg1 = ~0u;
1335 for (unsigned X : SegMap) {
1336 if (X == ~0u)
1337 continue;
1338 if (Seg0 == ~0u)
1339 Seg0 = X;
1340 else if (Seg1 != ~0u)
1341 break;
1342 if (X == ~1u || X != Seg0)
1343 Seg1 = X;
1344 }
1345
1346 if (SegCount == 1) {
1347 unsigned SrcOp = SegList[0] / 2;
1348 for (int I = 0; I != static_cast<int>(VecLen); ++I) {
1350 if (M >= 0) {
1351 M -= SrcOp * HwLen;
1353 }
1355 }
1356 return Inp[SrcOp];
1357 }
1358
1359 if (SegCount == 2) {
1360
1361
1362 assert(Seg0 != ~0u);
1363
1364
1365
1366 if (Seg0 == ~1u || Seg1 == ~1u) {
1367 if (Seg0 == Seg1) {
1368 Seg0 = SegList[0];
1369 Seg1 = SegList[1];
1370 } else if (Seg0 == ~1u) {
1371 Seg0 = SegList[0] != Seg1 ? SegList[0] : SegList[1];
1372 } else {
1373 assert(Seg1 == ~1u);
1374 Seg1 = SegList[0] != Seg0 ? SegList[0] : SegList[1];
1375 }
1376 }
1377 assert(Seg0 != ~1u && Seg1 != ~1u);
1378
1379 assert(Seg0 != Seg1 && "Expecting different segments");
1380 const SDLoc &dl(Results.InpNode);
1381 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(SegLen, dl)});
1382 OpRef HL = OpRef::res(Results.top());
1383
1384
1385
1386 if (Seg0 / 2 == Seg1 / 2) {
1387
1388 Va = Inp[Seg0 / 2];
1389 if (Seg0 > Seg1) {
1390
1391 Results.push(Hexagon::V6_vror, Ty, {Inp[Seg0 / 2], HL});
1392 Va = OpRef::res(Results.top());
1393 }
1395 } else if (Seg0 % 2 == Seg1 % 2) {
1396
1397
1398
1399 auto Vs = (Seg0 == 0 || Seg0 == 1) ? std::make_pair(Vb, Va)
1400 : std::make_pair(Va, Vb);
1401 Results.push(Hexagon::V6_vshuffvdd, PairTy, {Vs.first, Vs.second, HL});
1402 OpRef P = OpRef::res(Results.top());
1403 Va = (Seg0 == 0 || Seg0 == 2) ? OpRef::lo(P) : OpRef::hi(P);
1405 } else {
1406
1407 if ((Seg0 == 0 && Seg1 == 3) || (Seg0 == 2 && Seg1 == 1)) {
1408
1409
1410
1411 Results.push(Hexagon::V6_pred_scalar2, getBoolVT(), {HL});
1412 OpRef Qt = OpRef::res(Results.top());
1413 auto Vs = (Seg0 == 0) ? std::make_pair(Va, Vb)
1414 : std::make_pair(Vb, Va);
1415 Results.push(Hexagon::V6_vmux, Ty, {Qt, Vs.first, Vs.second});
1416 Va = OpRef::res(Results.top());
1418 } else {
1419
1420
1421
1422 assert(Seg0 == 1 || Seg0 == 3);
1423 }
1424 }
1425 }
1426
1427
1428
1429 ShuffleMask SMH(MaskH);
1430 assert(SMH.Mask.size() == VecLen);
1432
1433 if (SMH.MaxSrc - SMH.MinSrc >= static_cast<int>(HwLen)) {
1434
1437 ShuffleMask SW(Swapped);
1438 if (SW.MaxSrc - SW.MinSrc < static_cast<int>(HwLen)) {
1439 MaskA.assign(SW.Mask.begin(), SW.Mask.end());
1441 }
1442 }
1443 ShuffleMask SMA(MaskA);
1444 assert(SMA.Mask.size() == VecLen);
1445
1446 if (SMA.MaxSrc - SMA.MinSrc < static_cast<int>(HwLen)) {
1447 int ShiftR = SMA.MinSrc;
1448 if (ShiftR >= static_cast<int>(HwLen)) {
1449 Va = Vb;
1450 Vb = OpRef::undef(Ty);
1451 ShiftR -= HwLen;
1452 }
1453 OpRef RetVal = valign(Va, Vb, ShiftR, Ty, Results);
1454
1455 for (int I = 0; I != static_cast<int>(VecLen); ++I) {
1457 if (M != -1)
1458 M -= SMA.MinSrc;
1460 }
1461 return RetVal;
1462 }
1463
1464
1465
1466
1467
1468
1469 if (Options & PackMux) {
1470
1471
1472 BitVector Picked(HwLen);
1473 SmallVector<uint8_t,128> MuxBytes(HwLen);
1474 bool CanMux = true;
1475 for (int I = 0; I != static_cast<int>(VecLen); ++I) {
1477 if (M == -1)
1478 continue;
1479 if (M >= static_cast<int>(HwLen))
1480 M -= HwLen;
1481 else
1482 MuxBytes[M] = 0xFF;
1483 if (Picked[M]) {
1484 CanMux = false;
1485 break;
1486 }
1488 }
1489 if (CanMux)
1490 return vmuxs(MuxBytes, Va, Vb, Results);
1491 }
1492 return OpRef::fail();
1493}
1494
1495
1496
1497
1498OpRef HvxSelector::packp(ShuffleMask SM, OpRef Va, OpRef Vb,
1502 if (SegList.empty())
1503 return OpRef::undef(getPairVT(MVT::i8));
1504
1505
1506
1507 unsigned SegCount = SegList.size();
1508 if (SegCount > 2)
1509 return OpRef::fail();
1510
1511 MVT HalfTy = getSingleVT(MVT::i8);
1512
1513 OpRef Inp[2] = { Va, Vb };
1514 OpRef Out[2] = { OpRef::undef(HalfTy), OpRef::undef(HalfTy) };
1515
1516
1517 assert(SegCount <= 2);
1518
1519 for (int I = 0, E = SegList.size(); I != E; ++I) {
1520 unsigned S = SegList[I];
1521 OpRef Op = Inp[S / 2];
1522 Out[I] = (S & 1) ? OpRef::hi(Op) : OpRef::lo(Op);
1523 }
1524
1525
1526
1527
1528
1529
1530
1532 return concats(Out[0], Out[1], Results);
1533}
1534
1535OpRef HvxSelector::vmuxs(ArrayRef<uint8_t> Bytes, OpRef Va, OpRef Vb,
1538 MVT ByteTy = getSingleVT(MVT::i8);
1540 const SDLoc &dl(Results.InpNode);
1541 SDValue B = getVectorConstant(Bytes, dl);
1542 Results.push(Hexagon::V6_vd0, ByteTy, {});
1543 Results.push(Hexagon::V6_veqb, BoolTy, {OpRef(B), OpRef::res(-1)});
1544 Results.push(Hexagon::V6_vmux, ByteTy, {OpRef::res(-1), Vb, Va});
1545 return OpRef::res(Results.top());
1546}
1547
1548OpRef HvxSelector::vmuxp(ArrayRef<uint8_t> Bytes, OpRef Va, OpRef Vb,
1551 size_t S = Bytes.size() / 2;
1552 OpRef L = vmuxs(Bytes.take_front(S), OpRef::lo(Va), OpRef::lo(Vb), Results);
1553 OpRef H = vmuxs(Bytes.drop_front(S), OpRef::hi(Va), OpRef::hi(Vb), Results);
1554 return concats(L, H, Results);
1555}
1556
1557OpRef HvxSelector::shuffs1(ShuffleMask SM, OpRef Va, ResultStack &Results) {
1559 unsigned VecLen = SM.Mask.size();
1560 assert(HwLen == VecLen);
1561 (void)VecLen;
1562 assert(all_of(SM.Mask, [this](int M) { return M == -1 || M < int(HwLen); }));
1563
1565 return Va;
1567 return OpRef::undef(getSingleVT(MVT::i8));
1568
1569
1570 if (auto Dist = rotationDistance(SM, VecLen)) {
1571 OpRef Rotate = funnels(Va, Va, *Dist, Results);
1572 if (Rotate.isValid())
1573 return Rotate;
1574 }
1575 unsigned HalfLen = HwLen / 2;
1577
1578
1579
1580 std::pair<int, unsigned> Strip1 = findStrip(SM.Mask, 1, HalfLen);
1581 if ((Strip1.first & ~HalfLen) == 0 && Strip1.second == HalfLen) {
1582 std::pair<int, unsigned> Strip2 =
1584 if (Strip1 == Strip2) {
1585 const SDLoc &dl(Results.InpNode);
1586 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(HalfLen, dl)});
1587 Results.push(Hexagon::V6_vshuffvdd, getPairVT(MVT::i8),
1588 {Va, Va, OpRef::res(Results.top())});
1589 OpRef S = OpRef::res(Results.top());
1590 return (Strip1.first == 0) ? OpRef::lo(S) : OpRef::hi(S);
1591 }
1592 }
1593
1594 OpRef P = perfect(SM, Va, Results);
1595 if (P.isValid())
1596 return P;
1597 return butterfly(SM, Va, Results);
1598}
1599
1600OpRef HvxSelector::shuffs2(ShuffleMask SM, OpRef Va, OpRef Vb,
1604 return OpRef::undef(getSingleVT(MVT::i8));
1605
1606 OpRef C = contracting(SM, Va, Vb, Results);
1607 if (C.isValid())
1608 return C;
1609
1610 int VecLen = SM.Mask.size();
1612 OpRef P = packs(SM, Va, Vb, Results, PackedMask);
1613 if (P.isValid())
1614 return shuffs1(ShuffleMask(PackedMask), P, Results);
1615
1616
1617
1618
1620 splitMask(SM.Mask, MaskL, MaskR);
1621
1622 OpRef L = shuffs1(ShuffleMask(MaskL), Va, Results);
1623 OpRef R = shuffs1(ShuffleMask(MaskR), Vb, Results);
1624 if (.isValid() ||
.isValid())
1625 return OpRef::fail();
1626
1627 SmallVector<uint8_t, 128> Bytes(VecLen);
1628 for (int I = 0; I != VecLen; ++I) {
1629 if (MaskL[I] != -1)
1630 Bytes[I] = 0xFF;
1631 }
1632 return vmuxs(Bytes, L, R, Results);
1633}
1634
1635OpRef HvxSelector::shuffp1(ShuffleMask SM, OpRef Va, ResultStack &Results) {
1637 int VecLen = SM.Mask.size();
1638
1640 return Va;
1642 return OpRef::undef(getPairVT(MVT::i8));
1643
1645 OpRef P = packs(SM, OpRef::lo(Va), OpRef::hi(Va), Results, PackedMask);
1646 if (P.isValid()) {
1647 ShuffleMask PM(PackedMask);
1648 OpRef E = expanding(PM, P, Results);
1649 if (E.isValid())
1650 return E;
1651
1652 OpRef L = shuffs1(PM.lo(), P, Results);
1653 OpRef H = shuffs1(PM.hi(), P, Results);
1654 if (L.isValid() && H.isValid())
1655 return concats(L, H, Results);
1656 }
1657
1659
1660
1661
1662
1663
1664 OpRef R = perfect(SM, Va, Results);
1665 if (R.isValid())
1666 return R;
1667
1668 }
1669
1670 OpRef L = shuffs2(SM.lo(), OpRef::lo(Va), OpRef::hi(Va), Results);
1671 OpRef H = shuffs2(SM.hi(), OpRef::lo(Va), OpRef::hi(Va), Results);
1672 if (L.isValid() && H.isValid())
1673 return concats(L, H, Results);
1674
1675 return OpRef::fail();
1676}
1677
1678OpRef HvxSelector::shuffp2(ShuffleMask SM, OpRef Va, OpRef Vb,
1682 return OpRef::undef(getPairVT(MVT::i8));
1683
1684 int VecLen = SM.Mask.size();
1686 OpRef P = packp(SM, Va, Vb, Results, PackedMask);
1687 if (P.isValid())
1688 return shuffp1(ShuffleMask(PackedMask), P, Results);
1689
1691 splitMask(SM.Mask, MaskL, MaskR);
1692
1693 OpRef L = shuffp1(ShuffleMask(MaskL), Va, Results);
1694 OpRef R = shuffp1(ShuffleMask(MaskR), Vb, Results);
1695 if (.isValid() ||
.isValid())
1696 return OpRef::fail();
1697
1698
1700 for (int I = 0; I != VecLen; ++I) {
1701 if (MaskL[I] != -1)
1702 Bytes[I] = 0xFF;
1703 }
1704 return vmuxp(Bytes, L, R, Results);
1705}
1706
1707namespace {
1708 struct Deleter : public SelectionDAG::DAGNodeDeletedListener {
1709 template
1710 Deleter(SelectionDAG &D, T &C)
1711 : SelectionDAG::DAGNodeDeletedListener(D, [&C] (SDNode *N, SDNode *E) {
1713 }) {}
1714 };
1715
1716 template
1717 struct NullifyingVector : public T {
1718 DenseMap<SDNode*, SDNode**> Refs;
1719 NullifyingVector(T &&V) : T(V) {
1720 for (unsigned i = 0, e = T::size(); i != e; ++i) {
1721 SDNode *&N = T::operator[](i);
1723 }
1724 }
1728 *F->second = nullptr;
1729 }
1730 };
1731}
1732
1733void HvxSelector::select(SDNode *ISelN) {
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1746
1747
1748
1749
1750 DAG.RemoveDeadNodes();
1751
1752 SetVector<SDNode *> SubNodes;
1753
1755
1756
1757 auto IsISelN = [](SDNode *T) { return T->getOpcode() == HexagonISD::ISEL; };
1759 SubNodes.insert(N0);
1760 }
1761 if (SubNodes.empty()) {
1762 ISel.ReplaceNode(ISelN, N0);
1763 return;
1764 }
1765
1766
1767
1768
1769 SetVector<SDNode*> Dom, NonDom;
1771
1772 auto IsDomRec = [&Dom, &NonDom] (SDNode *T, auto Rec) -> bool {
1774 return true;
1775 if (T->use_empty() || NonDom.count(T))
1776 return false;
1777 for (SDNode *U : T->users()) {
1778
1779
1780 if (!Rec(U, Rec)) {
1782 return false;
1783 }
1784 }
1786 return true;
1787 };
1788
1789 auto IsDom = [&IsDomRec] (SDNode *T) { return IsDomRec(T, IsDomRec); };
1790
1791
1792 for (unsigned I = 0; I != SubNodes.size(); ++I) {
1794 SDNode *O = Op.getNode();
1795 if (IsDom(O))
1797 }
1798 }
1799
1800
1801 SetVector<SDNode*> TmpQ;
1802
1803 std::map<SDNode *, unsigned> OpCount;
1804 for (SDNode *T : Dom) {
1805 unsigned NumDomOps = llvm::count_if(T->ops(), [&Dom](const SDUse &U) {
1806 return Dom.count(U.getNode());
1807 });
1808
1809 OpCount.insert({T, NumDomOps});
1810 if (NumDomOps == 0)
1812 }
1813
1814 for (unsigned I = 0; I != TmpQ.size(); ++I) {
1815 SDNode *S = TmpQ[I];
1816 for (SDNode *U : S->users()) {
1817 if (U == ISelN)
1818 continue;
1819 auto F = OpCount.find(U);
1820 assert(F != OpCount.end());
1821 if (F->second > 0 && !--F->second)
1823 }
1824 }
1825
1826
1827 ISel.ReplaceNode(ISelN, N0);
1828
1830 NullifyingVector<decltype(TmpQ)::vector_type> Queue(TmpQ.takeVector());
1831
1832 Deleter DUQ(DAG, Queue);
1833 for (SDNode *S : reverse(Queue)) {
1834 if (S == nullptr)
1835 continue;
1837 ISel.Select(S);
1838 }
1839}
1840
1841bool HvxSelector::scalarizeShuffle(ArrayRef Mask, const SDLoc &dl,
1843 SDNode *N) {
1846 assert(ElemTy == MVT::i8);
1847 unsigned VecLen = Mask.size();
1848 bool HavePairs = (2*HwLen == VecLen);
1849 MVT SingleTy = getSingleVT(MVT::i8);
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1865 LLVMContext &Ctx = *DAG.getContext();
1866 MVT LegalTy = Lower.getTypeToTransformTo(Ctx, ElemTy).getSimpleVT();
1867 for (int I : Mask) {
1868 if (I < 0) {
1869 Ops.push_back(ISel.selectUndef(dl, LegalTy));
1870 continue;
1871 }
1874 if (M < VecLen) {
1875 Vec = Va;
1876 } else {
1877 Vec = Vb;
1878 M -= VecLen;
1879 }
1880 if (HavePairs) {
1881 if (M < HwLen) {
1882 Vec = DAG.getTargetExtractSubreg(Hexagon::vsub_lo, dl, SingleTy, Vec);
1883 } else {
1884 Vec = DAG.getTargetExtractSubreg(Hexagon::vsub_hi, dl, SingleTy, Vec);
1885 M -= HwLen;
1886 }
1887 }
1888 SDValue Idx = DAG.getConstant(M, dl, MVT::i32);
1892 Ops.push_back(L);
1893 }
1894
1896 if (2*HwLen == VecLen) {
1897 SDValue B0 = DAG.getBuildVector(SingleTy, dl, {Ops.data(), HwLen});
1899 SDValue B1 = DAG.getBuildVector(SingleTy, dl, {Ops.data()+HwLen, HwLen});
1901
1902
1903
1904
1906 } else {
1907 SDValue BV = DAG.getBuildVector(ResTy, dl, Ops);
1908 LV = Lower.LowerOperation(BV, DAG);
1909 }
1910
1911 assert(->use_empty());
1913 ISel.ReplaceNode(N, IS.getNode());
1915 DAG.RemoveDeadNodes();
1916 return true;
1917}
1918
1920 unsigned Width) {
1922 unsigned Impossible = ~(1u << Width) + 1;
1923 for (unsigned I = 0, E = Bs.size(); I != E; ++I) {
1925 if (B == 0xff)
1926 continue;
1927 if (~Impossible == 0)
1928 break;
1929 for (unsigned Log = 0; Log != Width; ++Log) {
1930 if (Impossible & (1u << Log))
1931 continue;
1932 unsigned Expected = (I >> Log) % 2;
1934 Impossible |= (1u << Log);
1935 }
1936 }
1937 return ~Impossible;
1938 };
1939
1941
1942 for (unsigned BitIdx = 0; BitIdx != Width; ++BitIdx) {
1944 for (int i = 0, e = SM.Mask.size(); i != e; ++i) {
1945 int M = SM.Mask[i];
1946 if (M < 0)
1947 BitValues[i] = 0xff;
1948 else
1949 BitValues[i] = (M & (1u << BitIdx)) != 0;
1950 }
1951 Worklist[BitIdx] = possibilities(BitValues, Width);
1952 }
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1992
1993 for (unsigned I = 0, E = Sorted.size(); I != E;) {
1994 unsigned P = Sorted[I], Count = 1;
1995 while (++I != E && P == Sorted[I])
1998
1999
2001 }
2002 }
2003
2004 return Worklist;
2005}
2006
2009
2010
2012
2013 for (unsigned I = 0; I != Width; ++I) {
2017 continue;
2018
2020
2021 for (unsigned J = I + 1; J != Width; ++J) {
2022 if (Comps[J] == P)
2023 Comps[J] ^= T;
2024 }
2026 }
2027
2028#ifndef NDEBUG
2029
2033 OrAll |= C;
2034 }
2035 assert(OrAll == (1u << Width) -1);
2036#endif
2037
2038 return Comps;
2039}
2040
2042 unsigned WrapAt) {
2043 std::optional Dist;
2044 for (int I = 0, E = SM.Mask.size(); I != E; ++I) {
2045 int M = SM.Mask[I];
2046 if (M < 0)
2047 continue;
2048 if (Dist) {
2049 if ((I + *Dist) % static_cast<int>(WrapAt) != M)
2050 return std::nullopt;
2051 } else {
2052
2053
2054
2055 Dist = M - I;
2056 if (Dist < 0)
2057 Dist = *Dist + WrapAt;
2058 }
2059 }
2060 return Dist;
2061}
2062
2063OpRef HvxSelector::contracting(ShuffleMask SM, OpRef Va, OpRef Vb,
2066 if (!Va.isValid() || !Vb.isValid())
2067 return OpRef::fail();
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078 int VecLen = SM.Mask.size();
2079
2080
2081 if (auto Dist = rotationDistance(SM, 2 * VecLen)) {
2082 OpRef Funnel = funnels(Va, Vb, *Dist, Results);
2083 if (Funnel.isValid())
2084 return Funnel;
2085 }
2086
2087 MVT SingleTy = getSingleVT(MVT::i8);
2088 MVT PairTy = getPairVT(MVT::i8);
2089
2090 auto same = [](ArrayRef Mask1, ArrayRef Mask2) -> bool {
2091 return Mask1 == Mask2;
2092 };
2093
2094 using PackConfig = std::pair<unsigned, bool>;
2095 PackConfig Packs[] = {
2096 {1, false},
2097 {1, true},
2098 {2, false},
2099 {2, true},
2100 };
2101
2102 {
2103 unsigned Opcodes[] = {
2104 Hexagon::V6_vpackeb,
2105 Hexagon::V6_vpackob,
2106 Hexagon::V6_vpackeh,
2107 Hexagon::V6_vpackoh,
2108 };
2109 for (int i = 0, e = std::size(Opcodes); i != e; ++i) {
2110 auto [Size, Odd] = Packs[i];
2112 Results.push(Opcodes[i], SingleTy, {Vb, Va});
2113 return OpRef::res(Results.top());
2114 }
2115 }
2116 }
2117
2118 {
2119 unsigned Opcodes[] = {
2120 Hexagon::V6_vshuffeb,
2121 Hexagon::V6_vshuffob,
2122 Hexagon::V6_vshufeh,
2123 Hexagon::V6_vshufoh,
2124 };
2125 for (int i = 0, e = std::size(Opcodes); i != e; ++i) {
2126 auto [Size, Odd] = Packs[i];
2128 Results.push(Opcodes[i], SingleTy, {Vb, Va});
2129 return OpRef::res(Results.top());
2130 }
2131 }
2132 }
2133
2134 {
2135
2136
2137
2138 unsigned Opcodes[] = {
2139 Hexagon::V6_vpackeb,
2140 Hexagon::V6_vpackob,
2141 Hexagon::V6_vpackeh,
2142 Hexagon::V6_vpackoh,
2143 };
2144 const SDLoc &dl(Results.InpNode);
2145
2146 for (int i = 0, e = std::size(Opcodes); i != e; ++i) {
2147 auto [Size, Odd] = Packs[i];
2149 Results.push(Hexagon::A2_tfrsi, MVT::i32,
2150 {getSignedConst32(-2 * Size, dl)});
2151 Results.push(Hexagon::V6_vdealvdd, PairTy, {Vb, Va, OpRef::res(-1)});
2153 Results.push(Opcodes[i], SingleTy,
2154 {OpRef::hi(vdeal), OpRef::lo(vdeal)});
2155 return OpRef::res(Results.top());
2156 }
2157 }
2158 }
2159
2161 Results.push(Hexagon::V6_vdealb4w, SingleTy, {Vb, Va});
2162 return OpRef::res(Results.top());
2163 }
2164
2165 return OpRef::fail();
2166}
2167
2168OpRef HvxSelector::expanding(ShuffleMask SM, OpRef Va, ResultStack &Results) {
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181 int VecLen = SM.Mask.size();
2182 assert(2*HwLen == unsigned(VecLen) && "Expecting vector-pair type");
2183
2184 std::pair<int,unsigned> Strip = findStrip(SM.Mask, 1, VecLen);
2185
2186
2187
2188
2189
2190
2191 if (Strip.first != 0)
2192 return OpRef::fail();
2193
2194
2195 if (Strip.second != 1 && Strip.second != 2)
2196 return OpRef::fail();
2197
2198 int N = VecLen;
2199 int L = Strip.second;
2200
2201
2202 for (int I = 2*L; I < N; I += 2*L) {
2204 if (S.second != unsigned(L))
2205 return OpRef::fail();
2206 if (2*S.first != I)
2207 return OpRef::fail();
2208 }
2209
2210 for (int I = L; I < N; I += 2*L) {
2212 if (S.first != -1 || S.second != unsigned(L))
2213 return OpRef::fail();
2214 }
2215
2216 unsigned Opc = Strip.second == 1 ? Hexagon::V6_vunpackub
2217 : Hexagon::V6_vunpackuh;
2218 Results.push(Opc, getPairVT(MVT::i8), {Va});
2219 return OpRef::res(Results.top());
2220}
2221
2222OpRef HvxSelector::perfect(ShuffleMask SM, OpRef Va, ResultStack &Results) {
2224
2225
2226
2227
2228
2229
2230
2231 int VecLen = SM.Mask.size();
2233 unsigned LogLen = Log2_32(VecLen);
2234 unsigned HwLog = Log2_32(HwLen);
2235
2236
2237 assert(LogLen == HwLog || LogLen == HwLog + 1);
2238 bool HavePairs = LogLen == HwLog + 1;
2239
2240 SmallVector<unsigned, 8> Perm(LogLen);
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2324 bool InvertedPair = false;
2325 if (HavePairs && SM.Mask[0] >= int(HwLen)) {
2326 for (int i = 0, e = SM.Mask.size(); i != e; ++i) {
2327 int M = SM.Mask[i];
2328 MaskStorage[i] = M >= int(HwLen) ? M - HwLen : M + HwLen;
2329 }
2330 InvertedPair = true;
2331 SM = ShuffleMask(MaskStorage);
2332 }
2333
2334 auto Comps = getPerfectCompletions(SM, LogLen);
2336 return OpRef::fail();
2337
2338 auto Pick = completeToPerfect(Comps, LogLen);
2339 for (unsigned I = 0; I != LogLen; ++I)
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367 using CycleType = SmallVector<unsigned, 8>;
2368 std::set Cycles;
2369 std::set All;
2370
2371 for (unsigned I : Perm)
2373
2374
2375
2376 auto canonicalize = [LogLen](const CycleType &C) -> CycleType {
2377 unsigned LogPos, N = C.size();
2378 for (LogPos = 0; LogPos != N; ++LogPos)
2379 if (C[LogPos] == LogLen - 1)
2380 break;
2381 if (LogPos == N)
2382 return C;
2383
2384 CycleType NewC(C.begin() + LogPos, C.end());
2385 NewC.append(C.begin(), C.begin() + LogPos);
2386 return NewC;
2387 };
2388
2389 auto pfs = [](const std::set &Cs, unsigned Len) {
2390
2391
2392 if (Cs.size() != 1)
2393 return 0u;
2394 const CycleType &C = *Cs.begin();
2395 if (C[0] != Len - 1)
2396 return 0u;
2399 return 0u;
2400
2401 bool IsDeal = true, IsShuff = true;
2402 for (unsigned I = 1; I != Len - D; ++I) {
2404 IsDeal = false;
2406 IsShuff = false;
2407 }
2408
2409 assert(!(IsDeal || IsShuff) || IsDeal != IsShuff);
2410 static unsigned Deals[] = {Hexagon::V6_vdealb, Hexagon::V6_vdealh};
2411 static unsigned Shufs[] = {Hexagon::V6_vshuffb, Hexagon::V6_vshuffh};
2412 return IsDeal ? Deals[D] : (IsShuff ? Shufs[D] : 0);
2413 };
2414
2415 while (.empty()) {
2416 unsigned A = *All.begin();
2418 CycleType C;
2420 for (unsigned B = Perm[A]; B != A; B = Perm[B]) {
2423 }
2424 if (C.size() <= 1)
2425 continue;
2426 Cycles.insert(canonicalize(C));
2427 }
2428
2429 MVT SingleTy = getSingleVT(MVT::i8);
2430 MVT PairTy = getPairVT(MVT::i8);
2431
2432
2433 if (unsigned(VecLen) == HwLen) {
2434 if (unsigned SingleOpc = pfs(Cycles, LogLen)) {
2435 Results.push(SingleOpc, SingleTy, {Va});
2436 return OpRef::res(Results.top());
2437 }
2438 }
2439
2440
2441
2442
2443
2444
2445
2446 SmallVector<unsigned, 8> SwapElems;
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457 if (!HavePairs)
2458 SwapElems.push_back(LogLen - 1);
2459 for (const CycleType &C : Cycles) {
2460
2461 unsigned First = (C[0] == LogLen - 1) ? 1 : 0;
2465 }
2466 if (!HavePairs)
2467 SwapElems.push_back(LogLen - 1);
2468
2469 const SDLoc &dl(Results.InpNode);
2470 OpRef Arg = HavePairs ? Va : concats(Va, OpRef::undef(SingleTy), Results);
2471 if (InvertedPair)
2472 Arg = concats(OpRef::hi(Arg), OpRef::lo(Arg), Results);
2473
2474 for (unsigned I = 0, E = SwapElems.size(); I != E;) {
2475 bool IsInc = I == E - 1 || SwapElems[I] < SwapElems[I + 1];
2476 unsigned S = (1u << SwapElems[I]);
2478 while (++I < E - 1 && IsInc == (SwapElems[I] < SwapElems[I + 1]))
2479 S |= 1u << SwapElems[I];
2480
2481
2482 S |= 1u << SwapElems[I];
2483 }
2484 ++I;
2485
2486
2487
2488
2489
2490
2492
2493 NodeTemplate Res;
2494 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getSignedConst32(SS, dl)});
2495 Res.Opc = IsInc ? Hexagon::V6_vshuffvdd : Hexagon::V6_vdealvdd;
2497 Res.Ops = {OpRef::hi(Arg), OpRef::lo(Arg), OpRef::res(-1)};
2499 Arg = OpRef::res(Results.top());
2500 }
2501
2502 return HavePairs ? Arg : OpRef::lo(Arg);
2503}
2504
2505OpRef HvxSelector::butterfly(ShuffleMask SM, OpRef Va, ResultStack &Results) {
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517 MVT ResTy = getSingleVT(MVT::i8);
2518 PermNetwork::Controls FC, RC;
2519 const SDLoc &dl(Results.InpNode);
2520 int VecLen = SM.Mask.size();
2521
2522 for (int M : SM.Mask) {
2523 if (M != -1 && M >= VecLen)
2524 return OpRef::fail();
2525 }
2526
2527
2528 ForwardDeltaNetwork FN(SM.Mask);
2529 if (FN.run(FC)) {
2530 SDValue Ctl = getVectorConstant(FC, dl);
2531 Results.push(Hexagon::V6_vdelta, ResTy, {Va, OpRef(Ctl)});
2532 return OpRef::res(Results.top());
2533 }
2534
2535
2536 ReverseDeltaNetwork RN(SM.Mask);
2537 if (RN.run(RC)) {
2538 SDValue Ctl = getVectorConstant(RC, dl);
2539 Results.push(Hexagon::V6_vrdelta, ResTy, {Va, OpRef(Ctl)});
2540 return OpRef::res(Results.top());
2541 }
2542
2543
2544 BenesNetwork BN(SM.Mask);
2545 if (BN.run(FC, RC)) {
2546 SDValue CtlF = getVectorConstant(FC, dl);
2547 SDValue CtlR = getVectorConstant(RC, dl);
2548 Results.push(Hexagon::V6_vdelta, ResTy, {Va, OpRef(CtlF)});
2549 Results.push(Hexagon::V6_vrdelta, ResTy,
2550 {OpRef::res(-1), OpRef(CtlR)});
2551 return OpRef::res(Results.top());
2552 }
2553
2554 return OpRef::fail();
2555}
2556
2557SDValue HvxSelector::getConst32(unsigned Val, const SDLoc &dl) {
2558 return DAG.getTargetConstant(Val, dl, MVT::i32);
2559}
2560
2561SDValue HvxSelector::getSignedConst32(int Val, const SDLoc &dl) {
2562 return DAG.getSignedTargetConstant(Val, dl, MVT::i32);
2563}
2564
2565SDValue HvxSelector::getVectorConstant(ArrayRef<uint8_t> Data,
2566 const SDLoc &dl) {
2569 Elems.push_back(DAG.getConstant(C, dl, MVT::i8));
2571 SDValue BV = DAG.getBuildVector(VecTy, dl, Elems);
2573 DAG.RemoveDeadNode(BV.getNode());
2575}
2576
2578 SDValue Inp = N->getOperand(0);
2579 MVT ResTy = N->getValueType(0).getSimpleVT();
2580 unsigned Idx = N->getConstantOperandVal(1);
2581
2586 assert(Idx == 0 || Idx == ResLen);
2587
2588 unsigned SubReg = Idx == 0 ? Hexagon::vsub_lo : Hexagon::vsub_hi;
2590
2592}
2593
2596 dbgs() << "Starting " << __func__ << " on node:\n";
2598 });
2599 MVT ResTy = N->getValueType(0).getSimpleVT();
2600
2601 assert(ResTy.isVector() && ResTy.getVectorElementType() == MVT::i8);
2602
2604 std::vector Mask(SN->getMask().begin(), SN->getMask().end());
2605
2606 for (int &Idx : Mask)
2607 if (Idx != -1 && Idx < 0)
2608 Idx = -1;
2609
2610 unsigned VecLen = Mask.size();
2611 bool HavePairs = (2*HwLen == VecLen);
2612 assert(ResTy.getSizeInBits() / 8 == VecLen);
2613
2614
2615
2616
2617 bool UseLeft = false, UseRight = false;
2618 for (unsigned I = 0; I != VecLen; ++I) {
2619 if (Mask[I] == -1)
2620 continue;
2621 unsigned Idx = Mask[I];
2622 assert(Idx < 2*VecLen);
2623 if (Idx < VecLen)
2624 UseLeft = true;
2625 else
2626 UseRight = true;
2627 }
2628
2630 dbgs() << "VecLen=" << VecLen << " HwLen=" << HwLen << " UseLeft="
2631 << UseLeft << " UseRight=" << UseRight << " HavePairs="
2632 << HavePairs << '\n';
2633 });
2634
2635 if (!UseLeft && !UseRight) {
2637 return;
2638 }
2639
2640 SDValue Vec0 = N->getOperand(0);
2641 SDValue Vec1 = N->getOperand(1);
2643
2644 ResultStack Results(SN);
2645 OpRef Va = OpRef::undef(ResTy);
2646 OpRef Vb = OpRef::undef(ResTy);
2647
2649 Results.push(TargetOpcode::COPY, ResTy, {Vec0});
2650 Va = OpRef::OpRef::res(Results.top());
2651 }
2653 Results.push(TargetOpcode::COPY, ResTy, {Vec1});
2654 Vb = OpRef::res(Results.top());
2655 }
2656
2657 OpRef Res = !HavePairs ? shuffs2(ShuffleMask(Mask), Va, Vb, Results)
2658 : shuffp2(ShuffleMask(Mask), Va, Vb, Results);
2659
2660 bool Done = Res.isValid();
2662
2663 Results.push(TargetOpcode::COPY, ResTy, {Res});
2665 } else {
2666 Done = scalarizeShuffle(Mask, SDLoc(N), ResTy, Vec0, Vec1, N);
2667 }
2668
2669 if () {
2670#ifndef NDEBUG
2671 dbgs() << "Unhandled shuffle:\n";
2672 SN->dumpr(&DAG);
2673#endif
2675 }
2676}
2677
2679
2680 MVT Ty = N->getValueType(0).getSimpleVT();
2682 SDValue VecV = N->getOperand(0);
2683 SDValue RotV = N->getOperand(1);
2684 SDNode *NewN = nullptr;
2685
2687 unsigned S = CN->getZExtValue() % HST.getVectorLength();
2688 if (S == 0) {
2691 NewN = DAG.getMachineNode(Hexagon::V6_valignbi, dl, Ty,
2692 {VecV, VecV, getConst32(S, dl)});
2693 }
2694 }
2695
2696 if (!NewN)
2697 NewN = DAG.getMachineNode(Hexagon::V6_vror, dl, Ty, {VecV, RotV});
2698
2699 ISel.ReplaceNode(N, NewN);
2700}
2701
2703 SDValue Vv = N->getOperand(0);
2704 SDValue Vu = N->getOperand(1);
2705 SDValue Rt = N->getOperand(2);
2706 SDNode *NewN = DAG.getMachineNode(Hexagon::V6_valignb, SDLoc(N),
2707 N->getValueType(0), {Vv, Vu, Rt});
2708 ISel.ReplaceNode(N, NewN);
2710}
2711
2712void HexagonDAGToDAGISel::PreprocessHvxISelDAG() {
2713 auto getNodes = [this]() -> std::vector<SDNode *> {
2714 std::vector<SDNode *> T;
2715 T.reserve(CurDAG->allnodes_size());
2716 for (SDNode &N : CurDAG->allnodes())
2718 return T;
2719 };
2720
2721 ppHvxShuffleOfShuffle(getNodes());
2722}
2723
2726 return std::hash<const void *>()(V.getNode()) +
2727 std::hash()(V.getResNo());
2728 };
2729};
2730
2731void HexagonDAGToDAGISel::ppHvxShuffleOfShuffle(std::vector<SDNode *> &&Nodes) {
2732
2733
2734
2735
2736
2737
2738
2739
2740
2742 unsigned HwLen = HST->getVectorLength();
2743
2744 struct SubVectorInfo {
2745 SubVectorInfo(SDValue S, unsigned H) : Src(S), HalfIdx(H) {}
2747 unsigned HalfIdx;
2748 };
2749
2750 using MapType = std::unordered_map<SDValue, unsigned>;
2751
2752 auto getMaskElt = [&](unsigned Idx, ShuffleVectorSDNode *Shuff0,
2753 ShuffleVectorSDNode *Shuff1,
2754 const MapType &OpMap) -> int {
2755
2756
2757
2758
2759
2760
2761 ShuffleVectorSDNode *OpShuff = Idx < HwLen ? Shuff0 : Shuff1;
2762 if (Idx >= HwLen)
2763 Idx -= HwLen;
2764
2765
2766 int MaybeN = OpShuff->getMaskElt(Idx);
2767 if (MaybeN < 0)
2768 return -1;
2769
2770 auto N = static_cast<unsigned>(MaybeN);
2771 unsigned SrcBase = N < HwLen ? OpMap.at(OpShuff->getOperand(0))
2773 if (N >= HwLen)
2774 N -= HwLen;
2775
2776 return N + SrcBase;
2777 };
2778
2780
2784 ArrayRef TopMask = This->getMask();
2785
2786
2787 assert(TopMask.size() == S0->getMask().size() &&
2788 TopMask.size() == S1->getMask().size());
2790
2792 for (unsigned I = 0; I != HwLen; ++I) {
2793 int MaybeM = TopMask[I];
2794 if (MaybeM >= 0) {
2795 FoldedMask[I] =
2796 getMaskElt(static_cast<unsigned>(MaybeM), S0, S1, OpMap);
2797 } else {
2798 FoldedMask[I] = -1;
2799 }
2800 }
2801
2802 std::fill(FoldedMask.begin() + HwLen, FoldedMask.end(), -1);
2803
2804
2805
2806
2807 const SDLoc &dl(TopShuff);
2815 };
2816
2817 auto getSourceInfo = [](SDValue V) -> std::optional {
2818 while (V.getOpcode() == ISD::BITCAST)
2821 return std::nullopt;
2822 return SubVectorInfo(V.getOperand(0),
2824 };
2825
2826 for (SDNode *N : Nodes) {
2828 continue;
2829 EVT ResTy = N->getValueType(0);
2831 continue;
2833 continue;
2834
2835 SDValue V0 = N->getOperand(0);
2836 SDValue V1 = N->getOperand(1);
2838 continue;
2840 continue;
2842 continue;
2843
2844
2845
2846 auto V0A = getSourceInfo(V0.getOperand(0));
2847 if (!V0A.has_value())
2848 continue;
2849 auto V0B = getSourceInfo(V0.getOperand(1));
2850 if (!V0B.has_value() || V0B->Src != V0A->Src)
2851 continue;
2852 auto V1A = getSourceInfo(V1.getOperand(0));
2853 if (!V1A.has_value() || V1A->Src != V0A->Src)
2854 continue;
2855 auto V1B = getSourceInfo(V1.getOperand(1));
2856 if (!V1B.has_value() || V1B->Src != V0A->Src)
2857 continue;
2858
2859
2860
2861 assert(V0A->Src.getValueType().getSizeInBits() == 16 * HwLen);
2862
2863 MapType OpMap = {
2864 {V0.getOperand(0), V0A->HalfIdx * HwLen},
2865 {V0.getOperand(1), V0B->HalfIdx * HwLen},
2866 {V1.getOperand(0), V1A->HalfIdx * HwLen},
2867 {V1.getOperand(1), V1B->HalfIdx * HwLen},
2868 };
2869 SDValue NewS = fold3(SDValue(N, 0), V0A->Src, std::move(OpMap));
2870 ReplaceNode(N, NewS.getNode());
2871 }
2872}
2873
2874void HexagonDAGToDAGISel::SelectHvxExtractSubvector(SDNode *N) {
2875 HvxSelector(*this, *CurDAG).selectExtractSubvector(N);
2876}
2877
2878void HexagonDAGToDAGISel::SelectHvxShuffle(SDNode *N) {
2879 HvxSelector(*this, *CurDAG).selectShuffle(N);
2880}
2881
2882void HexagonDAGToDAGISel::SelectHvxRor(SDNode *N) {
2883 HvxSelector(*this, *CurDAG).selectRor(N);
2884}
2885
2886void HexagonDAGToDAGISel::SelectHvxVAlign(SDNode *N) {
2887 HvxSelector(*this, *CurDAG).selectVAlign(N);
2888}
2889
2892 SDValue Chain = N->getOperand(0);
2894 SDValue Predicate = N->getOperand(3);
2896 SDValue Modifier = N->getOperand(5);
2898 SDValue ImmOperand = CurDAG->getTargetConstant(0, dl, MVT::i32);
2899
2900 unsigned Opcode;
2901 unsigned IntNo = N->getConstantOperandVal(1);
2902 switch (IntNo) {
2903 default:
2905 case Intrinsic::hexagon_V6_vgathermhq:
2906 case Intrinsic::hexagon_V6_vgathermhq_128B:
2907 Opcode = Hexagon::V6_vgathermhq_pseudo;
2908 break;
2909 case Intrinsic::hexagon_V6_vgathermwq:
2910 case Intrinsic::hexagon_V6_vgathermwq_128B:
2911 Opcode = Hexagon::V6_vgathermwq_pseudo;
2912 break;
2913 case Intrinsic::hexagon_V6_vgathermhwq:
2914 case Intrinsic::hexagon_V6_vgathermhwq_128B:
2915 Opcode = Hexagon::V6_vgathermhwq_pseudo;
2916 break;
2917 }
2918
2921 Predicate, Base, Modifier, Offset, Chain };
2922 SDNode *Result = CurDAG->getMachineNode(Opcode, dl, VTs, Ops);
2923
2926
2928}
2929
2932 SDValue Chain = N->getOperand(0);
2935 SDValue Modifier = N->getOperand(4);
2937 SDValue ImmOperand = CurDAG->getTargetConstant(0, dl, MVT::i32);
2938
2939 unsigned Opcode;
2940 unsigned IntNo = N->getConstantOperandVal(1);
2941 switch (IntNo) {
2942 default:
2944 case Intrinsic::hexagon_V6_vgathermh:
2945 case Intrinsic::hexagon_V6_vgathermh_128B:
2946 Opcode = Hexagon::V6_vgathermh_pseudo;
2947 break;
2948 case Intrinsic::hexagon_V6_vgathermw:
2949 case Intrinsic::hexagon_V6_vgathermw_128B:
2950 Opcode = Hexagon::V6_vgathermw_pseudo;
2951 break;
2952 case Intrinsic::hexagon_V6_vgathermhw:
2953 case Intrinsic::hexagon_V6_vgathermhw_128B:
2954 Opcode = Hexagon::V6_vgathermhw_pseudo;
2955 break;
2956 case Intrinsic::hexagon_V6_vgather_vscattermh:
2957 case Intrinsic::hexagon_V6_vgather_vscattermh_128B:
2958 Opcode = Hexagon::V6_vgather_vscatter_mh_pseudo;
2959 break;
2960 }
2961
2964 SDNode *Result = CurDAG->getMachineNode(Opcode, dl, VTs, Ops);
2965
2968
2970}
2971
2973 unsigned IID = N->getConstantOperandVal(0);
2975 switch (IID) {
2976 case Intrinsic::hexagon_V6_vaddcarry: {
2977 std::array<SDValue, 3> Ops = {
2978 {N->getOperand(1), N->getOperand(2), N->getOperand(3)}};
2979 SDVTList VTs = CurDAG->getVTList(MVT::v16i32, MVT::v64i1);
2980 Result = CurDAG->getMachineNode(Hexagon::V6_vaddcarry, SDLoc(N), VTs, Ops);
2981 break;
2982 }
2983 case Intrinsic::hexagon_V6_vaddcarry_128B: {
2984 std::array<SDValue, 3> Ops = {
2985 {N->getOperand(1), N->getOperand(2), N->getOperand(3)}};
2986 SDVTList VTs = CurDAG->getVTList(MVT::v32i32, MVT::v128i1);
2987 Result = CurDAG->getMachineNode(Hexagon::V6_vaddcarry, SDLoc(N), VTs, Ops);
2988 break;
2989 }
2990 case Intrinsic::hexagon_V6_vsubcarry: {
2991 std::array<SDValue, 3> Ops = {
2992 {N->getOperand(1), N->getOperand(2), N->getOperand(3)}};
2993 SDVTList VTs = CurDAG->getVTList(MVT::v16i32, MVT::v64i1);
2994 Result = CurDAG->getMachineNode(Hexagon::V6_vsubcarry, SDLoc(N), VTs, Ops);
2995 break;
2996 }
2997 case Intrinsic::hexagon_V6_vsubcarry_128B: {
2998 std::array<SDValue, 3> Ops = {
2999 {N->getOperand(1), N->getOperand(2), N->getOperand(3)}};
3000 SDVTList VTs = CurDAG->getVTList(MVT::v32i32, MVT::v128i1);
3001 Result = CurDAG->getMachineNode(Hexagon::V6_vsubcarry, SDLoc(N), VTs, Ops);
3002 break;
3003 }
3004 default:
3006 }
3010 CurDAG->RemoveDeadNode(N);
3011}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
const TargetInstrInfo & TII
static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, MCValue Val)
ReachingDefInfo InstSet InstSet & Ignore
Function Alias Analysis Results
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg, SDValue Val={})
This file implements the BitVector class.
static constexpr unsigned long long mask(BlockVerifier::State S)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
static bool isIdentity(ArrayRef< int > Mask)
Definition HexagonISelDAGToDAGHVX.cpp:1035
static std::pair< int, unsigned > findStrip(ArrayRef< int > A, int Inc, unsigned MaxLen)
Definition HexagonISelDAGToDAGHVX.cpp:1015
static const HexagonSubtarget & getHexagonSubtarget(SelectionDAG &G)
Definition HexagonISelDAGToDAGHVX.cpp:913
static void splitMask(ArrayRef< int > Mask, MutableArrayRef< int > MaskL, MutableArrayRef< int > MaskR)
Definition HexagonISelDAGToDAGHVX.cpp:997
static void packSegmentMask(ArrayRef< int > Mask, ArrayRef< unsigned > OutSegMap, unsigned SegLen, MutableArrayRef< int > PackedMask)
Definition HexagonISelDAGToDAGHVX.cpp:1105
static SmallVector< unsigned, 4 > getInputSegmentList(ShuffleMask SM, unsigned SegLen)
Definition HexagonISelDAGToDAGHVX.cpp:1051
static const HexagonTargetLowering & getHexagonLowering(SelectionDAG &G)
Definition HexagonISelDAGToDAGHVX.cpp:910
static SmallVector< unsigned, 4 > getOutputSegmentMap(ShuffleMask SM, unsigned SegLen)
Definition HexagonISelDAGToDAGHVX.cpp:1070
static bool isLowHalfOnly(ArrayRef< int > Mask)
Definition HexagonISelDAGToDAGHVX.cpp:1044
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
print mir2vec MIR2Vec Vocabulary Printer Pass
std::pair< MCSymbol *, MachineModuleInfoImpl::StubValueTy > PairTy
static bool isUndef(const MachineInstr &MI)
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
static Type * getValueType(Value *V)
Returns the type of the given value/instruction V.
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
static LLVM_ATTRIBUTE_ALWAYS_INLINE MVT::SimpleValueType getSimpleVT(const unsigned char *MatcherTable, unsigned &MatcherIndex)
getSimpleVT - Decode a value in MatcherTable, if it's a VBR encoded value, use GetVBR to decode it.
This file implements a set that has insertion order iteration characteristics.
#define DEBUG_WITH_TYPE(TYPE,...)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
ArrayRef< T > take_front(size_t N=1) const
Return a copy of *this with only the first N elements.
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
size_t size() const
size - Get the array size.
ArrayRef< T > take_back(size_t N=1) const
Return a copy of *this with only the last N elements.
iterator_range< const_set_bits_iterator > set_bits() const
iterator find(const_arg_type_t< KeyT > Val)
Tagged union holding either a T or a Error.
void print(raw_ostream &OS, AssemblyAnnotationWriter *AAW=nullptr, bool ShouldPreserveUseListOrder=false, bool IsForDebug=false) const
Print the function to an output stream with an optional AssemblyAnnotationWriter.
void SelectV65GatherPred(SDNode *N)
Definition HexagonISelDAGToDAGHVX.cpp:2890
void SelectV65Gather(SDNode *N)
Definition HexagonISelDAGToDAGHVX.cpp:2930
void SelectHVXDualOutput(SDNode *N)
Definition HexagonISelDAGToDAGHVX.cpp:2972
StringRef getName(unsigned Opcode) const
Returns the name for the instructions with the given opcode.
unsigned getVectorNumElements() const
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
A description of a memory reference used in the backend.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
A NodeSet contains a set of SUnit DAG nodes with additional information that assigns a priority to th...
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
bool isMachineOpcode() const
Test if this node has a post-isel opcode, directly corresponding to a MachineInstr opcode.
LLVM_ABI void dump() const
Dump this node, for debugging.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
LLVM_ABI void dumpr() const
Dump (recursively) this node and its use-def subgraph.
const SDValue & getOperand(unsigned Num) const
LLVM_ABI void print(raw_ostream &OS, const SelectionDAG *G=nullptr) const
iterator_range< user_iterator > users()
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
EVT getValueType() const
Return the ValueType of the referenced return value.
const SDValue & getOperand(unsigned i) const
unsigned getOpcode() const
void ReplaceUses(SDValue F, SDValue T)
ReplaceUses - replace all uses of the old node F with the use of the new node T.
void ReplaceNode(SDNode *F, SDNode *T)
Replace all uses of F with T, then remove F from the DAG.
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
LLVM_ABI SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
LLVM_ABI SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
LLVM_ABI SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
LLVM_ABI SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef< int > Mask)
Return an ISD::VECTOR_SHUFFLE node.
size_type size() const
Determine the number of elements in the SetVector.
void insert_range(Range &&R)
size_type count(const_arg_type key) const
Count the number of elements of a given key in the SetVector.
Vector takeVector()
Clear the SetVector and return the underlying vector.
bool empty() const
Determine if the SetVector is empty or not.
bool insert(const value_type &X)
Insert a new element into the SetVector.
int getMaskElt(unsigned Idx) const
static void commuteMask(MutableArrayRef< int > Mask)
Change values in a shuffle permute mask assuming the two vector operands have swapped position.
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
@ CONCAT_VECTORS
CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of vector type with the same length ...
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
@ Switch
The "resume-switch" lowering, where there are separate resume and destroy functions that are shared b...
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
NodeAddr< NodeBase * > Node
LLVM_ABI iterator begin() const
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
SmallVectorImpl< T >::const_pointer c_str(SmallVectorImpl< T > &str)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
void erase(Container &C, ValueType V)
Wrapper function to remove a value from a container:
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
auto reverse(ContainerTy &&C)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionAddr VTableAddr Count
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
void replace(R &&Range, const T &OldValue, const T &NewValue)
Provide wrappers to std::replace which take ranges instead of having to pass begin/end explicitly.
@ Sub
Subtraction of integers.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
DWARFExpression::Operation Op
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt copy(R &&Range, OutputIt Out)
constexpr int32_t SignExtend32(uint32_t X)
Sign-extend the number in the bottom B bits of X to a 32-bit integer.
auto count_if(R &&Range, UnaryPredicate P)
Wrapper function around std::count_if to count the number of times an element satisfying a given pred...
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
MaskT vshuffvdd(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Rt)
Definition HexagonISelDAGToDAGHVX.cpp:811
MaskT vpack(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Size, bool TakeOdd)
Definition HexagonISelDAGToDAGHVX.cpp:851
ArrayRef< int > hi(ArrayRef< int > Vuu)
Definition HexagonISelDAGToDAGHVX.cpp:809
auto mask(ShuffFunc S, unsigned Length, OptArgs... args) -> MaskT
Definition HexagonISelDAGToDAGHVX.cpp:898
MaskT vshuff(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Size, bool TakeOdd)
Definition HexagonISelDAGToDAGHVX.cpp:866
MaskT vdealb4w(ArrayRef< int > Vu, ArrayRef< int > Vv)
Definition HexagonISelDAGToDAGHVX.cpp:885
SmallVector< int, 128 > MaskT
Definition HexagonISelDAGToDAGHVX.cpp:800
MaskT vdeal(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Size, bool TakeOdd)
Definition HexagonISelDAGToDAGHVX.cpp:879
ArrayRef< int > lo(ArrayRef< int > Vuu)
Definition HexagonISelDAGToDAGHVX.cpp:808
MaskT vdealvdd(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Rt)
Definition HexagonISelDAGToDAGHVX.cpp:831
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
EVT getVectorElementType() const
Given a vector type, return the type of each element.
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
HvxSelector(HexagonDAGToDAGISel &HS, SelectionDAG &G)
Definition HexagonISelDAGToDAGHVX.cpp:925
MVT getSingleVT(MVT ElemTy) const
Definition HexagonISelDAGToDAGHVX.cpp:929
static SmallVector< uint32_t, 8 > completeToPerfect(ArrayRef< uint32_t > Completions, unsigned Width)
Definition HexagonISelDAGToDAGHVX.cpp:2008
const unsigned HwLen
Definition HexagonISelDAGToDAGHVX.cpp:923
HexagonDAGToDAGISel & ISel
Definition HexagonISelDAGToDAGHVX.cpp:920
SelectionDAG & DAG
Definition HexagonISelDAGToDAGHVX.cpp:921
const HexagonTargetLowering & Lower
Definition HexagonISelDAGToDAGHVX.cpp:919
void selectVAlign(SDNode *N)
Definition HexagonISelDAGToDAGHVX.cpp:2702
void selectExtractSubvector(SDNode *N)
Definition HexagonISelDAGToDAGHVX.cpp:2577
MVT getBoolVT() const
Definition HexagonISelDAGToDAGHVX.cpp:941
void selectRor(SDNode *N)
Definition HexagonISelDAGToDAGHVX.cpp:2678
void selectShuffle(SDNode *N)
Definition HexagonISelDAGToDAGHVX.cpp:2594
static SmallVector< uint32_t, 8 > getPerfectCompletions(ShuffleMask SM, unsigned Width)
Definition HexagonISelDAGToDAGHVX.cpp:1919
MVT getPairVT(MVT ElemTy) const
Definition HexagonISelDAGToDAGHVX.cpp:935
const HexagonSubtarget & HST
Definition HexagonISelDAGToDAGHVX.cpp:922
static std::optional< int > rotationDistance(ShuffleMask SM, unsigned WrapAt)
Definition HexagonISelDAGToDAGHVX.cpp:2041
This represents a list of ValueType's that has been intern'd by a SelectionDAG.
std::size_t operator()(SDValue V) const
Definition HexagonISelDAGToDAGHVX.cpp:2725