15#include "llvm/IR/IntrinsicsHexagon.h"
26#include <unordered_map>
30#define DEBUG_TYPE "hexagon-isel"
100enum class ColorKind {
None, Red, Black };
106 using MapType = std::map<Node, ColorKind>;
115 const MapType &colors()
const {
119 ColorKind other(ColorKind Color) {
120 if (Color == ColorKind::None)
121 return ColorKind::Red;
122 return Color == ColorKind::Red ? ColorKind::Black : ColorKind::Red;
130 std::set<Node> Needed;
132 using NodeSet = std::set<Node>;
133 std::map<Node,NodeSet> Edges;
137 return (Pos < Num/2) ? Pos + Num/2 : Pos - Num/2;
140 ColorKind getColor(
Node N) {
141 auto F = Colors.find(
N);
142 return F != Colors.end() ?
F->second : ColorKind::None;
145 std::pair<bool, ColorKind> getUniqueColor(
const NodeSet &Nodes);
152std::pair<bool, ColorKind> Coloring::getUniqueColor(
const NodeSet &Nodes) {
153 auto Color = ColorKind::None;
154 for (
Node N : Nodes) {
155 ColorKind ColorN = getColor(
N);
156 if (ColorN == ColorKind::None)
158 if (Color == ColorKind::None)
160 else if (Color != ColorKind::None && Color != ColorN)
161 return {
false, ColorKind::None };
163 return {
true, Color };
166void Coloring::build() {
168 for (
unsigned P = 0;
P != Order.size(); ++
P) {
172 Node PC = Order[conj(
P)];
178 for (
unsigned I = 0;
I != Order.size(); ++
I) {
179 if (!Needed.count(
I))
191bool Coloring::color() {
193 auto Enqueue = [
this,&FirstQ] (
Node N) {
196 for (
unsigned I = 0;
I != Q.
size(); ++
I) {
202 for (
Node N : Needed)
205 for (
Node N : FirstQ) {
209 auto P = getUniqueColor(Ns);
212 Colors[
N] = other(
P.second);
216 for (
auto E : Edges) {
218 if (!Needed.count(conj(
N)) || Colors.count(
N))
220 auto P = getUniqueColor(E.second);
223 Colors[
N] = other(
P.second);
228 std::vector<Node> WorkQ;
229 for (
auto E : Edges) {
231 if (!Colors.count(
N))
235 for (
Node N : WorkQ) {
237 auto P = getUniqueColor(Ns);
239 Colors[
N] = other(
P.second);
245 ColorKind ColorN = other(ColorKind::None);
246 ColorKind ColorC = other(ColorN);
249 for (
Node M : CopyNs) {
250 ColorKind ColorM = getColor(M);
251 if (ColorM == ColorC) {
264 for (
unsigned I = 0;
I != Order.size(); ++
I)
265 Colors.try_emplace(
I, ColorKind::None);
270#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
271void Coloring::dump()
const {
272 dbgs() <<
"{ Order: {";
273 for (
Node P : Order) {
280 dbgs() <<
" Needed: {";
281 for (
Node N : Needed)
285 dbgs() <<
" Edges: {\n";
286 for (
auto E : Edges) {
287 dbgs() <<
" " << E.first <<
" -> {";
288 for (
auto N : E.second)
294 auto ColorKindToName = [](ColorKind
C) {
296 case ColorKind::None:
300 case ColorKind::Black:
306 dbgs() <<
" Colors: {\n";
307 for (
auto C : Colors)
308 dbgs() <<
" " <<
C.first <<
" -> " << ColorKindToName(
C.second) <<
"\n";
318 using Controls = std::vector<uint8_t>;
319 using ElemType = int;
320 static constexpr ElemType
Ignore = ElemType(-1);
336 unsigned S = Order.size();
340 Table.resize(Order.size());
341 for (RowType &Row : Table)
342 Row.resize(Mult*Log, None);
345 void getControls(Controls &V,
unsigned StartAt,
uint8_t Dir)
const {
346 unsigned Size = Order.size();
348 for (
unsigned I = 0;
I !=
Size; ++
I) {
350 for (
unsigned L = 0;
L != Log; ++
L) {
351 unsigned C = ctl(
I, StartAt+L) ==
Switch;
362 uint8_t ctl(ElemType Pos,
unsigned Step)
const {
363 return Table[Pos][Step];
365 unsigned size()
const {
368 unsigned steps()
const {
374 std::vector<ElemType> Order;
375 using RowType = std::vector<uint8_t>;
376 std::vector<RowType> Table;
379struct ForwardDeltaNetwork :
public PermNetwork {
382 bool run(Controls &V) {
383 if (!route(Order.data(), Table.data(),
size(), 0))
385 getControls(V, 0, Forward);
390 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
393struct ReverseDeltaNetwork :
public PermNetwork {
396 bool run(Controls &V) {
397 if (!route(Order.data(), Table.data(),
size(), 0))
404 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
407struct BenesNetwork :
public PermNetwork {
410 bool run(Controls &
F, Controls &R) {
411 if (!route(Order.data(), Table.data(),
size(), 0))
414 getControls(
F, 0, Forward);
420 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
424bool ForwardDeltaNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
426 bool UseUp =
false, UseDown =
false;
433 for (ElemType J = 0; J != Num; ++J) {
441 S = (J < Num/2) ?
Pass : Switch;
443 S = (J < Num/2) ? Switch :
Pass;
446 ElemType
U = (S ==
Pass) ?
I : (
I < Num/2 ?
I+Num/2 :
I-Num/2);
451 if (
T[U][Step] != S &&
T[U][Step] !=
None)
456 for (ElemType J = 0; J != Num; ++J)
457 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
461 if (UseUp && !route(
P,
T,
Size/2, Step+1))
469bool ReverseDeltaNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
471 unsigned Pets = Log-1 - Step;
472 bool UseUp =
false, UseDown =
false;
477 const Coloring::MapType &
M =
G.colors();
481 ColorKind ColorUp = ColorKind::None;
482 for (ElemType J = 0; J != Num; ++J) {
488 ColorKind
C =
M.at(
I);
489 if (
C == ColorKind::None)
494 bool InpUp =
I < Num/2;
495 if (ColorUp == ColorKind::None)
496 ColorUp = InpUp ?
C :
G.other(
C);
497 if ((
C == ColorUp) != InpUp) {
504 S = (J < Num/2) ?
Pass : Switch;
507 S = (J < Num/2) ? Switch :
Pass;
515 for (ElemType J = 0, E =
Size / 2; J != E; ++J) {
517 ElemType PC =
P[J+
Size/2];
520 if (
T[J][Pets] == Switch)
522 if (
T[J+
Size/2][Pets] == Switch)
528 for (ElemType J = 0; J != Num; ++J)
529 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
533 if (UseUp && !route(
P,
T,
Size/2, Step+1))
541bool BenesNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
544 const Coloring::MapType &
M =
G.colors();
549 unsigned Pets = 2*Log-1 - Step;
550 bool UseUp =
false, UseDown =
false;
555 ColorKind ColorUp = ColorKind::None;
556 for (ElemType J = 0; J != Num; ++J) {
560 ColorKind
C =
M.at(
I);
561 if (
C == ColorKind::None)
563 if (ColorUp == ColorKind::None) {
564 ColorUp = (
I < Num / 2) ? ColorKind::Red : ColorKind::Black;
566 unsigned CI = (
I < Num/2) ?
I+Num/2 :
I-Num/2;
572 T[J][Pets] = (J < Num/2) ?
Pass : Switch;
579 T[J][Pets] = (J < Num/2) ? Switch :
Pass;
586 for (ElemType J = 0; J != Num/2; ++J) {
588 ElemType PC =
P[J+Num/2];
591 if (
T[J][Pets] == Switch)
593 if (
T[J+Num/2][Pets] == Switch)
599 for (ElemType J = 0; J != Num; ++J)
600 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
604 if (UseUp && !route(
P,
T,
Size/2, Step+1))
619 bool isValue()
const {
return OpV.getNode() !=
nullptr; }
622 static OpRef res(
int N) {
return OpRef(Whole | (
N & Index)); }
623 static OpRef
fail() {
return OpRef(Invalid); }
625 static OpRef
lo(
const OpRef &R) {
627 return OpRef(
R.OpN & (Undef | Index | LoHalf));
629 static OpRef
hi(
const OpRef &R) {
631 return OpRef(
R.OpN & (Undef | Index | HiHalf));
633 static OpRef undef(
MVT Ty) {
return OpRef(Undef | Ty.
SimpleTy); }
649 Whole = LoHalf | HiHalf,
659 OpRef(
unsigned N) : OpN(
N) {}
663 NodeTemplate() =
default;
666 std::vector<OpRef> Ops;
676 unsigned push(
const NodeTemplate &Res) {
678 return List.size()-1;
680 unsigned push(
unsigned Opc,
MVT Ty, std::vector<OpRef> &&Ops) {
687 bool empty()
const {
return List.empty(); }
688 unsigned size()
const {
return List.size(); }
689 unsigned top()
const {
return size()-1; }
690 const NodeTemplate &operator[](
unsigned I)
const {
return List[
I]; }
691 unsigned reset(
unsigned NewTop) {
692 List.resize(NewTop+1);
696 using BaseType = std::vector<NodeTemplate>;
697 BaseType::iterator
begin() {
return List.begin(); }
698 BaseType::iterator
end() {
return List.end(); }
699 BaseType::const_iterator
begin()
const {
return List.begin(); }
700 BaseType::const_iterator
end()
const {
return List.end(); }
709#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
712 OpV.getNode()->print(
OS, &
G);
723 if ((OpN & Whole) != Whole) {
724 assert((OpN & Whole) == LoHalf || (OpN & Whole) == HiHalf);
738 for (
const auto &R : Ops) {
748 OS <<
"Input node:\n";
752 OS <<
"Result templates:\n";
753 for (
unsigned I = 0, E =
List.size();
I != E; ++
I) {
754 OS <<
'[' <<
I <<
"] ";
767 MinSrc = (MinSrc == -1) ? M : std::min(MinSrc, M);
768 MaxSrc = (MaxSrc == -1) ? M : std::max(MaxSrc, M);
773 int MinSrc = -1, MaxSrc = -1;
775 ShuffleMask
lo()
const {
776 size_t H =
Mask.size()/2;
777 return ShuffleMask(
Mask.take_front(
H));
779 ShuffleMask
hi()
const {
780 size_t H =
Mask.size()/2;
781 return ShuffleMask(
Mask.take_back(
H));
785 OS <<
"MinSrc:" << MinSrc <<
", MaxSrc:" << MaxSrc <<
" {";
823 for (
int i = 0; i != Len; ++i) {
843 for (
int i = 0; i != Len; ++i) {
854 auto Odd =
static_cast<int>(TakeOdd);
855 for (
int i = 0, e = Len / (2 *
Size); i != e; ++i) {
856 for (
int b = 0; b !=
static_cast<int>(
Size); ++b) {
858 Vd[i *
Size + b] = Vv[(2 * i + Odd) *
Size + b];
859 Vd[i *
Size + b + Len / 2] = Vu[(2 * i + Odd) *
Size + b];
869 auto Odd =
static_cast<int>(TakeOdd);
870 for (
int i = 0, e = Len / (2 *
Size); i != e; ++i) {
871 for (
int b = 0; b !=
static_cast<int>(
Size); ++b) {
872 Vd[(2 * i + 0) *
Size + b] = Vv[(2 * i + Odd) *
Size + b];
873 Vd[(2 * i + 1) *
Size + b] = Vu[(2 * i + Odd) *
Size + b];
888 for (
int i = 0, e = Len / 4; i != e; ++i) {
889 Vd[0 * (Len / 4) + i] = Vv[4 * i + 0];
890 Vd[1 * (Len / 4) + i] = Vv[4 * i + 2];
891 Vd[2 * (Len / 4) + i] = Vu[4 * i + 0];
892 Vd[3 * (Len / 4) + i] = Vu[4 * i + 2];
897template <
typename ShuffFunc,
typename... OptArgs>
900 std::iota(Vu.begin(), Vu.end(),
Length);
902 return S(Vu, Vv,
args...);
930 assert(ElemTy != MVT::i1 &&
"Use getBoolVT for predicates");
936 assert(ElemTy != MVT::i1);
955 static std::optional<int>
rotationDistance(ShuffleMask SM,
unsigned WrapAt);
958 void select(
SDNode *ISelN);
959 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) {
1138 for (
unsigned i = 0; i != WorkQ.
size(); ++i) {
1142 for (
unsigned j = 0, f =
W->getNumOperands(); j != f; ++j)
1143 WorkQ.
insert(
W->getOperand(j).getNode());
1149 return !Nodes.empty();
1152void HvxSelector::materialize(
const ResultStack &
Results) {
1154 dbgs() <<
"Materializing\n";
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;
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
1196 SDNode *ResN = (
Node.Opc == TargetOpcode::COPY)
1197 ? Ops.front().getNode()
1199 Output.push_back(
SDValue(ResN, 0));
1202 SDNode *OutN = Output.back().getNode();
1205 dbgs() <<
"Generated node:\n";
1210 selectVectorConstants(OutN);
1214OpRef HvxSelector::concats(OpRef
Lo, OpRef
Hi, ResultStack &
Results) {
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)
1242 if (Amount > VecLen) {
1247 if (isUInt<3>(Amount)) {
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();
1283 OpRef Inp[2] = {Va, Vb};
1284 unsigned VecLen = SM.Mask.size();
1286 auto valign = [
this](OpRef
Lo, OpRef
Hi,
unsigned Amt,
MVT Ty,
1291 if (isUInt<3>(Amt) || isUInt<3>(
HwLen - Amt)) {
1292 bool IsRight = isUInt<3>(Amt);
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");
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)) {
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);
1443 assert(SMA.Mask.size() == VecLen);
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];
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();
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);
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());
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); }));
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) {
1585 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(HalfLen, dl)});
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);
1593 OpRef
P = perfect(SM, Va,
Results);
1596 return butterfly(SM, Va,
Results);
1599OpRef HvxSelector::shuffs2(ShuffleMask SM, OpRef Va, OpRef Vb,
1605 OpRef
C = contracting(SM, Va, Vb,
Results);
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();
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);
1647 OpRef E = expanding(PM,
P,
Results);
1653 if (
L.isValid() &&
H.isValid())
1663 OpRef
R = perfect(SM, Va,
Results);
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);
1708 template <
typename T>
1715 template <
typename T>
1716 struct NullifyingVector :
public T {
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) {
1760 if (SubNodes.
empty()) {
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) {
1802 std::map<SDNode *, unsigned> OpCount;
1805 return Dom.count(U.getNode());
1808 OpCount.insert({
T, NumDomOps});
1813 for (
unsigned I = 0;
I != TmpQ.
size(); ++
I) {
1818 auto F = OpCount.find(U);
1820 if (
F->second > 0 && !--
F->second)
1829 NullifyingVector<
decltype(TmpQ)::vector_type>
Queue(TmpQ.
takeVector());
1831 Deleter DUQ(
DAG, Queue);
1845 assert(ElemTy == MVT::i8);
1846 unsigned VecLen =
Mask.size();
1847 bool HavePairs = (2*
HwLen == VecLen);
1866 for (
int I : Mask) {
1895 if (2*
HwLen == VecLen) {
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();
2081 OpRef Funnel = funnels(Va, Vb, *Dist,
Results);
2082 if (Funnel.isValid())
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,
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, {getConst32(-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);
2235 assert(LogLen == HwLog || LogLen == HwLog + 1);
2236 bool HavePairs = LogLen == HwLog + 1;
2322 bool InvertedPair =
false;
2323 if (HavePairs && SM.Mask[0] >=
int(
HwLen)) {
2324 for (
int i = 0, e = SM.Mask.size(); i != e; ++i) {
2328 InvertedPair =
true;
2329 SM = ShuffleMask(MaskStorage);
2334 return OpRef::fail();
2337 for (
unsigned I = 0;
I != LogLen; ++
I)
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));
2431 if (
unsigned(VecLen) ==
HwLen) {
2432 if (
unsigned SingleOpc = pfs(Cycles, LogLen)) {
2433 Results.push(SingleOpc, SingleTy, {Va});
2434 return OpRef::res(
Results.top());
2457 for (
const CycleType &
C : Cycles) {
2459 unsigned First = (
C[0] == LogLen - 1) ? 1 : 0;
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];
2485 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(S, dl)});
2486 Res.Opc = IsInc ? Hexagon::V6_vshuffvdd : Hexagon::V6_vdealvdd;
2488 Res.Ops = {OpRef::hi(Arg), OpRef::lo(Arg), OpRef::res(-1)};
2490 Arg = OpRef::res(
Results.top());
2493 return HavePairs ? Arg : OpRef::lo(Arg);
2496OpRef HvxSelector::butterfly(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
2509 PermNetwork::Controls
FC, RC;
2511 int VecLen = SM.Mask.size();
2513 for (
int M : SM.Mask) {
2514 if (M != -1 && M >= VecLen)
2515 return OpRef::fail();
2519 ForwardDeltaNetwork FN(SM.Mask);
2521 SDValue Ctl = getVectorConstant(FC, dl);
2522 Results.push(Hexagon::V6_vdelta, ResTy, {Va, OpRef(Ctl)});
2523 return OpRef::res(
Results.top());
2527 ReverseDeltaNetwork
RN(SM.Mask);
2529 SDValue Ctl = getVectorConstant(RC, dl);
2530 Results.push(Hexagon::V6_vrdelta, ResTy, {Va, OpRef(Ctl)});
2531 return OpRef::res(
Results.top());
2535 BenesNetwork BN(SM.Mask);
2536 if (BN.run(FC, RC)) {
2537 SDValue CtlF = getVectorConstant(FC, dl);
2538 SDValue CtlR = getVectorConstant(RC, dl);
2539 Results.push(Hexagon::V6_vdelta, ResTy, {Va, OpRef(CtlF)});
2540 Results.push(Hexagon::V6_vrdelta, ResTy,
2541 {OpRef::res(-1), OpRef(CtlR)});
2542 return OpRef::res(
Results.top());
2545 return OpRef::fail();
2548SDValue HvxSelector::getConst32(
int Val,
const SDLoc &dl) {
2566 MVT ResTy =
N->getValueType(0).getSimpleVT();
2567 unsigned Idx =
N->getConstantOperandVal(1);
2575 unsigned SubReg =
Idx == 0 ? Hexagon::vsub_lo : Hexagon::vsub_hi;
2583 dbgs() <<
"Starting " << __func__ <<
" on node:\n";
2586 MVT ResTy =
N->getValueType(0).getSimpleVT();
2588 assert(ResTy.isVector() && ResTy.getVectorElementType() == MVT::i8);
2590 auto *SN = cast<ShuffleVectorSDNode>(
N);
2591 std::vector<int> Mask(SN->getMask().begin(), SN->getMask().end());
2593 for (
int &
Idx : Mask)
2594 if (
Idx != -1 &&
Idx < 0)
2597 unsigned VecLen = Mask.size();
2598 bool HavePairs = (2*
HwLen == VecLen);
2599 assert(ResTy.getSizeInBits() / 8 == VecLen);
2604 bool UseLeft =
false, UseRight =
false;
2605 for (
unsigned I = 0;
I != VecLen; ++
I) {
2608 unsigned Idx = Mask[
I];
2617 dbgs() <<
"VecLen=" << VecLen <<
" HwLen=" <<
HwLen <<
" UseLeft="
2618 << UseLeft <<
" UseRight=" << UseRight <<
" HavePairs="
2619 << HavePairs <<
'\n';
2622 if (!UseLeft && !UseRight) {
2632 OpRef Va = OpRef::undef(ResTy);
2633 OpRef Vb = OpRef::undef(ResTy);
2636 Results.push(TargetOpcode::COPY, ResTy, {Vec0});
2637 Va = OpRef::OpRef::res(
Results.top());
2640 Results.push(TargetOpcode::COPY, ResTy, {Vec1});
2641 Vb = OpRef::res(
Results.top());
2644 OpRef Res = !HavePairs ? shuffs2(ShuffleMask(Mask), Va, Vb,
Results)
2645 : shuffp2(ShuffleMask(Mask), Va, Vb,
Results);
2647 bool Done = Res.isValid();
2650 Results.push(TargetOpcode::COPY, ResTy, {Res});
2653 Done = scalarizeShuffle(Mask,
SDLoc(
N), ResTy, Vec0, Vec1,
N);
2658 dbgs() <<
"Unhandled shuffle:\n";
2667 MVT Ty =
N->getValueType(0).getSimpleVT();
2673 if (
auto *CN = dyn_cast<ConstantSDNode>(RotV.
getNode())) {
2677 }
else if (isUInt<3>(S)) {
2679 {VecV, VecV, getConst32(S, dl)});
2694 N->getValueType(0), {Vv, Vu, Rt});
2699void HexagonDAGToDAGISel::PreprocessHvxISelDAG() {
2700 auto getNodes = [
this]() -> std::vector<SDNode *> {
2701 std::vector<SDNode *>
T;
2708 ppHvxShuffleOfShuffle(getNodes());
2713 return std::hash<const void *>()(V.getNode()) +
2714 std::hash<unsigned>()(V.getResNo());
2718void HexagonDAGToDAGISel::ppHvxShuffleOfShuffle(std::vector<SDNode *> &&Nodes) {
2731 struct SubVectorInfo {
2732 SubVectorInfo(
SDValue S,
unsigned H) : Src(S), HalfIdx(
H) {}
2737 using MapType = std::unordered_map<SDValue, unsigned>;
2741 const MapType &OpMap) ->
int {
2757 auto N =
static_cast<unsigned>(MaybeN);
2758 unsigned SrcBase =
N < HwLen ? OpMap.at(OpShuff->
getOperand(0))
2768 auto *
This = cast<ShuffleVectorSDNode>(TopShuff);
2769 auto *S0 = cast<ShuffleVectorSDNode>(TopShuff.
getOperand(0));
2770 auto *
S1 = cast<ShuffleVectorSDNode>(TopShuff.
getOperand(1));
2774 assert(TopMask.
size() == S0->getMask().size() &&
2775 TopMask.
size() ==
S1->getMask().size());
2779 for (
unsigned I = 0;
I != HwLen; ++
I) {
2780 int MaybeM = TopMask[
I];
2783 getMaskElt(
static_cast<unsigned>(MaybeM), S0,
S1, OpMap);
2789 std::fill(FoldedMask.begin() + HwLen, FoldedMask.end(), -1);
2794 const SDLoc &dl(TopShuff);
2804 auto getSourceInfo = [](
SDValue V) -> std::optional<SubVectorInfo> {
2806 V =
V.getOperand(0);
2808 return std::nullopt;
2809 return SubVectorInfo(
V.getOperand(0),
2810 !cast<ConstantSDNode>(
V.getOperand(1))->isZero());
2816 EVT ResTy =
N->getValueType(0);
2834 if (!V0A.has_value())
2837 if (!V0B.has_value() || V0B->Src != V0A->Src)
2840 if (!V1A.has_value() || V1A->Src != V0A->Src)
2843 if (!V1B.has_value() || V1B->Src != V0A->Src)
2848 assert(V0A->Src.getValueType().getSizeInBits() == 16 * HwLen);
2861void HexagonDAGToDAGISel::SelectHvxExtractSubvector(
SDNode *
N) {
2865void HexagonDAGToDAGISel::SelectHvxShuffle(
SDNode *
N) {
2869void HexagonDAGToDAGISel::SelectHvxRor(
SDNode *
N) {
2873void HexagonDAGToDAGISel::SelectHvxVAlign(
SDNode *
N) {
2881 SDValue Predicate =
N->getOperand(3);
2883 SDValue Modifier =
N->getOperand(5);
2888 unsigned IntNo =
N->getConstantOperandVal(1);
2892 case Intrinsic::hexagon_V6_vgathermhq:
2893 case Intrinsic::hexagon_V6_vgathermhq_128B:
2894 Opcode = Hexagon::V6_vgathermhq_pseudo;
2896 case Intrinsic::hexagon_V6_vgathermwq:
2897 case Intrinsic::hexagon_V6_vgathermwq_128B:
2898 Opcode = Hexagon::V6_vgathermwq_pseudo;
2900 case Intrinsic::hexagon_V6_vgathermhwq:
2901 case Intrinsic::hexagon_V6_vgathermhwq_128B:
2902 Opcode = Hexagon::V6_vgathermhwq_pseudo;
2922 SDValue Modifier =
N->getOperand(4);
2927 unsigned IntNo =
N->getConstantOperandVal(1);
2931 case Intrinsic::hexagon_V6_vgathermh:
2932 case Intrinsic::hexagon_V6_vgathermh_128B:
2933 Opcode = Hexagon::V6_vgathermh_pseudo;
2935 case Intrinsic::hexagon_V6_vgathermw:
2936 case Intrinsic::hexagon_V6_vgathermw_128B:
2937 Opcode = Hexagon::V6_vgathermw_pseudo;
2939 case Intrinsic::hexagon_V6_vgathermhw:
2940 case Intrinsic::hexagon_V6_vgathermhw_128B:
2941 Opcode = Hexagon::V6_vgathermhw_pseudo;
2956 unsigned IID =
N->getConstantOperandVal(0);
2959 case Intrinsic::hexagon_V6_vaddcarry: {
2960 std::array<SDValue, 3> Ops = {
2961 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2966 case Intrinsic::hexagon_V6_vaddcarry_128B: {
2967 std::array<SDValue, 3> Ops = {
2968 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2973 case Intrinsic::hexagon_V6_vsubcarry: {
2974 std::array<SDValue, 3> Ops = {
2975 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2980 case Intrinsic::hexagon_V6_vsubcarry_128B: {
2981 std::array<SDValue, 3> Ops = {
2982 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefAnalysis InstSet InstSet & Ignore
Function Alias Analysis Results
static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val)
static void fail(const SDLoc &DL, SelectionDAG &DAG, const Twine &Msg, SDValue Val={})
This file implements the BitVector class.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
#define LLVM_ATTRIBUTE_UNUSED
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
const HexagonInstrInfo * TII
static bool isIdentity(ArrayRef< int > Mask)
static std::pair< int, unsigned > findStrip(ArrayRef< int > A, int Inc, unsigned MaxLen)
static bool isUndef(ArrayRef< int > Mask)
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)
std::pair< MCSymbol *, MachineModuleInfoImpl::StubValueTy > PairTy
static bool isUndef(const MachineInstr &MI)
static bool isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
static Type * getValueType(Value *V)
Returns the type of the given value/instruction V.
static LLVM_ATTRIBUTE_ALWAYS_INLINE MVT::SimpleValueType getSimpleVT(const unsigned char *MatcherTable, unsigned &MatcherIndex)
getSimpleVT - Decode a value in MatcherTable, if it's a VBR encoded value, use GetVBR to decode it.
This file implements a set that has insertion order iteration characteristics.
#define DEBUG_WITH_TYPE(TYPE,...)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
ArrayRef< T > take_front(size_t N=1) const
Return a copy of *this with only the first N elements.
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
size_t size() const
size - Get the array size.
ArrayRef< T > take_back(size_t N=1) const
Return a copy of *this with only the last N elements.
iterator_range< const_set_bits_iterator > set_bits() const
This class represents an Operation in the Expression.
iterator find(const_arg_type_t< KeyT > Val)
Tagged union holding either a T or a Error.
void print(raw_ostream &OS, AssemblyAnnotationWriter *AAW=nullptr, bool ShouldPreserveUseListOrder=false, bool IsForDebug=false) const
Print the function to an output stream with an optional AssemblyAnnotationWriter.
void Select(SDNode *N) override
Main hook for targets to transform nodes into machine nodes.
void SelectV65GatherPred(SDNode *N)
friend struct HvxSelector
void SelectV65Gather(SDNode *N)
void SelectHVXDualOutput(SDNode *N)
unsigned getVectorLength() const
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override
This callback is invoked for operations that are unsupported by the target, which are registered to u...
This is an important class for using LLVM in a threaded context.
unsigned getVectorNumElements() const
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
A description of a memory reference used in the backend.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
MutableArrayRef< T > take_back(size_t N=1) const
Return a copy of *this with only the last N elements.
MutableArrayRef< T > take_front(size_t N=1) const
Return a copy of *this with only the first N elements.
A NodeSet contains a set of SUnit DAG nodes with additional information that assigns a priority to th...
Pass interface - Implemented by all 'passes'.
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
iterator_range< user_iterator > users()
Represents a use of a SDNode.
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...
LLVM_ABI SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef< SDValue > Ops)
Return an ISD::BUILD_VECTOR node.
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 void setNodeMemRefs(MachineSDNode *N, ArrayRef< MachineMemOperand * > NewMemRefs)
Mutate the specified machine node's memory references to the provided list.
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 void RemoveDeadNodes()
This method deletes all unreachable nodes in the SelectionDAG.
LLVM_ABI void RemoveDeadNode(SDNode *N)
Remove the specified node from the system.
LLVM_ABI SDValue getTargetExtractSubreg(int SRIdx, const SDLoc &DL, EVT VT, SDValue Operand)
A convenience function for creating TargetInstrInfo::EXTRACT_SUBREG nodes.
iterator_range< allnodes_iterator > allnodes()
LLVM_ABI SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
ilist< SDNode >::size_type allnodes_size() const
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
LLVMContext * getContext() const
LLVM_ABI SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef< int > Mask)
Return an ISD::VECTOR_SHUFFLE node.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
void insert_range(Range &&R)
Vector takeVector()
Clear the SetVector and return the underlying vector.
size_type count(const key_type &key) const
Count the number of elements of a given key in the SetVector.
bool empty() const
Determine if the SetVector is empty or not.
bool insert(const value_type &X)
Insert a new element into the SetVector.
This SDNode is used to implement the code generator support for the llvm IR shufflevector instruction...
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)
pointer data()
Return a pointer to the vector's buffer, even if empty().
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetInstrInfo - Interface to description of machine instruction set.
virtual EVT getTypeToTransformTo(LLVMContext &Context, EVT VT) const
For types supported by the target, this is an identity function.
This class implements an extremely fast bulk output stream that can only output to a stream.
#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...
@ Undef
Value of the register doesn't matter.
@ Switch
The "resume-switch" lowering, where there are separate resume and destroy functions that are shared b...
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
LLVM_ABI const_iterator begin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get begin iterator over path.
LLVM_ABI const_iterator end(StringRef path LLVM_LIFETIME_BOUND)
Get end iterator over path.
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.
int popcount(T Value) noexcept
Count the number of set bits in a value.
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.
SmallVectorImpl< T >::const_pointer c_str(SmallVectorImpl< T > &str)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
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.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
@ 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.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
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...
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)
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