From: Krzysztof Parzyszek Date: Fri, 17 Feb 2023 17:39:04 +0000 (-0800) Subject: [Hexagon] Improve selection algorithm in HvxSelector::select X-Git-Tag: upstream/17.0.6~16853 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a069eda1baedb05788549504bd39a17e334ef1cf;p=platform%2Fupstream%2Fllvm.git [Hexagon] Improve selection algorithm in HvxSelector::select The previous algorithm could order nodes incorrectly, this one strictly follows the topological order. --- diff --git a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp index 020fb2d..57b5f9a 100644 --- a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp +++ b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAGHVX.cpp @@ -1749,40 +1749,72 @@ void HvxSelector::select(SDNode *ISelN) { // node in the DAG. assert(ISelN->getOpcode() == HexagonISD::ISEL); SDNode *N0 = ISelN->getOperand(0).getNode(); - if (N0->isMachineOpcode()) { - ISel.ReplaceNode(ISelN, N0); - return; - } // There could have been nodes created (i.e. inserted into the DAG) // that are now dead. Remove them, in case they use any of the nodes // to select (and make them look shared). DAG.RemoveDeadNodes(); - SetVector SubNodes, TmpQ; - std::map NumOps; + SetVector SubNodes; + + if (!N0->isMachineOpcode()) { + // Don't want to select N0 if it's shared with another node, except if + // it's shared with other ISELs. + auto IsISelN = [](SDNode *T) { return T->getOpcode() == HexagonISD::ISEL; }; + if (llvm::all_of(N0->uses(), IsISelN)) + SubNodes.insert(N0); + } + if (SubNodes.empty()) { + ISel.ReplaceNode(ISelN, N0); + return; + } + + // Need to manually select the nodes that are dominated by the ISEL. Other + // nodes are reachable from the rest of the DAG, and so will be selected + // by the DAG selection routine. + SetVector Dom, NonDom; + Dom.insert(N0); + + auto IsDomRec = [&Dom, &NonDom] (SDNode *T, auto Rec) -> bool { + if (Dom.count(T)) + return true; + if (T->use_empty() || NonDom.count(T)) + return false; + for (SDNode *U : T->uses()) { + // If T is reachable from a known non-dominated node, then T itself + // is non-dominated. + if (!Rec(U, Rec)) { + NonDom.insert(T); + return false; + } + } + Dom.insert(T); + return true; + }; - // Don't want to select N0 if it's shared with another node, except if - // it's shared with other ISELs. - auto IsISelN = [](SDNode *T) { return T->getOpcode() == HexagonISD::ISEL; }; - if (llvm::all_of(N0->uses(), IsISelN)) - SubNodes.insert(N0); + auto IsDom = [&IsDomRec] (SDNode *T) { return IsDomRec(T, IsDomRec); }; - auto InSubNodes = [&SubNodes](SDNode *T) { return SubNodes.count(T); }; + // Add the rest of nodes dominated by ISEL to SubNodes. for (unsigned I = 0; I != SubNodes.size(); ++I) { - SDNode *S = SubNodes[I]; - unsigned OpN = 0; - // Only add subnodes that are only reachable from N0. - for (SDValue Op : S->ops()) { + for (SDValue Op : SubNodes[I]->ops()) { SDNode *O = Op.getNode(); - if (llvm::all_of(O->uses(), InSubNodes)) { + if (IsDom(O)) SubNodes.insert(O); - ++OpN; - } } - NumOps.insert({S, OpN}); - if (OpN == 0) - TmpQ.insert(S); + } + + // Do a topological sort of nodes from Dom. + SetVector TmpQ; + + std::map OpCount; + for (SDNode *T : Dom) { + unsigned NumDomOps = llvm::count_if(T->ops(), [&Dom](const SDUse &U) { + return Dom.count(U.getNode()); + }); + + OpCount.insert({T, NumDomOps}); + if (NumDomOps == 0) + TmpQ.insert(T); } for (unsigned I = 0; I != TmpQ.size(); ++I) { @@ -1790,8 +1822,8 @@ void HvxSelector::select(SDNode *ISelN) { for (SDNode *U : S->uses()) { if (U == ISelN) continue; - auto F = NumOps.find(U); - assert(F != NumOps.end()); + auto F = OpCount.find(U); + assert(F != OpCount.end()); if (F->second > 0 && !--F->second) TmpQ.insert(F->first); } diff --git a/llvm/test/CodeGen/Hexagon/autohvx/isel-shuffle-isdisel.ll b/llvm/test/CodeGen/Hexagon/autohvx/isel-shuffle-isdisel.ll new file mode 100644 index 0000000..7fd3809 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/autohvx/isel-shuffle-isdisel.ll @@ -0,0 +1,21 @@ +; RUN: llc -march=hexagon < %s | FileCheck %s + +; Check that this compiles successfully. +; CHECK: dealloc_return + +target datalayout = "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048" +target triple = "hexagon" + +define dso_local fastcc void @f0(ptr %a0) unnamed_addr #0 { +b0: + %v0 = load <96 x float>, ptr poison, align 4 + %v1 = shufflevector <96 x float> %v0, <96 x float> poison, <32 x i32> + %v2 = fptrunc <32 x float> %v1 to <32 x half> + %v3 = getelementptr half, ptr %a0, i32 0 + %v4 = shufflevector <32 x half> zeroinitializer, <32 x half> %v2, <64 x i32> + %v5 = shufflevector <64 x half> %v4, <64 x half> poison, <96 x i32> + store <96 x half> %v5, ptr %v3, align 2 + ret void +} + +attributes #0 = { "target-features"="+hvxv69,+hvx-length128b,+hvx-qfloat,-hvx-ieee-fp" }