天天看點

LLVM學習筆記(32)

3.4.4.3.4. OPC_EmitMergeInputChainsN等

OPC_EmitInteger,OPC_EmitRegister,OPC_EmitRegister2,OPC_EmitConvertToTarget都是用于部分生成目标指令DAG的操作符。它們與目标機器相關,是以需要目标機器相關的資訊(寄存器目前還是虛拟的,尚與目标機器無關)。

SelectionDAGISel::SelectCodeCommon(續)

2949      case OPC_EmitInteger: {

2950        MVT::SimpleValueType VT =

2951          (MVT::SimpleValueType)MatcherTable[MatcherIndex++];

2952        int64_t Val = MatcherTable[MatcherIndex++];

2953        if (Val & 128)

2954          Val = GetVBR(Val, MatcherTable, MatcherIndex);

2955        RecordedNodes.push_back(std::pair<SDValue, SDNode*>(

2956                                CurDAG->getTargetConstant(Val, SDLoc(NodeToMatch),

2957                                                          VT), nullptr));

2958        continue;

2959      }

2960      case OPC_EmitRegister: {

2961        MVT::SimpleValueType VT =

2962          (MVT::SimpleValueType)MatcherTable[MatcherIndex++];

2963        unsigned RegNo = MatcherTable[MatcherIndex++];

2964        RecordedNodes.push_back(std::pair<SDValue, SDNode*>(

2965                                CurDAG->getRegister(RegNo, VT), nullptr));

2966        continue;

2967      }

2968      case OPC_EmitRegister2: {

2969        // For targets w/ more than 256 register names, the register enum

2970        // values are stored in two bytes in the matcher table (just like

2971        // opcodes).

2972        MVT::SimpleValueType VT =

2973          (MVT::SimpleValueType)MatcherTable[MatcherIndex++];

2974        unsigned RegNo = MatcherTable[MatcherIndex++];

2975        RegNo |= MatcherTable[MatcherIndex++] << 8;

2976        RecordedNodes.push_back(std::pair<SDValue, SDNode*>(

2977                                CurDAG->getRegister(RegNo, VT), nullptr));

2978        continue;

2979      }

2980 

2981      case OPC_EmitConvertToTarget:  {

2982        // Convert from IMM/FPIMM to target version.

2983        unsigned RecNo = MatcherTable[MatcherIndex++];

2984        assert(RecNo < RecordedNodes.size() && "Invalid EmitConvertToTarget");

2985        SDValue Imm = RecordedNodes[RecNo].first;

2986 

2987        if (Imm->getOpcode() == ISD::Constant) {

2988          const ConstantInt *Val=cast<ConstantSDNode>(Imm)->getConstantIntValue();

2989          Imm = CurDAG->getConstant(*Val, SDLoc(NodeToMatch), Imm.getValueType(),   <-- v7.0删除

2990                                    true);

        Imm = CurDAG->getTargetConstant(*Val, SDLoc(NodeToMatch),                              <-- v7.0增加

                                        Imm.getValueType());

2991        } else if (Imm->getOpcode() == ISD::ConstantFP) {

2992          const ConstantFP *Val=cast<ConstantFPSDNode>(Imm)->getConstantFPValue();

2993          Imm = CurDAG->getConstantFP(*Val, SDLoc(NodeToMatch),                                      <-- v7.0删除

2994                                      Imm.getValueType(), true);

        Imm = CurDAG->getTargetConstantFP(*Val, SDLoc(NodeToMatch),                          <-- v7.0增加

                                          Imm.getValueType());

2995        }

2996 

2997        RecordedNodes.push_back(std::make_pair(Imm, RecordedNodes[RecNo].second));

2998        continue;

2999      }

3000 

3001      case OPC_EmitMergeInputChains1_0:    // OPC_EmitMergeInputChains, 1, 0

3002      case OPC_EmitMergeInputChains1_1: {  // OPC_EmitMergeInputChains, 1, 1

    case OPC_EmitMergeInputChains1_2: {  // OPC_EmitMergeInputChains, 1, 2            <-- v7.0增加

3003        // These are space-optimized forms of OPC_EmitMergeInputChains.

3004        assert(!InputChain.getNode() &&

3005               "EmitMergeInputChains should be the first chain producing node");

3006        assert(ChainNodesMatched.empty() &&

3007               "Should only have one EmitMergeInputChains per match");

3008 

3009        // Read all of the chained nodes.

3010        unsigned RecNo = Opcode == OPC_EmitMergeInputChains1_1;                                  <-- v7.0删除

      unsigned RecNo = Opcode - OPC_EmitMergeInputChains1_0;                                     <-- v7.0增加

3011        assert(RecNo < RecordedNodes.size() && "Invalid EmitMergeInputChains");

3012        ChainNodesMatched.push_back(RecordedNodes[RecNo].first.getNode());

3013 

3014        // FIXME: What if other value results of the node have uses not matched

3015        // by this pattern?

3016        if (ChainNodesMatched.back() != NodeToMatch &&

3017            !RecordedNodes[RecNo].first.hasOneUse()) {

3018          ChainNodesMatched.clear();

3019          break;

3020        }

3021 

3022        // Merge the input chains if they are not intra-pattern references.

3023        InputChain = HandleMergeInputChains(ChainNodesMatched, CurDAG);

3024 

3025        if (!InputChain.getNode())

3026          break;  // Failed to merge.

3027        continue;

3028      }

3029 

3030      case OPC_EmitMergeInputChains: {

3031        assert(!InputChain.getNode() &&

3032               "EmitMergeInputChains should be the first chain producing node");

3033        // This node gets a list of nodes we matched in the input that have

3034        // chains.  We want to token factor all of the input chains to these nodes

3035        // together.  However, if any of the input chains is actually one of the

3036        // nodes matched in this pattern, then we have an intra-match reference.

3037        // Ignore these because the newly token factored chain should not refer to

3038        // the old nodes.

3039        unsigned NumChains = MatcherTable[MatcherIndex++];

3040        assert(NumChains != 0 && "Can't TF zero chains");

3041 

3042        assert(ChainNodesMatched.empty() &&

3043               "Should only have one EmitMergeInputChains per match");

3044 

3045        // Read all of the chained nodes.

3046        for (unsigned i = 0; i != NumChains; ++i) {

3047          unsigned RecNo = MatcherTable[MatcherIndex++];

3048          assert(RecNo < RecordedNodes.size() && "Invalid EmitMergeInputChains");

3049          ChainNodesMatched.push_back(RecordedNodes[RecNo].first.getNode());

3050 

3051          // FIXME: What if other value results of the node have uses not matched

3052          // by this pattern?

3053          if (ChainNodesMatched.back() != NodeToMatch &&

3054              !RecordedNodes[RecNo].first.hasOneUse()) {

3055            ChainNodesMatched.clear();

3056            break;

3057          }

3058        }

3059 

3060        // If the inner loop broke out, the match fails.

3061        if (ChainNodesMatched.empty())

3062          break;

3063 

3064        // Merge the input chains if they are not intra-pattern references.

3065        InputChain = HandleMergeInputChains(ChainNodesMatched, CurDAG);

3066 

3067        if (!InputChain.getNode())

3068          break;  // Failed to merge.

3069 

3070        continue;

3071      }

OPC_EmitMergeInputChainsN表示比對DAG中有節點需要輸傳入連結節點,指令選擇器需要嘗試産生公共的輸傳入連結節點。首先在容器ChainNodesMatched裡記錄合乎條件的鍊節點的使用者(3016與3053行條件,NodeToMatch以外的SDNode對象隻能有一個使用者)。

注意那些把生成DAG加入RecordedNodes容器的OPC_XXX操作。在前面生成它們對應的Matcher對象時,已經通過NextRecordedOperandNo算好了它們在這個容器的位置。它現在就是加入這個位置,是以前面位置的計算與這裡對RecordedNodes的push_back()是一一對應的。這些位置也已經寫在MatcherTable中,比如OPC_CheckSame操作,它的操作數就是比較對象的索引。

接着調用下面的函數嘗試甄别合并鍊節點使用者是否會導緻環的出現。

2185  static SDValue

2186  HandleMergeInputChains(SmallVectorImpl<SDNode*> &ChainNodesMatched,

2187                         SelectionDAG *CurDAG) {

2188    // Walk all of the chained nodes we've matched, recursively scanning down the

2189    // users of the chain result. This adds any TokenFactor nodes that are caught

2190    // in between chained nodes to the chained and interior nodes list.

2191    SmallVector<SDNode*, 3> InteriorChainedNodes;

2192   for (unsigned i = 0, e = ChainNodesMatched.size(); i != e; ++i) {

2193      if (WalkChainUsers(ChainNodesMatched[i], ChainNodesMatched,

2194                         InteriorChainedNodes) == CR_InducesCycle)

2195        return SDValue(); // Would induce a cycle.

2196    }

2197 

2198    // Okay, we have walked all the matched nodes and collected TokenFactor nodes

2199    // that we are interested in.  Form our input TokenFactor node.

2200    SmallVector<SDValue, 3> InputChains;

2201   for (unsigned i = 0, e = ChainNodesMatched.size(); i != e; ++i) {

2202      // Add the input chain of this node to the InputChains list (which will be

2203      // the operands of the generated TokenFactor) if it's not an interior node.

2204      SDNode *N = ChainNodesMatched[i];

2205      if (N->getOpcode() != ISD::TokenFactor) {

2206        if (std::count(InteriorChainedNodes.begin(),InteriorChainedNodes.end(),N))

2207          continue;

2208 

2209        // Otherwise, add the input chain.

2210        SDValue InChain = ChainNodesMatched[i]->getOperand(0);

2211        assert(InChain.getValueType() == MVT::Other && "Not a chain");

2212        InputChains.push_back(InChain);

2213        continue;

2214      }

2215 

2216      // If we have a token factor, we want to add all inputs of the token factor

2217      // that are not part of the pattern we're matching.

2218      for (const SDValue &Op : N->op_values()) {

2219        if (!std::count(ChainNodesMatched.begin(), ChainNodesMatched.end(),

2220                        Op.getNode()))

2221          InputChains.push_back(Op);

2222      }

2223    }

2224 

2225    if (InputChains.size() == 1)

2226      return InputChains[0];

2227    return CurDAG->getNode(ISD::TokenFactor, SDLoc(ChainNodesMatched[0]),

2228                           MVT::Other, InputChains);

2229  }

2192行的循環通過WalkChainUsers()方法逐個測試ChainNodesMatched内的成員是否會形成誘導環。如果是,處理失敗,進而比對也宣告失敗。

對于ChainNodesMatched中某個成員,在對應的WalkChainUsers()調用中,在2073行查找使用這個鍊節點的使用者。

2067  static ChainResult

2068  WalkChainUsers(const SDNode *ChainedNode,

2069                 SmallVectorImpl<SDNode*> &ChainedNodesInPattern,

2070                 SmallVectorImpl<SDNode*> &InteriorChainedNodes) {

2071    ChainResult Result = CR_Simple;

2072 

2073    for (SDNode::use_iterator UI = ChainedNode->use_begin(),

2074           E = ChainedNode->use_end(); UI != E; ++UI) {

2075      // Make sure the use is of the chain, not some other value we produce.

2076      if (UI.getUse().getValueType() != MVT::Other) continue;

2077 

2078      SDNode *User = *UI;

2079 

2080      if (User->getOpcode() == ISD::HANDLENODE)  // Root of the graph.

2081        continue;

2082 

2083      // If we see an already-selected machine node, then we've gone beyond the

2084      // pattern that we're selecting down into the already selected chunk of the

2085      // DAG.

2086      unsigned UserOpcode = User->getOpcode();

2087      if (User->isMachineOpcode() ||

2088          UserOpcode == ISD::CopyToReg ||

2089          UserOpcode == ISD::CopyFromReg ||

2090          UserOpcode == ISD::INLINEASM ||

2091          UserOpcode == ISD::EH_LABEL ||

2092          UserOpcode == ISD::LIFETIME_START ||

2093          UserOpcode == ISD::LIFETIME_END) {

2094        // If their node ID got reset to -1 then they've already been selected.

2095        // Treat them like a MachineOpcode.

2096        if (User->getNodeId() == -1)

2097          continue;

2098      }

2099 

2100      // If we have a TokenFactor, we handle it specially.

2101      if (User->getOpcode() != ISD::TokenFactor) {

2102        // If the node isn't a token factor and isn't part of our pattern, then it

2103        // must be a random chained node in between two nodes we're selecting.

2104        // This happens when we have something like:

2105        //   x = load ptr

2106        //   call

2107        //   y = x+4

2108        //   store y -> ptr

2109        // Because we structurally match the load/store as a read/modify/write,

2110        // but the call is chained between them.  We cannot fold in this case

2111        // because it would induce a cycle in the graph.

2112        if (!std::count(ChainedNodesInPattern.begin(),

2113                        ChainedNodesInPattern.end(), User))

2114          return CR_InducesCycle;

2115 

2116        // Otherwise we found a node that is part of our pattern.  For example in:

2117        //   x = load ptr

2118        //   y = x+4

2119        //   store y -> ptr

2120        // This would happen when we're scanning down from the load and see the

2121        // store as a user.  Record that there is a use of ChainedNode that is

2122        // part of the pattern and keep scanning uses.

2123        Result = CR_LeadsToInteriorNode;

2124        InteriorChainedNodes.push_back(User);

2125        continue;

2126      }

2127 

2128      // If we found a TokenFactor, there are two cases to consider: first if the

2129      // TokenFactor is just hanging "below" the pattern we're matching (i.e. no

2130      // uses of the TF are in our pattern) we just want to ignore it.  Second,

2131      // the TokenFactor can be sandwiched in between two chained nodes, like so:

2132      //     [Load chain]

2133      //               ^

2134      //               |

2135      //              [Load]

2136      //               ^        ^

2137      //               |          \                    DAG's like cheese

2138      //              /             \                       do you?

2139      //            /                |

2140      // [TokenFactor]   [Op]

2141      //           ^                 ^

2142      //           |                 |

2143      //            \               /

2144      //              \           /

2145      //               [Store]

2146      //

2147      // In this case, the TokenFactor becomes part of our match and we rewrite it

2148      // as a new TokenFactor.

2149      //

2150      // To distinguish these two cases, do a recursive walk down the uses.

2151      switch (WalkChainUsers(User, ChainedNodesInPattern, InteriorChainedNodes)) {

2152      case CR_Simple:

2153        // If the uses of the TokenFactor are just already-selected nodes, ignore

2154        // it, it is "below" our pattern.

2155        continue;

2156      case CR_InducesCycle:

2157        // If the uses of the TokenFactor lead to nodes that are not part of our

2158        // pattern that are not selected, folding would turn this into a cycle,

2159        // bail out now.

2160        return CR_InducesCycle;

2161      case CR_LeadsToInteriorNode:

2162        break;  // Otherwise, keep processing.

2163      }

2164 

2165      // Okay, we know we're in the interesting interior case.  The TokenFactor

2166      // is now going to be considered part of the pattern so that we rewrite its

2167      // uses (it may have uses that are not part of the pattern) with the

2168      // ultimate chain result of the generated code.  We will also add its chain

2169     // inputs as inputs to the ultimate TokenFactor we create.

2170      Result = CR_LeadsToInteriorNode;

2171      ChainedNodesInPattern.push_back(User);

2172      InteriorChainedNodes.push_back(User);

2173      continue;

2174    }

2175 

2176    return Result;

2177  }

在2101行,ISD::TokenFactor類型的SDNode節點是我們要産生的(見HandleMergeInputChains()的2227行)。代表有副作用操作的DAG的鍊節點總是成對的,一個輸出,一個輸入。該方法中的注釋已經詳細地解釋了代碼的邏輯,不再重複。

回到HandleMergeInputChains(),如果不會導緻環,就可以建構對應的ISD::TokenFactor節點。并把它傳回給SelectionDAGISel::SelectCodeCommon()中的InputChain。如果這個節點不能成功建立,目前的指令比對就失敗了,需要進入出錯處理,嘗試比對下一個指令。

V7.0的處理相比之精簡不少,不再需要繁瑣、難懂的WalkChainUsers():

2489  static SDValue

2490  HandleMergeInputChains(SmallVectorImpl<SDNode*> &ChainNodesMatched,

2491                         SelectionDAG *CurDAG) {

2492 

2493    SmallPtrSet<const SDNode *, 16> Visited;

2494    SmallVector<const SDNode *, 8> Worklist;

2495    SmallVector<SDValue, 3> InputChains;

2496    unsigned int Max = 8192;

2497 

2498    // Quick exit on trivial merge.

2499    if (ChainNodesMatched.size() == 1)

2500      return ChainNodesMatched[0]->getOperand(0);

2501 

2502    // Add chains that aren't already added (internal). Peek through

2503    // token factors.

2504    std::function<void(const SDValue)> AddChains = [&](const SDValue V) {

2505      if (V.getValueType() != MVT::Other)

2506        return;

2507      if (V->getOpcode() == ISD::EntryToken)

2508        return;

2509      if (!Visited.insert(V.getNode()).second)

2510        return;

2511      if (V->getOpcode() == ISD::TokenFactor) {

2512        for (const SDValue &Op : V->op_values())

2513          AddChains(Op);

2514      } else

2515        InputChains.push_back(V);

2516    };

2517 

2518    for (auto *N : ChainNodesMatched) {

2519      Worklist.push_back(N);

2520      Visited.insert(N);

2521    }

2522 

2523    while (!Worklist.empty())

2524      AddChains(Worklist.pop_back_val()->getOperand(0));

2525 

2526    // Skip the search if there are no chain dependencies.

2527    if (InputChains.size() == 0)

2528      return CurDAG->getEntryNode();

2529 

2530    // If one of these chains is a successor of input, we must have a

2531    // node that is both the predecessor and successor of the

2532    // to-be-merged nodes. Fail.

2533    Visited.clear();

2534    for (SDValue V : InputChains)

2535      Worklist.push_back(V.getNode());

2536 

2537    for (auto *N : ChainNodesMatched)

2538      if (SDNode::hasPredecessorHelper(N, Visited, Worklist, Max, true))

2539        return SDValue();

2540 

2541    // Return merged chain.

2542    if (InputChains.size() == 1)

2543      return InputChains[0];

2544    return CurDAG->getNode(ISD::TokenFactor, SDLoc(ChainNodesMatched[0]),

2545                           MVT::Other, InputChains);

2546  }

HandleMergeInputChains()與前面的findNonImmUse()類似,通過hasPredecessorHelper()方法來查找作為輸入參數的鍊節點中是否存在作為它們操作數(該節點本身是它們的後繼)前驅情形。如果存在,該節點将同時為這些操作數的前驅與後繼,是以不能合并。