15#include "llvm/IR/IntrinsicsHexagon.h"
29#define DEBUG_TYPE "hexagon-isel"
99enum class ColorKind {
None, Red, Black };
105 using MapType = std::map<Node, ColorKind>;
114 const MapType &colors()
const {
118 ColorKind other(ColorKind Color) {
119 if (Color == ColorKind::None)
120 return ColorKind::Red;
121 return Color == ColorKind::Red ? ColorKind::Black : ColorKind::Red;
129 std::set<Node> Needed;
131 using NodeSet = std::set<Node>;
132 std::map<Node,NodeSet> Edges;
136 return (Pos < Num/2) ? Pos + Num/2 : Pos - Num/2;
139 ColorKind getColor(
Node N) {
140 auto F = Colors.find(
N);
141 return F != Colors.end() ?
F->second : ColorKind::None;
144 std::pair<bool, ColorKind> getUniqueColor(
const NodeSet &Nodes);
151std::pair<bool, ColorKind> Coloring::getUniqueColor(
const NodeSet &Nodes) {
152 auto Color = ColorKind::None;
153 for (Node
N : Nodes) {
154 ColorKind ColorN = getColor(
N);
155 if (ColorN == ColorKind::None)
157 if (Color == ColorKind::None)
159 else if (Color != ColorKind::None && Color != ColorN)
160 return {
false, ColorKind::None };
162 return {
true, Color };
165void Coloring::build() {
167 for (
unsigned P = 0;
P != Order.size(); ++
P) {
171 Node PC = Order[conj(
P)];
177 for (
unsigned I = 0;
I != Order.size(); ++
I) {
178 if (!Needed.count(
I))
184 NodeSet &Is = Edges[
I];
190bool Coloring::color() {
191 SetVector<Node> FirstQ;
192 auto Enqueue = [
this,&FirstQ] (Node
N) {
195 for (
unsigned I = 0;
I != Q.
size(); ++
I) {
196 NodeSet &Ns = Edges[Q[
I]];
201 for (Node
N : Needed)
204 for (Node
N : FirstQ) {
207 NodeSet &Ns = Edges[
N];
208 auto P = getUniqueColor(Ns);
211 Colors[
N] = other(
P.second);
215 for (
auto E : Edges) {
217 if (!Needed.count(conj(
N)) || Colors.count(
N))
219 auto P = getUniqueColor(
E.second);
222 Colors[
N] = other(
P.second);
227 std::vector<Node> WorkQ;
228 for (
auto E : Edges) {
230 if (!Colors.count(
N))
234 for (Node
N : WorkQ) {
235 NodeSet &Ns = Edges[
N];
236 auto P = getUniqueColor(Ns);
238 Colors[
N] = other(
P.second);
244 ColorKind ColorN = other(ColorKind::None);
245 ColorKind ColorC = other(ColorN);
246 NodeSet &Cs = Edges[
C];
248 for (Node M : CopyNs) {
249 ColorKind ColorM = getColor(M);
250 if (ColorM == ColorC) {
263 for (
unsigned I = 0;
I != Order.size(); ++
I)
264 Colors.try_emplace(
I, ColorKind::None);
269#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
270void Coloring::dump()
const {
271 dbgs() <<
"{ Order: {";
272 for (Node
P : Order) {
279 dbgs() <<
" Needed: {";
280 for (Node
N : Needed)
284 dbgs() <<
" Edges: {\n";
285 for (
auto E : Edges) {
286 dbgs() <<
" " <<
E.first <<
" -> {";
287 for (
auto N :
E.second)
293 auto ColorKindToName = [](ColorKind
C) {
295 case ColorKind::None:
299 case ColorKind::Black:
305 dbgs() <<
" Colors: {\n";
306 for (
auto C : Colors)
307 dbgs() <<
" " <<
C.first <<
" -> " << ColorKindToName(
C.second) <<
"\n";
317 using Controls = std::vector<uint8_t>;
318 using ElemType = int;
319 static constexpr ElemType
Ignore = ElemType(-1);
335 unsigned S = Order.size();
339 Table.resize(Order.size());
340 for (RowType &Row : Table)
341 Row.resize(Mult*Log,
None);
344 void getControls(Controls &V,
unsigned StartAt, uint8_t Dir)
const {
345 unsigned Size = Order.size();
347 for (
unsigned I = 0;
I !=
Size; ++
I) {
349 for (
unsigned L = 0;
L != Log; ++
L) {
350 unsigned C = ctl(
I, StartAt+L) == Switch;
361 uint8_t ctl(ElemType Pos,
unsigned Step)
const {
362 return Table[Pos][Step];
364 unsigned size()
const {
367 unsigned steps()
const {
373 std::vector<ElemType> Order;
374 using RowType = std::vector<uint8_t>;
375 std::vector<RowType> Table;
378struct ForwardDeltaNetwork :
public PermNetwork {
381 bool run(Controls &V) {
382 if (!route(Order.data(), Table.data(),
size(), 0))
384 getControls(V, 0, Forward);
389 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
392struct ReverseDeltaNetwork :
public PermNetwork {
395 bool run(Controls &V) {
396 if (!route(Order.data(), Table.data(),
size(), 0))
403 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
406struct BenesNetwork :
public PermNetwork {
409 bool run(Controls &
F, Controls &R) {
410 if (!route(Order.data(), Table.data(),
size(), 0))
413 getControls(
F, 0, Forward);
419 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
423bool ForwardDeltaNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
425 bool UseUp =
false, UseDown =
false;
432 for (ElemType J = 0; J != Num; ++J) {
442 S = (J < Num/2) ? Switch :
Pass;
445 ElemType
U = (S ==
Pass) ?
I : (
I < Num/2 ?
I+Num/2 :
I-Num/2);
450 if (
T[U][Step] != S &&
T[U][Step] !=
None)
455 for (ElemType J = 0; J != Num; ++J)
456 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
460 if (UseUp && !route(
P,
T,
Size/2, Step+1))
468bool ReverseDeltaNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
470 unsigned Pets =
Log-1 - Step;
471 bool UseUp =
false, UseDown =
false;
476 const Coloring::MapType &
M =
G.colors();
480 ColorKind ColorUp = ColorKind::None;
481 for (ElemType J = 0; J != Num; ++J) {
487 ColorKind
C =
M.at(
I);
488 if (
C == ColorKind::None)
493 bool InpUp =
I < Num/2;
494 if (ColorUp == ColorKind::None)
495 ColorUp = InpUp ?
C :
G.other(
C);
496 if ((
C == ColorUp) != InpUp) {
506 S = (J < Num/2) ? Switch :
Pass;
514 for (ElemType J = 0,
E =
Size / 2; J !=
E; ++J) {
516 ElemType PC =
P[J+
Size/2];
519 if (
T[J][Pets] == Switch)
521 if (
T[J+
Size/2][Pets] == Switch)
527 for (ElemType J = 0; J != Num; ++J)
528 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
532 if (UseUp && !route(
P,
T,
Size/2, Step+1))
540bool BenesNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
543 const Coloring::MapType &
M =
G.colors();
548 unsigned Pets = 2*
Log-1 - Step;
549 bool UseUp =
false, UseDown =
false;
554 ColorKind ColorUp = ColorKind::None;
555 for (ElemType J = 0; J != Num; ++J) {
559 ColorKind
C =
M.at(
I);
560 if (
C == ColorKind::None)
562 if (ColorUp == ColorKind::None) {
563 ColorUp = (
I < Num / 2) ? ColorKind::Red : ColorKind::Black;
565 unsigned CI = (
I < Num/2) ?
I+Num/2 :
I-Num/2;
578 T[J][Pets] = (J < Num/2) ? Switch :
Pass;
585 for (ElemType J = 0; J != Num/2; ++J) {
587 ElemType PC =
P[J+Num/2];
590 if (
T[J][Pets] == Switch)
592 if (
T[J+Num/2][Pets] == Switch)
598 for (ElemType J = 0; J != Num; ++J)
599 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
603 if (UseUp && !route(
P,
T,
Size/2, Step+1))
618 bool isValue()
const {
return OpV.
getNode() !=
nullptr; }
621 static OpRef res(
int N) {
return OpRef(Whole | (
N & Index)); }
624 static OpRef
lo(
const OpRef &R) {
626 return OpRef(
R.OpN & (
Undef | Index | LoHalf));
628 static OpRef
hi(
const OpRef &R) {
630 return OpRef(
R.OpN & (
Undef | Index | HiHalf));
632 static OpRef undef(MVT Ty) {
return OpRef(
Undef | Ty.
SimpleTy); }
648 Whole = LoHalf | HiHalf,
655 void print(raw_ostream &OS,
const SelectionDAG &
G)
const;
658 OpRef(
unsigned N) : OpN(
N) {}
662 NodeTemplate() =
default;
665 std::vector<OpRef>
Ops;
671 ResultStack(SDNode *Inp)
675 unsigned push(
const NodeTemplate &Res) {
677 return List.size()-1;
679 unsigned push(
unsigned Opc, MVT Ty, std::vector<OpRef> &&
Ops) {
686 bool empty()
const {
return List.empty(); }
687 unsigned size()
const {
return List.size(); }
688 unsigned top()
const {
return size()-1; }
689 const NodeTemplate &operator[](
unsigned I)
const {
return List[
I]; }
690 unsigned reset(
unsigned NewTop) {
691 List.resize(NewTop+1);
695 using BaseType = std::vector<NodeTemplate>;
696 BaseType::iterator
begin() {
return List.begin(); }
697 BaseType::iterator
end() {
return List.end(); }
698 BaseType::const_iterator
begin()
const {
return List.begin(); }
699 BaseType::const_iterator
end()
const {
return List.end(); }
704 void print(raw_ostream &OS,
const SelectionDAG &
G)
const;
708#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
709void OpRef::print(raw_ostream &OS,
const SelectionDAG &
G)
const {
722 if ((OpN & Whole) != Whole) {
723 assert((OpN & Whole) == LoHalf || (OpN & Whole) == HiHalf);
732void NodeTemplate::print(raw_ostream &OS,
const SelectionDAG &
G)
const {
733 const TargetInstrInfo &
TII = *
G.getSubtarget().getInstrInfo();
734 OS <<
format(
"%8s", EVT(Ty).getEVTString().
c_str()) <<
" "
737 for (
const auto &R :
Ops) {
746void ResultStack::print(raw_ostream &OS,
const SelectionDAG &
G)
const {
747 OS <<
"Input node:\n";
751 OS <<
"Result templates:\n";
752 for (
unsigned I = 0,
E =
List.size();
I !=
E; ++
I) {
753 OS <<
'[' <<
I <<
"] ";
762 ShuffleMask(ArrayRef<int> M) : Mask(
M) {
766 MinSrc = (MinSrc == -1) ? M : std::
min(MinSrc,
M);
767 MaxSrc = (MaxSrc == -1) ?
M : std::max(MaxSrc, M);
772 int MinSrc = -1, MaxSrc = -1;
774 ShuffleMask
lo()
const {
775 size_t H =
Mask.size()/2;
776 return ShuffleMask(
Mask.take_front(
H));
778 ShuffleMask
hi()
const {
779 size_t H =
Mask.size()/2;
780 return ShuffleMask(
Mask.take_back(
H));
783 void print(raw_ostream &OS)
const {
784 OS <<
"MinSrc:" << MinSrc <<
", MaxSrc:" << MaxSrc <<
" {";
792raw_ostream &
operator<<(raw_ostream &OS,
const ShuffleMask &
SM) {
822 for (
int i = 0; i != Len; ++i) {
842 for (
int i = 0; i != Len; ++i) {
853 auto Odd =
static_cast<int>(TakeOdd);
854 for (
int i = 0, e = Len / (2 *
Size); i != e; ++i) {
855 for (
int b = 0; b !=
static_cast<int>(
Size); ++b) {
857 Vd[i *
Size + b] = Vv[(2 * i + Odd) *
Size + b];
858 Vd[i *
Size + b + Len / 2] = Vu[(2 * i + Odd) *
Size + b];
868 auto Odd =
static_cast<int>(TakeOdd);
869 for (
int i = 0, e = Len / (2 *
Size); i != e; ++i) {
870 for (
int b = 0; b !=
static_cast<int>(
Size); ++b) {
871 Vd[(2 * i + 0) *
Size + b] = Vv[(2 * i + Odd) *
Size + b];
872 Vd[(2 * i + 1) *
Size + b] = Vu[(2 * i + Odd) *
Size + b];
887 for (
int i = 0, e = Len / 4; i != e; ++i) {
888 Vd[0 * (Len / 4) + i] = Vv[4 * i + 0];
889 Vd[1 * (Len / 4) + i] = Vv[4 * i + 2];
890 Vd[2 * (Len / 4) + i] = Vu[4 * i + 0];
891 Vd[3 * (Len / 4) + i] = Vu[4 * i + 2];
896template <
typename ShuffFunc,
typename... OptArgs>
899 std::iota(Vu.begin(), Vu.end(),
Length);
901 return S(Vu, Vv,
args...);
929 assert(ElemTy != MVT::i1 &&
"Use getBoolVT for predicates");
930 unsigned NumElems =
HwLen / (ElemTy.getSizeInBits() / 8);
935 assert(ElemTy != MVT::i1);
936 unsigned NumElems = (2 *
HwLen) / (ElemTy.getSizeInBits() / 8);
945 void selectExtractSubvector(
SDNode *
N);
954 static std::optional<int> rotationDistance(ShuffleMask
SM,
unsigned WrapAt);
957 void select(
SDNode *ISelN);
958 void materialize(
const ResultStack &
Results);
968 OpRef concats(OpRef Va, OpRef Vb, ResultStack &
Results);
969 OpRef funnels(OpRef Va, OpRef Vb,
int Amount, ResultStack &
Results);
971 OpRef packs(ShuffleMask
SM, OpRef Va, OpRef Vb, ResultStack &
Results,
973 OpRef packp(ShuffleMask
SM, OpRef Va, OpRef Vb, ResultStack &
Results,
980 OpRef shuffs1(ShuffleMask
SM, OpRef Va, ResultStack &
Results);
981 OpRef shuffs2(ShuffleMask
SM, OpRef Va, OpRef Vb, ResultStack &
Results);
982 OpRef shuffp1(ShuffleMask
SM, OpRef Va, ResultStack &
Results);
983 OpRef shuffp2(ShuffleMask
SM, OpRef Va, OpRef Vb, ResultStack &
Results);
985 OpRef butterfly(ShuffleMask
SM, OpRef Va, ResultStack &
Results);
986 OpRef contracting(ShuffleMask
SM, OpRef Va, OpRef Vb, ResultStack &
Results);
987 OpRef expanding(ShuffleMask
SM, OpRef Va, ResultStack &
Results);
988 OpRef perfect(ShuffleMask
SM, OpRef Va, ResultStack &
Results);
990 bool selectVectorConstants(
SDNode *
N);
998 unsigned VecLen = Mask.size();
1000 for (
unsigned I = 0;
I != VecLen; ++
I) {
1003 MaskL[
I] = MaskR[
I] = -1;
1004 }
else if (
unsigned(M) < VecLen) {
1009 MaskR[
I] = M-VecLen;
1016 assert(
A.size() > 0 &&
A.size() >= MaxLen);
1019 for (
unsigned I = 1;
I != MaxLen; ++
I) {
1020 if (
A[
I] -
E != Inc)
1024 return {
F, MaxLen };
1028 for (
int Idx : Mask)
1035 for (
int I = 0,
E = Mask.size();
I !=
E; ++
I) {
1037 if (M >= 0 && M !=
I)
1044 int L = Mask.size();
1047 return llvm::all_of(Mask.drop_front(L / 2), [](
int M) { return M < 0; });
1054 if (
SM.MaxSrc == -1)
1057 unsigned Shift =
Log2_32(SegLen);
1060 for (
int M :
SM.Mask) {
1062 Segs.
set(M >> Shift);
1080 unsigned MaskLen =
SM.Mask.size();
1081 assert(MaskLen % SegLen == 0);
1084 for (
int S = 0,
E = Map.size(); S !=
E; ++S) {
1086 for (
int I = 0;
I !=
static_cast<int>(SegLen); ++
I) {
1087 int M =
SM.Mask[S*SegLen +
I];
1090 unsigned G = M / SegLen;
1093 }
else if (Idx !=
G) {
1107 for (
int I = OutSegMap.
size() - 1;
I >= 0; --
I) {
1108 unsigned S = OutSegMap[
I];
1109 assert(S != ~0u &&
"Unexpected undef");
1110 assert(S != ~1u &&
"Unexpected multi");
1111 if (InvMap.
size() <= S)
1116 unsigned Shift =
Log2_32(SegLen);
1117 for (
int I = 0,
E = Mask.size();
I !=
E; ++
I) {
1120 int OutIdx = InvMap[M >> Shift];
1121 M = (M & (SegLen-1)) + SegLen*OutIdx;
1127bool HvxSelector::selectVectorConstants(SDNode *
N) {
1133 SetVector<SDNode*> WorkQ;
1138 for (
unsigned i = 0; i != WorkQ.
size(); ++i) {
1139 SDNode *
W = WorkQ[i];
1142 for (
unsigned j = 0, f =
W->getNumOperands(); j != f; ++j)
1143 WorkQ.
insert(
W->getOperand(j).getNode());
1146 for (SDNode *L : Nodes)
1149 return !Nodes.empty();
1152void HvxSelector::materialize(
const ResultStack &
Results) {
1154 dbgs() <<
"Materializing\n";
1159 const SDLoc &dl(
Results.InpNode);
1160 std::vector<SDValue> Output;
1164 std::vector<SDValue>
Ops;
1165 for (
const OpRef &R :
Node.Ops) {
1168 Ops.push_back(
R.OpV);
1171 if (
R.OpN & OpRef::Undef) {
1173 Ops.push_back(ISel.selectUndef(dl, MVT(SVT)));
1177 unsigned Part =
R.OpN & OpRef::Whole;
1178 int Idx =
SignExtend32(
R.OpN & OpRef::Index, OpRef::IndexBits);
1181 assert(Idx >= 0 &&
unsigned(Idx) < Output.size());
1183 MVT OpTy =
Op.getValueType().getSimpleVT();
1184 if (Part != OpRef::Whole) {
1185 assert(Part == OpRef::LoHalf || Part == OpRef::HiHalf);
1188 unsigned Sub = (Part == OpRef::LoHalf) ? Hexagon::vsub_lo
1190 Op = DAG.getTargetExtractSubreg(
Sub, dl, HalfTy,
Op);
1196 SDNode *ResN = (
Node.Opc == TargetOpcode::COPY)
1197 ?
Ops.front().getNode()
1199 Output.push_back(
SDValue(ResN, 0));
1202 SDNode *OutN = Output.back().getNode();
1203 SDNode *InpN =
Results.InpNode;
1205 dbgs() <<
"Generated node:\n";
1209 ISel.ReplaceNode(InpN, OutN);
1210 selectVectorConstants(OutN);
1211 DAG.RemoveDeadNodes();
1214OpRef HvxSelector::concats(OpRef
Lo, OpRef
Hi, ResultStack &
Results) {
1216 const SDLoc &dl(
Results.InpNode);
1217 Results.push(TargetOpcode::REG_SEQUENCE, getPairVT(MVT::i8), {
1218 getConst32(Hexagon::HvxWRRegClassID, dl),
1219 Lo, getConst32(Hexagon::vsub_lo, dl),
1220 Hi, getConst32(Hexagon::vsub_hi, dl),
1222 return OpRef::res(
Results.top());
1225OpRef HvxSelector::funnels(OpRef Va, OpRef Vb,
int Amount,
1230 auto VecLen =
static_cast<int>(HwLen);
1234 if (Amount == VecLen)
1237 MVT Ty = getSingleVT(MVT::i8);
1238 const SDLoc &dl(
Results.InpNode);
1242 if (Amount > VecLen) {
1248 SDValue A = getConst32(Amount, dl);
1249 Results.push(Hexagon::V6_valignbi, Ty, {Vb, Va,
A});
1250 }
else if (
isUInt<3>(VecLen - Amount)) {
1251 SDValue A = getConst32(VecLen - Amount, dl);
1252 Results.push(Hexagon::V6_vlalignbi, Ty, {Vb, Va,
A});
1254 SDValue A = getConst32(Amount, dl);
1255 Results.push(Hexagon::A2_tfrsi, Ty, {
A});
1256 Results.push(Hexagon::V6_valignb, Ty, {Vb, Va, OpRef::res(-1)});
1258 return OpRef::res(
Results.top());
1264OpRef HvxSelector::packs(ShuffleMask
SM, OpRef Va, OpRef Vb,
1268 if (!Va.isValid() || !Vb.isValid())
1269 return OpRef::fail();
1281 MVT Ty = getSingleVT(MVT::i8);
1282 MVT
PairTy = getPairVT(MVT::i8);
1283 OpRef Inp[2] = {Va, Vb};
1284 unsigned VecLen =
SM.Mask.size();
1286 auto valign = [
this](OpRef
Lo, OpRef
Hi,
unsigned Amt, MVT Ty,
1290 const SDLoc &dl(
Results.InpNode);
1293 SDValue S = getConst32(IsRight ? Amt : HwLen - Amt, dl);
1294 unsigned Opc = IsRight ? Hexagon::V6_valignbi : Hexagon::V6_vlalignbi;
1296 return OpRef::res(
Results.top());
1298 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(Amt, dl)});
1299 OpRef
A = OpRef::res(
Results.top());
1301 return OpRef::res(
Results.top());
1305 unsigned SegLen = HwLen / 2;
1311 unsigned SegCount = SegList.
size();
1314 if (SegList.
empty())
1315 return OpRef::undef(Ty);
1333 unsigned Seg0 = ~0
u, Seg1 = ~0
u;
1334 for (
unsigned X : SegMap) {
1339 else if (Seg1 != ~0u)
1341 if (
X == ~1u ||
X != Seg0)
1345 if (SegCount == 1) {
1346 unsigned SrcOp = SegList[0] / 2;
1347 for (
int I = 0;
I !=
static_cast<int>(VecLen); ++
I) {
1358 if (SegCount == 2) {
1365 if (Seg0 == ~1u || Seg1 == ~1u) {
1369 }
else if (Seg0 == ~1u) {
1370 Seg0 = SegList[0] != Seg1 ? SegList[0] : SegList[1];
1373 Seg1 = SegList[0] != Seg0 ? SegList[0] : SegList[1];
1376 assert(Seg0 != ~1u && Seg1 != ~1u);
1378 assert(Seg0 != Seg1 &&
"Expecting different segments");
1379 const SDLoc &dl(
Results.InpNode);
1380 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(SegLen, dl)});
1381 OpRef HL = OpRef::res(
Results.top());
1385 if (Seg0 / 2 == Seg1 / 2) {
1390 Results.push(Hexagon::V6_vror, Ty, {Inp[Seg0 / 2], HL});
1391 Va = OpRef::res(
Results.top());
1394 }
else if (Seg0 % 2 == Seg1 % 2) {
1398 auto Vs = (Seg0 == 0 || Seg0 == 1) ? std::make_pair(Vb, Va)
1399 : std::make_pair(Va, Vb);
1400 Results.push(Hexagon::V6_vshuffvdd,
PairTy, {Vs.first, Vs.second, HL});
1401 OpRef
P = OpRef::res(
Results.top());
1402 Va = (Seg0 == 0 || Seg0 == 2) ? OpRef::lo(
P) : OpRef::hi(
P);
1406 if ((Seg0 == 0 && Seg1 == 3) || (Seg0 == 2 && Seg1 == 1)) {
1410 Results.push(Hexagon::V6_pred_scalar2, getBoolVT(), {HL});
1411 OpRef Qt = OpRef::res(
Results.top());
1412 auto Vs = (Seg0 == 0) ? std::make_pair(Va, Vb)
1413 : std::make_pair(Vb, Va);
1414 Results.push(Hexagon::V6_vmux, Ty, {Qt, Vs.first, Vs.second});
1415 Va = OpRef::res(
Results.top());
1421 assert(Seg0 == 1 || Seg0 == 3);
1428 ShuffleMask SMH(MaskH);
1429 assert(SMH.Mask.size() == VecLen);
1432 if (SMH.MaxSrc - SMH.MinSrc >=
static_cast<int>(HwLen)) {
1436 ShuffleMask SW(Swapped);
1437 if (SW.MaxSrc - SW.MinSrc <
static_cast<int>(HwLen)) {
1438 MaskA.assign(SW.Mask.begin(), SW.Mask.end());
1442 ShuffleMask
SMA(MaskA);
1445 if (
SMA.MaxSrc -
SMA.MinSrc <
static_cast<int>(HwLen)) {
1446 int ShiftR =
SMA.MinSrc;
1447 if (ShiftR >=
static_cast<int>(HwLen)) {
1449 Vb = OpRef::undef(Ty);
1452 OpRef RetVal = valign(Va, Vb, ShiftR, Ty,
Results);
1454 for (
int I = 0;
I !=
static_cast<int>(VecLen); ++
I) {
1455 int M =
SMA.Mask[
I];
1471 BitVector Picked(HwLen);
1472 SmallVector<uint8_t,128> MuxBytes(HwLen);
1474 for (
int I = 0;
I !=
static_cast<int>(VecLen); ++
I) {
1478 if (M >=
static_cast<int>(HwLen))
1489 return vmuxs(MuxBytes, Va, Vb,
Results);
1491 return OpRef::fail();
1497OpRef HvxSelector::packp(ShuffleMask
SM, OpRef Va, OpRef Vb,
1501 if (SegList.empty())
1502 return OpRef::undef(getPairVT(MVT::i8));
1506 unsigned SegCount = SegList.size();
1508 return OpRef::fail();
1510 MVT HalfTy = getSingleVT(MVT::i8);
1512 OpRef Inp[2] = { Va, Vb };
1513 OpRef Out[2] = { OpRef::undef(HalfTy), OpRef::undef(HalfTy) };
1518 for (
int I = 0,
E = SegList.size();
I !=
E; ++
I) {
1519 unsigned S = SegList[
I];
1520 OpRef
Op = Inp[S / 2];
1521 Out[
I] = (S & 1) ? OpRef::hi(
Op) : OpRef::lo(
Op);
1531 return concats(Out[0], Out[1],
Results);
1534OpRef HvxSelector::vmuxs(ArrayRef<uint8_t> Bytes, OpRef Va, OpRef Vb,
1537 MVT ByteTy = getSingleVT(MVT::i8);
1539 const SDLoc &dl(
Results.InpNode);
1540 SDValue B = getVectorConstant(Bytes, dl);
1541 Results.push(Hexagon::V6_vd0, ByteTy, {});
1542 Results.push(Hexagon::V6_veqb, BoolTy, {OpRef(
B), OpRef::res(-1)});
1543 Results.push(Hexagon::V6_vmux, ByteTy, {OpRef::res(-1), Vb, Va});
1544 return OpRef::res(
Results.top());
1547OpRef HvxSelector::vmuxp(ArrayRef<uint8_t> Bytes, OpRef Va, OpRef Vb,
1550 size_t S = Bytes.
size() / 2;
1556OpRef HvxSelector::shuffs1(ShuffleMask
SM, OpRef Va, ResultStack &
Results) {
1558 unsigned VecLen =
SM.Mask.size();
1561 assert(
all_of(
SM.Mask, [
this](
int M) { return M == -1 || M < int(HwLen); }));
1566 return OpRef::undef(getSingleVT(MVT::i8));
1569 if (
auto Dist = rotationDistance(
SM, VecLen)) {
1570 OpRef Rotate = funnels(Va, Va, *Dist,
Results);
1571 if (Rotate.isValid())
1574 unsigned HalfLen = HwLen / 2;
1579 std::pair<int, unsigned> Strip1 =
findStrip(
SM.Mask, 1, HalfLen);
1580 if ((Strip1.first & ~HalfLen) == 0 && Strip1.second == HalfLen) {
1581 std::pair<int, unsigned> Strip2 =
1582 findStrip(
SM.Mask.drop_front(HalfLen), 1, HalfLen);
1583 if (Strip1 == Strip2) {
1584 const SDLoc &dl(
Results.InpNode);
1585 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(HalfLen, dl)});
1586 Results.push(Hexagon::V6_vshuffvdd, getPairVT(MVT::i8),
1587 {Va, Va, OpRef::res(
Results.top())});
1588 OpRef S = OpRef::res(
Results.top());
1589 return (Strip1.first == 0) ? OpRef::lo(S) : OpRef::
hi(S);
1599OpRef HvxSelector::shuffs2(ShuffleMask
SM, OpRef Va, OpRef Vb,
1603 return OpRef::undef(getSingleVT(MVT::i8));
1609 int VecLen =
SM.Mask.size();
1611 OpRef
P = packs(
SM, Va, Vb,
Results, PackedMask);
1613 return shuffs1(ShuffleMask(PackedMask),
P,
Results);
1621 OpRef
L = shuffs1(ShuffleMask(MaskL), Va,
Results);
1622 OpRef
R = shuffs1(ShuffleMask(MaskR), Vb,
Results);
1623 if (!
L.isValid() || !
R.isValid())
1624 return OpRef::fail();
1626 SmallVector<uint8_t, 128> Bytes(VecLen);
1627 for (
int I = 0;
I != VecLen; ++
I) {
1631 return vmuxs(Bytes, L, R,
Results);
1634OpRef HvxSelector::shuffp1(ShuffleMask
SM, OpRef Va, ResultStack &
Results) {
1636 int VecLen =
SM.Mask.size();
1641 return OpRef::undef(getPairVT(MVT::i8));
1644 OpRef
P = packs(
SM, OpRef::lo(Va), OpRef::hi(Va),
Results, PackedMask);
1646 ShuffleMask PM(PackedMask);
1653 if (
L.isValid() &&
H.isValid())
1669 OpRef
L = shuffs2(
SM.lo(), OpRef::lo(Va), OpRef::hi(Va),
Results);
1670 OpRef
H = shuffs2(
SM.hi(), OpRef::lo(Va), OpRef::hi(Va),
Results);
1671 if (
L.isValid() &&
H.isValid())
1674 return OpRef::fail();
1677OpRef HvxSelector::shuffp2(ShuffleMask
SM, OpRef Va, OpRef Vb,
1681 return OpRef::undef(getPairVT(MVT::i8));
1683 int VecLen =
SM.Mask.size();
1685 OpRef
P = packp(
SM, Va, Vb,
Results, PackedMask);
1687 return shuffp1(ShuffleMask(PackedMask),
P,
Results);
1692 OpRef
L = shuffp1(ShuffleMask(MaskL), Va,
Results);
1693 OpRef
R = shuffp1(ShuffleMask(MaskR), Vb,
Results);
1694 if (!
L.isValid() || !
R.isValid())
1695 return OpRef::fail();
1699 for (
int I = 0;
I != VecLen; ++
I) {
1703 return vmuxp(Bytes, L, R,
Results);
1707 struct Deleter :
public SelectionDAG::DAGNodeDeletedListener {
1708 template <
typename T>
1709 Deleter(SelectionDAG &
D,
T &
C)
1710 : SelectionDAG::DAGNodeDeletedListener(
D, [&
C] (SDNode *
N, SDNode *
E) {
1715 template <
typename T>
1716 struct NullifyingVector :
public T {
1717 DenseMap<SDNode*, SDNode**> Refs;
1718 NullifyingVector(
T &&V) :
T(
V) {
1719 for (
unsigned i = 0, e = T::size(); i !=
e; ++i) {
1720 SDNode *&
N = T::operator[](i);
1726 if (
F != Refs.
end())
1727 *
F->second =
nullptr;
1732void HvxSelector::select(SDNode *ISelN) {
1749 DAG.RemoveDeadNodes();
1751 SetVector<SDNode *> SubNodes;
1760 if (SubNodes.
empty()) {
1761 ISel.ReplaceNode(ISelN, N0);
1768 SetVector<SDNode*> Dom, NonDom;
1771 auto IsDomRec = [&Dom, &NonDom] (SDNode *
T,
auto Rec) ->
bool {
1774 if (
T->use_empty() || NonDom.
count(
T))
1776 for (SDNode *U :
T->users()) {
1788 auto IsDom = [&IsDomRec] (SDNode *
T) {
return IsDomRec(
T, IsDomRec); };
1791 for (
unsigned I = 0;
I != SubNodes.
size(); ++
I) {
1793 SDNode *
O =
Op.getNode();
1800 SetVector<SDNode*> TmpQ;
1802 std::map<SDNode *, unsigned> OpCount;
1803 for (SDNode *
T : Dom) {
1804 unsigned NumDomOps =
llvm::count_if(
T->ops(), [&Dom](
const SDUse &U) {
1805 return Dom.count(U.getNode());
1808 OpCount.insert({
T, NumDomOps});
1813 for (
unsigned I = 0;
I != TmpQ.
size(); ++
I) {
1814 SDNode *S = TmpQ[
I];
1815 for (SDNode *U : S->
users()) {
1818 auto F = OpCount.find(U);
1820 if (
F->second > 0 && !--
F->second)
1826 ISel.ReplaceNode(ISelN, N0);
1829 NullifyingVector<
decltype(TmpQ)::vector_type>
Queue(TmpQ.
takeVector());
1831 Deleter DUQ(DAG, Queue);
1832 for (SDNode *S :
reverse(Queue)) {
1840bool HvxSelector::scalarizeShuffle(ArrayRef<int> Mask,
const SDLoc &dl,
1845 assert(ElemTy == MVT::i8);
1846 unsigned VecLen =
Mask.size();
1847 bool HavePairs = (2*HwLen == VecLen);
1848 MVT SingleTy = getSingleVT(MVT::i8);
1864 LLVMContext &Ctx = *DAG.getContext();
1865 MVT LegalTy =
Lower.getTypeToTransformTo(Ctx, ElemTy).getSimpleVT();
1866 for (
int I : Mask) {
1868 Ops.push_back(ISel.selectUndef(dl, LegalTy));
1881 Vec = DAG.getTargetExtractSubreg(Hexagon::vsub_lo, dl, SingleTy, Vec);
1883 Vec = DAG.getTargetExtractSubreg(Hexagon::vsub_hi, dl, SingleTy, Vec);
1887 SDValue Idx = DAG.getConstant(M, dl, MVT::i32);
1895 if (2*HwLen == VecLen) {
1896 SDValue B0 = DAG.getBuildVector(SingleTy, dl, {
Ops.data(), HwLen});
1898 SDValue B1 = DAG.getBuildVector(SingleTy, dl, {
Ops.data()+HwLen, HwLen});
1906 SDValue BV = DAG.getBuildVector(ResTy, dl,
Ops);
1907 LV =
Lower.LowerOperation(BV, DAG);
1914 DAG.RemoveDeadNodes();
1921 unsigned Impossible = ~(1u << Width) + 1;
1922 for (
unsigned I = 0, E = Bs.
size();
I != E; ++
I) {
1926 if (~Impossible == 0)
1928 for (
unsigned Log = 0; Log != Width; ++Log) {
1929 if (Impossible & (1u << Log))
1933 Impossible |= (1u << Log);
1941 for (
unsigned BitIdx = 0; BitIdx != Width; ++BitIdx) {
1943 for (
int i = 0, e =
SM.Mask.size(); i != e; ++i) {
1946 BitValues[i] = 0xff;
1948 BitValues[i] = (M & (1u << BitIdx)) != 0;
1950 Worklist[BitIdx] = possibilities(BitValues, Width);
1992 for (
unsigned I = 0, E = Sorted.
size();
I != E;) {
1993 unsigned P = Sorted[
I],
Count = 1;
1994 while (++
I != E &&
P == Sorted[
I])
2012 for (
unsigned I = 0;
I != Width; ++
I) {
2020 for (
unsigned J =
I + 1; J != Width; ++J) {
2034 assert(OrAll == (1u << Width) -1);
2042 std::optional<int> Dist;
2043 for (
int I = 0, E =
SM.Mask.size();
I != E; ++
I) {
2048 if ((
I + *Dist) %
static_cast<int>(WrapAt) != M)
2049 return std::nullopt;
2056 Dist = *Dist + WrapAt;
2062OpRef HvxSelector::contracting(ShuffleMask
SM, OpRef Va, OpRef Vb,
2065 if (!Va.isValid() || !Vb.isValid())
2066 return OpRef::fail();
2077 int VecLen =
SM.Mask.size();
2080 if (
auto Dist = rotationDistance(
SM, 2 * VecLen)) {
2081 OpRef Funnel = funnels(Va, Vb, *Dist,
Results);
2082 if (Funnel.isValid())
2086 MVT SingleTy = getSingleVT(MVT::i8);
2087 MVT
PairTy = getPairVT(MVT::i8);
2089 auto same = [](ArrayRef<int> Mask1, ArrayRef<int> Mask2) ->
bool {
2090 return Mask1 == Mask2;
2093 using PackConfig = std::pair<unsigned, bool>;
2094 PackConfig Packs[] = {
2102 unsigned Opcodes[] = {
2103 Hexagon::V6_vpackeb,
2104 Hexagon::V6_vpackob,
2105 Hexagon::V6_vpackeh,
2106 Hexagon::V6_vpackoh,
2108 for (
int i = 0, e = std::size(Opcodes); i !=
e; ++i) {
2109 auto [
Size, Odd] = Packs[i];
2111 Results.push(Opcodes[i], SingleTy, {Vb, Va});
2112 return OpRef::res(
Results.top());
2118 unsigned Opcodes[] = {
2119 Hexagon::V6_vshuffeb,
2120 Hexagon::V6_vshuffob,
2121 Hexagon::V6_vshufeh,
2122 Hexagon::V6_vshufoh,
2124 for (
int i = 0, e = std::size(Opcodes); i !=
e; ++i) {
2125 auto [
Size, Odd] = Packs[i];
2127 Results.push(Opcodes[i], SingleTy, {Vb, Va});
2128 return OpRef::res(
Results.top());
2137 unsigned Opcodes[] = {
2138 Hexagon::V6_vpackeb,
2139 Hexagon::V6_vpackob,
2140 Hexagon::V6_vpackeh,
2141 Hexagon::V6_vpackoh,
2143 const SDLoc &dl(
Results.InpNode);
2145 for (
int i = 0, e = std::size(Opcodes); i !=
e; ++i) {
2146 auto [
Size, Odd] = Packs[i];
2148 Results.push(Hexagon::A2_tfrsi, MVT::i32,
2149 {getSignedConst32(-2 *
Size, dl)});
2150 Results.push(Hexagon::V6_vdealvdd,
PairTy, {Vb, Va, OpRef::res(-1)});
2152 Results.push(Opcodes[i], SingleTy,
2153 {OpRef::hi(vdeal), OpRef::lo(vdeal)});
2154 return OpRef::res(
Results.top());
2160 Results.push(Hexagon::V6_vdealb4w, SingleTy, {Vb, Va});
2161 return OpRef::res(
Results.top());
2164 return OpRef::fail();
2167OpRef HvxSelector::expanding(ShuffleMask
SM, OpRef Va, ResultStack &
Results) {
2180 int VecLen =
SM.Mask.size();
2181 assert(2*HwLen ==
unsigned(VecLen) &&
"Expecting vector-pair type");
2183 std::pair<int,unsigned> Strip =
findStrip(
SM.Mask, 1, VecLen);
2190 if (Strip.first != 0)
2191 return OpRef::fail();
2194 if (Strip.second != 1 && Strip.second != 2)
2195 return OpRef::fail();
2198 int L = Strip.second;
2201 for (
int I = 2*L;
I <
N;
I += 2*
L) {
2203 if (S.second !=
unsigned(L))
2204 return OpRef::fail();
2206 return OpRef::fail();
2209 for (
int I = L;
I <
N;
I += 2*
L) {
2211 if (S.first != -1 || S.second !=
unsigned(L))
2212 return OpRef::fail();
2215 unsigned Opc = Strip.second == 1 ? Hexagon::V6_vunpackub
2216 : Hexagon::V6_vunpackuh;
2218 return OpRef::res(
Results.top());
2221OpRef HvxSelector::perfect(ShuffleMask
SM, OpRef Va, ResultStack &
Results) {
2230 int VecLen =
SM.Mask.size();
2232 unsigned LogLen =
Log2_32(VecLen);
2233 unsigned HwLog =
Log2_32(HwLen);
2236 assert(LogLen == HwLog || LogLen == HwLog + 1);
2237 bool HavePairs = LogLen == HwLog + 1;
2239 SmallVector<unsigned, 8> Perm(LogLen);
2323 bool InvertedPair =
false;
2324 if (HavePairs &&
SM.Mask[0] >=
int(HwLen)) {
2325 for (
int i = 0, e =
SM.Mask.size(); i != e; ++i) {
2327 MaskStorage[i] =
M >= int(HwLen) ?
M - HwLen :
M + HwLen;
2329 InvertedPair =
true;
2330 SM = ShuffleMask(MaskStorage);
2333 auto Comps = getPerfectCompletions(
SM, LogLen);
2335 return OpRef::fail();
2337 auto Pick = completeToPerfect(Comps, LogLen);
2338 for (
unsigned I = 0;
I != LogLen; ++
I)
2366 using CycleType = SmallVector<unsigned, 8>;
2367 std::set<CycleType> Cycles;
2368 std::set<unsigned>
All;
2370 for (
unsigned I : Perm)
2375 auto canonicalize = [LogLen](
const CycleType &
C) -> CycleType {
2376 unsigned LogPos,
N =
C.size();
2377 for (LogPos = 0; LogPos !=
N; ++LogPos)
2378 if (
C[LogPos] == LogLen - 1)
2383 CycleType NewC(
C.begin() + LogPos,
C.end());
2384 NewC.append(
C.begin(),
C.begin() + LogPos);
2388 auto pfs = [](
const std::set<CycleType> &Cs,
unsigned Len) {
2393 const CycleType &
C = *Cs.begin();
2394 if (
C[0] != Len - 1)
2396 int D =
Len -
C.size();
2397 if (
D != 0 &&
D != 1)
2400 bool IsDeal =
true, IsShuff =
true;
2401 for (
unsigned I = 1;
I !=
Len -
D; ++
I) {
2402 if (
C[
I] != Len - 1 -
I)
2404 if (
C[
I] !=
I - (1 -
D))
2408 assert(!(IsDeal || IsShuff) || IsDeal != IsShuff);
2409 static unsigned Deals[] = {Hexagon::V6_vdealb, Hexagon::V6_vdealh};
2410 static unsigned Shufs[] = {Hexagon::V6_vshuffb, Hexagon::V6_vshuffh};
2411 return IsDeal ? Deals[
D] : (IsShuff ? Shufs[
D] : 0);
2414 while (!
All.empty()) {
2415 unsigned A = *
All.begin();
2419 for (
unsigned B = Perm[
A];
B !=
A;
B = Perm[
B]) {
2425 Cycles.insert(canonicalize(
C));
2428 MVT SingleTy = getSingleVT(MVT::i8);
2429 MVT
PairTy = getPairVT(MVT::i8);
2432 if (
unsigned(VecLen) == HwLen) {
2433 if (
unsigned SingleOpc = pfs(Cycles, LogLen)) {
2434 Results.push(SingleOpc, SingleTy, {Va});
2435 return OpRef::res(
Results.top());
2445 SmallVector<unsigned, 8> SwapElems;
2458 for (
const CycleType &
C : Cycles) {
2460 unsigned First = (
C[0] == LogLen - 1) ? 1 : 0;
2468 const SDLoc &dl(
Results.InpNode);
2469 OpRef Arg = HavePairs ? Va : concats(Va, OpRef::undef(SingleTy),
Results);
2471 Arg = concats(OpRef::hi(Arg), OpRef::lo(Arg),
Results);
2473 for (
unsigned I = 0,
E = SwapElems.
size();
I !=
E;) {
2474 bool IsInc =
I ==
E - 1 || SwapElems[
I] < SwapElems[
I + 1];
2475 unsigned S = (1u << SwapElems[
I]);
2477 while (++
I <
E - 1 && IsInc == (SwapElems[
I] < SwapElems[
I + 1]))
2478 S |= 1u << SwapElems[
I];
2481 S |= 1u << SwapElems[
I];
2493 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getSignedConst32(SS, dl)});
2494 Res.Opc = IsInc ? Hexagon::V6_vshuffvdd : Hexagon::V6_vdealvdd;
2496 Res.Ops = {OpRef::hi(Arg), OpRef::lo(Arg), OpRef::res(-1)};
2498 Arg = OpRef::res(
Results.top());
2501 return HavePairs ? Arg : OpRef::lo(Arg);
2504OpRef HvxSelector::butterfly(ShuffleMask
SM, OpRef Va, ResultStack &
Results) {
2516 MVT ResTy = getSingleVT(MVT::i8);
2517 PermNetwork::Controls
FC, RC;
2518 const SDLoc &dl(
Results.InpNode);
2519 int VecLen =
SM.Mask.size();
2521 for (
int M :
SM.Mask) {
2522 if (M != -1 && M >= VecLen)
2523 return OpRef::fail();
2527 ForwardDeltaNetwork FN(
SM.Mask);
2529 SDValue Ctl = getVectorConstant(FC, dl);
2530 Results.push(Hexagon::V6_vdelta, ResTy, {Va, OpRef(Ctl)});
2531 return OpRef::res(
Results.top());
2535 ReverseDeltaNetwork
RN(
SM.Mask);
2537 SDValue Ctl = getVectorConstant(RC, dl);
2538 Results.push(Hexagon::V6_vrdelta, ResTy, {Va, OpRef(Ctl)});
2539 return OpRef::res(
Results.top());
2543 BenesNetwork BN(
SM.Mask);
2544 if (BN.run(FC, RC)) {
2545 SDValue CtlF = getVectorConstant(FC, dl);
2546 SDValue CtlR = getVectorConstant(RC, dl);
2547 Results.push(Hexagon::V6_vdelta, ResTy, {Va, OpRef(CtlF)});
2548 Results.push(Hexagon::V6_vrdelta, ResTy,
2549 {OpRef::res(-1), OpRef(CtlR)});
2550 return OpRef::res(
Results.top());
2553 return OpRef::fail();
2556SDValue HvxSelector::getConst32(
unsigned Val,
const SDLoc &dl) {
2557 return DAG.getTargetConstant(Val, dl, MVT::i32);
2560SDValue HvxSelector::getSignedConst32(
int Val,
const SDLoc &dl) {
2561 return DAG.getSignedTargetConstant(Val, dl, MVT::i32);
2564SDValue HvxSelector::getVectorConstant(ArrayRef<uint8_t>
Data,
2567 for (uint8_t
C :
Data)
2568 Elems.
push_back(DAG.getConstant(
C, dl, MVT::i8));
2570 SDValue BV = DAG.getBuildVector(VecTy, dl, Elems);
2572 DAG.RemoveDeadNode(BV.
getNode());
2578 MVT ResTy =
N->getValueType(0).getSimpleVT();
2579 unsigned Idx =
N->getConstantOperandVal(1);
2585 assert(Idx == 0 || Idx == ResLen);
2587 unsigned SubReg = Idx == 0 ? Hexagon::vsub_lo : Hexagon::vsub_hi;
2595 dbgs() <<
"Starting " << __func__ <<
" on node:\n";
2598 MVT ResTy =
N->getValueType(0).getSimpleVT();
2600 assert(ResTy.isVectorOf(MVT::i8));
2603 std::vector<int> Mask(SN->getMask().begin(), SN->getMask().end());
2605 for (
int &Idx : Mask)
2606 if (Idx != -1 && Idx < 0)
2609 unsigned VecLen = Mask.size();
2610 bool HavePairs = (2*
HwLen == VecLen);
2611 assert(ResTy.getSizeInBits() / 8 == VecLen);
2616 bool UseLeft =
false, UseRight =
false;
2617 for (
unsigned I = 0;
I != VecLen; ++
I) {
2620 unsigned Idx = Mask[
I];
2629 dbgs() <<
"VecLen=" << VecLen <<
" HwLen=" <<
HwLen <<
" UseLeft="
2630 << UseLeft <<
" UseRight=" << UseRight <<
" HavePairs="
2631 << HavePairs <<
'\n';
2634 if (!UseLeft && !UseRight) {
2644 OpRef Va = OpRef::undef(ResTy);
2645 OpRef Vb = OpRef::undef(ResTy);
2648 Results.push(TargetOpcode::COPY, ResTy, {Vec0});
2649 Va = OpRef::OpRef::res(
Results.top());
2652 Results.push(TargetOpcode::COPY, ResTy, {Vec1});
2653 Vb = OpRef::res(
Results.top());
2656 OpRef Res = !HavePairs ? shuffs2(ShuffleMask(Mask), Va, Vb,
Results)
2657 : shuffp2(ShuffleMask(Mask), Va, Vb,
Results);
2659 bool Done = Res.isValid();
2662 Results.push(TargetOpcode::COPY, ResTy, {Res});
2665 Done = scalarizeShuffle(Mask,
SDLoc(
N), ResTy, Vec0, Vec1,
N);
2670 dbgs() <<
"Unhandled shuffle:\n";
2679 MVT Ty =
N->getValueType(0).getSimpleVT();
2686 unsigned S = CN->getZExtValue() %
HST.getVectorLength();
2690 NewN =
DAG.getMachineNode(Hexagon::V6_valignbi, dl, Ty,
2691 {VecV, VecV, getConst32(S, dl)});
2696 NewN =
DAG.getMachineNode(Hexagon::V6_vror, dl, Ty, {VecV, RotV});
2698 ISel.ReplaceNode(
N, NewN);
2706 N->getValueType(0), {Vv, Vu, Rt});
2707 ISel.ReplaceNode(
N, NewN);
2708 DAG.RemoveDeadNode(
N);
2711void HexagonDAGToDAGISel::PreprocessHvxISelDAG() {
2712 auto getNodes = [
this]() -> std::vector<SDNode *> {
2713 std::vector<SDNode *>
T;
2714 T.reserve(CurDAG->allnodes_size());
2715 for (
SDNode &
N : CurDAG->allnodes())
2720 ppHvxShuffleOfShuffle(getNodes());
2725 return std::hash<const void *>()(V.getNode()) +
2726 std::hash<unsigned>()(V.getResNo());
2730void HexagonDAGToDAGISel::ppHvxShuffleOfShuffle(std::vector<SDNode *> &&Nodes) {
2741 unsigned HwLen = HST->getVectorLength();
2743 struct SubVectorInfo {
2744 SubVectorInfo(
SDValue S,
unsigned H) : Src(S), HalfIdx(
H) {}
2749 using MapType = DenseMap<SDValue, unsigned>;
2751 auto getMaskElt = [&](
unsigned Idx, ShuffleVectorSDNode *Shuff0,
2752 ShuffleVectorSDNode *Shuff1,
2753 const MapType &OpMap) ->
int {
2760 ShuffleVectorSDNode *OpShuff = Idx < HwLen ? Shuff0 : Shuff1;
2769 auto N =
static_cast<unsigned>(MaybeN);
2770 unsigned SrcBase =
N < HwLen ? OpMap.at(OpShuff->
getOperand(0))
2783 ArrayRef<int> TopMask =
This->getMask();
2786 assert(TopMask.
size() == S0->getMask().size() &&
2787 TopMask.
size() ==
S1->getMask().size());
2791 for (
unsigned I = 0;
I != HwLen; ++
I) {
2792 int MaybeM = TopMask[
I];
2795 getMaskElt(
static_cast<unsigned>(MaybeM), S0,
S1, OpMap);
2801 std::fill(FoldedMask.begin() + HwLen, FoldedMask.end(), -1);
2806 const SDLoc &dl(TopShuff);
2816 auto getSourceInfo = [](
SDValue V) -> std::optional<SubVectorInfo> {
2818 V =
V.getOperand(0);
2820 return std::nullopt;
2821 return SubVectorInfo(
V.getOperand(0),
2825 for (SDNode *
N : Nodes) {
2828 EVT ResTy =
N->getValueType(0);
2846 if (!V0A.has_value())
2849 if (!V0B.has_value() || V0B->Src != V0A->Src)
2851 auto V1A = getSourceInfo(
V1.getOperand(0));
2852 if (!V1A.has_value() || V1A->Src != V0A->Src)
2854 auto V1B = getSourceInfo(
V1.getOperand(1));
2855 if (!V1B.has_value() || V1B->Src != V0A->Src)
2860 assert(V0A->Src.getValueType().getSizeInBits() == 16 * HwLen);
2865 {
V1.getOperand(0), V1A->HalfIdx * HwLen},
2866 {
V1.getOperand(1), V1B->HalfIdx * HwLen},
2873void HexagonDAGToDAGISel::SelectHvxExtractSubvector(SDNode *
N) {
2874 HvxSelector(*
this, *CurDAG).selectExtractSubvector(
N);
2877void HexagonDAGToDAGISel::SelectHvxShuffle(SDNode *
N) {
2878 HvxSelector(*
this, *CurDAG).selectShuffle(
N);
2881void HexagonDAGToDAGISel::SelectHvxRor(SDNode *
N) {
2882 HvxSelector(*
this, *CurDAG).selectRor(
N);
2885void HexagonDAGToDAGISel::SelectHvxVAlign(SDNode *
N) {
2886 HvxSelector(*
this, *CurDAG).selectVAlign(
N);
2893 SDValue Predicate =
N->getOperand(3);
2895 SDValue Modifier =
N->getOperand(5);
2897 SDValue ImmOperand =
CurDAG->getTargetConstant(0, dl, MVT::i32);
2900 unsigned IntNo =
N->getConstantOperandVal(1);
2904 case Intrinsic::hexagon_V6_vgathermhq:
2905 case Intrinsic::hexagon_V6_vgathermhq_128B:
2906 Opcode = Hexagon::V6_vgathermhq_pseudo;
2908 case Intrinsic::hexagon_V6_vgathermwq:
2909 case Intrinsic::hexagon_V6_vgathermwq_128B:
2910 Opcode = Hexagon::V6_vgathermwq_pseudo;
2912 case Intrinsic::hexagon_V6_vgathermhwq:
2913 case Intrinsic::hexagon_V6_vgathermhwq_128B:
2914 Opcode = Hexagon::V6_vgathermhwq_pseudo;
2934 SDValue Modifier =
N->getOperand(4);
2936 SDValue ImmOperand =
CurDAG->getTargetConstant(0, dl, MVT::i32);
2939 unsigned IntNo =
N->getConstantOperandVal(1);
2943 case Intrinsic::hexagon_V6_vgathermh:
2944 case Intrinsic::hexagon_V6_vgathermh_128B:
2945 Opcode = Hexagon::V6_vgathermh_pseudo;
2947 case Intrinsic::hexagon_V6_vgathermw:
2948 case Intrinsic::hexagon_V6_vgathermw_128B:
2949 Opcode = Hexagon::V6_vgathermw_pseudo;
2951 case Intrinsic::hexagon_V6_vgathermhw:
2952 case Intrinsic::hexagon_V6_vgathermhw_128B:
2953 Opcode = Hexagon::V6_vgathermhw_pseudo;
2955 case Intrinsic::hexagon_V6_vgather_vscattermh:
2956 case Intrinsic::hexagon_V6_vgather_vscattermh_128B:
2957 Opcode = Hexagon::V6_vgather_vscatter_mh_pseudo;
2972 unsigned IID =
N->getConstantOperandVal(0);
2975 case Intrinsic::hexagon_V6_vaddcarry: {
2976 std::array<SDValue, 3>
Ops = {
2977 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2979 Result =
CurDAG->getMachineNode(Hexagon::V6_vaddcarry,
SDLoc(
N), VTs,
Ops);
2982 case Intrinsic::hexagon_V6_vaddcarry_128B: {
2983 std::array<SDValue, 3>
Ops = {
2984 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2986 Result =
CurDAG->getMachineNode(Hexagon::V6_vaddcarry,
SDLoc(
N), VTs,
Ops);
2989 case Intrinsic::hexagon_V6_vsubcarry: {
2990 std::array<SDValue, 3>
Ops = {
2991 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2993 Result =
CurDAG->getMachineNode(Hexagon::V6_vsubcarry,
SDLoc(
N), VTs,
Ops);
2996 case Intrinsic::hexagon_V6_vsubcarry_128B: {
2997 std::array<SDValue, 3>
Ops = {
2998 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
3000 Result =
CurDAG->getMachineNode(Hexagon::V6_vsubcarry,
SDLoc(
N), VTs,
Ops);
3014 return Opcode == Intrinsic::hexagon_V6_vabs_hf_128B ||
3015 Opcode == Intrinsic::hexagon_V6_vabs_sf_128B ||
3016 Opcode == Intrinsic::hexagon_V6_vsub_hf_hf_128B ||
3017 Opcode == Intrinsic::hexagon_V6_vadd_hf_hf_128B ||
3018 Opcode == Intrinsic::hexagon_V6_vadd_sf_hf_128B ||
3019 Opcode == Intrinsic::hexagon_V6_vsub_sf_hf_128B ||
3020 Opcode == Intrinsic::hexagon_V6_vadd_sf_sf_128B ||
3021 Opcode == Intrinsic::hexagon_V6_vsub_sf_sf_128B ||
3022 Opcode == Intrinsic::hexagon_V6_vassign_fp_128B ||
3023 Opcode == Intrinsic::hexagon_V6_vfmin_hf_128B ||
3024 Opcode == Intrinsic::hexagon_V6_vfmin_sf_128B ||
3025 Opcode == Intrinsic::hexagon_V6_vfmax_hf_128B ||
3026 Opcode == Intrinsic::hexagon_V6_vfmax_sf_128B ||
3027 Opcode == Intrinsic::hexagon_V6_vfneg_hf_128B ||
3028 Opcode == Intrinsic::hexagon_V6_vfneg_sf_128B ||
3029 Opcode == Intrinsic::hexagon_V6_vmpy_sf_hf_acc_128B ||
3030 Opcode == Intrinsic::hexagon_V6_vmpy_hf_hf_acc_128B ||
3031 Opcode == Intrinsic::hexagon_V6_vmpy_sf_hf_128B ||
3032 Opcode == Intrinsic::hexagon_V6_vmpy_hf_hf_128B ||
3033 Opcode == Intrinsic::hexagon_V6_vmpy_sf_sf_128B ||
3034 Opcode == Intrinsic::hexagon_V6_vcvt_sf_hf_128B ||
3035 Opcode == Intrinsic::hexagon_V6_vcvt_hf_h_128B;
3042 MVT ResTy =
N->getValueType(0).getSimpleVT();
3046 case Intrinsic::hexagon_V6_vadd_sf_sf_128B: {
3048 Hexagon::V6_vadd_sf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3049 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3057 case Intrinsic::hexagon_V6_vsub_sf_sf_128B: {
3059 Hexagon::V6_vsub_sf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3060 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3068 case Intrinsic::hexagon_V6_vadd_hf_hf_128B: {
3070 Hexagon::V6_vadd_hf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3071 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_hf_qf16,
DL,
3079 case Intrinsic::hexagon_V6_vsub_hf_hf_128B: {
3081 Hexagon::V6_vsub_hf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3082 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_hf_qf16,
DL,
3095 case Intrinsic::hexagon_V6_vadd_sf_hf_128B: {
3097 SDNode *SplatPseudoNode =
3098 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, ResTy, Const);
3100 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3101 N->getOperand(1),
SDValue(SplatPseudoNode, 0));
3103 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3104 N->getOperand(2),
SDValue(SplatPseudoNode, 0));
3107 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNodeOp1, 0));
3109 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNodeOp1, 0));
3111 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNodeOp2, 0));
3113 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNodeOp2, 0));
3115 SDNode *LoAddNode =
CurDAG->getMachineNode(Hexagon::V6_vadd_qf32,
DL,
3116 MVT::v32i32, LoRegOp1, LoRegOp2);
3117 SDNode *HiAddNode =
CurDAG->getMachineNode(Hexagon::V6_vadd_qf32,
DL,
3118 MVT::v32i32, HiRegOp1, HiRegOp2);
3121 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(LoAddNode, 0));
3123 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(HiAddNode, 0));
3126 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3127 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3128 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3130 SDValue(ConvLoNode, 0), SubRegL};
3131 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
3145 case Intrinsic::hexagon_V6_vsub_sf_hf_128B: {
3147 SDNode *SplatPseudoNode =
3148 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, ResTy, Const);
3150 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3151 N->getOperand(1),
SDValue(SplatPseudoNode, 0));
3153 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3154 N->getOperand(2),
SDValue(SplatPseudoNode, 0));
3157 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNodeOp1, 0));
3159 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNodeOp1, 0));
3161 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNodeOp2, 0));
3163 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNodeOp2, 0));
3165 SDNode *LoSubNode =
CurDAG->getMachineNode(Hexagon::V6_vsub_qf32,
DL,
3166 MVT::v32i32, LoRegOp1, LoRegOp2);
3167 SDNode *HiSubNode =
CurDAG->getMachineNode(Hexagon::V6_vsub_qf32,
DL,
3168 MVT::v32i32, HiRegOp1, HiRegOp2);
3171 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(LoSubNode, 0));
3173 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(HiSubNode, 0));
3176 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3177 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3178 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3180 SDValue(ConvLoNode, 0), SubRegL};
3181 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
3189 case Intrinsic::hexagon_V6_vassign_fp_128B: {
3190 SDNode *AssignNode =
CurDAG->getMachineNode(Hexagon::V6_vassign,
DL, ResTy,
3198 case Intrinsic::hexagon_V6_vmpy_hf_hf_128B: {
3200 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, MVT::v64i32,
3201 N->getOperand(1),
N->getOperand(2));
3202 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_hf_qf32,
DL,
3210 case Intrinsic::hexagon_V6_vmpy_sf_sf_128B: {
3212 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_sf,
DL, ResTy,
3213 N->getOperand(1),
N->getOperand(2));
3214 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3222 case Intrinsic::hexagon_V6_vmpy_sf_hf_128B: {
3224 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3225 N->getOperand(1),
N->getOperand(2));
3227 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3229 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3230 SDNode *ConvLoNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3231 MVT::v32i32, LoReg);
3232 SDNode *ConvHiNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3233 MVT::v32i32, HiReg);
3236 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3237 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3238 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3240 SDValue(ConvLoNode, 0), SubRegL};
3241 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
3254 case Intrinsic::hexagon_V6_vmpy_hf_hf_acc_128B: {
3256 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, MVT::v64i32,
3257 N->getOperand(2),
N->getOperand(3));
3261 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, MVT::v64i32, Const);
3263 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, MVT::v64i32,
3264 N->getOperand(1),
SDValue(SplatConstNode, 0));
3267 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3269 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3271 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(WidenAcc, 0));
3273 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(WidenAcc, 0));
3276 Hexagon::V6_vadd_qf32,
DL, MVT::v32i32, LoWidenAcc, LoMpyNode);
3278 Hexagon::V6_vadd_qf32,
DL, MVT::v32i32, HiWidenAcc, HiMpyNode);
3281 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3282 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3283 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3285 SDValue(LoAddNode, 0), SubRegL};
3286 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
3289 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_hf_qf32,
DL,
3299 case Intrinsic::hexagon_V6_vmpy_sf_hf_acc_128B: {
3301 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3302 N->getOperand(2),
N->getOperand(3));
3305 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3307 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3310 Hexagon::vsub_lo,
DL, MVT::v32i32,
N->getOperand(1));
3312 Hexagon::vsub_hi,
DL, MVT::v32i32,
N->getOperand(1));
3315 Hexagon::V6_vadd_qf32_mix,
DL, MVT::v32i32, LoRegMpy, LoRegDest);
3317 Hexagon::V6_vadd_qf32_mix,
DL, MVT::v32i32, HiRegMpy, HiRegDest);
3320 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(LoAddNode, 0));
3322 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(HiAddNode, 0));
3325 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3326 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3327 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3329 SDValue(ConvLoNode, 0), SubRegL};
3330 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
3338 case Intrinsic::hexagon_V6_vfmin_hf_128B: {
3340 Hexagon::V6_vmin_hf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3346 case Intrinsic::hexagon_V6_vfmin_sf_128B: {
3348 Hexagon::V6_vmin_sf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3354 case Intrinsic::hexagon_V6_vfmax_hf_128B: {
3356 Hexagon::V6_vmax_hf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3362 case Intrinsic::hexagon_V6_vfmax_sf_128B: {
3364 Hexagon::V6_vmax_sf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3372 case Intrinsic::hexagon_V6_vabs_hf_128B: {
3374 SDNode *SplatPseudoNode =
3375 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, ResTy, Const);
3377 CurDAG->getMachineNode(Hexagon::V6_vand,
DL, ResTy,
N->getOperand(1),
3386 case Intrinsic::hexagon_V6_vabs_sf_128B: {
3388 SDNode *SplatPseudoNode =
3389 CurDAG->getMachineNode(Hexagon::PS_vsplatiw,
DL, ResTy, Const);
3391 CurDAG->getMachineNode(Hexagon::V6_vand,
DL, ResTy,
N->getOperand(1),
3400 case Intrinsic::hexagon_V6_vfneg_hf_128B: {
3402 SDNode *SplatPseudoNode =
3403 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, ResTy, Const);
3405 CurDAG->getMachineNode(Hexagon::V6_vxor,
DL, ResTy,
N->getOperand(1),
3414 case Intrinsic::hexagon_V6_vfneg_sf_128B: {
3416 SDNode *SplatPseudoNode =
3417 CurDAG->getMachineNode(Hexagon::PS_vsplatiw,
DL, ResTy, Const);
3419 CurDAG->getMachineNode(Hexagon::V6_vxor,
DL, ResTy,
N->getOperand(1),
3426 case Intrinsic::hexagon_V6_vcvt_hf_h_128B: {
3427 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_hf_h,
DL, ResTy,
3437 case Intrinsic::hexagon_V6_vcvt_sf_hf_128B: {
3439 SDNode *SplatPseudoNode =
3440 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, ResTy, Const);
3442 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3443 N->getOperand(1),
SDValue(SplatPseudoNode, 0));
3446 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3448 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3449 SDNode *ConvLoNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3450 MVT::v32i32, LoReg);
3451 SDNode *ConvHiNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3452 MVT::v32i32, HiReg);
3455 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3456 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3457 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3459 SDValue(ConvLoNode, 0), SubRegL};
3460 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, MCValue Val)
ReachingDefInfo InstSet InstSet & Ignore
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
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.
const HexagonInstrInfo * TII
static bool isIdentity(ArrayRef< int > Mask)
static std::pair< int, unsigned > findStrip(ArrayRef< int > A, int Inc, unsigned MaxLen)
static const HexagonSubtarget & getHexagonSubtarget(SelectionDAG &G)
static void splitMask(ArrayRef< int > Mask, MutableArrayRef< int > MaskL, MutableArrayRef< int > MaskR)
static void packSegmentMask(ArrayRef< int > Mask, ArrayRef< unsigned > OutSegMap, unsigned SegLen, MutableArrayRef< int > PackedMask)
static SmallVector< unsigned, 4 > getInputSegmentList(ShuffleMask SM, unsigned SegLen)
static const HexagonTargetLowering & getHexagonLowering(SelectionDAG &G)
static SmallVector< unsigned, 4 > getOutputSegmentMap(ShuffleMask SM, unsigned SegLen)
static bool isLowHalfOnly(ArrayRef< int > Mask)
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 constexpr unsigned SMA(unsigned Version)
static constexpr unsigned SM(unsigned Version)
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
static Type * getValueType(Value *V, bool LookThroughCmp=false)
Returns the "element 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 uint8_t *MatcherTable, size_t &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.
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
Get the array size.
ArrayRef< T > take_back(size_t N=1) const
Return a copy of *this with only the last N elements.
BitVector & set()
Set all bits in the bitvector.
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.
bool isIEEEHVXIntrinsic(unsigned)
void translateIEEEIntrinsicToQFloat(SDNode *N, unsigned &Opcode)
void SelectV65GatherPred(SDNode *N)
void SelectV65Gather(SDNode *N)
void SelectHVXDualOutput(SDNode *N)
unsigned getVectorNumElements() const
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
A description of a memory reference used in the backend.
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
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 ...
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ 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...
DXILDebugInfoMap run(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.
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
SmallVectorImpl< T >::const_pointer c_str(SmallVectorImpl< T > &str)
constexpr NextUseDistance min(NextUseDistance A, NextUseDistance B)
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.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
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.
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<X> - 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)
MaskT vpack(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Size, bool TakeOdd)
ArrayRef< int > hi(ArrayRef< int > Vuu)
auto mask(ShuffFunc S, unsigned Length, OptArgs... args) -> MaskT
MaskT vshuff(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Size, bool TakeOdd)
MaskT vdealb4w(ArrayRef< int > Vu, ArrayRef< int > Vv)
SmallVector< int, 128 > MaskT
MaskT vdeal(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Size, bool TakeOdd)
ArrayRef< int > lo(ArrayRef< int > Vuu)
MaskT vdealvdd(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Rt)
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)
MVT getSingleVT(MVT ElemTy) const
static SmallVector< uint32_t, 8 > completeToPerfect(ArrayRef< uint32_t > Completions, unsigned Width)
HexagonDAGToDAGISel & ISel
const HexagonTargetLowering & Lower
void selectVAlign(SDNode *N)
void selectExtractSubvector(SDNode *N)
void selectRor(SDNode *N)
void selectShuffle(SDNode *N)
static SmallVector< uint32_t, 8 > getPerfectCompletions(ShuffleMask SM, unsigned Width)
MVT getPairVT(MVT ElemTy) const
const HexagonSubtarget & HST
static std::optional< int > rotationDistance(ShuffleMask SM, unsigned WrapAt)
This represents a list of ValueType's that has been intern'd by a SelectionDAG.
std::size_t operator()(SDValue V) const