Skip to content

Commit 33bb3ef

Browse files
author
Krzysztof Parzyszek
committed
[Hexagon] Generalize handling of SDNodes created during ISel
The selection of HVX shuffles can produce more nodes in the DAG, which need special handling, or otherwise they would be left unselected by the main selection code. Make the handling of such nodes more general.
1 parent 473b364 commit 33bb3ef

File tree

3 files changed

+88
-87
lines changed

3 files changed

+88
-87
lines changed

llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp

Lines changed: 84 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,7 @@ namespace llvm {
828828
void selectVAlign(SDNode *N);
829829

830830
private:
831+
void select(SDNode *ISelN);
831832
void materialize(const ResultStack &Results);
832833

833834
SDValue getVectorConstant(ArrayRef<uint8_t> Data, const SDLoc &dl);
@@ -931,46 +932,19 @@ bool HvxSelector::selectVectorConstants(SDNode *N) {
931932
SmallVector<SDNode*,4> Nodes;
932933
SetVector<SDNode*> WorkQ;
933934

934-
// The one-use test for VSPLATW's operand may fail due to dead nodes
935-
// left over in the DAG.
936-
DAG.RemoveDeadNodes();
937-
938935
// The DAG can change (due to CSE) during selection, so cache all the
939936
// unselected nodes first to avoid traversing a mutating DAG.
940-
941-
auto IsNodeToSelect = [] (SDNode *N) {
942-
if (N->isMachineOpcode())
943-
return false;
944-
switch (N->getOpcode()) {
945-
case HexagonISD::VZERO:
946-
case HexagonISD::VSPLATW:
947-
return true;
948-
case ISD::LOAD: {
949-
SDValue Addr = cast<LoadSDNode>(N)->getBasePtr();
950-
unsigned AddrOpc = Addr.getOpcode();
951-
if (AddrOpc == HexagonISD::AT_PCREL || AddrOpc == HexagonISD::CP)
952-
if (Addr.getOperand(0).getOpcode() == ISD::TargetConstantPool)
953-
return true;
954-
}
955-
break;
956-
}
957-
// Make sure to select the operand of VSPLATW.
958-
bool IsSplatOp = N->hasOneUse() &&
959-
N->use_begin()->getOpcode() == HexagonISD::VSPLATW;
960-
return IsSplatOp;
961-
};
962-
963937
WorkQ.insert(N);
964938
for (unsigned i = 0; i != WorkQ.size(); ++i) {
965939
SDNode *W = WorkQ[i];
966-
if (IsNodeToSelect(W))
940+
if (!W->isMachineOpcode() && W->getOpcode() == HexagonISD::ISEL)
967941
Nodes.push_back(W);
968942
for (unsigned j = 0, f = W->getNumOperands(); j != f; ++j)
969943
WorkQ.insert(W->getOperand(j).getNode());
970944
}
971945

972946
for (SDNode *L : Nodes)
973-
ISel.Select(L);
947+
select(L);
974948

975949
return !Nodes.empty();
976950
}
@@ -1358,6 +1332,82 @@ namespace {
13581332
};
13591333
}
13601334

1335+
void HvxSelector::select(SDNode *ISelN) {
1336+
// What's important here is to select the right set of nodes. The main
1337+
// selection algorithm loops over nodes in a topological order, i.e. users
1338+
// are visited before their operands.
1339+
//
1340+
// It is an error to have an unselected node with a selected operand, and
1341+
// there is an assertion in the main selector code to enforce that.
1342+
//
1343+
// Such a situation could occur if we selected a node, which is both a
1344+
// subnode of ISelN, and a subnode of an unrelated (and yet unselected)
1345+
// node in the DAG.
1346+
assert(ISelN->getOpcode() == HexagonISD::ISEL);
1347+
SDNode *N0 = ISelN->getOperand(0).getNode();
1348+
if (N0->isMachineOpcode()) {
1349+
ISel.ReplaceNode(ISelN, N0);
1350+
return;
1351+
}
1352+
1353+
// There could have been nodes created (i.e. inserted into the DAG)
1354+
// that are now dead. Remove them, in case they use any of the nodes
1355+
// to select (and make them look shared).
1356+
DAG.RemoveDeadNodes();
1357+
1358+
SetVector<SDNode*> SubNodes, TmpQ;
1359+
std::map<SDNode*,unsigned> NumOps;
1360+
1361+
// Don't want to select N0 if it's shared with another node, except if
1362+
// it's shared with other ISELs.
1363+
auto IsISelN = [](SDNode *T) { return T->getOpcode() == HexagonISD::ISEL; };
1364+
if (llvm::all_of(N0->uses(), IsISelN))
1365+
SubNodes.insert(N0);
1366+
1367+
auto InSubNodes = [&SubNodes](SDNode *T) { return SubNodes.count(T); };
1368+
for (unsigned I = 0; I != SubNodes.size(); ++I) {
1369+
SDNode *S = SubNodes[I];
1370+
unsigned OpN = 0;
1371+
// Only add subnodes that are only reachable from N0.
1372+
for (SDValue Op : S->ops()) {
1373+
SDNode *O = Op.getNode();
1374+
if (llvm::all_of(O->uses(), InSubNodes)) {
1375+
SubNodes.insert(O);
1376+
++OpN;
1377+
}
1378+
}
1379+
NumOps.insert({S, OpN});
1380+
if (OpN == 0)
1381+
TmpQ.insert(S);
1382+
}
1383+
1384+
for (unsigned I = 0; I != TmpQ.size(); ++I) {
1385+
SDNode *S = TmpQ[I];
1386+
for (SDNode *U : S->uses()) {
1387+
if (U == ISelN)
1388+
continue;
1389+
auto F = NumOps.find(U);
1390+
assert(F != NumOps.end());
1391+
if (F->second > 0 && !--F->second)
1392+
TmpQ.insert(F->first);
1393+
}
1394+
}
1395+
1396+
// Remove the marker.
1397+
ISel.ReplaceNode(ISelN, N0);
1398+
1399+
assert(SubNodes.size() == TmpQ.size());
1400+
NullifyingVector<decltype(TmpQ)::vector_type> Queue(TmpQ.takeVector());
1401+
1402+
Deleter DUQ(DAG, Queue);
1403+
for (SDNode *S : reverse(Queue)) {
1404+
if (S == nullptr)
1405+
continue;
1406+
DEBUG_WITH_TYPE("isel", {dbgs() << "HVX selecting: "; S->dump(&DAG);});
1407+
ISel.Select(S);
1408+
}
1409+
}
1410+
13611411
bool HvxSelector::scalarizeShuffle(ArrayRef<int> Mask, const SDLoc &dl,
13621412
MVT ResTy, SDValue Va, SDValue Vb,
13631413
SDNode *N) {
@@ -1379,12 +1429,7 @@ bool HvxSelector::scalarizeShuffle(ArrayRef<int> Mask, const SDLoc &dl,
13791429
// nodes, these nodes would not be selected (since the "local" selection
13801430
// only visits nodes that are not in AllNodes).
13811431
// To avoid this issue, remove all dead nodes from the DAG now.
1382-
DAG.RemoveDeadNodes();
1383-
DenseSet<SDNode*> AllNodes;
1384-
for (SDNode &S : DAG.allnodes())
1385-
AllNodes.insert(&S);
1386-
1387-
Deleter DUA(DAG, AllNodes);
1432+
// DAG.RemoveDeadNodes();
13881433

13891434
SmallVector<SDValue,128> Ops;
13901435
LLVMContext &Ctx = *DAG.getContext();
@@ -1434,57 +1479,9 @@ bool HvxSelector::scalarizeShuffle(ArrayRef<int> Mask, const SDLoc &dl,
14341479
}
14351480

14361481
assert(!N->use_empty());
1437-
ISel.ReplaceNode(N, LV.getNode());
1438-
1439-
if (AllNodes.count(LV.getNode())) {
1440-
DAG.RemoveDeadNodes();
1441-
return true;
1442-
}
1443-
1444-
// The lowered build-vector node will now need to be selected. It needs
1445-
// to be done here because this node and its submodes are not included
1446-
// in the main selection loop.
1447-
// Implement essentially the same topological ordering algorithm as is
1448-
// used in SelectionDAGISel.
1449-
1450-
SetVector<SDNode*> SubNodes, TmpQ;
1451-
std::map<SDNode*,unsigned> NumOps;
1452-
1453-
SubNodes.insert(LV.getNode());
1454-
for (unsigned I = 0; I != SubNodes.size(); ++I) {
1455-
unsigned OpN = 0;
1456-
SDNode *S = SubNodes[I];
1457-
for (SDValue Op : S->ops()) {
1458-
if (AllNodes.count(Op.getNode()))
1459-
continue;
1460-
SubNodes.insert(Op.getNode());
1461-
++OpN;
1462-
}
1463-
NumOps.insert({S, OpN});
1464-
if (OpN == 0)
1465-
TmpQ.insert(S);
1466-
}
1467-
1468-
for (unsigned I = 0; I != TmpQ.size(); ++I) {
1469-
SDNode *S = TmpQ[I];
1470-
for (SDNode *U : S->uses()) {
1471-
if (!SubNodes.count(U))
1472-
continue;
1473-
auto F = NumOps.find(U);
1474-
assert(F != NumOps.end());
1475-
assert(F->second > 0);
1476-
if (!--F->second)
1477-
TmpQ.insert(F->first);
1478-
}
1479-
}
1480-
assert(SubNodes.size() == TmpQ.size());
1481-
NullifyingVector<decltype(TmpQ)::vector_type> Queue(TmpQ.takeVector());
1482-
1483-
Deleter DUQ(DAG, Queue);
1484-
for (SDNode *S : reverse(Queue))
1485-
if (S != nullptr)
1486-
ISel.Select(S);
1487-
1482+
SDValue IS = DAG.getNode(HexagonISD::ISEL, dl, ResTy, LV);
1483+
ISel.ReplaceNode(N, IS.getNode());
1484+
select(IS.getNode());
14881485
DAG.RemoveDeadNodes();
14891486
return true;
14901487
}
@@ -2014,7 +2011,7 @@ SDValue HvxSelector::getVectorConstant(ArrayRef<uint8_t> Data,
20142011
SDValue BV = DAG.getBuildVector(VecTy, dl, Elems);
20152012
SDValue LV = Lower.LowerOperation(BV, DAG);
20162013
DAG.RemoveDeadNode(BV.getNode());
2017-
return LV;
2014+
return DAG.getNode(HexagonISD::ISEL, dl, VecTy, LV);
20182015
}
20192016

20202017
void HvxSelector::selectShuffle(SDNode *N) {

llvm/lib/Target/Hexagon/HexagonISelLowering.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,6 +1865,7 @@ const char* HexagonTargetLowering::getTargetNodeName(unsigned Opcode) const {
18651865
case HexagonISD::VPACKL: return "HexagonISD::VPACKL";
18661866
case HexagonISD::VUNPACK: return "HexagonISD::VUNPACK";
18671867
case HexagonISD::VUNPACKU: return "HexagonISD::VUNPACKU";
1868+
case HexagonISD::ISEL: return "HexagonISD::ISEL";
18681869
case HexagonISD::OP_END: break;
18691870
}
18701871
return nullptr;

llvm/lib/Target/Hexagon/HexagonISelLowering.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ enum NodeType : unsigned {
9696
// unspecified.
9797
VUNPACK, // Unpacking into low elements with sign extension.
9898
VUNPACKU, // Unpacking into low elements with zero extension.
99+
ISEL, // Marker for nodes that were created during ISel, and
100+
// which need explicit selection (would have been left
101+
// unselected otherwise).
99102
OP_END
100103
};
101104

0 commit comments

Comments
 (0)