15#include "llvm/IR/IntrinsicsHexagon.h"
28#define DEBUG_TYPE "hexagon-isel"
98enum class ColorKind {
None, Red, Black };
104 using MapType = std::map<Node, ColorKind>;
113 const MapType &colors()
const {
117 ColorKind other(ColorKind Color) {
118 if (Color == ColorKind::None)
119 return ColorKind::Red;
120 return Color == ColorKind::Red ? ColorKind::Black : ColorKind::Red;
128 std::set<Node> Needed;
130 using NodeSet = std::set<Node>;
131 std::map<Node,NodeSet> Edges;
135 return (Pos < Num/2) ? Pos + Num/2 : Pos - Num/2;
138 ColorKind getColor(
Node N) {
139 auto F = Colors.find(
N);
140 return F != Colors.end() ?
F->second : ColorKind::None;
143 std::pair<bool, ColorKind> getUniqueColor(
const NodeSet &Nodes);
150std::pair<bool, ColorKind> Coloring::getUniqueColor(
const NodeSet &Nodes) {
151 auto Color = ColorKind::None;
152 for (Node
N : Nodes) {
153 ColorKind ColorN = getColor(
N);
154 if (ColorN == ColorKind::None)
156 if (Color == ColorKind::None)
158 else if (Color != ColorKind::None && Color != ColorN)
159 return {
false, ColorKind::None };
161 return {
true, Color };
164void Coloring::build() {
166 for (
unsigned P = 0;
P != Order.size(); ++
P) {
170 Node PC = Order[conj(
P)];
176 for (
unsigned I = 0;
I != Order.size(); ++
I) {
177 if (!Needed.count(
I))
183 NodeSet &Is = Edges[
I];
189bool Coloring::color() {
190 SetVector<Node> FirstQ;
191 auto Enqueue = [
this,&FirstQ] (Node
N) {
194 for (
unsigned I = 0;
I != Q.
size(); ++
I) {
195 NodeSet &Ns = Edges[Q[
I]];
200 for (Node
N : Needed)
203 for (Node
N : FirstQ) {
206 NodeSet &Ns = Edges[
N];
207 auto P = getUniqueColor(Ns);
210 Colors[
N] = other(
P.second);
214 for (
auto E : Edges) {
216 if (!Needed.count(conj(
N)) || Colors.count(
N))
218 auto P = getUniqueColor(
E.second);
221 Colors[
N] = other(
P.second);
226 std::vector<Node> WorkQ;
227 for (
auto E : Edges) {
229 if (!Colors.count(
N))
233 for (Node
N : WorkQ) {
234 NodeSet &Ns = Edges[
N];
235 auto P = getUniqueColor(Ns);
237 Colors[
N] = other(
P.second);
243 ColorKind ColorN = other(ColorKind::None);
244 ColorKind ColorC = other(ColorN);
245 NodeSet &Cs = Edges[
C];
247 for (Node M : CopyNs) {
248 ColorKind ColorM = getColor(M);
249 if (ColorM == ColorC) {
262 for (
unsigned I = 0;
I != Order.size(); ++
I)
263 Colors.try_emplace(
I, ColorKind::None);
268#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
269void Coloring::dump()
const {
270 dbgs() <<
"{ Order: {";
271 for (Node
P : Order) {
278 dbgs() <<
" Needed: {";
279 for (Node
N : Needed)
283 dbgs() <<
" Edges: {\n";
284 for (
auto E : Edges) {
285 dbgs() <<
" " <<
E.first <<
" -> {";
286 for (
auto N :
E.second)
292 auto ColorKindToName = [](ColorKind
C) {
294 case ColorKind::None:
298 case ColorKind::Black:
304 dbgs() <<
" Colors: {\n";
305 for (
auto C : Colors)
306 dbgs() <<
" " <<
C.first <<
" -> " << ColorKindToName(
C.second) <<
"\n";
316 using Controls = std::vector<uint8_t>;
317 using ElemType = int;
318 static constexpr ElemType
Ignore = ElemType(-1);
334 unsigned S = Order.size();
338 Table.resize(Order.size());
339 for (RowType &Row :
Table)
340 Row.resize(Mult*Log,
None);
343 void getControls(Controls &V,
unsigned StartAt, uint8_t Dir)
const {
344 unsigned Size = Order.size();
346 for (
unsigned I = 0;
I !=
Size; ++
I) {
348 for (
unsigned L = 0;
L != Log; ++
L) {
349 unsigned C = ctl(
I, StartAt+L) == Switch;
360 uint8_t ctl(ElemType Pos,
unsigned Step)
const {
361 return Table[Pos][Step];
363 unsigned size()
const {
366 unsigned steps()
const {
372 std::vector<ElemType> Order;
373 using RowType = std::vector<uint8_t>;
374 std::vector<RowType>
Table;
377struct ForwardDeltaNetwork :
public PermNetwork {
380 bool run(Controls &V) {
381 if (!route(Order.data(),
Table.data(),
size(), 0))
383 getControls(V, 0, Forward);
388 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
391struct ReverseDeltaNetwork :
public PermNetwork {
394 bool run(Controls &V) {
395 if (!route(Order.data(),
Table.data(),
size(), 0))
402 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
405struct BenesNetwork :
public PermNetwork {
408 bool run(Controls &
F, Controls &R) {
409 if (!route(Order.data(),
Table.data(),
size(), 0))
412 getControls(
F, 0, Forward);
418 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
422bool ForwardDeltaNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
424 bool UseUp =
false, UseDown =
false;
431 for (ElemType J = 0; J != Num; ++J) {
441 S = (J < Num/2) ? Switch :
Pass;
444 ElemType
U = (S ==
Pass) ?
I : (
I < Num/2 ?
I+Num/2 :
I-Num/2);
449 if (
T[U][Step] != S &&
T[U][Step] !=
None)
454 for (ElemType J = 0; J != Num; ++J)
455 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
459 if (UseUp && !route(
P,
T,
Size/2, Step+1))
467bool ReverseDeltaNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
469 unsigned Pets =
Log-1 - Step;
470 bool UseUp =
false, UseDown =
false;
475 const Coloring::MapType &
M =
G.colors();
479 ColorKind ColorUp = ColorKind::None;
480 for (ElemType J = 0; J != Num; ++J) {
486 ColorKind
C =
M.at(
I);
487 if (
C == ColorKind::None)
492 bool InpUp =
I < Num/2;
493 if (ColorUp == ColorKind::None)
494 ColorUp = InpUp ?
C :
G.other(
C);
495 if ((
C == ColorUp) != InpUp) {
505 S = (J < Num/2) ? Switch :
Pass;
513 for (ElemType J = 0,
E =
Size / 2; J !=
E; ++J) {
515 ElemType PC =
P[J+
Size/2];
518 if (
T[J][Pets] == Switch)
520 if (
T[J+
Size/2][Pets] == Switch)
526 for (ElemType J = 0; J != Num; ++J)
527 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
531 if (UseUp && !route(
P,
T,
Size/2, Step+1))
539bool BenesNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
542 const Coloring::MapType &
M =
G.colors();
547 unsigned Pets = 2*
Log-1 - Step;
548 bool UseUp =
false, UseDown =
false;
553 ColorKind ColorUp = ColorKind::None;
554 for (ElemType J = 0; J != Num; ++J) {
558 ColorKind
C =
M.at(
I);
559 if (
C == ColorKind::None)
561 if (ColorUp == ColorKind::None) {
562 ColorUp = (
I < Num / 2) ? ColorKind::Red : ColorKind::Black;
564 unsigned CI = (
I < Num/2) ?
I+Num/2 :
I-Num/2;
577 T[J][Pets] = (J < Num/2) ? Switch :
Pass;
584 for (ElemType J = 0; J != Num/2; ++J) {
586 ElemType PC =
P[J+Num/2];
589 if (
T[J][Pets] == Switch)
591 if (
T[J+Num/2][Pets] == Switch)
597 for (ElemType J = 0; J != Num; ++J)
598 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
602 if (UseUp && !route(
P,
T,
Size/2, Step+1))
617 bool isValue()
const {
return OpV.
getNode() !=
nullptr; }
620 static OpRef res(
int N) {
return OpRef(Whole | (
N & Index)); }
623 static OpRef
lo(
const OpRef &R) {
625 return OpRef(
R.OpN & (
Undef | Index | LoHalf));
627 static OpRef
hi(
const OpRef &R) {
629 return OpRef(
R.OpN & (
Undef | Index | HiHalf));
631 static OpRef undef(MVT Ty) {
return OpRef(
Undef | Ty.
SimpleTy); }
647 Whole = LoHalf | HiHalf,
654 void print(raw_ostream &OS,
const SelectionDAG &
G)
const;
657 OpRef(
unsigned N) : OpN(
N) {}
661 NodeTemplate() =
default;
664 std::vector<OpRef>
Ops;
670 ResultStack(SDNode *Inp)
674 unsigned push(
const NodeTemplate &Res) {
676 return List.size()-1;
678 unsigned push(
unsigned Opc, MVT Ty, std::vector<OpRef> &&
Ops) {
685 bool empty()
const {
return List.empty(); }
686 unsigned size()
const {
return List.size(); }
687 unsigned top()
const {
return size()-1; }
688 const NodeTemplate &operator[](
unsigned I)
const {
return List[
I]; }
689 unsigned reset(
unsigned NewTop) {
690 List.resize(NewTop+1);
694 using BaseType = std::vector<NodeTemplate>;
695 BaseType::iterator
begin() {
return List.begin(); }
696 BaseType::iterator
end() {
return List.end(); }
697 BaseType::const_iterator
begin()
const {
return List.begin(); }
698 BaseType::const_iterator
end()
const {
return List.end(); }
703 void print(raw_ostream &OS,
const SelectionDAG &
G)
const;
707#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
708void OpRef::print(raw_ostream &OS,
const SelectionDAG &
G)
const {
721 if ((OpN & Whole) != Whole) {
722 assert((OpN & Whole) == LoHalf || (OpN & Whole) == HiHalf);
731void NodeTemplate::print(raw_ostream &OS,
const SelectionDAG &
G)
const {
732 const TargetInstrInfo &
TII = *
G.getSubtarget().getInstrInfo();
733 OS <<
format(
"%8s", EVT(Ty).getEVTString().
c_str()) <<
" "
736 for (
const auto &R :
Ops) {
745void ResultStack::print(raw_ostream &OS,
const SelectionDAG &
G)
const {
746 OS <<
"Input node:\n";
750 OS <<
"Result templates:\n";
751 for (
unsigned I = 0,
E =
List.size();
I !=
E; ++
I) {
752 OS <<
'[' <<
I <<
"] ";
761 ShuffleMask(ArrayRef<int> M) : Mask(
M) {
765 MinSrc = (MinSrc == -1) ? M : std::
min(MinSrc,
M);
766 MaxSrc = (MaxSrc == -1) ?
M : std::max(MaxSrc, M);
771 int MinSrc = -1, MaxSrc = -1;
773 ShuffleMask
lo()
const {
774 size_t H =
Mask.size()/2;
775 return ShuffleMask(
Mask.take_front(
H));
777 ShuffleMask
hi()
const {
778 size_t H =
Mask.size()/2;
779 return ShuffleMask(
Mask.take_back(
H));
782 void print(raw_ostream &OS)
const {
783 OS <<
"MinSrc:" << MinSrc <<
", MaxSrc:" << MaxSrc <<
" {";
791raw_ostream &
operator<<(raw_ostream &OS,
const ShuffleMask &SM) {
821 for (
int i = 0; i != Len; ++i) {
841 for (
int i = 0; i != Len; ++i) {
852 auto Odd =
static_cast<int>(TakeOdd);
853 for (
int i = 0, e = Len / (2 *
Size); i != e; ++i) {
854 for (
int b = 0; b !=
static_cast<int>(
Size); ++b) {
856 Vd[i *
Size + b] = Vv[(2 * i + Odd) *
Size + b];
857 Vd[i *
Size + b + Len / 2] = Vu[(2 * i + Odd) *
Size + b];
867 auto Odd =
static_cast<int>(TakeOdd);
868 for (
int i = 0, e = Len / (2 *
Size); i != e; ++i) {
869 for (
int b = 0; b !=
static_cast<int>(
Size); ++b) {
870 Vd[(2 * i + 0) *
Size + b] = Vv[(2 * i + Odd) *
Size + b];
871 Vd[(2 * i + 1) *
Size + b] = Vu[(2 * i + Odd) *
Size + b];
886 for (
int i = 0, e = Len / 4; i != e; ++i) {
887 Vd[0 * (Len / 4) + i] = Vv[4 * i + 0];
888 Vd[1 * (Len / 4) + i] = Vv[4 * i + 2];
889 Vd[2 * (Len / 4) + i] = Vu[4 * i + 0];
890 Vd[3 * (Len / 4) + i] = Vu[4 * i + 2];
895template <
typename ShuffFunc,
typename... OptArgs>
898 std::iota(Vu.begin(), Vu.end(),
Length);
900 return S(Vu, Vv,
args...);
928 assert(ElemTy != MVT::i1 &&
"Use getBoolVT for predicates");
929 unsigned NumElems =
HwLen / (ElemTy.getSizeInBits() / 8);
934 assert(ElemTy != MVT::i1);
935 unsigned NumElems = (2 *
HwLen) / (ElemTy.getSizeInBits() / 8);
944 void selectExtractSubvector(
SDNode *
N);
953 static std::optional<int> rotationDistance(ShuffleMask SM,
unsigned WrapAt);
956 void select(
SDNode *ISelN);
957 void materialize(
const ResultStack &
Results);
967 OpRef concats(OpRef Va, OpRef Vb, ResultStack &
Results);
968 OpRef funnels(OpRef Va, OpRef Vb,
int Amount, ResultStack &
Results);
970 OpRef packs(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &
Results,
972 OpRef packp(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &
Results,
979 OpRef shuffs1(ShuffleMask SM, OpRef Va, ResultStack &
Results);
980 OpRef shuffs2(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &
Results);
981 OpRef shuffp1(ShuffleMask SM, OpRef Va, ResultStack &
Results);
982 OpRef shuffp2(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &
Results);
984 OpRef butterfly(ShuffleMask SM, OpRef Va, ResultStack &
Results);
985 OpRef contracting(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &
Results);
986 OpRef expanding(ShuffleMask SM, OpRef Va, ResultStack &
Results);
987 OpRef perfect(ShuffleMask SM, OpRef Va, ResultStack &
Results);
989 bool selectVectorConstants(
SDNode *
N);
997 unsigned VecLen = Mask.size();
999 for (
unsigned I = 0;
I != VecLen; ++
I) {
1002 MaskL[
I] = MaskR[
I] = -1;
1003 }
else if (
unsigned(M) < VecLen) {
1008 MaskR[
I] = M-VecLen;
1015 assert(
A.size() > 0 &&
A.size() >= MaxLen);
1018 for (
unsigned I = 1;
I != MaxLen; ++
I) {
1019 if (
A[
I] -
E != Inc)
1023 return {
F, MaxLen };
1027 for (
int Idx : Mask)
1034 for (
int I = 0,
E = Mask.size();
I !=
E; ++
I) {
1036 if (M >= 0 && M !=
I)
1043 int L = Mask.size();
1046 return llvm::all_of(Mask.drop_front(L / 2), [](
int M) { return M < 0; });
1053 if (SM.MaxSrc == -1)
1056 unsigned Shift =
Log2_32(SegLen);
1059 for (
int M : SM.Mask) {
1061 Segs.
set(M >> Shift);
1079 unsigned MaskLen = SM.Mask.
size();
1080 assert(MaskLen % SegLen == 0);
1083 for (
int S = 0,
E = Map.size(); S !=
E; ++S) {
1085 for (
int I = 0;
I !=
static_cast<int>(SegLen); ++
I) {
1086 int M = SM.Mask[S*SegLen +
I];
1089 unsigned G = M / SegLen;
1092 }
else if (Idx !=
G) {
1106 for (
int I = OutSegMap.
size() - 1;
I >= 0; --
I) {
1107 unsigned S = OutSegMap[
I];
1108 assert(S != ~0u &&
"Unexpected undef");
1109 assert(S != ~1u &&
"Unexpected multi");
1110 if (InvMap.
size() <= S)
1115 unsigned Shift =
Log2_32(SegLen);
1116 for (
int I = 0,
E = Mask.size();
I !=
E; ++
I) {
1119 int OutIdx = InvMap[M >> Shift];
1120 M = (M & (SegLen-1)) + SegLen*OutIdx;
1126bool HvxSelector::selectVectorConstants(SDNode *
N) {
1132 SetVector<SDNode*> WorkQ;
1137 for (
unsigned i = 0; i != WorkQ.
size(); ++i) {
1138 SDNode *
W = WorkQ[i];
1141 for (
unsigned j = 0, f =
W->getNumOperands(); j != f; ++j)
1142 WorkQ.
insert(
W->getOperand(j).getNode());
1145 for (SDNode *L : Nodes)
1148 return !Nodes.empty();
1151void HvxSelector::materialize(
const ResultStack &
Results) {
1153 dbgs() <<
"Materializing\n";
1158 const SDLoc &dl(
Results.InpNode);
1159 std::vector<SDValue> Output;
1163 std::vector<SDValue>
Ops;
1164 for (
const OpRef &R :
Node.Ops) {
1167 Ops.push_back(
R.OpV);
1170 if (
R.OpN & OpRef::Undef) {
1172 Ops.push_back(ISel.selectUndef(dl, MVT(SVT)));
1176 unsigned Part =
R.OpN & OpRef::Whole;
1177 int Idx =
SignExtend32(
R.OpN & OpRef::Index, OpRef::IndexBits);
1180 assert(Idx >= 0 &&
unsigned(Idx) < Output.size());
1182 MVT OpTy =
Op.getValueType().getSimpleVT();
1183 if (Part != OpRef::Whole) {
1184 assert(Part == OpRef::LoHalf || Part == OpRef::HiHalf);
1187 unsigned Sub = (Part == OpRef::LoHalf) ? Hexagon::vsub_lo
1189 Op = DAG.getTargetExtractSubreg(
Sub, dl, HalfTy,
Op);
1195 SDNode *ResN = (
Node.Opc == TargetOpcode::COPY)
1196 ?
Ops.front().getNode()
1198 Output.push_back(
SDValue(ResN, 0));
1201 SDNode *OutN = Output.back().getNode();
1202 SDNode *InpN =
Results.InpNode;
1204 dbgs() <<
"Generated node:\n";
1208 ISel.ReplaceNode(InpN, OutN);
1209 selectVectorConstants(OutN);
1210 DAG.RemoveDeadNodes();
1213OpRef HvxSelector::concats(OpRef
Lo, OpRef
Hi, ResultStack &
Results) {
1215 const SDLoc &dl(
Results.InpNode);
1216 Results.push(TargetOpcode::REG_SEQUENCE, getPairVT(MVT::i8), {
1217 getConst32(Hexagon::HvxWRRegClassID, dl),
1218 Lo, getConst32(Hexagon::vsub_lo, dl),
1219 Hi, getConst32(Hexagon::vsub_hi, dl),
1221 return OpRef::res(
Results.top());
1224OpRef HvxSelector::funnels(OpRef Va, OpRef Vb,
int Amount,
1229 auto VecLen =
static_cast<int>(HwLen);
1233 if (Amount == VecLen)
1236 MVT Ty = getSingleVT(MVT::i8);
1237 const SDLoc &dl(
Results.InpNode);
1241 if (Amount > VecLen) {
1247 SDValue A = getConst32(Amount, dl);
1248 Results.push(Hexagon::V6_valignbi, Ty, {Vb, Va,
A});
1249 }
else if (
isUInt<3>(VecLen - Amount)) {
1250 SDValue A = getConst32(VecLen - Amount, dl);
1251 Results.push(Hexagon::V6_vlalignbi, Ty, {Vb, Va,
A});
1253 SDValue A = getConst32(Amount, dl);
1254 Results.push(Hexagon::A2_tfrsi, Ty, {
A});
1255 Results.push(Hexagon::V6_valignb, Ty, {Vb, Va, OpRef::res(-1)});
1257 return OpRef::res(
Results.top());
1263OpRef HvxSelector::packs(ShuffleMask SM, OpRef Va, OpRef Vb,
1267 if (!Va.isValid() || !Vb.isValid())
1268 return OpRef::fail();
1280 MVT Ty = getSingleVT(MVT::i8);
1281 MVT
PairTy = getPairVT(MVT::i8);
1282 OpRef Inp[2] = {Va, Vb};
1283 unsigned VecLen = SM.Mask.
size();
1285 auto valign = [
this](OpRef
Lo, OpRef
Hi,
unsigned Amt, MVT Ty,
1289 const SDLoc &dl(
Results.InpNode);
1292 SDValue S = getConst32(IsRight ? Amt : HwLen - Amt, dl);
1293 unsigned Opc = IsRight ? Hexagon::V6_valignbi : Hexagon::V6_vlalignbi;
1295 return OpRef::res(
Results.top());
1297 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(Amt, dl)});
1298 OpRef
A = OpRef::res(
Results.top());
1300 return OpRef::res(
Results.top());
1304 unsigned SegLen = HwLen / 2;
1310 unsigned SegCount = SegList.
size();
1313 if (SegList.
empty())
1314 return OpRef::undef(Ty);
1332 unsigned Seg0 = ~0
u, Seg1 = ~0
u;
1333 for (
unsigned X : SegMap) {
1338 else if (Seg1 != ~0u)
1340 if (
X == ~1u ||
X != Seg0)
1344 if (SegCount == 1) {
1345 unsigned SrcOp = SegList[0] / 2;
1346 for (
int I = 0;
I !=
static_cast<int>(VecLen); ++
I) {
1357 if (SegCount == 2) {
1364 if (Seg0 == ~1u || Seg1 == ~1u) {
1368 }
else if (Seg0 == ~1u) {
1369 Seg0 = SegList[0] != Seg1 ? SegList[0] : SegList[1];
1372 Seg1 = SegList[0] != Seg0 ? SegList[0] : SegList[1];
1375 assert(Seg0 != ~1u && Seg1 != ~1u);
1377 assert(Seg0 != Seg1 &&
"Expecting different segments");
1378 const SDLoc &dl(
Results.InpNode);
1379 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(SegLen, dl)});
1380 OpRef HL = OpRef::res(
Results.top());
1384 if (Seg0 / 2 == Seg1 / 2) {
1389 Results.push(Hexagon::V6_vror, Ty, {Inp[Seg0 / 2], HL});
1390 Va = OpRef::res(
Results.top());
1393 }
else if (Seg0 % 2 == Seg1 % 2) {
1397 auto Vs = (Seg0 == 0 || Seg0 == 1) ? std::make_pair(Vb, Va)
1398 : std::make_pair(Va, Vb);
1399 Results.push(Hexagon::V6_vshuffvdd,
PairTy, {Vs.first, Vs.second, HL});
1400 OpRef
P = OpRef::res(
Results.top());
1401 Va = (Seg0 == 0 || Seg0 == 2) ? OpRef::lo(
P) : OpRef::hi(
P);
1405 if ((Seg0 == 0 && Seg1 == 3) || (Seg0 == 2 && Seg1 == 1)) {
1409 Results.push(Hexagon::V6_pred_scalar2, getBoolVT(), {HL});
1410 OpRef Qt = OpRef::res(
Results.top());
1411 auto Vs = (Seg0 == 0) ? std::make_pair(Va, Vb)
1412 : std::make_pair(Vb, Va);
1413 Results.push(Hexagon::V6_vmux, Ty, {Qt, Vs.first, Vs.second});
1414 Va = OpRef::res(
Results.top());
1420 assert(Seg0 == 1 || Seg0 == 3);
1427 ShuffleMask SMH(MaskH);
1428 assert(SMH.Mask.size() == VecLen);
1431 if (SMH.MaxSrc - SMH.MinSrc >=
static_cast<int>(HwLen)) {
1435 ShuffleMask SW(Swapped);
1436 if (SW.MaxSrc - SW.MinSrc <
static_cast<int>(HwLen)) {
1437 MaskA.assign(SW.Mask.begin(), SW.Mask.end());
1441 ShuffleMask SMA(MaskA);
1442 assert(SMA.Mask.size() == VecLen);
1444 if (SMA.MaxSrc - SMA.MinSrc <
static_cast<int>(HwLen)) {
1445 int ShiftR = SMA.MinSrc;
1446 if (ShiftR >=
static_cast<int>(HwLen)) {
1448 Vb = OpRef::undef(Ty);
1451 OpRef RetVal = valign(Va, Vb, ShiftR, Ty,
Results);
1453 for (
int I = 0;
I !=
static_cast<int>(VecLen); ++
I) {
1454 int M = SMA.Mask[
I];
1470 BitVector Picked(HwLen);
1471 SmallVector<uint8_t,128> MuxBytes(HwLen);
1473 for (
int I = 0;
I !=
static_cast<int>(VecLen); ++
I) {
1477 if (M >=
static_cast<int>(HwLen))
1488 return vmuxs(MuxBytes, Va, Vb,
Results);
1490 return OpRef::fail();
1496OpRef HvxSelector::packp(ShuffleMask SM, OpRef Va, OpRef Vb,
1500 if (SegList.empty())
1501 return OpRef::undef(getPairVT(MVT::i8));
1505 unsigned SegCount = SegList.size();
1507 return OpRef::fail();
1509 MVT HalfTy = getSingleVT(MVT::i8);
1511 OpRef Inp[2] = { Va, Vb };
1512 OpRef Out[2] = { OpRef::undef(HalfTy), OpRef::undef(HalfTy) };
1517 for (
int I = 0,
E = SegList.size();
I !=
E; ++
I) {
1518 unsigned S = SegList[
I];
1519 OpRef
Op = Inp[S / 2];
1520 Out[
I] = (S & 1) ? OpRef::hi(
Op) : OpRef::lo(
Op);
1530 return concats(Out[0], Out[1],
Results);
1533OpRef HvxSelector::vmuxs(ArrayRef<uint8_t> Bytes, OpRef Va, OpRef Vb,
1536 MVT ByteTy = getSingleVT(MVT::i8);
1538 const SDLoc &dl(
Results.InpNode);
1539 SDValue B = getVectorConstant(Bytes, dl);
1540 Results.push(Hexagon::V6_vd0, ByteTy, {});
1541 Results.push(Hexagon::V6_veqb, BoolTy, {OpRef(
B), OpRef::res(-1)});
1542 Results.push(Hexagon::V6_vmux, ByteTy, {OpRef::res(-1), Vb, Va});
1543 return OpRef::res(
Results.top());
1546OpRef HvxSelector::vmuxp(ArrayRef<uint8_t> Bytes, OpRef Va, OpRef Vb,
1549 size_t S = Bytes.
size() / 2;
1555OpRef HvxSelector::shuffs1(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
1557 unsigned VecLen = SM.Mask.
size();
1560 assert(
all_of(SM.Mask, [
this](
int M) { return M == -1 || M < int(HwLen); }));
1565 return OpRef::undef(getSingleVT(MVT::i8));
1568 if (
auto Dist = rotationDistance(SM, VecLen)) {
1569 OpRef Rotate = funnels(Va, Va, *Dist,
Results);
1570 if (Rotate.isValid())
1573 unsigned HalfLen = HwLen / 2;
1578 std::pair<int, unsigned> Strip1 =
findStrip(SM.Mask, 1, HalfLen);
1579 if ((Strip1.first & ~HalfLen) == 0 && Strip1.second == HalfLen) {
1580 std::pair<int, unsigned> Strip2 =
1582 if (Strip1 == Strip2) {
1583 const SDLoc &dl(
Results.InpNode);
1584 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(HalfLen, dl)});
1585 Results.push(Hexagon::V6_vshuffvdd, getPairVT(MVT::i8),
1586 {Va, Va, OpRef::res(
Results.top())});
1587 OpRef S = OpRef::res(
Results.top());
1588 return (Strip1.first == 0) ? OpRef::lo(S) : OpRef::
hi(S);
1592 OpRef
P = perfect(SM, Va,
Results);
1595 return butterfly(SM, Va,
Results);
1598OpRef HvxSelector::shuffs2(ShuffleMask SM, OpRef Va, OpRef Vb,
1602 return OpRef::undef(getSingleVT(MVT::i8));
1604 OpRef
C = contracting(SM, Va, Vb,
Results);
1608 int VecLen = SM.Mask.
size();
1610 OpRef
P = packs(SM, Va, Vb,
Results, PackedMask);
1612 return shuffs1(ShuffleMask(PackedMask),
P,
Results);
1620 OpRef
L = shuffs1(ShuffleMask(MaskL), Va,
Results);
1621 OpRef
R = shuffs1(ShuffleMask(MaskR), Vb,
Results);
1622 if (!
L.isValid() || !
R.isValid())
1623 return OpRef::fail();
1625 SmallVector<uint8_t, 128> Bytes(VecLen);
1626 for (
int I = 0;
I != VecLen; ++
I) {
1630 return vmuxs(Bytes, L, R,
Results);
1633OpRef HvxSelector::shuffp1(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
1635 int VecLen = SM.Mask.
size();
1640 return OpRef::undef(getPairVT(MVT::i8));
1643 OpRef
P = packs(SM, OpRef::lo(Va), OpRef::hi(Va),
Results, PackedMask);
1645 ShuffleMask PM(PackedMask);
1652 if (
L.isValid() &&
H.isValid())
1662 OpRef
R = perfect(SM, Va,
Results);
1668 OpRef
L = shuffs2(SM.lo(), OpRef::lo(Va), OpRef::hi(Va),
Results);
1669 OpRef
H = shuffs2(SM.hi(), OpRef::lo(Va), OpRef::hi(Va),
Results);
1670 if (
L.isValid() &&
H.isValid())
1673 return OpRef::fail();
1676OpRef HvxSelector::shuffp2(ShuffleMask SM, OpRef Va, OpRef Vb,
1680 return OpRef::undef(getPairVT(MVT::i8));
1682 int VecLen = SM.Mask.
size();
1684 OpRef
P = packp(SM, Va, Vb,
Results, PackedMask);
1686 return shuffp1(ShuffleMask(PackedMask),
P,
Results);
1691 OpRef
L = shuffp1(ShuffleMask(MaskL), Va,
Results);
1692 OpRef
R = shuffp1(ShuffleMask(MaskR), Vb,
Results);
1693 if (!
L.isValid() || !
R.isValid())
1694 return OpRef::fail();
1698 for (
int I = 0;
I != VecLen; ++
I) {
1702 return vmuxp(Bytes, L, R,
Results);
1706 struct Deleter :
public SelectionDAG::DAGNodeDeletedListener {
1707 template <
typename T>
1708 Deleter(SelectionDAG &
D,
T &
C)
1709 : SelectionDAG::DAGNodeDeletedListener(
D, [&
C] (SDNode *
N, SDNode *
E) {
1714 template <
typename T>
1715 struct NullifyingVector :
public T {
1716 DenseMap<SDNode*, SDNode**> Refs;
1717 NullifyingVector(
T &&V) :
T(
V) {
1718 for (
unsigned i = 0, e = T::size(); i !=
e; ++i) {
1719 SDNode *&
N = T::operator[](i);
1725 if (
F != Refs.
end())
1726 *
F->second =
nullptr;
1731void HvxSelector::select(SDNode *ISelN) {
1748 DAG.RemoveDeadNodes();
1750 SetVector<SDNode *> SubNodes;
1759 if (SubNodes.
empty()) {
1760 ISel.ReplaceNode(ISelN, N0);
1767 SetVector<SDNode*> Dom, NonDom;
1770 auto IsDomRec = [&Dom, &NonDom] (SDNode *
T,
auto Rec) ->
bool {
1773 if (
T->use_empty() || NonDom.
count(
T))
1775 for (SDNode *U :
T->users()) {
1787 auto IsDom = [&IsDomRec] (SDNode *
T) {
return IsDomRec(
T, IsDomRec); };
1790 for (
unsigned I = 0;
I != SubNodes.
size(); ++
I) {
1792 SDNode *
O =
Op.getNode();
1799 SetVector<SDNode*> TmpQ;
1801 std::map<SDNode *, unsigned> OpCount;
1802 for (SDNode *
T : Dom) {
1803 unsigned NumDomOps =
llvm::count_if(
T->ops(), [&Dom](
const SDUse &U) {
1804 return Dom.count(U.getNode());
1807 OpCount.insert({
T, NumDomOps});
1812 for (
unsigned I = 0;
I != TmpQ.
size(); ++
I) {
1813 SDNode *S = TmpQ[
I];
1814 for (SDNode *U : S->
users()) {
1817 auto F = OpCount.find(U);
1819 if (
F->second > 0 && !--
F->second)
1825 ISel.ReplaceNode(ISelN, N0);
1828 NullifyingVector<
decltype(TmpQ)::vector_type>
Queue(TmpQ.
takeVector());
1830 Deleter DUQ(DAG, Queue);
1831 for (SDNode *S :
reverse(Queue)) {
1839bool HvxSelector::scalarizeShuffle(ArrayRef<int> Mask,
const SDLoc &dl,
1844 assert(ElemTy == MVT::i8);
1845 unsigned VecLen =
Mask.size();
1846 bool HavePairs = (2*HwLen == VecLen);
1847 MVT SingleTy = getSingleVT(MVT::i8);
1863 LLVMContext &Ctx = *DAG.getContext();
1864 MVT LegalTy =
Lower.getTypeToTransformTo(Ctx, ElemTy).getSimpleVT();
1865 for (
int I : Mask) {
1867 Ops.push_back(ISel.selectUndef(dl, LegalTy));
1880 Vec = DAG.getTargetExtractSubreg(Hexagon::vsub_lo, dl, SingleTy, Vec);
1882 Vec = DAG.getTargetExtractSubreg(Hexagon::vsub_hi, dl, SingleTy, Vec);
1886 SDValue Idx = DAG.getConstant(M, dl, MVT::i32);
1894 if (2*HwLen == VecLen) {
1895 SDValue B0 = DAG.getBuildVector(SingleTy, dl, {
Ops.data(), HwLen});
1897 SDValue B1 = DAG.getBuildVector(SingleTy, dl, {
Ops.data()+HwLen, HwLen});
1905 SDValue BV = DAG.getBuildVector(ResTy, dl,
Ops);
1906 LV =
Lower.LowerOperation(BV, DAG);
1911 ISel.ReplaceNode(
N,
IS.getNode());
1912 select(
IS.getNode());
1913 DAG.RemoveDeadNodes();
1920 unsigned Impossible = ~(1u << Width) + 1;
1921 for (
unsigned I = 0, E = Bs.
size();
I != E; ++
I) {
1925 if (~Impossible == 0)
1927 for (
unsigned Log = 0; Log != Width; ++Log) {
1928 if (Impossible & (1u << Log))
1932 Impossible |= (1u << Log);
1940 for (
unsigned BitIdx = 0; BitIdx != Width; ++BitIdx) {
1942 for (
int i = 0, e = SM.Mask.
size(); i != e; ++i) {
1945 BitValues[i] = 0xff;
1947 BitValues[i] = (M & (1u << BitIdx)) != 0;
1949 Worklist[BitIdx] = possibilities(BitValues, Width);
1991 for (
unsigned I = 0, E = Sorted.
size();
I != E;) {
1992 unsigned P = Sorted[
I],
Count = 1;
1993 while (++
I != E &&
P == Sorted[
I])
2011 for (
unsigned I = 0;
I != Width; ++
I) {
2019 for (
unsigned J =
I + 1; J != Width; ++J) {
2033 assert(OrAll == (1u << Width) -1);
2041 std::optional<int> Dist;
2042 for (
int I = 0, E = SM.Mask.
size();
I != E; ++
I) {
2047 if ((
I + *Dist) %
static_cast<int>(WrapAt) != M)
2048 return std::nullopt;
2055 Dist = *Dist + WrapAt;
2061OpRef HvxSelector::contracting(ShuffleMask SM, OpRef Va, OpRef Vb,
2064 if (!Va.isValid() || !Vb.isValid())
2065 return OpRef::fail();
2076 int VecLen = SM.Mask.
size();
2079 if (
auto Dist = rotationDistance(SM, 2 * VecLen)) {
2080 OpRef Funnel = funnels(Va, Vb, *Dist,
Results);
2081 if (Funnel.isValid())
2085 MVT SingleTy = getSingleVT(MVT::i8);
2086 MVT
PairTy = getPairVT(MVT::i8);
2088 auto same = [](ArrayRef<int> Mask1, ArrayRef<int> Mask2) ->
bool {
2089 return Mask1 == Mask2;
2092 using PackConfig = std::pair<unsigned, bool>;
2093 PackConfig Packs[] = {
2101 unsigned Opcodes[] = {
2102 Hexagon::V6_vpackeb,
2103 Hexagon::V6_vpackob,
2104 Hexagon::V6_vpackeh,
2105 Hexagon::V6_vpackoh,
2107 for (
int i = 0, e = std::size(Opcodes); i !=
e; ++i) {
2108 auto [
Size, Odd] = Packs[i];
2110 Results.push(Opcodes[i], SingleTy, {Vb, Va});
2111 return OpRef::res(
Results.top());
2117 unsigned Opcodes[] = {
2118 Hexagon::V6_vshuffeb,
2119 Hexagon::V6_vshuffob,
2120 Hexagon::V6_vshufeh,
2121 Hexagon::V6_vshufoh,
2123 for (
int i = 0, e = std::size(Opcodes); i !=
e; ++i) {
2124 auto [
Size, Odd] = Packs[i];
2126 Results.push(Opcodes[i], SingleTy, {Vb, Va});
2127 return OpRef::res(
Results.top());
2136 unsigned Opcodes[] = {
2137 Hexagon::V6_vpackeb,
2138 Hexagon::V6_vpackob,
2139 Hexagon::V6_vpackeh,
2140 Hexagon::V6_vpackoh,
2142 const SDLoc &dl(
Results.InpNode);
2144 for (
int i = 0, e = std::size(Opcodes); i !=
e; ++i) {
2145 auto [
Size, Odd] = Packs[i];
2147 Results.push(Hexagon::A2_tfrsi, MVT::i32,
2148 {getSignedConst32(-2 *
Size, dl)});
2149 Results.push(Hexagon::V6_vdealvdd,
PairTy, {Vb, Va, OpRef::res(-1)});
2151 Results.push(Opcodes[i], SingleTy,
2152 {OpRef::hi(vdeal), OpRef::lo(vdeal)});
2153 return OpRef::res(
Results.top());
2159 Results.push(Hexagon::V6_vdealb4w, SingleTy, {Vb, Va});
2160 return OpRef::res(
Results.top());
2163 return OpRef::fail();
2166OpRef HvxSelector::expanding(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
2179 int VecLen = SM.Mask.
size();
2180 assert(2*HwLen ==
unsigned(VecLen) &&
"Expecting vector-pair type");
2182 std::pair<int,unsigned> Strip =
findStrip(SM.Mask, 1, VecLen);
2189 if (Strip.first != 0)
2190 return OpRef::fail();
2193 if (Strip.second != 1 && Strip.second != 2)
2194 return OpRef::fail();
2197 int L = Strip.second;
2200 for (
int I = 2*L;
I <
N;
I += 2*
L) {
2202 if (S.second !=
unsigned(L))
2203 return OpRef::fail();
2205 return OpRef::fail();
2208 for (
int I = L;
I <
N;
I += 2*
L) {
2210 if (S.first != -1 || S.second !=
unsigned(L))
2211 return OpRef::fail();
2214 unsigned Opc = Strip.second == 1 ? Hexagon::V6_vunpackub
2215 : Hexagon::V6_vunpackuh;
2217 return OpRef::res(
Results.top());
2220OpRef HvxSelector::perfect(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
2229 int VecLen = SM.Mask.
size();
2231 unsigned LogLen =
Log2_32(VecLen);
2232 unsigned HwLog =
Log2_32(HwLen);
2235 assert(LogLen == HwLog || LogLen == HwLog + 1);
2236 bool HavePairs = LogLen == HwLog + 1;
2238 SmallVector<unsigned, 8> Perm(LogLen);
2322 bool InvertedPair =
false;
2323 if (HavePairs && SM.Mask[0] >=
int(HwLen)) {
2324 for (
int i = 0, e = SM.Mask.
size(); i != e; ++i) {
2326 MaskStorage[i] =
M >= int(HwLen) ?
M - HwLen :
M + HwLen;
2328 InvertedPair =
true;
2329 SM = ShuffleMask(MaskStorage);
2332 auto Comps = getPerfectCompletions(SM, LogLen);
2334 return OpRef::fail();
2336 auto Pick = completeToPerfect(Comps, LogLen);
2337 for (
unsigned I = 0;
I != LogLen; ++
I)
2365 using CycleType = SmallVector<unsigned, 8>;
2366 std::set<CycleType> Cycles;
2367 std::set<unsigned>
All;
2369 for (
unsigned I : Perm)
2374 auto canonicalize = [LogLen](
const CycleType &
C) -> CycleType {
2375 unsigned LogPos,
N =
C.size();
2376 for (LogPos = 0; LogPos !=
N; ++LogPos)
2377 if (
C[LogPos] == LogLen - 1)
2382 CycleType NewC(
C.begin() + LogPos,
C.end());
2383 NewC.append(
C.begin(),
C.begin() + LogPos);
2387 auto pfs = [](
const std::set<CycleType> &Cs,
unsigned Len) {
2392 const CycleType &
C = *Cs.begin();
2393 if (
C[0] != Len - 1)
2395 int D =
Len -
C.size();
2396 if (
D != 0 &&
D != 1)
2399 bool IsDeal =
true, IsShuff =
true;
2400 for (
unsigned I = 1;
I !=
Len -
D; ++
I) {
2401 if (
C[
I] != Len - 1 -
I)
2403 if (
C[
I] !=
I - (1 -
D))
2407 assert(!(IsDeal || IsShuff) || IsDeal != IsShuff);
2408 static unsigned Deals[] = {Hexagon::V6_vdealb, Hexagon::V6_vdealh};
2409 static unsigned Shufs[] = {Hexagon::V6_vshuffb, Hexagon::V6_vshuffh};
2410 return IsDeal ? Deals[
D] : (IsShuff ? Shufs[
D] : 0);
2413 while (!
All.empty()) {
2414 unsigned A = *
All.begin();
2418 for (
unsigned B = Perm[
A];
B !=
A;
B = Perm[
B]) {
2424 Cycles.insert(canonicalize(
C));
2427 MVT SingleTy = getSingleVT(MVT::i8);
2428 MVT
PairTy = getPairVT(MVT::i8);
2431 if (
unsigned(VecLen) == HwLen) {
2432 if (
unsigned SingleOpc = pfs(Cycles, LogLen)) {
2433 Results.push(SingleOpc, SingleTy, {Va});
2434 return OpRef::res(
Results.top());
2444 SmallVector<unsigned, 8> SwapElems;
2457 for (
const CycleType &
C : Cycles) {
2459 unsigned First = (
C[0] == LogLen - 1) ? 1 : 0;
2467 const SDLoc &dl(
Results.InpNode);
2468 OpRef Arg = HavePairs ? Va : concats(Va, OpRef::undef(SingleTy),
Results);
2470 Arg = concats(OpRef::hi(Arg), OpRef::lo(Arg),
Results);
2472 for (
unsigned I = 0,
E = SwapElems.
size();
I !=
E;) {
2473 bool IsInc =
I ==
E - 1 || SwapElems[
I] < SwapElems[
I + 1];
2474 unsigned S = (1u << SwapElems[
I]);
2476 while (++
I <
E - 1 && IsInc == (SwapElems[
I] < SwapElems[
I + 1]))
2477 S |= 1u << SwapElems[
I];
2480 S |= 1u << SwapElems[
I];
2492 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getSignedConst32(SS, dl)});
2493 Res.Opc = IsInc ? Hexagon::V6_vshuffvdd : Hexagon::V6_vdealvdd;
2495 Res.Ops = {OpRef::hi(Arg), OpRef::lo(Arg), OpRef::res(-1)};
2497 Arg = OpRef::res(
Results.top());
2500 return HavePairs ? Arg : OpRef::lo(Arg);
2503OpRef HvxSelector::butterfly(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
2515 MVT ResTy = getSingleVT(MVT::i8);
2516 PermNetwork::Controls
FC, RC;
2517 const SDLoc &dl(
Results.InpNode);
2518 int VecLen = SM.Mask.
size();
2520 for (
int M : SM.Mask) {
2521 if (M != -1 && M >= VecLen)
2522 return OpRef::fail();
2526 ForwardDeltaNetwork FN(SM.Mask);
2528 SDValue Ctl = getVectorConstant(FC, dl);
2529 Results.push(Hexagon::V6_vdelta, ResTy, {Va, OpRef(Ctl)});
2530 return OpRef::res(
Results.top());
2534 ReverseDeltaNetwork
RN(SM.Mask);
2536 SDValue Ctl = getVectorConstant(RC, dl);
2537 Results.push(Hexagon::V6_vrdelta, ResTy, {Va, OpRef(Ctl)});
2538 return OpRef::res(
Results.top());
2542 BenesNetwork BN(SM.Mask);
2543 if (BN.run(FC, RC)) {
2544 SDValue CtlF = getVectorConstant(FC, dl);
2545 SDValue CtlR = getVectorConstant(RC, dl);
2546 Results.push(Hexagon::V6_vdelta, ResTy, {Va, OpRef(CtlF)});
2547 Results.push(Hexagon::V6_vrdelta, ResTy,
2548 {OpRef::res(-1), OpRef(CtlR)});
2549 return OpRef::res(
Results.top());
2552 return OpRef::fail();
2555SDValue HvxSelector::getConst32(
unsigned Val,
const SDLoc &dl) {
2556 return DAG.getTargetConstant(Val, dl, MVT::i32);
2559SDValue HvxSelector::getSignedConst32(
int Val,
const SDLoc &dl) {
2560 return DAG.getSignedTargetConstant(Val, dl, MVT::i32);
2563SDValue HvxSelector::getVectorConstant(ArrayRef<uint8_t>
Data,
2566 for (uint8_t
C :
Data)
2567 Elems.
push_back(DAG.getConstant(
C, dl, MVT::i8));
2569 SDValue BV = DAG.getBuildVector(VecTy, dl, Elems);
2571 DAG.RemoveDeadNode(BV.
getNode());
2577 MVT ResTy =
N->getValueType(0).getSimpleVT();
2578 unsigned Idx =
N->getConstantOperandVal(1);
2584 assert(Idx == 0 || Idx == ResLen);
2586 unsigned SubReg = Idx == 0 ? Hexagon::vsub_lo : Hexagon::vsub_hi;
2594 dbgs() <<
"Starting " << __func__ <<
" on node:\n";
2597 MVT ResTy =
N->getValueType(0).getSimpleVT();
2599 assert(ResTy.isVectorOf(MVT::i8));
2602 std::vector<int> Mask(SN->getMask().begin(), SN->getMask().end());
2604 for (
int &Idx : Mask)
2605 if (Idx != -1 && Idx < 0)
2608 unsigned VecLen = Mask.size();
2609 bool HavePairs = (2*
HwLen == VecLen);
2610 assert(ResTy.getSizeInBits() / 8 == VecLen);
2615 bool UseLeft =
false, UseRight =
false;
2616 for (
unsigned I = 0;
I != VecLen; ++
I) {
2619 unsigned Idx = Mask[
I];
2628 dbgs() <<
"VecLen=" << VecLen <<
" HwLen=" <<
HwLen <<
" UseLeft="
2629 << UseLeft <<
" UseRight=" << UseRight <<
" HavePairs="
2630 << HavePairs <<
'\n';
2633 if (!UseLeft && !UseRight) {
2643 OpRef Va = OpRef::undef(ResTy);
2644 OpRef Vb = OpRef::undef(ResTy);
2647 Results.push(TargetOpcode::COPY, ResTy, {Vec0});
2648 Va = OpRef::OpRef::res(
Results.top());
2651 Results.push(TargetOpcode::COPY, ResTy, {Vec1});
2652 Vb = OpRef::res(
Results.top());
2655 OpRef Res = !HavePairs ? shuffs2(ShuffleMask(Mask), Va, Vb,
Results)
2656 : shuffp2(ShuffleMask(Mask), Va, Vb,
Results);
2658 bool Done = Res.isValid();
2661 Results.push(TargetOpcode::COPY, ResTy, {Res});
2664 Done = scalarizeShuffle(Mask,
SDLoc(
N), ResTy, Vec0, Vec1,
N);
2669 dbgs() <<
"Unhandled shuffle:\n";
2678 MVT Ty =
N->getValueType(0).getSimpleVT();
2685 unsigned S = CN->getZExtValue() %
HST.getVectorLength();
2689 NewN =
DAG.getMachineNode(Hexagon::V6_valignbi, dl, Ty,
2690 {VecV, VecV, getConst32(S, dl)});
2695 NewN =
DAG.getMachineNode(Hexagon::V6_vror, dl, Ty, {VecV, RotV});
2697 ISel.ReplaceNode(
N, NewN);
2705 N->getValueType(0), {Vv, Vu, Rt});
2706 ISel.ReplaceNode(
N, NewN);
2707 DAG.RemoveDeadNode(
N);
2710void HexagonDAGToDAGISel::PreprocessHvxISelDAG() {
2711 auto getNodes = [
this]() -> std::vector<SDNode *> {
2712 std::vector<SDNode *>
T;
2713 T.reserve(CurDAG->allnodes_size());
2714 for (
SDNode &
N : CurDAG->allnodes())
2719 ppHvxShuffleOfShuffle(getNodes());
2724 return std::hash<const void *>()(V.getNode()) +
2725 std::hash<unsigned>()(V.getResNo());
2729void HexagonDAGToDAGISel::ppHvxShuffleOfShuffle(std::vector<SDNode *> &&Nodes) {
2740 unsigned HwLen = HST->getVectorLength();
2742 struct SubVectorInfo {
2743 SubVectorInfo(
SDValue S,
unsigned H) : Src(S), HalfIdx(
H) {}
2748 using MapType = DenseMap<SDValue, unsigned>;
2750 auto getMaskElt = [&](
unsigned Idx, ShuffleVectorSDNode *Shuff0,
2751 ShuffleVectorSDNode *Shuff1,
2752 const MapType &OpMap) ->
int {
2759 ShuffleVectorSDNode *OpShuff = Idx < HwLen ? Shuff0 : Shuff1;
2768 auto N =
static_cast<unsigned>(MaybeN);
2769 unsigned SrcBase =
N < HwLen ? OpMap.at(OpShuff->
getOperand(0))
2782 ArrayRef<int> TopMask =
This->getMask();
2785 assert(TopMask.
size() == S0->getMask().size() &&
2786 TopMask.
size() ==
S1->getMask().size());
2790 for (
unsigned I = 0;
I != HwLen; ++
I) {
2791 int MaybeM = TopMask[
I];
2794 getMaskElt(
static_cast<unsigned>(MaybeM), S0,
S1, OpMap);
2800 std::fill(FoldedMask.begin() + HwLen, FoldedMask.end(), -1);
2805 const SDLoc &dl(TopShuff);
2815 auto getSourceInfo = [](
SDValue V) -> std::optional<SubVectorInfo> {
2817 V =
V.getOperand(0);
2819 return std::nullopt;
2820 return SubVectorInfo(
V.getOperand(0),
2824 for (SDNode *
N : Nodes) {
2827 EVT ResTy =
N->getValueType(0);
2845 if (!V0A.has_value())
2848 if (!V0B.has_value() || V0B->Src != V0A->Src)
2850 auto V1A = getSourceInfo(
V1.getOperand(0));
2851 if (!V1A.has_value() || V1A->Src != V0A->Src)
2853 auto V1B = getSourceInfo(
V1.getOperand(1));
2854 if (!V1B.has_value() || V1B->Src != V0A->Src)
2859 assert(V0A->Src.getValueType().getSizeInBits() == 16 * HwLen);
2864 {
V1.getOperand(0), V1A->HalfIdx * HwLen},
2865 {
V1.getOperand(1), V1B->HalfIdx * HwLen},
2872void HexagonDAGToDAGISel::SelectHvxExtractSubvector(SDNode *
N) {
2873 HvxSelector(*
this, *CurDAG).selectExtractSubvector(
N);
2876void HexagonDAGToDAGISel::SelectHvxShuffle(SDNode *
N) {
2877 HvxSelector(*
this, *CurDAG).selectShuffle(
N);
2880void HexagonDAGToDAGISel::SelectHvxRor(SDNode *
N) {
2881 HvxSelector(*
this, *CurDAG).selectRor(
N);
2884void HexagonDAGToDAGISel::SelectHvxVAlign(SDNode *
N) {
2885 HvxSelector(*
this, *CurDAG).selectVAlign(
N);
2892 SDValue Predicate =
N->getOperand(3);
2894 SDValue Modifier =
N->getOperand(5);
2896 SDValue ImmOperand =
CurDAG->getTargetConstant(0, dl, MVT::i32);
2899 unsigned IntNo =
N->getConstantOperandVal(1);
2903 case Intrinsic::hexagon_V6_vgathermhq:
2904 case Intrinsic::hexagon_V6_vgathermhq_128B:
2905 Opcode = Hexagon::V6_vgathermhq_pseudo;
2907 case Intrinsic::hexagon_V6_vgathermwq:
2908 case Intrinsic::hexagon_V6_vgathermwq_128B:
2909 Opcode = Hexagon::V6_vgathermwq_pseudo;
2911 case Intrinsic::hexagon_V6_vgathermhwq:
2912 case Intrinsic::hexagon_V6_vgathermhwq_128B:
2913 Opcode = Hexagon::V6_vgathermhwq_pseudo;
2933 SDValue Modifier =
N->getOperand(4);
2935 SDValue ImmOperand =
CurDAG->getTargetConstant(0, dl, MVT::i32);
2938 unsigned IntNo =
N->getConstantOperandVal(1);
2942 case Intrinsic::hexagon_V6_vgathermh:
2943 case Intrinsic::hexagon_V6_vgathermh_128B:
2944 Opcode = Hexagon::V6_vgathermh_pseudo;
2946 case Intrinsic::hexagon_V6_vgathermw:
2947 case Intrinsic::hexagon_V6_vgathermw_128B:
2948 Opcode = Hexagon::V6_vgathermw_pseudo;
2950 case Intrinsic::hexagon_V6_vgathermhw:
2951 case Intrinsic::hexagon_V6_vgathermhw_128B:
2952 Opcode = Hexagon::V6_vgathermhw_pseudo;
2954 case Intrinsic::hexagon_V6_vgather_vscattermh:
2955 case Intrinsic::hexagon_V6_vgather_vscattermh_128B:
2956 Opcode = Hexagon::V6_vgather_vscatter_mh_pseudo;
2971 unsigned IID =
N->getConstantOperandVal(0);
2974 case Intrinsic::hexagon_V6_vaddcarry: {
2975 std::array<SDValue, 3>
Ops = {
2976 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2978 Result =
CurDAG->getMachineNode(Hexagon::V6_vaddcarry,
SDLoc(
N), VTs,
Ops);
2981 case Intrinsic::hexagon_V6_vaddcarry_128B: {
2982 std::array<SDValue, 3>
Ops = {
2983 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2985 Result =
CurDAG->getMachineNode(Hexagon::V6_vaddcarry,
SDLoc(
N), VTs,
Ops);
2988 case Intrinsic::hexagon_V6_vsubcarry: {
2989 std::array<SDValue, 3>
Ops = {
2990 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2992 Result =
CurDAG->getMachineNode(Hexagon::V6_vsubcarry,
SDLoc(
N), VTs,
Ops);
2995 case Intrinsic::hexagon_V6_vsubcarry_128B: {
2996 std::array<SDValue, 3>
Ops = {
2997 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2999 Result =
CurDAG->getMachineNode(Hexagon::V6_vsubcarry,
SDLoc(
N), VTs,
Ops);
3013 return Opcode == Intrinsic::hexagon_V6_vabs_hf_128B ||
3014 Opcode == Intrinsic::hexagon_V6_vabs_sf_128B ||
3015 Opcode == Intrinsic::hexagon_V6_vsub_hf_hf_128B ||
3016 Opcode == Intrinsic::hexagon_V6_vadd_hf_hf_128B ||
3017 Opcode == Intrinsic::hexagon_V6_vadd_sf_hf_128B ||
3018 Opcode == Intrinsic::hexagon_V6_vsub_sf_hf_128B ||
3019 Opcode == Intrinsic::hexagon_V6_vadd_sf_sf_128B ||
3020 Opcode == Intrinsic::hexagon_V6_vsub_sf_sf_128B ||
3021 Opcode == Intrinsic::hexagon_V6_vassign_fp_128B ||
3022 Opcode == Intrinsic::hexagon_V6_vfmin_hf_128B ||
3023 Opcode == Intrinsic::hexagon_V6_vfmin_sf_128B ||
3024 Opcode == Intrinsic::hexagon_V6_vfmax_hf_128B ||
3025 Opcode == Intrinsic::hexagon_V6_vfmax_sf_128B ||
3026 Opcode == Intrinsic::hexagon_V6_vfneg_hf_128B ||
3027 Opcode == Intrinsic::hexagon_V6_vfneg_sf_128B ||
3028 Opcode == Intrinsic::hexagon_V6_vmpy_sf_hf_acc_128B ||
3029 Opcode == Intrinsic::hexagon_V6_vmpy_hf_hf_acc_128B ||
3030 Opcode == Intrinsic::hexagon_V6_vmpy_sf_hf_128B ||
3031 Opcode == Intrinsic::hexagon_V6_vmpy_hf_hf_128B ||
3032 Opcode == Intrinsic::hexagon_V6_vmpy_sf_sf_128B ||
3033 Opcode == Intrinsic::hexagon_V6_vcvt_sf_hf_128B ||
3034 Opcode == Intrinsic::hexagon_V6_vcvt_hf_h_128B;
3041 MVT ResTy =
N->getValueType(0).getSimpleVT();
3045 case Intrinsic::hexagon_V6_vadd_sf_sf_128B: {
3047 Hexagon::V6_vadd_sf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3048 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3056 case Intrinsic::hexagon_V6_vsub_sf_sf_128B: {
3058 Hexagon::V6_vsub_sf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3059 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3067 case Intrinsic::hexagon_V6_vadd_hf_hf_128B: {
3069 Hexagon::V6_vadd_hf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3070 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_hf_qf16,
DL,
3078 case Intrinsic::hexagon_V6_vsub_hf_hf_128B: {
3080 Hexagon::V6_vsub_hf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3081 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_hf_qf16,
DL,
3094 case Intrinsic::hexagon_V6_vadd_sf_hf_128B: {
3096 SDNode *SplatPseudoNode =
3097 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, ResTy, Const);
3099 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3100 N->getOperand(1),
SDValue(SplatPseudoNode, 0));
3102 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3103 N->getOperand(2),
SDValue(SplatPseudoNode, 0));
3106 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNodeOp1, 0));
3108 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNodeOp1, 0));
3110 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNodeOp2, 0));
3112 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNodeOp2, 0));
3114 SDNode *LoAddNode =
CurDAG->getMachineNode(Hexagon::V6_vadd_qf32,
DL,
3115 MVT::v32i32, LoRegOp1, LoRegOp2);
3116 SDNode *HiAddNode =
CurDAG->getMachineNode(Hexagon::V6_vadd_qf32,
DL,
3117 MVT::v32i32, HiRegOp1, HiRegOp2);
3120 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(LoAddNode, 0));
3122 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(HiAddNode, 0));
3125 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3126 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3127 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3129 SDValue(ConvLoNode, 0), SubRegL};
3130 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
3144 case Intrinsic::hexagon_V6_vsub_sf_hf_128B: {
3146 SDNode *SplatPseudoNode =
3147 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, ResTy, Const);
3149 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3150 N->getOperand(1),
SDValue(SplatPseudoNode, 0));
3152 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3153 N->getOperand(2),
SDValue(SplatPseudoNode, 0));
3156 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNodeOp1, 0));
3158 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNodeOp1, 0));
3160 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNodeOp2, 0));
3162 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNodeOp2, 0));
3164 SDNode *LoSubNode =
CurDAG->getMachineNode(Hexagon::V6_vsub_qf32,
DL,
3165 MVT::v32i32, LoRegOp1, LoRegOp2);
3166 SDNode *HiSubNode =
CurDAG->getMachineNode(Hexagon::V6_vsub_qf32,
DL,
3167 MVT::v32i32, HiRegOp1, HiRegOp2);
3170 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(LoSubNode, 0));
3172 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(HiSubNode, 0));
3175 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3176 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3177 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3179 SDValue(ConvLoNode, 0), SubRegL};
3180 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
3188 case Intrinsic::hexagon_V6_vassign_fp_128B: {
3189 SDNode *AssignNode =
CurDAG->getMachineNode(Hexagon::V6_vassign,
DL, ResTy,
3197 case Intrinsic::hexagon_V6_vmpy_hf_hf_128B: {
3199 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, MVT::v64i32,
3200 N->getOperand(1),
N->getOperand(2));
3201 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_hf_qf32,
DL,
3209 case Intrinsic::hexagon_V6_vmpy_sf_sf_128B: {
3211 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_sf,
DL, ResTy,
3212 N->getOperand(1),
N->getOperand(2));
3213 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3221 case Intrinsic::hexagon_V6_vmpy_sf_hf_128B: {
3223 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3224 N->getOperand(1),
N->getOperand(2));
3226 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3228 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3229 SDNode *ConvLoNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3230 MVT::v32i32, LoReg);
3231 SDNode *ConvHiNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3232 MVT::v32i32, HiReg);
3235 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3236 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3237 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3239 SDValue(ConvLoNode, 0), SubRegL};
3240 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
3253 case Intrinsic::hexagon_V6_vmpy_hf_hf_acc_128B: {
3255 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, MVT::v64i32,
3256 N->getOperand(2),
N->getOperand(3));
3260 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, MVT::v64i32, Const);
3262 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, MVT::v64i32,
3263 N->getOperand(1),
SDValue(SplatConstNode, 0));
3266 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3268 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3270 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(WidenAcc, 0));
3272 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(WidenAcc, 0));
3275 Hexagon::V6_vadd_qf32,
DL, MVT::v32i32, LoWidenAcc, LoMpyNode);
3277 Hexagon::V6_vadd_qf32,
DL, MVT::v32i32, HiWidenAcc, HiMpyNode);
3280 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3281 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3282 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3284 SDValue(LoAddNode, 0), SubRegL};
3285 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
3288 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_hf_qf32,
DL,
3298 case Intrinsic::hexagon_V6_vmpy_sf_hf_acc_128B: {
3300 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3301 N->getOperand(2),
N->getOperand(3));
3304 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3306 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3309 Hexagon::vsub_lo,
DL, MVT::v32i32,
N->getOperand(1));
3311 Hexagon::vsub_hi,
DL, MVT::v32i32,
N->getOperand(1));
3314 Hexagon::V6_vadd_qf32_mix,
DL, MVT::v32i32, LoRegMpy, LoRegDest);
3316 Hexagon::V6_vadd_qf32_mix,
DL, MVT::v32i32, HiRegMpy, HiRegDest);
3319 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(LoAddNode, 0));
3321 Hexagon::V6_vconv_sf_qf32,
DL, MVT::v32i32,
SDValue(HiAddNode, 0));
3324 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3325 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3326 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3328 SDValue(ConvLoNode, 0), SubRegL};
3329 SDNode *RS =
CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE,
DL,
3337 case Intrinsic::hexagon_V6_vfmin_hf_128B: {
3339 Hexagon::V6_vmin_hf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3345 case Intrinsic::hexagon_V6_vfmin_sf_128B: {
3347 Hexagon::V6_vmin_sf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3353 case Intrinsic::hexagon_V6_vfmax_hf_128B: {
3355 Hexagon::V6_vmax_hf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3361 case Intrinsic::hexagon_V6_vfmax_sf_128B: {
3363 Hexagon::V6_vmax_sf,
DL, ResTy,
N->getOperand(1),
N->getOperand(2));
3371 case Intrinsic::hexagon_V6_vabs_hf_128B: {
3373 SDNode *SplatPseudoNode =
3374 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, ResTy, Const);
3376 CurDAG->getMachineNode(Hexagon::V6_vand,
DL, ResTy,
N->getOperand(1),
3385 case Intrinsic::hexagon_V6_vabs_sf_128B: {
3387 SDNode *SplatPseudoNode =
3388 CurDAG->getMachineNode(Hexagon::PS_vsplatiw,
DL, ResTy, Const);
3390 CurDAG->getMachineNode(Hexagon::V6_vand,
DL, ResTy,
N->getOperand(1),
3399 case Intrinsic::hexagon_V6_vfneg_hf_128B: {
3401 SDNode *SplatPseudoNode =
3402 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, ResTy, Const);
3404 CurDAG->getMachineNode(Hexagon::V6_vxor,
DL, ResTy,
N->getOperand(1),
3413 case Intrinsic::hexagon_V6_vfneg_sf_128B: {
3415 SDNode *SplatPseudoNode =
3416 CurDAG->getMachineNode(Hexagon::PS_vsplatiw,
DL, ResTy, Const);
3418 CurDAG->getMachineNode(Hexagon::V6_vxor,
DL, ResTy,
N->getOperand(1),
3425 case Intrinsic::hexagon_V6_vcvt_hf_h_128B: {
3426 SDNode *ConvNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_hf_h,
DL, ResTy,
3436 case Intrinsic::hexagon_V6_vcvt_sf_hf_128B: {
3438 SDNode *SplatPseudoNode =
3439 CurDAG->getMachineNode(Hexagon::PS_vsplatih,
DL, ResTy, Const);
3441 CurDAG->getMachineNode(Hexagon::V6_vmpy_qf32_hf,
DL, ResTy,
3442 N->getOperand(1),
SDValue(SplatPseudoNode, 0));
3445 Hexagon::vsub_lo,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3447 Hexagon::vsub_hi,
DL, MVT::v32i32,
SDValue(MpyNode, 0));
3448 SDNode *ConvLoNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3449 MVT::v32i32, LoReg);
3450 SDNode *ConvHiNode =
CurDAG->getMachineNode(Hexagon::V6_vconv_sf_qf32,
DL,
3451 MVT::v32i32, HiReg);
3454 CurDAG->getTargetConstant(Hexagon::HvxWRRegClassID,
DL, MVT::i32);
3455 SDValue SubRegL =
CurDAG->getTargetConstant(Hexagon::vsub_lo,
DL, MVT::i32);
3456 SDValue SubRegH =
CurDAG->getTargetConstant(Hexagon::vsub_hi,
DL, MVT::i32);
3458 SDValue(ConvLoNode, 0), SubRegL};
3459 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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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 bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
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.
@ 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
Type * getValueType(Value *V, bool ReVec, bool LookThroughCmp)
Returns the "element type" of the given value/instruction V.
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.
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.
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.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
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