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) {
200 FirstQ.
insert(Q.begin(), Q.end());
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 if (Colors.count(
I) == 0)
266 Colors[
I] = ColorKind::None;
271#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
272void Coloring::dump()
const {
273 dbgs() <<
"{ Order: {";
274 for (
Node P : Order) {
281 dbgs() <<
" Needed: {";
282 for (
Node N : Needed)
286 dbgs() <<
" Edges: {\n";
287 for (
auto E : Edges) {
288 dbgs() <<
" " << E.first <<
" -> {";
289 for (
auto N : E.second)
295 auto ColorKindToName = [](ColorKind
C) {
297 case ColorKind::None:
301 case ColorKind::Black:
307 dbgs() <<
" Colors: {\n";
308 for (
auto C : Colors)
309 dbgs() <<
" " <<
C.first <<
" -> " << ColorKindToName(
C.second) <<
"\n";
319 using Controls = std::vector<uint8_t>;
320 using ElemType = int;
321 static constexpr ElemType
Ignore = ElemType(-1);
337 unsigned S = Order.size();
341 Table.resize(Order.size());
342 for (RowType &Row : Table)
343 Row.resize(Mult*Log, None);
346 void getControls(Controls &V,
unsigned StartAt,
uint8_t Dir)
const {
347 unsigned Size = Order.size();
349 for (
unsigned I = 0;
I !=
Size; ++
I) {
351 for (
unsigned L = 0;
L != Log; ++
L) {
352 unsigned C = ctl(
I, StartAt+L) ==
Switch;
363 uint8_t ctl(ElemType Pos,
unsigned Step)
const {
364 return Table[Pos][Step];
366 unsigned size()
const {
369 unsigned steps()
const {
375 std::vector<ElemType> Order;
376 using RowType = std::vector<uint8_t>;
377 std::vector<RowType> Table;
380struct ForwardDeltaNetwork :
public PermNetwork {
383 bool run(Controls &V) {
384 if (!route(Order.data(), Table.data(),
size(), 0))
386 getControls(V, 0, Forward);
391 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
394struct ReverseDeltaNetwork :
public PermNetwork {
397 bool run(Controls &V) {
398 if (!route(Order.data(), Table.data(),
size(), 0))
405 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
408struct BenesNetwork :
public PermNetwork {
411 bool run(Controls &
F, Controls &R) {
412 if (!route(Order.data(), Table.data(),
size(), 0))
415 getControls(
F, 0, Forward);
421 bool route(ElemType *
P, RowType *
T,
unsigned Size,
unsigned Step);
425bool ForwardDeltaNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
427 bool UseUp =
false, UseDown =
false;
434 for (ElemType J = 0; J != Num; ++J) {
442 S = (J < Num/2) ?
Pass : Switch;
444 S = (J < Num/2) ? Switch :
Pass;
447 ElemType
U = (S ==
Pass) ?
I : (
I < Num/2 ?
I+Num/2 :
I-Num/2);
452 if (
T[U][Step] != S &&
T[U][Step] !=
None)
457 for (ElemType J = 0; J != Num; ++J)
458 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
462 if (UseUp && !route(
P,
T,
Size/2, Step+1))
470bool ReverseDeltaNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
472 unsigned Pets = Log-1 - Step;
473 bool UseUp =
false, UseDown =
false;
478 const Coloring::MapType &
M =
G.colors();
482 ColorKind ColorUp = ColorKind::None;
483 for (ElemType J = 0; J != Num; ++J) {
489 ColorKind
C =
M.at(
I);
490 if (
C == ColorKind::None)
495 bool InpUp =
I < Num/2;
496 if (ColorUp == ColorKind::None)
497 ColorUp = InpUp ?
C :
G.other(
C);
498 if ((
C == ColorUp) != InpUp) {
505 S = (J < Num/2) ?
Pass : Switch;
508 S = (J < Num/2) ? Switch :
Pass;
516 for (ElemType J = 0, E =
Size / 2; J != E; ++J) {
518 ElemType PC =
P[J+
Size/2];
521 if (
T[J][Pets] == Switch)
523 if (
T[J+
Size/2][Pets] == Switch)
529 for (ElemType J = 0; J != Num; ++J)
530 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
534 if (UseUp && !route(
P,
T,
Size/2, Step+1))
542bool BenesNetwork::route(ElemType *
P, RowType *
T,
unsigned Size,
545 const Coloring::MapType &
M =
G.colors();
550 unsigned Pets = 2*Log-1 - Step;
551 bool UseUp =
false, UseDown =
false;
556 ColorKind ColorUp = ColorKind::None;
557 for (ElemType J = 0; J != Num; ++J) {
561 ColorKind
C =
M.at(
I);
562 if (
C == ColorKind::None)
564 if (ColorUp == ColorKind::None) {
565 ColorUp = (
I < Num / 2) ? ColorKind::Red : ColorKind::Black;
567 unsigned CI = (
I < Num/2) ?
I+Num/2 :
I-Num/2;
573 T[J][Pets] = (J < Num/2) ?
Pass : Switch;
580 T[J][Pets] = (J < Num/2) ? Switch :
Pass;
587 for (ElemType J = 0; J != Num/2; ++J) {
589 ElemType PC =
P[J+Num/2];
592 if (
T[J][Pets] == Switch)
594 if (
T[J+Num/2][Pets] == Switch)
600 for (ElemType J = 0; J != Num; ++J)
601 if (
P[J] !=
Ignore &&
P[J] >= Num/2)
605 if (UseUp && !route(
P,
T,
Size/2, Step+1))
620 bool isValue()
const {
return OpV.getNode() !=
nullptr; }
623 static OpRef res(
int N) {
return OpRef(Whole | (
N & Index)); }
624 static OpRef
fail() {
return OpRef(Invalid); }
626 static OpRef
lo(
const OpRef &R) {
628 return OpRef(
R.OpN & (Undef | Index | LoHalf));
630 static OpRef
hi(
const OpRef &R) {
632 return OpRef(
R.OpN & (Undef | Index | HiHalf));
634 static OpRef undef(
MVT Ty) {
return OpRef(Undef | Ty.
SimpleTy); }
650 Whole = LoHalf | HiHalf,
660 OpRef(
unsigned N) : OpN(
N) {}
664 NodeTemplate() =
default;
667 std::vector<OpRef> Ops;
677 unsigned push(
const NodeTemplate &Res) {
679 return List.size()-1;
681 unsigned push(
unsigned Opc,
MVT Ty, std::vector<OpRef> &&Ops) {
688 bool empty()
const {
return List.empty(); }
689 unsigned size()
const {
return List.size(); }
690 unsigned top()
const {
return size()-1; }
691 const NodeTemplate &operator[](
unsigned I)
const {
return List[
I]; }
692 unsigned reset(
unsigned NewTop) {
693 List.resize(NewTop+1);
697 using BaseType = std::vector<NodeTemplate>;
698 BaseType::iterator
begin() {
return List.begin(); }
699 BaseType::iterator
end() {
return List.end(); }
700 BaseType::const_iterator
begin()
const {
return List.begin(); }
701 BaseType::const_iterator
end()
const {
return List.end(); }
710#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
713 OpV.getNode()->print(
OS, &
G);
724 if ((OpN & Whole) != Whole) {
725 assert((OpN & Whole) == LoHalf || (OpN & Whole) == HiHalf);
739 for (
const auto &R : Ops) {
749 OS <<
"Input node:\n";
753 OS <<
"Result templates:\n";
754 for (
unsigned I = 0, E =
List.size();
I != E; ++
I) {
755 OS <<
'[' <<
I <<
"] ";
768 MinSrc = (MinSrc == -1) ? M : std::min(MinSrc, M);
769 MaxSrc = (MaxSrc == -1) ? M : std::max(MaxSrc, M);
774 int MinSrc = -1, MaxSrc = -1;
776 ShuffleMask
lo()
const {
777 size_t H =
Mask.size()/2;
778 return ShuffleMask(
Mask.take_front(
H));
780 ShuffleMask
hi()
const {
781 size_t H =
Mask.size()/2;
782 return ShuffleMask(
Mask.take_back(
H));
786 OS <<
"MinSrc:" << MinSrc <<
", MaxSrc:" << MaxSrc <<
" {";
824 for (
int i = 0; i != Len; ++i) {
844 for (
int i = 0; i != Len; ++i) {
855 auto Odd =
static_cast<int>(TakeOdd);
856 for (
int i = 0, e = Len / (2 *
Size); i != e; ++i) {
857 for (
int b = 0; b !=
static_cast<int>(
Size); ++b) {
859 Vd[i *
Size + b] = Vv[(2 * i + Odd) *
Size + b];
860 Vd[i *
Size + b + Len / 2] = Vu[(2 * i + Odd) *
Size + b];
870 auto Odd =
static_cast<int>(TakeOdd);
871 for (
int i = 0, e = Len / (2 *
Size); i != e; ++i) {
872 for (
int b = 0; b !=
static_cast<int>(
Size); ++b) {
873 Vd[(2 * i + 0) *
Size + b] = Vv[(2 * i + Odd) *
Size + b];
874 Vd[(2 * i + 1) *
Size + b] = Vu[(2 * i + Odd) *
Size + b];
889 for (
int i = 0, e = Len / 4; i != e; ++i) {
890 Vd[0 * (Len / 4) + i] = Vv[4 * i + 0];
891 Vd[1 * (Len / 4) + i] = Vv[4 * i + 2];
892 Vd[2 * (Len / 4) + i] = Vu[4 * i + 0];
893 Vd[3 * (Len / 4) + i] = Vu[4 * i + 2];
898template <
typename ShuffFunc,
typename... OptArgs>
901 std::iota(Vu.begin(), Vu.end(),
Length);
903 return S(Vu, Vv,
args...);
931 assert(ElemTy != MVT::i1 &&
"Use getBoolVT for predicates");
937 assert(ElemTy != MVT::i1);
956 static std::optional<int>
rotationDistance(ShuffleMask SM,
unsigned WrapAt);
959 void select(
SDNode *ISelN);
960 void materialize(
const ResultStack &
Results);
969 OpRef concats(OpRef Va, OpRef Vb, ResultStack &
Results);
970 OpRef funnels(OpRef Va, OpRef Vb,
int Amount, ResultStack &
Results);
972 OpRef packs(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &
Results,
974 OpRef packp(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &
Results,
981 OpRef shuffs1(ShuffleMask SM, OpRef Va, ResultStack &
Results);
982 OpRef shuffs2(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &
Results);
983 OpRef shuffp1(ShuffleMask SM, OpRef Va, ResultStack &
Results);
984 OpRef shuffp2(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &
Results);
986 OpRef butterfly(ShuffleMask SM, OpRef Va, ResultStack &
Results);
987 OpRef contracting(ShuffleMask SM, OpRef Va, OpRef Vb, ResultStack &
Results);
988 OpRef expanding(ShuffleMask SM, OpRef Va, ResultStack &
Results);
989 OpRef perfect(ShuffleMask SM, OpRef Va, ResultStack &
Results);
991 bool selectVectorConstants(
SDNode *
N);
999 unsigned VecLen = Mask.size();
1001 for (
unsigned I = 0;
I != VecLen; ++
I) {
1004 MaskL[
I] = MaskR[
I] = -1;
1005 }
else if (
unsigned(M) < VecLen) {
1010 MaskR[
I] = M-VecLen;
1017 assert(
A.size() > 0 &&
A.size() >= MaxLen);
1020 for (
unsigned I = 1;
I != MaxLen; ++
I) {
1021 if (
A[
I] - E != Inc)
1025 return {
F, MaxLen };
1029 for (
int Idx : Mask)
1036 for (
int I = 0, E = Mask.size();
I != E; ++
I) {
1038 if (M >= 0 && M !=
I)
1045 int L = Mask.size();
1048 return llvm::all_of(Mask.drop_front(L / 2), [](
int M) { return M < 0; });
1055 if (SM.MaxSrc == -1)
1058 unsigned Shift =
Log2_32(SegLen);
1061 for (
int M : SM.Mask) {
1063 Segs.
set(M >> Shift);
1082 unsigned MaskLen = SM.Mask.
size();
1083 assert(MaskLen % SegLen == 0);
1086 for (
int S = 0, E = Map.size(); S != E; ++S) {
1088 for (
int I = 0;
I !=
static_cast<int>(SegLen); ++
I) {
1089 int M = SM.Mask[S*SegLen +
I];
1092 unsigned G = M / SegLen;
1095 }
else if (
Idx !=
G) {
1109 for (
int I = OutSegMap.
size() - 1;
I >= 0; --
I) {
1110 unsigned S = OutSegMap[
I];
1111 assert(S != ~0u &&
"Unexpected undef");
1112 assert(S != ~1u &&
"Unexpected multi");
1113 if (InvMap.
size() <= S)
1118 unsigned Shift =
Log2_32(SegLen);
1119 for (
int I = 0, E = Mask.size();
I != E; ++
I) {
1122 int OutIdx = InvMap[M >> Shift];
1123 M = (M & (SegLen-1)) + SegLen*OutIdx;
1129bool HvxSelector::selectVectorConstants(
SDNode *
N) {
1140 for (
unsigned i = 0; i != WorkQ.
size(); ++i) {
1144 for (
unsigned j = 0, f =
W->getNumOperands(); j != f; ++j)
1145 WorkQ.
insert(
W->getOperand(j).getNode());
1151 return !Nodes.empty();
1154void HvxSelector::materialize(
const ResultStack &
Results) {
1156 dbgs() <<
"Materializing\n";
1162 std::vector<SDValue> Output;
1166 std::vector<SDValue> Ops;
1167 for (
const OpRef &R :
Node.Ops) {
1170 Ops.push_back(
R.OpV);
1173 if (
R.OpN & OpRef::Undef) {
1175 Ops.push_back(
ISel.selectUndef(dl,
MVT(SVT)));
1179 unsigned Part =
R.OpN & OpRef::Whole;
1185 MVT OpTy =
Op.getValueType().getSimpleVT();
1186 if (Part != OpRef::Whole) {
1187 assert(Part == OpRef::LoHalf || Part == OpRef::HiHalf);
1190 unsigned Sub = (Part == OpRef::LoHalf) ? Hexagon::vsub_lo
1198 SDNode *ResN = (
Node.Opc == TargetOpcode::COPY)
1199 ? Ops.front().getNode()
1201 Output.push_back(
SDValue(ResN, 0));
1204 SDNode *OutN = Output.back().getNode();
1207 dbgs() <<
"Generated node:\n";
1212 selectVectorConstants(OutN);
1216OpRef HvxSelector::concats(OpRef
Lo, OpRef
Hi, ResultStack &
Results) {
1220 getConst32(Hexagon::HvxWRRegClassID, dl),
1221 Lo, getConst32(Hexagon::vsub_lo, dl),
1222 Hi, getConst32(Hexagon::vsub_hi, dl),
1224 return OpRef::res(
Results.top());
1227OpRef HvxSelector::funnels(OpRef Va, OpRef Vb,
int Amount,
1232 auto VecLen =
static_cast<int>(
HwLen);
1236 if (Amount == VecLen)
1244 if (Amount > VecLen) {
1249 if (isUInt<3>(Amount)) {
1250 SDValue A = getConst32(Amount, dl);
1251 Results.push(Hexagon::V6_valignbi, Ty, {Vb, Va,
A});
1252 }
else if (isUInt<3>(VecLen - Amount)) {
1253 SDValue A = getConst32(VecLen - Amount, dl);
1254 Results.push(Hexagon::V6_vlalignbi, Ty, {Vb, Va,
A});
1256 SDValue A = getConst32(Amount, dl);
1257 Results.push(Hexagon::A2_tfrsi, Ty, {
A});
1258 Results.push(Hexagon::V6_valignb, Ty, {Vb, Va, OpRef::res(-1)});
1260 return OpRef::res(
Results.top());
1266OpRef HvxSelector::packs(ShuffleMask SM, OpRef Va, OpRef Vb,
1270 if (!Va.isValid() || !Vb.isValid())
1271 return OpRef::fail();
1274 std::copy(SM.Mask.begin(), SM.Mask.end(), NewMask.
begin());
1278 std::copy(SM.Mask.begin(), SM.Mask.end(), NewMask.
begin());
1285 OpRef Inp[2] = {Va, Vb};
1286 unsigned VecLen = SM.Mask.size();
1288 auto valign = [
this](OpRef
Lo, OpRef
Hi,
unsigned Amt,
MVT Ty,
1293 if (isUInt<3>(Amt) || isUInt<3>(
HwLen - Amt)) {
1294 bool IsRight = isUInt<3>(Amt);
1295 SDValue S = getConst32(IsRight ? Amt :
HwLen - Amt, dl);
1296 unsigned Opc = IsRight ? Hexagon::V6_valignbi : Hexagon::V6_vlalignbi;
1298 return OpRef::res(
Results.top());
1300 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(Amt, dl)});
1301 OpRef
A = OpRef::res(
Results.top());
1303 return OpRef::res(
Results.top());
1307 unsigned SegLen =
HwLen / 2;
1313 unsigned SegCount = SegList.
size();
1316 if (SegList.
empty())
1317 return OpRef::undef(Ty);
1335 unsigned Seg0 = ~0
u, Seg1 = ~0
u;
1336 for (
unsigned X : SegMap) {
1341 else if (Seg1 != ~0u)
1343 if (
X == ~1u ||
X != Seg0)
1347 if (SegCount == 1) {
1348 unsigned SrcOp = SegList[0] / 2;
1349 for (
int I = 0;
I !=
static_cast<int>(VecLen); ++
I) {
1360 if (SegCount == 2) {
1367 if (Seg0 == ~1u || Seg1 == ~1u) {
1371 }
else if (Seg0 == ~1u) {
1372 Seg0 = SegList[0] != Seg1 ? SegList[0] : SegList[1];
1375 Seg1 = SegList[0] != Seg0 ? SegList[0] : SegList[1];
1378 assert(Seg0 != ~1u && Seg1 != ~1u);
1380 assert(Seg0 != Seg1 &&
"Expecting different segments");
1382 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(SegLen, dl)});
1383 OpRef HL = OpRef::res(
Results.top());
1387 if (Seg0 / 2 == Seg1 / 2) {
1392 Results.push(Hexagon::V6_vror, Ty, {Inp[Seg0 / 2], HL});
1393 Va = OpRef::res(
Results.top());
1396 }
else if (Seg0 % 2 == Seg1 % 2) {
1400 auto Vs = (Seg0 == 0 || Seg0 == 1) ? std::make_pair(Vb, Va)
1401 : std::make_pair(Va, Vb);
1402 Results.push(Hexagon::V6_vshuffvdd,
PairTy, {Vs.first, Vs.second, HL});
1403 OpRef
P = OpRef::res(
Results.top());
1404 Va = (Seg0 == 0 || Seg0 == 2) ? OpRef::lo(
P) : OpRef::hi(
P);
1408 if ((Seg0 == 0 && Seg1 == 3) || (Seg0 == 2 && Seg1 == 1)) {
1413 OpRef Qt = OpRef::res(
Results.top());
1414 auto Vs = (Seg0 == 0) ? std::make_pair(Va, Vb)
1415 : std::make_pair(Vb, Va);
1416 Results.push(Hexagon::V6_vmux, Ty, {Qt, Vs.first, Vs.second});
1417 Va = OpRef::res(
Results.top());
1423 assert(Seg0 == 1 || Seg0 == 3);
1430 ShuffleMask SMH(MaskH);
1431 assert(SMH.Mask.size() == VecLen);
1434 if (SMH.MaxSrc - SMH.MinSrc >=
static_cast<int>(
HwLen)) {
1438 ShuffleMask SW(Swapped);
1439 if (SW.MaxSrc - SW.MinSrc <
static_cast<int>(
HwLen)) {
1440 MaskA.assign(SW.Mask.begin(), SW.Mask.end());
1444 ShuffleMask SMA(MaskA);
1445 assert(SMA.Mask.size() == VecLen);
1447 if (SMA.MaxSrc - SMA.MinSrc <
static_cast<int>(
HwLen)) {
1448 int ShiftR = SMA.MinSrc;
1449 if (ShiftR >=
static_cast<int>(
HwLen)) {
1451 Vb = OpRef::undef(Ty);
1454 OpRef RetVal = valign(Va, Vb, ShiftR, Ty,
Results);
1456 for (
int I = 0;
I !=
static_cast<int>(VecLen); ++
I) {
1457 int M = SMA.Mask[
I];
1476 for (
int I = 0;
I !=
static_cast<int>(VecLen); ++
I) {
1480 if (M >=
static_cast<int>(
HwLen))
1491 return vmuxs(MuxBytes, Va, Vb,
Results);
1493 return OpRef::fail();
1499OpRef HvxSelector::packp(ShuffleMask SM, OpRef Va, OpRef Vb,
1503 if (SegList.empty())
1504 return OpRef::undef(
getPairVT(MVT::i8));
1508 unsigned SegCount = SegList.size();
1510 return OpRef::fail();
1514 OpRef Inp[2] = { Va, Vb };
1515 OpRef Out[2] = { OpRef::undef(HalfTy), OpRef::undef(HalfTy) };
1520 for (
int I = 0, E = SegList.size();
I != E; ++
I) {
1521 unsigned S = SegList[
I];
1522 OpRef
Op = Inp[S / 2];
1523 Out[
I] = (S & 1) ? OpRef::hi(
Op) : OpRef::lo(
Op);
1533 return concats(Out[0], Out[1],
Results);
1542 SDValue B = getVectorConstant(Bytes, dl);
1543 Results.push(Hexagon::V6_vd0, ByteTy, {});
1544 Results.push(Hexagon::V6_veqb, BoolTy, {OpRef(
B), OpRef::res(-1)});
1545 Results.push(Hexagon::V6_vmux, ByteTy, {OpRef::res(-1), Vb, Va});
1546 return OpRef::res(
Results.top());
1552 size_t S = Bytes.
size() / 2;
1558OpRef HvxSelector::shuffs1(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
1560 unsigned VecLen = SM.Mask.size();
1563 assert(
all_of(SM.Mask, [
this](
int M) { return M == -1 || M < int(HwLen); }));
1572 OpRef Rotate = funnels(Va, Va, *Dist,
Results);
1573 if (Rotate.isValid())
1576 unsigned HalfLen =
HwLen / 2;
1581 std::pair<int, unsigned> Strip1 =
findStrip(SM.Mask, 1, HalfLen);
1582 if ((Strip1.first & ~HalfLen) == 0 && Strip1.second == HalfLen) {
1583 std::pair<int, unsigned> Strip2 =
1584 findStrip(SM.Mask.drop_front(HalfLen), 1, HalfLen);
1585 if (Strip1 == Strip2) {
1587 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(HalfLen, dl)});
1589 {Va, Va, OpRef::res(
Results.top())});
1590 OpRef S = OpRef::res(
Results.top());
1591 return (Strip1.first == 0) ? OpRef::lo(S) : OpRef::
hi(S);
1595 OpRef
P = perfect(SM, Va,
Results);
1598 return butterfly(SM, Va,
Results);
1601OpRef HvxSelector::shuffs2(ShuffleMask SM, OpRef Va, OpRef Vb,
1607 OpRef
C = contracting(SM, Va, Vb,
Results);
1611 int VecLen = SM.Mask.size();
1613 OpRef
P = packs(SM, Va, Vb,
Results, PackedMask);
1615 return shuffs1(ShuffleMask(PackedMask),
P,
Results);
1623 OpRef
L = shuffs1(ShuffleMask(MaskL), Va,
Results);
1624 OpRef
R = shuffs1(ShuffleMask(MaskR), Vb,
Results);
1625 if (!
L.isValid() || !
R.isValid())
1626 return OpRef::fail();
1629 for (
int I = 0;
I != VecLen; ++
I) {
1633 return vmuxs(Bytes, L, R,
Results);
1636OpRef HvxSelector::shuffp1(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
1638 int VecLen = SM.Mask.size();
1643 return OpRef::undef(
getPairVT(MVT::i8));
1646 OpRef
P = packs(SM, OpRef::lo(Va), OpRef::hi(Va),
Results, PackedMask);
1648 ShuffleMask PM(PackedMask);
1649 OpRef E = expanding(PM,
P,
Results);
1655 if (
L.isValid() &&
H.isValid())
1665 OpRef
R = perfect(SM, Va,
Results);
1671 OpRef
L = shuffs2(SM.lo(), OpRef::lo(Va), OpRef::hi(Va),
Results);
1672 OpRef
H = shuffs2(SM.hi(), OpRef::lo(Va), OpRef::hi(Va),
Results);
1673 if (
L.isValid() &&
H.isValid())
1676 return OpRef::fail();
1679OpRef HvxSelector::shuffp2(ShuffleMask SM, OpRef Va, OpRef Vb,
1683 return OpRef::undef(
getPairVT(MVT::i8));
1685 int VecLen = SM.Mask.size();
1687 OpRef
P = packp(SM, Va, Vb,
Results, PackedMask);
1689 return shuffp1(ShuffleMask(PackedMask),
P,
Results);
1694 OpRef
L = shuffp1(ShuffleMask(MaskL), Va,
Results);
1695 OpRef
R = shuffp1(ShuffleMask(MaskR), Vb,
Results);
1696 if (!
L.isValid() || !
R.isValid())
1697 return OpRef::fail();
1701 for (
int I = 0;
I != VecLen; ++
I) {
1705 return vmuxp(Bytes, L, R,
Results);
1710 template <
typename T>
1717 template <
typename T>
1718 struct NullifyingVector :
public T {
1720 NullifyingVector(
T &&V) :
T(
V) {
1721 for (
unsigned i = 0, e = T::size(); i !=
e; ++i) {
1722 SDNode *&
N = T::operator[](i);
1728 if (
F != Refs.
end())
1729 *
F->second =
nullptr;
1734void HvxSelector::select(
SDNode *ISelN) {
1762 if (SubNodes.
empty()) {
1773 auto IsDomRec = [&Dom, &NonDom] (
SDNode *
T,
auto Rec) ->
bool {
1776 if (
T->use_empty() || NonDom.
count(
T))
1778 for (
SDNode *U :
T->users()) {
1790 auto IsDom = [&IsDomRec] (
SDNode *
T) {
return IsDomRec(
T, IsDomRec); };
1793 for (
unsigned I = 0;
I != SubNodes.
size(); ++
I) {
1804 std::map<SDNode *, unsigned> OpCount;
1807 return Dom.count(U.getNode());
1810 OpCount.insert({
T, NumDomOps});
1815 for (
unsigned I = 0;
I != TmpQ.
size(); ++
I) {
1820 auto F = OpCount.find(U);
1822 if (
F->second > 0 && !--
F->second)
1831 NullifyingVector<
decltype(TmpQ)::vector_type>
Queue(TmpQ.
takeVector());
1833 Deleter DUQ(
DAG, Queue);
1847 assert(ElemTy == MVT::i8);
1848 unsigned VecLen =
Mask.size();
1849 bool HavePairs = (2*
HwLen == VecLen);
1868 for (
int I : Mask) {
1897 if (2*
HwLen == VecLen) {
1923 unsigned Impossible = ~(1u << Width) + 1;
1924 for (
unsigned I = 0, E = Bs.
size();
I != E; ++
I) {
1928 if (~Impossible == 0)
1930 for (
unsigned Log = 0; Log != Width; ++Log) {
1931 if (Impossible & (1u << Log))
1935 Impossible |= (1u << Log);
1943 for (
unsigned BitIdx = 0; BitIdx != Width; ++BitIdx) {
1945 for (
int i = 0, e = SM.Mask.size(); i != e; ++i) {
1948 BitValues[i] = 0xff;
1950 BitValues[i] = (M & (1u << BitIdx)) != 0;
1952 Worklist[BitIdx] = possibilities(BitValues, Width);
1994 for (
unsigned I = 0, E = Sorted.
size();
I != E;) {
1995 unsigned P = Sorted[
I], Count = 1;
1996 while (++
I != E &&
P == Sorted[
I])
2014 for (
unsigned I = 0;
I != Width; ++
I) {
2022 for (
unsigned J =
I + 1; J != Width; ++J) {
2036 assert(OrAll == (1u << Width) -1);
2044 std::optional<int> Dist;
2045 for (
int I = 0, E = SM.Mask.size();
I != E; ++
I) {
2050 if ((
I + *Dist) %
static_cast<int>(WrapAt) != M)
2051 return std::nullopt;
2058 Dist = *Dist + WrapAt;
2064OpRef HvxSelector::contracting(ShuffleMask SM, OpRef Va, OpRef Vb,
2067 if (!Va.isValid() || !Vb.isValid())
2068 return OpRef::fail();
2079 int VecLen = SM.Mask.size();
2083 OpRef Funnel = funnels(Va, Vb, *Dist,
Results);
2084 if (Funnel.isValid())
2092 return Mask1 == Mask2;
2095 using PackConfig = std::pair<unsigned, bool>;
2096 PackConfig Packs[] = {
2104 unsigned Opcodes[] = {
2105 Hexagon::V6_vpackeb,
2106 Hexagon::V6_vpackob,
2107 Hexagon::V6_vpackeh,
2108 Hexagon::V6_vpackoh,
2110 for (
int i = 0, e = std::size(Opcodes); i !=
e; ++i) {
2111 auto [
Size, Odd] = Packs[i];
2113 Results.push(Opcodes[i], SingleTy, {Vb, Va});
2114 return OpRef::res(
Results.top());
2120 unsigned Opcodes[] = {
2121 Hexagon::V6_vshuffeb,
2122 Hexagon::V6_vshuffob,
2123 Hexagon::V6_vshufeh,
2124 Hexagon::V6_vshufoh,
2126 for (
int i = 0, e = std::size(Opcodes); i !=
e; ++i) {
2127 auto [
Size, Odd] = Packs[i];
2129 Results.push(Opcodes[i], SingleTy, {Vb, Va});
2130 return OpRef::res(
Results.top());
2139 unsigned Opcodes[] = {
2140 Hexagon::V6_vpackeb,
2141 Hexagon::V6_vpackob,
2142 Hexagon::V6_vpackeh,
2143 Hexagon::V6_vpackoh,
2147 for (
int i = 0, e = std::size(Opcodes); i !=
e; ++i) {
2148 auto [
Size, Odd] = Packs[i];
2150 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(-2 *
Size, dl)});
2151 Results.push(Hexagon::V6_vdealvdd,
PairTy, {Vb, Va, OpRef::res(-1)});
2153 Results.push(Opcodes[i], SingleTy,
2154 {OpRef::hi(vdeal), OpRef::lo(vdeal)});
2155 return OpRef::res(
Results.top());
2161 Results.push(Hexagon::V6_vdealb4w, SingleTy, {Vb, Va});
2162 return OpRef::res(
Results.top());
2165 return OpRef::fail();
2168OpRef HvxSelector::expanding(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
2181 int VecLen = SM.Mask.size();
2182 assert(2*
HwLen ==
unsigned(VecLen) &&
"Expecting vector-pair type");
2184 std::pair<int,unsigned> Strip =
findStrip(SM.Mask, 1, VecLen);
2191 if (Strip.first != 0)
2192 return OpRef::fail();
2195 if (Strip.second != 1 && Strip.second != 2)
2196 return OpRef::fail();
2199 int L = Strip.second;
2202 for (
int I = 2*L;
I <
N;
I += 2*
L) {
2204 if (S.second !=
unsigned(L))
2205 return OpRef::fail();
2207 return OpRef::fail();
2210 for (
int I = L;
I <
N;
I += 2*
L) {
2212 if (S.first != -1 || S.second !=
unsigned(L))
2213 return OpRef::fail();
2216 unsigned Opc = Strip.second == 1 ? Hexagon::V6_vunpackub
2217 : Hexagon::V6_vunpackuh;
2219 return OpRef::res(
Results.top());
2222OpRef HvxSelector::perfect(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
2231 int VecLen = SM.Mask.size();
2233 unsigned LogLen =
Log2_32(VecLen);
2237 assert(LogLen == HwLog || LogLen == HwLog + 1);
2238 bool HavePairs = LogLen == HwLog + 1;
2324 bool InvertedPair =
false;
2325 if (HavePairs && SM.Mask[0] >=
int(
HwLen)) {
2326 for (
int i = 0, e = SM.Mask.size(); i != e; ++i) {
2330 InvertedPair =
true;
2331 SM = ShuffleMask(MaskStorage);
2336 return OpRef::fail();
2339 for (
unsigned I = 0;
I != LogLen; ++
I)
2368 std::set<CycleType> Cycles;
2369 std::set<unsigned>
All;
2371 for (
unsigned I : Perm)
2376 auto canonicalize = [LogLen](
const CycleType &
C) -> CycleType {
2377 unsigned LogPos,
N =
C.size();
2378 for (LogPos = 0; LogPos !=
N; ++LogPos)
2379 if (
C[LogPos] == LogLen - 1)
2384 CycleType NewC(
C.begin() + LogPos,
C.end());
2385 NewC.append(
C.begin(),
C.begin() + LogPos);
2389 auto pfs = [](
const std::set<CycleType> &Cs,
unsigned Len) {
2394 const CycleType &
C = *Cs.begin();
2395 if (
C[0] != Len - 1)
2397 int D =
Len -
C.size();
2398 if (
D != 0 &&
D != 1)
2401 bool IsDeal =
true, IsShuff =
true;
2402 for (
unsigned I = 1;
I !=
Len -
D; ++
I) {
2403 if (
C[
I] != Len - 1 -
I)
2405 if (
C[
I] !=
I - (1 -
D))
2409 assert(!(IsDeal || IsShuff) || IsDeal != IsShuff);
2410 static unsigned Deals[] = {Hexagon::V6_vdealb, Hexagon::V6_vdealh};
2411 static unsigned Shufs[] = {Hexagon::V6_vshuffb, Hexagon::V6_vshuffh};
2412 return IsDeal ? Deals[
D] : (IsShuff ? Shufs[
D] : 0);
2415 while (!
All.empty()) {
2416 unsigned A = *
All.begin();
2420 for (
unsigned B = Perm[
A];
B !=
A;
B = Perm[
B]) {
2426 Cycles.insert(canonicalize(
C));
2433 if (
unsigned(VecLen) ==
HwLen) {
2434 if (
unsigned SingleOpc = pfs(Cycles, LogLen)) {
2435 Results.push(SingleOpc, SingleTy, {Va});
2436 return OpRef::res(
Results.top());
2459 for (
const CycleType &
C : Cycles) {
2461 unsigned First = (
C[0] == LogLen - 1) ? 1 : 0;
2470 OpRef Arg = HavePairs ? Va : concats(Va, OpRef::undef(SingleTy),
Results);
2472 Arg = concats(OpRef::hi(Arg), OpRef::lo(Arg),
Results);
2474 for (
unsigned I = 0, E = SwapElems.
size();
I != E;) {
2475 bool IsInc =
I == E - 1 || SwapElems[
I] < SwapElems[
I + 1];
2476 unsigned S = (1u << SwapElems[
I]);
2478 while (++
I < E - 1 && IsInc == (SwapElems[
I] < SwapElems[
I + 1]))
2479 S |= 1u << SwapElems[
I];
2482 S |= 1u << SwapElems[
I];
2487 Results.push(Hexagon::A2_tfrsi, MVT::i32, {getConst32(S, dl)});
2488 Res.Opc = IsInc ? Hexagon::V6_vshuffvdd : Hexagon::V6_vdealvdd;
2490 Res.Ops = {OpRef::hi(Arg), OpRef::lo(Arg), OpRef::res(-1)};
2492 Arg = OpRef::res(
Results.top());
2495 return HavePairs ? Arg : OpRef::lo(Arg);
2498OpRef HvxSelector::butterfly(ShuffleMask SM, OpRef Va, ResultStack &
Results) {
2511 PermNetwork::Controls
FC, RC;
2513 int VecLen = SM.Mask.size();
2515 for (
int M : SM.Mask) {
2516 if (M != -1 && M >= VecLen)
2517 return OpRef::fail();
2521 ForwardDeltaNetwork FN(SM.Mask);
2523 SDValue Ctl = getVectorConstant(FC, dl);
2524 Results.push(Hexagon::V6_vdelta, ResTy, {Va, OpRef(Ctl)});
2525 return OpRef::res(
Results.top());
2529 ReverseDeltaNetwork
RN(SM.Mask);
2531 SDValue Ctl = getVectorConstant(RC, dl);
2532 Results.push(Hexagon::V6_vrdelta, ResTy, {Va, OpRef(Ctl)});
2533 return OpRef::res(
Results.top());
2537 BenesNetwork BN(SM.Mask);
2538 if (BN.run(FC, RC)) {
2539 SDValue CtlF = getVectorConstant(FC, dl);
2540 SDValue CtlR = getVectorConstant(RC, dl);
2541 Results.push(Hexagon::V6_vdelta, ResTy, {Va, OpRef(CtlF)});
2542 Results.push(Hexagon::V6_vrdelta, ResTy,
2543 {OpRef::res(-1), OpRef(CtlR)});
2544 return OpRef::res(
Results.top());
2547 return OpRef::fail();
2550SDValue HvxSelector::getConst32(
int Val,
const SDLoc &dl) {
2568 MVT ResTy =
N->getValueType(0).getSimpleVT();
2569 unsigned Idx =
N->getConstantOperandVal(1);
2577 unsigned SubReg =
Idx == 0 ? Hexagon::vsub_lo : Hexagon::vsub_hi;
2585 dbgs() <<
"Starting " << __func__ <<
" on node:\n";
2588 MVT ResTy =
N->getValueType(0).getSimpleVT();
2590 assert(ResTy.isVector() && ResTy.getVectorElementType() == MVT::i8);
2592 auto *SN = cast<ShuffleVectorSDNode>(
N);
2593 std::vector<int> Mask(SN->getMask().begin(), SN->getMask().end());
2595 for (
int &
Idx : Mask)
2596 if (
Idx != -1 &&
Idx < 0)
2599 unsigned VecLen = Mask.size();
2600 bool HavePairs = (2*
HwLen == VecLen);
2601 assert(ResTy.getSizeInBits() / 8 == VecLen);
2606 bool UseLeft =
false, UseRight =
false;
2607 for (
unsigned I = 0;
I != VecLen; ++
I) {
2610 unsigned Idx = Mask[
I];
2619 dbgs() <<
"VecLen=" << VecLen <<
" HwLen=" <<
HwLen <<
" UseLeft="
2620 << UseLeft <<
" UseRight=" << UseRight <<
" HavePairs="
2621 << HavePairs <<
'\n';
2624 if (!UseLeft && !UseRight) {
2634 OpRef Va = OpRef::undef(ResTy);
2635 OpRef Vb = OpRef::undef(ResTy);
2638 Results.push(TargetOpcode::COPY, ResTy, {Vec0});
2639 Va = OpRef::OpRef::res(
Results.top());
2642 Results.push(TargetOpcode::COPY, ResTy, {Vec1});
2643 Vb = OpRef::res(
Results.top());
2646 OpRef Res = !HavePairs ? shuffs2(ShuffleMask(Mask), Va, Vb,
Results)
2647 : shuffp2(ShuffleMask(Mask), Va, Vb,
Results);
2649 bool Done = Res.isValid();
2652 Results.push(TargetOpcode::COPY, ResTy, {Res});
2655 Done = scalarizeShuffle(Mask,
SDLoc(
N), ResTy, Vec0, Vec1,
N);
2660 dbgs() <<
"Unhandled shuffle:\n";
2669 MVT Ty =
N->getValueType(0).getSimpleVT();
2675 if (
auto *CN = dyn_cast<ConstantSDNode>(RotV.
getNode())) {
2679 }
else if (isUInt<3>(S)) {
2681 {VecV, VecV, getConst32(S, dl)});
2696 N->getValueType(0), {Vv, Vu, Rt});
2701void HexagonDAGToDAGISel::PreprocessHvxISelDAG() {
2702 auto getNodes = [
this]() -> std::vector<SDNode *> {
2703 std::vector<SDNode *>
T;
2710 ppHvxShuffleOfShuffle(getNodes());
2715 return std::hash<const void *>()(V.getNode()) +
2716 std::hash<unsigned>()(V.getResNo());
2720void HexagonDAGToDAGISel::ppHvxShuffleOfShuffle(std::vector<SDNode *> &&Nodes) {
2733 struct SubVectorInfo {
2734 SubVectorInfo(
SDValue S,
unsigned H) : Src(S), HalfIdx(
H) {}
2739 using MapType = std::unordered_map<SDValue, unsigned>;
2743 const MapType &OpMap) ->
int {
2759 auto N =
static_cast<unsigned>(MaybeN);
2760 unsigned SrcBase =
N < HwLen ? OpMap.at(OpShuff->
getOperand(0))
2770 auto *
This = cast<ShuffleVectorSDNode>(TopShuff);
2771 auto *S0 = cast<ShuffleVectorSDNode>(TopShuff.
getOperand(0));
2772 auto *
S1 = cast<ShuffleVectorSDNode>(TopShuff.
getOperand(1));
2776 assert(TopMask.
size() == S0->getMask().size() &&
2777 TopMask.
size() ==
S1->getMask().size());
2781 for (
unsigned I = 0;
I != HwLen; ++
I) {
2782 int MaybeM = TopMask[
I];
2785 getMaskElt(
static_cast<unsigned>(MaybeM), S0,
S1, OpMap);
2791 std::fill(FoldedMask.begin() + HwLen, FoldedMask.end(), -1);
2796 const SDLoc &dl(TopShuff);
2806 auto getSourceInfo = [](
SDValue V) -> std::optional<SubVectorInfo> {
2808 V =
V.getOperand(0);
2810 return std::nullopt;
2811 return SubVectorInfo(
V.getOperand(0),
2812 !cast<ConstantSDNode>(
V.getOperand(1))->isZero());
2818 EVT ResTy =
N->getValueType(0);
2836 if (!V0A.has_value())
2839 if (!V0B.has_value() || V0B->Src != V0A->Src)
2842 if (!V1A.has_value() || V1A->Src != V0A->Src)
2845 if (!V1B.has_value() || V1B->Src != V0A->Src)
2850 assert(V0A->Src.getValueType().getSizeInBits() == 16 * HwLen);
2863void HexagonDAGToDAGISel::SelectHvxExtractSubvector(
SDNode *
N) {
2867void HexagonDAGToDAGISel::SelectHvxShuffle(
SDNode *
N) {
2871void HexagonDAGToDAGISel::SelectHvxRor(
SDNode *
N) {
2875void HexagonDAGToDAGISel::SelectHvxVAlign(
SDNode *
N) {
2883 SDValue Predicate =
N->getOperand(3);
2885 SDValue Modifier =
N->getOperand(5);
2890 unsigned IntNo =
N->getConstantOperandVal(1);
2894 case Intrinsic::hexagon_V6_vgathermhq:
2895 case Intrinsic::hexagon_V6_vgathermhq_128B:
2896 Opcode = Hexagon::V6_vgathermhq_pseudo;
2898 case Intrinsic::hexagon_V6_vgathermwq:
2899 case Intrinsic::hexagon_V6_vgathermwq_128B:
2900 Opcode = Hexagon::V6_vgathermwq_pseudo;
2902 case Intrinsic::hexagon_V6_vgathermhwq:
2903 case Intrinsic::hexagon_V6_vgathermhwq_128B:
2904 Opcode = Hexagon::V6_vgathermhwq_pseudo;
2924 SDValue Modifier =
N->getOperand(4);
2929 unsigned IntNo =
N->getConstantOperandVal(1);
2933 case Intrinsic::hexagon_V6_vgathermh:
2934 case Intrinsic::hexagon_V6_vgathermh_128B:
2935 Opcode = Hexagon::V6_vgathermh_pseudo;
2937 case Intrinsic::hexagon_V6_vgathermw:
2938 case Intrinsic::hexagon_V6_vgathermw_128B:
2939 Opcode = Hexagon::V6_vgathermw_pseudo;
2941 case Intrinsic::hexagon_V6_vgathermhw:
2942 case Intrinsic::hexagon_V6_vgathermhw_128B:
2943 Opcode = Hexagon::V6_vgathermhw_pseudo;
2958 unsigned IID =
N->getConstantOperandVal(0);
2961 case Intrinsic::hexagon_V6_vaddcarry: {
2962 std::array<SDValue, 3> Ops = {
2963 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2968 case Intrinsic::hexagon_V6_vaddcarry_128B: {
2969 std::array<SDValue, 3> Ops = {
2970 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2975 case Intrinsic::hexagon_V6_vsubcarry: {
2976 std::array<SDValue, 3> Ops = {
2977 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
2982 case Intrinsic::hexagon_V6_vsubcarry_128B: {
2983 std::array<SDValue, 3> Ops = {
2984 {
N->getOperand(1),
N->getOperand(2),
N->getOperand(3)}};
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
#define DEBUG_WITH_TYPE(TYPE,...)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
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 isValid(const char C)
Returns true if C is a valid mangled character: <0-9a-zA-Z_>.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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.
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.
void dump() const
Dump this node, for debugging.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
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...
SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
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.
SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
void setNodeMemRefs(MachineSDNode *N, ArrayRef< MachineMemOperand * > NewMemRefs)
Mutate the specified machine node's memory references to the provided list.
SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
void RemoveDeadNodes()
This method deletes all unreachable nodes in the SelectionDAG.
void RemoveDeadNode(SDNode *N)
Remove the specified node from the system.
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()
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
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.
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.
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
const_iterator end(StringRef path)
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 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)
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.
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)
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