LLVM学习笔记(33)

3.4.4.3.5. OPC_MorphNodeTo等

下面的OPC_EmitCopyToReg表示将值拷贝到一个物理寄存器的一个操作,3081行通过目标机器SelectionDAG实例的getCopyToReg()方法在Chain与glue的链上插入CopyToReg的节点。3093行的RunSDNodeXForm()是前面为目标机器生成的执行SDNodeXForm所代表操作的方法。

SelectionDAGISel::SelectCodeCommon(续)

3073      case OPC_EmitCopyToReg: {

3074        unsigned RecNo = MatcherTable[MatcherIndex++];

3075        assert(RecNo < RecordedNodes.size() && "Invalid EmitCopyToReg");

3076        unsigned DestPhysReg = MatcherTable[MatcherIndex++];

3077 

3078        if (!InputChain.getNode())

3079          InputChain = CurDAG->getEntryNode();

3080 

3081        InputChain = CurDAG->getCopyToReg(InputChain, SDLoc(NodeToMatch),

3082                                          DestPhysReg, RecordedNodes[RecNo].first,

3083                                          InputGlue);

3084 

3085        InputGlue = InputChain.getValue(1);

3086        continue;

3087      }

3088 

3089      case OPC_EmitNodeXForm: {

3090        unsigned XFormNo = MatcherTable[MatcherIndex++];

3091        unsigned RecNo = MatcherTable[MatcherIndex++];

3092        assert(RecNo < RecordedNodes.size() && "Invalid EmitNodeXForm");

3093        SDValue Res = RunSDNodeXForm(RecordedNodes[RecNo].first, XFormNo);

3094        RecordedNodes.push_back(std::pair<SDValue,SDNode*>(Res, nullptr));

3095        continue;

3096      }

 

    case OPC_Coverage: {                                                                                                          <- v7.0增加

      // This is emitted right before MorphNode/EmitNode.

      // So it should be safe to assume that this node has been selected

      unsigned index = MatcherTable[MatcherIndex++];

      index |= (MatcherTable[MatcherIndex++] << 8);

      dbgs() << "COVERED: " << getPatternForIndex(index) << "\n";

      dbgs() << "INCLUDED: " << getIncludePathForIndex(index) << "\n";

      continue;

    }

3097 

3098      case OPC_EmitNode:

3099      case OPC_MorphNodeTo: {

    case OPC_EmitNode0:    case OPC_EmitNode1:    case OPC_EmitNode2:                <- v7.0增加

    case OPC_MorphNodeTo0: case OPC_MorphNodeTo1: case OPC_MorphNodeTo2: {

3100        uint16_t TargetOpc = MatcherTable[MatcherIndex++];

3101        TargetOpc |= (unsigned short)MatcherTable[MatcherIndex++] << 8;

3102        unsigned EmitNodeInfo = MatcherTable[MatcherIndex++];

3103        // Get the result VT list.

3104        unsigned NumVTs = MatcherTable[MatcherIndex++];                                                <- v7.0删除

      unsigned NumVTs;                                                                                                             <- v7.0增加

      // If this is one of the compressed forms, get the number of VTs based

      // on the Opcode. Otherwise read the next byte from the table.

      if (Opcode >= OPC_MorphNodeTo0 && Opcode <= OPC_MorphNodeTo2)

        NumVTs = Opcode - OPC_MorphNodeTo0;

      else if (Opcode >= OPC_EmitNode0 && Opcode <= OPC_EmitNode2)

        NumVTs = Opcode - OPC_EmitNode0;

      else

        NumVTs = MatcherTable[MatcherIndex++];

3105        SmallVector<EVT, 4> VTs;

3106        for (unsigned i = 0; i != NumVTs; ++i) {

3107          MVT::SimpleValueType VT =

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

3109          if (VT == MVT::iPTR)

3110            VT = TLI->getPointerTy(CurDAG->getDataLayout()).SimpleTy;

3111          VTs.push_back(VT);

3112        }

3113 

3114        if (EmitNodeInfo & OPFL_Chain)

3115          VTs.push_back(MVT::Other);

3116        if (EmitNodeInfo & OPFL_GlueOutput)

3117          VTs.push_back(MVT::Glue);

3118 

3119        // This is hot code, so optimize the two most common cases of 1 and 2

3120        // results.

3121        SDVTList VTList;

3122        if (VTs.size() == 1)

3123          VTList = CurDAG->getVTList(VTs[0]);

3124        else if (VTs.size() == 2)

3125          VTList = CurDAG->getVTList(VTs[0], VTs[1]);

3126        else

3127          VTList = CurDAG->getVTList(VTs);

3128 

3129        // Get the operand list.

3130        unsigned NumOps = MatcherTable[MatcherIndex++];

3131        SmallVector<SDValue, 8> Ops;

3132        for (unsigned i = 0; i != NumOps; ++i) {

3133          unsigned RecNo = MatcherTable[MatcherIndex++];

3134          if (RecNo & 128)

3135            RecNo = GetVBR(RecNo, MatcherTable, MatcherIndex);

3136 

3137          assert(RecNo < RecordedNodes.size() && "Invalid EmitNode");

3138          Ops.push_back(RecordedNodes[RecNo].first);

3139        }

3140 

3141        // If there are variadic operands to add, handle them now.

3142        if (EmitNodeInfo & OPFL_VariadicInfo) {

3143          // Determine the start index to copy from.

3144          unsigned FirstOpToCopy = getNumFixedFromVariadicInfo(EmitNodeInfo);

3145         FirstOpToCopy += (EmitNodeInfo & OPFL_Chain) ? 1 : 0;

3146          assert(NodeToMatch->getNumOperands() >= FirstOpToCopy &&

3147                 "Invalid variadic node");

3148          // Copy all of the variadic operands, not including a potential glue

3149          // input.

3150          for (unsigned i = FirstOpToCopy, e = NodeToMatch->getNumOperands();

3151               i != e; ++i) {

3152            SDValue V = NodeToMatch->getOperand(i);

3153            if (V.getValueType() == MVT::Glue) break;

3154            Ops.push_back(V);

3155          }

3156        }

3157 

3158        // If this has chain/glue inputs, add them.

3159        if (EmitNodeInfo & OPFL_Chain)

3160          Ops.push_back(InputChain);

3161        if ((EmitNodeInfo & OPFL_GlueInput) && InputGlue.getNode() != nullptr)

3162          Ops.push_back(InputGlue);

3163 

3164        // Create the node.

3165        SDNode *Res = nullptr;                                                                                                      <- v7.0删除

3166        if (Opcode != OPC_MorphNodeTo) {

3167          // If this is a normal EmitNode command, just create the new node and

3168          // add the results to the RecordedNodes list.

3169          Res = CurDAG->getMachineNode(TargetOpc, SDLoc(NodeToMatch),

3170                                       VTList, Ops);

3171 

3172          // Add all the non-glue/non-chain results to the RecordedNodes list.

3173          for (unsigned i = 0, e = VTs.size(); i != e; ++i) {

3174            if (VTs[i] == MVT::Other || VTs[i] == MVT::Glue) break;

3175            RecordedNodes.push_back(std::pair<SDValue,SDNode*>(SDValue(Res, i),

3176                                                               nullptr));

3177          }

3178 

3179        } else if (NodeToMatch->getOpcode() != ISD::DELETED_NODE) {

3180         Res = MorphNode(NodeToMatch, TargetOpc, VTList, Ops, EmitNodeInfo);

3181        } else {

3182          // NodeToMatch was eliminated by CSE when the target changed the DAG.

3183          // We will visit the equivalent node later.

3184          DEBUG(dbgs() << "Node was eliminated by CSE\n");

3185          return nullptr;

3186        }

 

      MachineSDNode *Res = nullptr;                                                                                       <- v7.0增加

      bool IsMorphNodeTo = Opcode == OPC_MorphNodeTo ||

                     (Opcode >= OPC_MorphNodeTo0 && Opcode <= OPC_MorphNodeTo2);

      if (!IsMorphNodeTo) {

        // If this is a normal EmitNode command, just create the new node and

        // add the results to the RecordedNodes list.

        Res = CurDAG->getMachineNode(TargetOpc, SDLoc(NodeToMatch),

                                     VTList, Ops);

 

        // Add all the non-glue/non-chain results to the RecordedNodes list.

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

          if (VTs[i] == MVT::Other || VTs[i] == MVT::Glue) break;

          RecordedNodes.push_back(std::pair<SDValue,SDNode*>(SDValue(Res, i),

                                                             nullptr));

        }

      } else {

        assert(NodeToMatch->getOpcode() != ISD::DELETED_NODE &&

               "NodeToMatch was removed partway through selection");

        SelectionDAG::DAGNodeDeletedListener NDL(*CurDAG, [&](SDNode *N,

                                                              SDNode *E) {

          CurDAG->salvageDebugInfo(*N);

          auto &Chain = ChainNodesMatched;

          assert((!E || !is_contained(Chain, N)) &&

                 "Chain node replaced during MorphNode");

          Chain.erase(std::remove(Chain.begin(), Chain.end(), N), Chain.end());

        });

à    Res = cast<MachineSDNode>(MorphNode(NodeToMatch, TargetOpc, VTList,

                                            Ops, EmitNodeInfo));

      }

注意在v7.0代码里,à行的cast<MachineSDNode>是为了确定SDNode实例的NodeType小于0(即选择成功,因为如果这个SDNode实例与MachineSDNode不等价,cast()方法将触发断言。参考MachineSDNodeclassof()方法),并不是为了真正将SDNode指针转换为MachineSDNode指针。

而到了遇见OPC_EmitNode或OPC_MorphNodeTo时,表示匹配马上就要完成了,要为匹配成功的指令生成代表其结果的MachineSDNode,这个节点将代替被匹配成功的DAG。

我们前面看到OPC_MorphNodeTo后面跟的是这么一串内容:

/*1792*/            OPC_MorphNodeTo, TARGET_VAL(X86::SHR16mi), 0|OPFL_Chain|OPFL_MemRefs,

                        1/*#VTs*/, MVT::i32, 6/*#Ops*/, 4, 5, 6, 7, 8, 9,

                    // Src: (st (srl:i16 (ld:i16 addr:iPTR:$dst)<<P:Predicate_unindexedload>><<P:Predicate_loadi16>>, (imm:i8):$src), addr:iPTR:$dst)<<P:Predicate_unindexedstore>><<P:Predicate_store>> - Complexity = 50

                    // Dst: (SHR16mi:i32 addr:iPTR:$dst, (imm:i8):$src)

首先是表示目标机器上所对应的指令助记符(2个字节),它是将要生成的MachineSDNode的NodeType(实际上这些枚举值是根据TD里对应指令定义的名字生成的)。随后是记录该操作属性的字节。接下来就是结果类型数组,以及操作数列表。3100~3165行都是解析这些字节,准备参数列表Ops。注意3138行,Ops也是来自由容器RecordedNodes里记录的SDNode实例。

对于OPC_EmitNode,匹配真正结束要等到OPC_CompleteMatch出现,因此在3166~3176行准备一个具有指定操作码的MachineSDNode实例,将代表结果的SDValue实例记录到RecordedNodes,OPC_CompleteMatch将使用这些结果。至于OPC_MorphNodeTo,它是OPC_EmitNode与OPC_CompleteMatch的合体,因此通过下面的方法来了结这次的匹配。

2232  SDNode *SelectionDAGISel::

2233  MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTList,

2234            ArrayRef<SDValue> Ops, unsigned EmitNodeInfo) {

2235    // It is possible we're using MorphNodeTo to replace a node with no

2236    // normal results with one that has a normal result (or we could be

2237    // adding a chain) and the input could have glue and chains as well.

2238    // In this case we need to shift the operands down.

2239   // FIXME: This is a horrible hack and broken in obscure cases, no worse

2240    // than the old isel though.

2241    int OldGlueResultNo = -1, OldChainResultNo = -1;

2242 

2243    unsigned NTMNumResults = Node->getNumValues();

2244    if (Node->getValueType(NTMNumResults-1) == MVT::Glue) {

2245      OldGlueResultNo = NTMNumResults-1;

2246      if (NTMNumResults != 1 &&

2247          Node->getValueType(NTMNumResults-2) == MVT::Other)

2248        OldChainResultNo = NTMNumResults-2;

2249    } else if (Node->getValueType(NTMNumResults-1) == MVT::Other)

2250      OldChainResultNo = NTMNumResults-1;

2251 

2252    // Call the underlying SelectionDAG routine to do the transmogrification. Note

2253    // that this deletes operands of the old node that become dead.

2254   SDNode *Res = CurDAG->MorphNodeTo(Node, ~TargetOpc, VTList, Ops);

2255 

2256    // MorphNodeTo can operate in two ways: if an existing node with the

2257    // specified operands exists, it can just return it.  Otherwise, it

2258    // updates the node in place to have the requested operands.

2259    if (Res == Node) {

2260      // If we updated the node in place, reset the node ID.  To the isel,

2261     // this should be just like a newly allocated machine node.

2262      Res->setNodeId(-1);

2263    }

2264 

2265    unsigned ResNumResults = Res->getNumValues();

2266    // Move the glue if needed.

2267    if ((EmitNodeInfo & OPFL_GlueOutput) && OldGlueResultNo != -1 &&

2268        (unsigned)OldGlueResultNo != ResNumResults-1)

2269      CurDAG->ReplaceAllUsesOfValueWith(SDValue(Node, OldGlueResultNo),              <- v7.0删除

2270                                        SDValue(Res, ResNumResults-1));

    ReplaceUses(SDValue(Node, OldGlueResultNo),                                                           <- v7.0增加

                SDValue(Res, ResNumResults - 1));

2271 

2272    if ((EmitNodeInfo & OPFL_GlueOutput) != 0)

2273      --ResNumResults;

2274 

2275    // Move the chain reference if needed.

2276    if ((EmitNodeInfo & OPFL_Chain) && OldChainResultNo != -1 &&

2277        (unsigned)OldChainResultNo != ResNumResults-1)

2278      CurDAG->ReplaceAllUsesOfValueWith(SDValue(Node, OldChainResultNo),            <- v7.0删除

2279                                        SDValue(Res, ResNumResults-1));

    ReplaceUses(SDValue(Node, OldChainResultNo),                                                          <- v7.0增加

                SDValue(Res, ResNumResults - 1));

2280 

2281    // Otherwise, no replacement happened because the node already exists. Replace

2282    // Uses of the old node with the new one.

2283    if (Res != Node)                                                                                                                        <- v7.0删除

2284      CurDAG->ReplaceAllUsesWith(Node, Res);

  if (Res != Node) {                                                                                                                      <- v7.0增加

    ReplaceNode(Node, Res);

  } else {

    EnforceNodeIdInvariant(Res);

  }

2285 

2286    return Res;

2287  }

因为结果是目标机器相关的,因此由目标机器SelectionDAG的MorphNodeTo()方法来构建表示匹配结果的SDNode实例。注意在2254行的调用时将TargetOpc取反,这样很容易通过NodeType是否小于0来判断SDNode实例是否是指令选择的结果(在下面5840行赋值为TargetOpc)。

5824  SDNode *SelectionDAG::MorphNodeTo(SDNode *N, unsigned Opc,

5825                                    SDVTList VTs, ArrayRef<SDValue> Ops) {

5826    unsigned NumOps = Ops.size();

5827    // If an identical node already exists, use it.

5828    void *IP = nullptr;

5829    if (VTs.VTs[VTs.NumVTs-1] != MVT::Glue) {

5830      FoldingSetNodeID ID;

5831      AddNodeIDNode(ID, Opc, VTs, Ops);

5832      if (SDNode *ON = FindNodeOrInsertPos(ID, N->getDebugLoc(), IP))

5833        return UpdadeSDLocOnMergedSDNode(ON, SDLoc(N));

5834    }

5835 

5836    if (!RemoveNodeFromCSEMaps(N))

5837      IP = nullptr;

5838 

5839    // Start the morphing.

5840    N->NodeType = Opc;

5841    N->ValueList = VTs.VTs;

5842    N->NumValues = VTs.NumVTs;

5843 

5844    // Clear the operands list, updating used nodes to remove this from their

5845    // use list.  Keep track of any operands that become dead as a result.

5846    SmallPtrSet<SDNode*, 16> DeadNodeSet;

5847    for (SDNode::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ) {

5848      SDUse &Use = *I++;

5849      SDNode *Used = Use.getNode();

5850      Use.set(SDValue());

5851      if (Used->use_empty())

5852        DeadNodeSet.insert(Used);

5853    }

5854 

5855   if (MachineSDNode *MN = dyn_cast<MachineSDNode>(N)) {                                      <- v7.0删除

5856      // Initialize the memory references information.

5857      MN->setMemRefs(nullptr, nullptr);

5858      // If NumOps is larger than the # of operands we can have in a                                 <- v7.0删除

5859      // MachineSDNode, reallocate the operand list.

5860      if (NumOps > MN->NumOperands || !MN->OperandsNeedDelete) {

5861        if (MN->OperandsNeedDelete)

5862          delete[] MN->OperandList;

5863        if (NumOps > array_lengthof(MN->LocalOperands))

5864          // We're creating a final node that will live unmorphed for the

5865          // remainder of the current SelectionDAG iteration, so we can allocate

5866          // the operands directly out of a pool with no recycling metadata.

5867          MN->InitOperands(OperandAllocator.Allocate<SDUse>(NumOps),

5868                           Ops.data(), NumOps);

5869        else

5870         MN->InitOperands(MN->LocalOperands, Ops.data(), NumOps);

5871        MN->OperandsNeedDelete = false;

5872      } else

5873        MN->InitOperands(MN->OperandList, Ops.data(), NumOps);

5874    } else {

5875      // If NumOps is larger than the # of operands we currently have, reallocate

5876      // the operand list.

5877      if (NumOps > N->NumOperands) {

5878        if (N->OperandsNeedDelete)

5879          delete[] N->OperandList;

5880        N->InitOperands(new SDUse[NumOps], Ops.data(), NumOps);

5881        N->OperandsNeedDelete = true;

5882      } else

5883        N->InitOperands(N->OperandList, Ops.data(), NumOps);

5884    }

  // Swap for an appropriately sized array from the recycler.                                       <- v7.0增加

  removeOperands(N);

  createOperands(N, Ops);

5885 

5886    // Delete any nodes that are still dead after adding the uses for the

5887    // new operands.

5888    if (!DeadNodeSet.empty()) {

5889      SmallVector<SDNode *, 16> DeadNodes;

5890      for (SDNode *N : DeadNodeSet)

5891        if (N->use_empty())

5892          DeadNodes.push_back(N);

5893      RemoveDeadNodes(DeadNodes);

5894    }

5895 

5896    if (IP)

5897     CSEMap.InsertNode(N, IP);   // Memoize the new node.

5898    return N;

5899  }

如果选中的指令不修改标志寄存器,就可以首先检查是否存在相同的MachineSDNode。5830行的FoldingSetNodeID()用于收集一个节点中所有的数据比特,然后为这个节点产生一个哈希值。因为SDNode是从FoldingSetNode派生的,所以适用这样的方法。

为了理解这段代码,我们需要深入5832行FoldingSet的GetOrInsertNode()方法。它的定义看上去不复杂。但这是一个模板类的方法,这里的T是在定义CSEMap时给出的,即SDNode。

444       T *GetOrInsertNode(Node *N) {

445         return static_cast<T *>(FoldingSetImpl::GetOrInsertNode(N));

446       }

FoldingSet所用到的哈希表的具体实现由基类FoldingSetImpl提供,它不是模板类(v7.0中它也被实现为模板,原来FoldingSetImpl的功能移到了基类FoldingSetBase中。因为v7.0还定义了另一个派生类ContextualFoldingSet)。

380     FoldingSetImpl::Node *FoldingSetImpl::GetOrInsertNode(FoldingSetImpl::Node *N) {

381       FoldingSetNodeID ID;

382       GetNodeProfile(N, ID);

383       void *IP;

384       if (Node *E = FindNodeOrInsertPos(ID, IP))

385         return E;

386       InsertNode(N, IP);

387       return N;

388     }

381行的FoldingSetNodeID唯一的数据成员是SmallVector<unsigned, 32> Bits,用来收集使得特定节点能被唯一识别的比特数据。它还提供了一个ComputeHash()方法来根据这些比特位计算哈希值。382行FoldingSet的GetNodeProfile()就是根据FoldingSet中不同的节点类型填充这些比特。

400       void GetNodeProfile(Node *N, FoldingSetNodeID &ID) const override {

401         T *TN = static_cast<T *>(N);

402         FoldingSetTrait<T>::Profile(*TN, ID);

403       }

402行的FoldingSetTrait使用的是非特化的模板类定义(对指针类型特化了):

240     template<typename T> struct FoldingSetTrait

241       : public DefaultFoldingSetTrait<T> {};

因此,402行的Profile方法是基类DefaultFoldingSetTrait提供的:

212       static void Profile(const T &X, FoldingSetNodeID &ID) {

213         X.Profile(ID);

214       }

这里的X是FoldingSet模板类具现时指定的模板参数,对于CSEMap,就是SDNode。因此,213行调用的是下面的方法:

6597  void SDNode::Profile(FoldingSetNodeID &ID) const {

6598    AddNodeIDNode(ID, this);

6599  }

AddNodeIDNode()的定义则是:

565     static void AddNodeIDNode(FoldingSetNodeID &ID, const SDNode *N) {

566       AddNodeIDOpcode(ID, N->getOpcode());

567       // Add the return value info.

568       AddNodeIDValueTypes(ID, N->getVTList());

569       // Add the operand info.

570       AddNodeIDOperands(ID, N->ops());

571    

572       // Handle SDNode leafs with special info.

573       AddNodeIDCustom(ID, N);

574     }

它分别调用了这些方法:

372     static void AddNodeIDOpcode(FoldingSetNodeID &ID, unsigned OpC)  {

373       ID.AddInteger(OpC);

374     }

 

378     static void AddNodeIDValueTypes(FoldingSetNodeID &ID, SDVTList VTList) {

379       ID.AddPointer(VTList.VTs);

380     }

 

394     static void AddNodeIDOperands(FoldingSetNodeID &ID,

395                                   ArrayRef<SDValue> Ops) {

396       for (auto& Op : Ops) {

397         ID.AddPointer(Op.getNode());

398         ID.AddInteger(Op.getResNo());

399       }

400     }

 

429     static void AddNodeIDCustom(FoldingSetNodeID &ID, const SDNode *N) {

430       switch (N->getOpcode()) {

431       case ISD::TargetExternalSymbol:

432       case ISD::ExternalSymbol:

433       case ISD::MCSymbol:

434         llvm_unreachable("Should only be used on nodes with operands");

435       default: break// Normal nodes don't need extra info.

436       case ISD::TargetConstant:

437       case ISD::Constant: {

438         const ConstantSDNode *C = cast<ConstantSDNode>(N);

439         ID.AddPointer(C->getConstantIntValue());

440         ID.AddBoolean(C->isOpaque());

441         break;

442       }

443       case ISD::TargetConstantFP:

444       case ISD::ConstantFP: {

445         ID.AddPointer(cast<ConstantFPSDNode>(N)->getConstantFPValue());

446         break;

447       }

448       case ISD::TargetGlobalAddress:

449       case ISD::GlobalAddress:

450       case ISD::TargetGlobalTLSAddress:

451       case ISD::GlobalTLSAddress: {

452         const GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(N);

453         ID.AddPointer(GA->getGlobal());

454         ID.AddInteger(GA->getOffset());

455         ID.AddInteger(GA->getTargetFlags());

456         ID.AddInteger(GA->getAddressSpace());                                                                           <- v7.0删除

457         break;

458       }

459       case ISD::BasicBlock:

460         ID.AddPointer(cast<BasicBlockSDNode>(N)->getBasicBlock());

461         break;

462       case ISD::Register:

463         ID.AddInteger(cast<RegisterSDNode>(N)->getReg());

464         break;

465       case ISD::RegisterMask:

466         ID.AddPointer(cast<RegisterMaskSDNode>(N)->getRegMask());

467         break;

468       case ISD::SRCVALUE:

469         ID.AddPointer(cast<SrcValueSDNode>(N)->getValue());

470         break;

471       case ISD::FrameIndex:

472       case ISD::TargetFrameIndex:

473         ID.AddInteger(cast<FrameIndexSDNode>(N)->getIndex());

474         break;

475       case ISD::JumpTable:

476       case ISD::TargetJumpTable:

477       ID.AddInteger(cast<JumpTableSDNode>(N)->getIndex());

478         ID.AddInteger(cast<JumpTableSDNode>(N)->getTargetFlags());

479         break;

480       case ISD::ConstantPool:

481       case ISD::TargetConstantPool: {

482         const ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(N);

483         ID.AddInteger(CP->getAlignment());

484         ID.AddInteger(CP->getOffset());

485         if (CP->isMachineConstantPoolEntry())

486           CP->getMachineCPVal()->addSelectionDAGCSEId(ID);

487         else

488           ID.AddPointer(CP->getConstVal());

489         ID.AddInteger(CP->getTargetFlags());

490         break;

491       }

492       case ISD::TargetIndex: {

493         const TargetIndexSDNode *TI = cast<TargetIndexSDNode>(N);

494         ID.AddInteger(TI->getIndex());

495         ID.AddInteger(TI->getOffset());

496         ID.AddInteger(TI->getTargetFlags());

497         break;

498       }

499       case ISD::LOAD: {

500         const LoadSDNode *LD = cast<LoadSDNode>(N);

501         ID.AddInteger(LD->getMemoryVT().getRawBits());

502         ID.AddInteger(LD->getRawSubclassData());

503         ID.AddInteger(LD->getPointerInfo().getAddrSpace());

504         break;

505       }

506       case ISD::STORE: {

507         const StoreSDNode *ST = cast<StoreSDNode>(N);

508         ID.AddInteger(ST->getMemoryVT().getRawBits());

509         ID.AddInteger(ST->getRawSubclassData());

510         ID.AddInteger(ST->getPointerInfo().getAddrSpace());

511         break;

512       }

  case ISD::MLOAD: {                                                                                                                  <- v7.0增加

    const MaskedLoadSDNode *MLD = cast<MaskedLoadSDNode>(N);

    ID.AddInteger(MLD->getMemoryVT().getRawBits());

    ID.AddInteger(MLD->getRawSubclassData());

    ID.AddInteger(MLD->getPointerInfo().getAddrSpace());

    break;

  }

  case ISD::MSTORE: {

    const MaskedStoreSDNode *MST = cast<MaskedStoreSDNode>(N);

    ID.AddInteger(MST->getMemoryVT().getRawBits());

    ID.AddInteger(MST->getRawSubclassData());

    ID.AddInteger(MST->getPointerInfo().getAddrSpace());

    break;

  }

  case ISD::MGATHER: {

    const MaskedGatherSDNode *MG = cast<MaskedGatherSDNode>(N);

    ID.AddInteger(MG->getMemoryVT().getRawBits());

    ID.AddInteger(MG->getRawSubclassData());

    ID.AddInteger(MG->getPointerInfo().getAddrSpace());

    break;

  }

  case ISD::MSCATTER: {

    const MaskedScatterSDNode *MS = cast<MaskedScatterSDNode>(N);

    ID.AddInteger(MS->getMemoryVT().getRawBits());

    ID.AddInteger(MS->getRawSubclassData());

    ID.AddInteger(MS->getPointerInfo().getAddrSpace());

    break;

  }

513       case ISD::ATOMIC_CMP_SWAP:

514       case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS:

515       case ISD::ATOMIC_SWAP:

516       case ISD::ATOMIC_LOAD_ADD:

517       case ISD::ATOMIC_LOAD_SUB:

518       case ISD::ATOMIC_LOAD_AND:

519       case ISD::ATOMIC_LOAD_OR:

520       case ISD::ATOMIC_LOAD_XOR:

521       case ISD::ATOMIC_LOAD_NAND:

522       case ISD::ATOMIC_LOAD_MIN:

523       case ISD::ATOMIC_LOAD_MAX:

524       case ISD::ATOMIC_LOAD_UMIN:

525       case ISD::ATOMIC_LOAD_UMAX:

526       case ISD::ATOMIC_LOAD:

527       case ISD::ATOMIC_STORE: {

528         const AtomicSDNode *AT = cast<AtomicSDNode>(N);

529         ID.AddInteger(AT->getMemoryVT().getRawBits());

530         ID.AddInteger(AT->getRawSubclassData());

531         ID.AddInteger(AT->getPointerInfo().getAddrSpace());

532         break;

533       }

534       case ISD::PREFETCH: {

535         const MemSDNode *PF = cast<MemSDNode>(N);

536         ID.AddInteger(PF->getPointerInfo().getAddrSpace());

537         break;

538       }

539       case ISD::VECTOR_SHUFFLE: {

540         const ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(N);

541         for (unsigned i = 0, e = N->getValueType(0).getVectorNumElements();

542              i != e; ++i)

543           ID.AddInteger(SVN->getMaskElt(i));

544         break;

545       }

546       case ISD::TargetBlockAddress:

547       case ISD::BlockAddress: {

548         const BlockAddressSDNode *BA = cast<BlockAddressSDNode>(N);

549         ID.AddPointer(BA->getBlockAddress());

550         ID.AddInteger(BA->getOffset());

551         ID.AddInteger(BA->getTargetFlags());

552         break;

553       }

554       } // end switch (N->getOpcode())

555    

556       AddNodeIDFlags(ID, N);

557    

558       // Target specific memory nodes could also have address spaces to check.

559       if (N->isTargetMemoryOpcode())

560         ID.AddInteger(cast<MemSDNode>(N)->getPointerInfo().getAddrSpace());

561     }

除了记录操作码、操作数地址、返回值地址、类型,方法AddNodeIDCustom()还根据SDNode的派生类型进行进一步的记录,以确保有更好的区分度。这里的哈希方法采用了N3333[1]所提出的算法与接口,它确保k1==k2,就必然有h (k1) == h (k2)。那么FoldingSetImpl::GetOrInsertNode()所调用的FindNodeOrInsertPos()方法涵盖了下列的方法调用:

451       T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {

452         return static_cast<T *>(FoldingSetImpl::FindNodeOrInsertPos(ID, InsertPos));

453       }

下面288行的GetBucketFor()方法返回该哈希值所对应的桶,这个桶是哈希值相同的SDNode对象组成的链表。

284     FoldingSetImpl::Node

285     *FoldingSetImpl::FindNodeOrInsertPos(const FoldingSetNodeID &ID,

286                                          void *&InsertPos) {

287       unsigned IDHash = ID.ComputeHash();

288       void **Bucket = GetBucketFor(IDHash, Buckets, NumBuckets);

289       void *Probe = *Bucket;

290      

291       InsertPos = nullptr;

292      

293       FoldingSetNodeID TempID;

294       while (Node *NodeInBucket = GetNextPtr(Probe)) {

295         if (NodeEquals(NodeInBucket, ID, IDHash, TempID))

296           return NodeInBucket;

297         TempID.clear();

298    

299         Probe = NodeInBucket->getNextInBucket();

300       }

301      

302       // Didn't find the node, return null with the bucket as the InsertPos.

303       InsertPos = Bucket;

304       return nullptr;

305     }

295行的NodeEquals()是FoldingSet的方法,它的定义如下:

406       bool NodeEquals(Node *N, const FoldingSetNodeID &ID, unsigned IDHash,

407                       FoldingSetNodeID &TempID) const override {

408         T *TN = static_cast<T *>(N);

409         return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID);

410       }

409行的Equals有多个特化版本,我们只看非特化版本,它来自基类DefaultFoldingSetTrait。

358     template<typename T>

359     inline bool

360     DefaultFoldingSetTrait<T>::Equals(T &X, const FoldingSetNodeID &ID,

361                                       unsigned /*IDHash*/,

362                                       FoldingSetNodeID &TempID) {

363       FoldingSetTrait<T>::Profile(X, TempID);

364       return TempID == ID;

365     }

在这里我们又看到了Profile()这个方法,前面我们就是使用这个方法来收集计算哈希值所需要的比特位的。在364行通过FoldingSetNodeID的比较操作符来比较这两个FoldingSetNodeID实例:

152     bool FoldingSetNodeID::operator==(const FoldingSetNodeID &RHS) const {

153       return *this == FoldingSetNodeIDRef(RHS.Bits.data(), RHS.Bits.size());

154     }

 

158     bool FoldingSetNodeID::operator==(FoldingSetNodeIDRef RHS) const {

159       return FoldingSetNodeIDRef(Bits.data(), Bits.size()) == RHS;

160     }

 

34       bool FoldingSetNodeIDRef::operator==(FoldingSetNodeIDRef RHS) const {

35         if (Size != RHS.Size) return false;

36         return memcmp(Data, RHS.Data, Size*sizeof(*Data)) == 0;

37       }

看到最终我们是通过比较比特位来确定两个对象是否相等。因为不是使用地址作为比较的标准,因此存在不同的SDNode实例按上述标准是相同的情况。

如果没有存在的相同实例,或者选中指令会修改标志寄存器,就要进入5836行,通过方法RemoveNodeFromCSEMaps()将这个SDNode实例从CSEMap(或者别的容器)删除。如果SDNode没有记录,在5837行将IP置0。

778     bool SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) {

779       bool Erased = false;

780       switch (N->getOpcode()) {

781       case ISD::HANDLENODE: return false;  // noop.

782       case ISD::CONDCODE:

783         assert(CondCodeNodes[cast<CondCodeSDNode>(N)->get()] &&

784                "Cond code doesn't exist!");

785         Erased = CondCodeNodes[cast<CondCodeSDNode>(N)->get()] != nullptr;

786        CondCodeNodes[cast<CondCodeSDNode>(N)->get()] = nullptr;

787         break;

788       case ISD::ExternalSymbol:

789         Erased = ExternalSymbols.erase(cast<ExternalSymbolSDNode>(N)->getSymbol());

790         break;

791       case ISD::TargetExternalSymbol: {

792         ExternalSymbolSDNode *ESN = cast<ExternalSymbolSDNode>(N);

793         Erased = TargetExternalSymbols.erase(

794                    std::pair<std::string,unsigned char>(ESN->getSymbol(),

795                                                         ESN->getTargetFlags()));

796         break;

797       }

798       case ISD::MCSymbol: {

799         auto *MCSN = cast<MCSymbolSDNode>(N);

800         Erased = MCSymbols.erase(MCSN->getMCSymbol());

801         break;

802       }

803       case ISD::VALUETYPE: {

804         EVT VT = cast<VTSDNode>(N)->getVT();

805         if (VT.isExtended()) {

806           Erased = ExtendedValueTypeNodes.erase(VT);

807         } else {

808           Erased = ValueTypeNodes[VT.getSimpleVT().SimpleTy] != nullptr;

809           ValueTypeNodes[VT.getSimpleVT().SimpleTy] = nullptr;

810         }

811         break;

812       }

813       default:

814         // Remove it from the CSE Map.

815         assert(N->getOpcode() != ISD::DELETED_NODE && "DELETED_NODE in CSEMap!");

816         assert(N->getOpcode() != ISD::EntryToken && "EntryToken in CSEMap!");

817         Erased = CSEMap.RemoveNode(N);

818         break;

819       }

820     #ifndef NDEBUG

821       // Verify that the node was actually in one of the CSE maps, unless it has a

822       // flag result (which cannot be CSE'd) or is one of the special cases that are

823       // not subject to CSE.

824       if (!Erased && N->getValueType(N->getNumValues()-1) != MVT::Glue &&

825           !N->isMachineOpcode() && !doNotCSE(N)) {

826         N->dump(this);

827         dbgs() << "\n";

828         llvm_unreachable("Node is not in map!");

829       }

830     #endif

831       return Erased;

832     }

SelectionDAG::MorphNodeTo()接下来在5847行循环检查当前节点是唯一使用者的节点,将它们记录到DeadNodeSet容器,为后面回收它们做准备。接着,为这个节点重新准备操作数,这些操作数就是参数Ops,它是SelectionDAGISel对象RecordedNodes容器中已经选择好的SDValue对象。SDNode的方法InitOperands()将更新其中的OperandList。

812       void InitOperands(SDUse *Ops, const SDValue *Vals, unsigned N) {

813         for (unsigned i = 0; i != N; ++i) {

814           Ops[i].setUser(this);

815           Ops[i].setInitial(Vals[i]);

816         }

817         NumOperands = N;

818         assert(NumOperands == N &&

819                "NumOperands wasn't wide enough for its operands!");

820         OperandList = Ops;

821         checkForCycles(this);

822       }

注意,如果选中指令会修改标志寄存器,那么在上面的处理中,先从容器中(CSEMap或其他)删除它。然后在下面的ReplaceAllUsesOfValueWith()调用里,通过AddModifiedNodeToCSEMaps()方法将它加入CSEMap。

SelectionDAG::MorphNodeTo()将处理后的SDNode实例返回给SelectionDAGISel::MorphNode()的变量Res。除非已有相同的对象存在,SelectionDAGISel::MorphNode()的2259行条件总是满足的,这样重置这个对象的NodeId,使得在指令选择器看来这是个新的节点。

V7.0删除了SelectionDAG::MorphNodeTo()58585884行的代码。取而代之,调用了下面的函数。首先是通过SelectionDAG::removeOperands()释放NodeToMatch的操作数,而不是将类型局限于MachineSDNode

366       void removeOperands(SDNode *Node) {

367         if (!Node->OperandList)

368           return;

369         OperandRecycler.deallocate(

370             ArrayRecycler<SDUse>::Capacity::get(Node->NumOperands),

371             Node->OperandList);

372         Node->NumOperands = 0;

373         Node->OperandList = nullptr;

374       }

然后通过SelectionDAG::createOperands()NodeToMatch设置前面准备好的操作数。注意,这里的操作数包含了更新的链节点与黏结节点,因此不再需要OPC_MarkGlueResults类型的Matcher来对黏结节点进行特别处理。

8682  void SelectionDAG::createOperands(SDNode *Node, ArrayRef<SDValue> Vals) {

8683    assert(!Node->OperandList && "Node already has operands");

8684    SDUse *Ops = OperandRecycler.allocate(

8685      ArrayRecycler<SDUse>::Capacity::get(Vals.size()), OperandAllocator);

8686 

8687    bool IsDivergent = false;

8688    for (unsigned I = 0; I != Vals.size(); ++I) {

8689      Ops[I].setUser(Node);

8690      Ops[I].setInitial(Vals[I]);

8691      if (Ops[I].Val.getValueType() != MVT::Other) // Skip Chain. It does not carry divergence.

8692        IsDivergent = IsDivergent || Ops[I].getNode()->isDivergent();

8693    }

8694    Node->NumOperands = Vals.size();

8695    Node->OperandList = Ops;

8696    IsDivergent |= TLI->isSDNodeSourceOfDivergence(Node, FLI, DA);

8697    if (!TLI->isSDNodeAlwaysUniform(Node))

8698      Node->SDNodeBits.IsDivergent = IsDivergent;

8699    checkForCycles(Node);

8700  }

V7.0引入了一个FunctionPass——DivergenceAnalysis。用于检查GPU程序里的分支是否发散。SDNodeIsDivergent域用于保存这个分析的结果。8699行的checkForCycles()检查这个SDNode节点是否构成了一个环(SelectionDAG是不允许这样的,DAG本身就不能是环)。

接下来,在2267行,如果选择指令会使用标志寄存器,而且选中指令产生个数不同的结果,因为标志寄存器的结果(glue)总是最后一个结果,就要将这个旧值在使用的地方替换为新值。对链节点的处理也是类似的,最后如果SelectionDAG::MorphNodeTo()生成了新节点,也要在使用的地方替换旧节点。

6295  void SelectionDAG::ReplaceAllUsesOfValueWith(SDValue From, SDValue To){

6296    // Handle the really simple, really trivial case efficiently.

6297    if (From == To) return;

6298 

6299    // Handle the simple, trivial, case efficiently.

6300    if (From.getNode()->getNumValues() == 1) {

6301      ReplaceAllUsesWith(From, To);

6302      return;

6303    }

6304 

6305    // Iterate over just the existing users of From. See the comments in

6306    // the ReplaceAllUsesWith above.

6307    SDNode::use_iterator UI = From.getNode()->use_begin(),

6308                        UE = From.getNode()->use_end();

6309    RAUWUpdateListener Listener(*this, UI, UE);

6310    while (UI != UE) {

6311      SDNode *User = *UI;

6312      bool UserRemovedFromCSEMaps = false;

6313 

6314      // A user can appear in a use list multiple times, and when this

6315      // happens the uses are usually next to each other in the list.

6316      // To help reduce the number of CSE recomputations, process all

6317      // the uses of this user that we can find this way.

6318      do {

6319        SDUse &Use = UI.getUse();

6320 

6321        // Skip uses of different values from the same node.

6322        if (Use.getResNo() != From.getResNo()) {

6323          ++UI;

6324          continue;

6325        }

6326 

6327        // If this node hasn't been modified yet, it's still in the CSE maps,

6328        // so remove its old self from the CSE maps.

6329        if (!UserRemovedFromCSEMaps) {

6330          RemoveNodeFromCSEMaps(User);

6331          UserRemovedFromCSEMaps = true;

6332        }

6333 

6334        ++UI;

6335        Use.set(To);

      if (To->isDivergent() != From->isDivergent())                                                             ß v7.0增加

        updateDivergence(User)

6336      } while (UI != UE && *UI == User);

6337 

6338      // We are iterating over all uses of the From node, so if a use

6339      // doesn't use the specific value, no changes are made.

6340      if (!UserRemovedFromCSEMaps)

6341        continue;

6342 

6343      // Now that we have modified User, add it back to the CSE maps.  If it

6344      // already exists there, recursively merge the results together.

6345      AddModifiedNodeToCSEMaps(User);

6346    }

6347 

6348    // If we just RAUW'd the root, take note.

6349    if (From == getRoot())

6350      setRoot(To);

6351  }

如果节点只有一个结果,调用ReplaceAllUsesWith()方法就可以了,我们后面再来看这个方法。如果有多个结果,从6307行开始遍历这些结果的使用者。在6309行创建一个RAUWUpdateListener对象,这个对象的定义如下:

6139  class RAUWUpdateListener : public SelectionDAG::DAGUpdateListener {

6140    SDNode::use_iterator &UI;

6141    SDNode::use_iterator &UE;

6142 

6143    void NodeDeleted(SDNode *N, SDNode *E) override {

6144      // Increment the iterator as needed.

6145      while (UI != UE && N == *UI)

6146        ++UI;

6147    }

6148 

6149  public:

6150    RAUWUpdateListener(SelectionDAG &d,

6151                       SDNode::use_iterator &ui,

6152                       SDNode::use_iterator &ue)

6153      : SelectionDAG::DAGUpdateListener(d), UI(ui), UE(ue) {}

6154  };

基类SelectionDAG::DAGUpdateListener的定义则是:

225       struct DAGUpdateListener {

226         DAGUpdateListener *const Next;

227         SelectionDAG &DAG;

228    

229         explicit DAGUpdateListener(SelectionDAG &D)

230           : Next(D.UpdateListeners), DAG(D) {

231           DAG.UpdateListeners = this;

232         }

233    

234         virtual ~DAGUpdateListener() {

235           assert(DAG.UpdateListeners == this &&

236                  "DAGUpdateListeners must be destroyed in LIFO order");

237           DAG.UpdateListeners = Next;

238         }

239    

240         /// The node N that was deleted and, if E is not null, an

241         /// equivalent node E that replaced it.

242         virtual void NodeDeleted(SDNode *N, SDNode *E);

243    

244         /// The node N that was updated.

245         virtual void NodeUpdated(SDNode *N);

246       };

基类的构造函数将自己加入SelectionDAG对象的UpdateListeners更新监听者。当SelectionDAG删除一个指定SDNode对象时,它将依次调用UpdateListeners注册对象的NodeDeleted()方法来处理这个对象。而当SelectionDAG修改一个SDNode对象时,它将依次调用UpdateListeners注册对象的NodeUpdated()方法来处理这个对象。对RAUWUpdateListener来说,它的NodeUpdated()方法在迭代器SDNode::use_iterator所指向的对象被删除时,使该迭代器指向下一个对象。NodeUpdated()方法则是空的。

RAUWUpdateListener使用的迭代器SDNode::use_iterator用于遍历一个指定SDNode对象的使用者。在6307与6308行使用了这些SDNode的方法来准备这个迭代器:

513       use_iterator use_begin() const {

514         return use_iterator(UseList);

515       }

516    

517     static use_iterator use_end() { return use_iterator(nullptr); }

UI保存了SDNode的SDUse*类型成员UseList。在6311行,SDNode::use_iterator的提领方法返回当前SDUse的所援引的SDNode对象。

496         SDNode *operator*() const {

497           assert(Op && "Cannot dereference end iterator!");

498           return Op->getUser();

499         }

Op的类型是SDUse*,操作符*返回的是一个SDNode指针。因此6336行的第二个条件是确保该循环所访问的所有SDUse都是援引同一个SDNode实例(即User,它本身就是一个指针)。这样,6319行拿到的Use总是同一个,即都援引User(迭代器SDNode::use_iterator的getUse方法返回Op的引用)。在6335行将这些SDUse实例所援引的SDValue对象从From改为To。

在6345行向CSEMap加入修改后的User。如果CSEMap中存在与User哈希值相同的匹配节点(但不是同一个对象),将会进入下面845行的分支,用User(即参数N)替换这个对象。

839     void

840     SelectionDAG::AddModifiedNodeToCSEMaps(SDNode *N) {

841       // For node types that aren't CSE'd, just act as if no identical node

842       // already exists.

843       if (!doNotCSE(N)) {

844         SDNode *Existing = CSEMap.GetOrInsertNode(N);

845         if (Existing != N) {

846           // If there was already an existing matching node, use ReplaceAllUsesWith

847           // to replace the dead one with the existing one.  This can cause

848           // recursive merging of other unrelated nodes down the line.

849           ReplaceAllUsesWith(N, Existing);

850    

851           // N is now dead. Inform the listeners and delete it.

852           for (DAGUpdateListener *DUL = UpdateListeners; DUL; DUL = DUL->Next)

853             DUL->NodeDeleted(N, Existing);

854           DeleteNodeNotInCSEMaps(N);

855           return;

856         }

857       }

858    

859       // If the node doesn't already exist, we updated it.  Inform listeners.

860       for (DAGUpdateListener *DUL = UpdateListeners; DUL; DUL = DUL->Next)

861         DUL->NodeUpdated(N);

862     }

对不能CSE由处理的节点(黏结节点、HANDLENODE以及EH_LABEL节点),则需要依次调用UpdateListeners注册对象的NodeUpdated()方法处理这个对象。这里的RAUWUpdateListener的NodeUpdated()方法是空的。

SelectionDAG::ReplaceAllUsesWith()的定义与上面的SelectionDAG::ReplaceAllUsesOfValueWith()非常类似。SelectionDAG定义的几个ReplaceAllUsesWith()类型的方法都可视为一个功能的几个便利封装。

6210  void SelectionDAG::ReplaceAllUsesWith(SDNode *From, SDNode *To) {

6211  #ifndef NDEBUG

6212    for (unsigned i = 0, e = From->getNumValues(); i != e; ++i)

6213      assert((!From->hasAnyUseOfValue(i) ||

6214             From->getValueType(i) == To->getValueType(i)) &&

6215             "Cannot use this version of ReplaceAllUsesWith!");

6216  #endif

6217 

6218    // Handle the trivial case.

6219    if (From == To)

6220      return;

6221 

6222     // Iterate over just the existing users of From. See the comments in

6223    // the ReplaceAllUsesWith above.

6224     SDNode::use_iterator UI = From->use_begin(), UE = From->use_end();

6225     RAUWUpdateListener Listener(*this, UI, UE);

6226     while (UI != UE) {

6227       SDNode *User = *UI;

6228 

6229       // This node is about to morph, remove its old self from the CSE maps.

6230       RemoveNodeFromCSEMaps(User);

6231 

6232      // A user can appear in a use list multiple times, and when this

6233      // happens the uses are usually next to each other in the list.

6234      // To help reduce the number of CSE recomputations, process all

6235      // the uses of this user that we can find this way.

6236      do {

6237        SDUse &Use = UI.getUse();

6238        ++UI;

6239        Use.setNode(To);

      if (To->isDivergent() != From->isDivergent())                                                              ß v7.0增加

        updateDivergence(User);

6240      } while (UI != UE && *UI == User);

6241 

6242      // Now that we have modified User, add it back to the CSE maps.  If it

6243      // already exists there, recursively merge the results together.

6244      AddModifiedNodeToCSEMaps(User);

6245    }

6246 

6247    // If we just RAUW'd the root, take note.

6248    if (From == getRoot().getNode())

6249      setRoot(SDValue(To, getRoot().getResNo()));

6250  }

替代是一个迭代的过程,在6244行会对From的所有使用者调用AddModifiedNodeToCSEMaps(),而在这个函数里则又会对这些使用者的使用者递归调用自己,直到最终一级的使用者(即没有对它们的使用)。SelectDAG是一个有根的DAG,因此类SelectDAG中成员Root(SDValue类型)记录这个根。6248行的getRoot()方法只是返回这个成员的引用。而setRoot()方法则是设置这个成员,同时需要检查设置这个根是否会导致环。

因为这个广泛而深入的递归过程,在AddModifiedNodeToCSEMaps()以及ReplaceAllUsesWith()中都存在一个do while循环来处理援引同一个的SDUse对象,以减少递归的次数。

至于SelectionDAG::ReplaceAllUsesOfValueWith()所使用的另一个版本的ReplaceAllUsesWith(),则有如下的定义。事实上,这些ReplaceAllUsesWith()的定义都是类似的。

6163  void SelectionDAG::ReplaceAllUsesWith(SDValue FromN, SDValue To) {

6164    SDNode *From = FromN.getNode();

6165    assert(From->getNumValues() == 1 && FromN.getResNo() == 0 &&

6166           "Cannot replace with this method!");

6167    assert(From != To.getNode() && "Cannot replace uses of with self");

6168 

6169    // Iterate over all the existing uses of From. New uses will be added

6170    // to the beginning of the use list, which we avoid visiting.

6171    // This specifically avoids visiting uses of From that arise while the

6172    // replacement is happening, because any such uses would be the result

6173    // of CSE: If an existing node looks like From after one of its operands

6174    // is replaced by To, we don't want to replace of all its users with To

6175    // too. See PR3018 for more info.

6176    SDNode::use_iterator UI = From->use_begin(), UE = From->use_end();

6177    RAUWUpdateListener Listener(*this, UI, UE);

6178    while (UI != UE) {

6179      SDNode *User = *UI;

6180 

6181      // This node is about to morph, remove its old self from the CSE maps.

6182      RemoveNodeFromCSEMaps(User);

6183 

6184      // A user can appear in a use list multiple times, and when this

6185      // happens the uses are usually next to each other in the list.

6186      // To help reduce the number of CSE recomputations, process all

6187      // the uses of this user that we can find this way.

6188      do {

6189        SDUse &Use = UI.getUse();

6190        ++UI;

6191        Use.set(To);

6192      } while (UI != UE && *UI == User);

6193 

6194      // Now that we have modified User, add it back to the CSE maps.  If it

6195      // already exists there, recursively merge the results together.

6196      AddModifiedNodeToCSEMaps(User);

6197    }

6198 

6199    // If we just RAUW'd the root, take note.

6200    if (FromN == getRoot())

6201      setRoot(To);

6202  }

SelectionDAGISel:: MorphNode()v7.0ReplaceUses()替换了ReplaceAllUsesOfValueWith()

220       void ReplaceUses(SDNode *F, SDNode *T) {

221         CurDAG->ReplaceAllUsesWith(F, T);

222         EnforceNodeIdInvariant(T);

223       }

这个方法除了调用ReplaceAllUsesOfValueWith(),还调用下面的方法将选中节点的NodeId置为负数。

984     void SelectionDAGISel::EnforceNodeIdInvariant(SDNode *Node) {

985       SmallVector<SDNode *, 4> Nodes;

986       Nodes.push_back(Node);

987    

988       while (!Nodes.empty()) {

989         SDNode *N = Nodes.pop_back_val();

990         for (auto *U : N->uses()) {

991           auto UId = U->getNodeId();

992           if (UId > 0) {

993             InvalidateNodeId(U);

994             Nodes.push_back(U);

995           }

996         }

997       }

998     }

InvalidateNodeId()的做法与我们前面看到的NodeId是一致的。

1003  void SelectionDAGISel::InvalidateNodeId(SDNode *N) {

1004    int InvalidId = -(N->getNodeId() + 1);

1005    N->setNodeId(InvalidId);

1006  }

回到SelectCodeCommon()。不管是OPC_MorphNodeTo,还是OPC_EmitNode,得到了Res后都要进入下面的代码,设置对内存使用的信息。3206行得到的MCInstrDesc实例取决于目标机器,对于X86,它实际上指向数组X86Insts中对应该指令的项。这个数组是由TableGen处理选项“-gen-instr-info”时生成的,包含了目标机器每条指令的有关信息。这里暂时不深入细节。

SelectionDAGISel::SelectCodeCommon(续)

3188        // If the node had chain/glue results, update our notion of the current

3189        // chain and glue.

3190        if (EmitNodeInfo & OPFL_GlueOutput) {

3191          InputGlue = SDValue(Res, VTs.size()-1);

3192          if (EmitNodeInfo & OPFL_Chain)

3193            InputChain = SDValue(Res, VTs.size()-2);

3194        } else if (EmitNodeInfo & OPFL_Chain)

3195          InputChain = SDValue(Res, VTs.size()-1);

3196 

3197        // If the OPFL_MemRefs glue is set on this node, slap all of the

3198        // accumulated memrefs onto it.

3199        //

3200        // FIXME: This is vastly incorrect for patterns with multiple outputs

3201        // instructions that access memory and for ComplexPatterns that match

3202        // loads.

3203        if (EmitNodeInfo & OPFL_MemRefs) {

3204          // Only attach load or store memory operands if the generated

3205          // instruction may load or store.

3206          const MCInstrDesc &MCID = TII->get(TargetOpc);

3207          bool mayLoad = MCID.mayLoad();

3208          bool mayStore = MCID.mayStore();

3209 

3210          unsigned NumMemRefs = 0;

3211          for (SmallVectorImpl<MachineMemOperand *>::const_iterator I =

3212                 MatchedMemRefs.begin(), E = MatchedMemRefs.end(); I != E; ++I) {

3213            if ((*I)->isLoad()) {

3214              if (mayLoad)

3215                ++NumMemRefs;

3216            } else if ((*I)->isStore()) {

3217              if (mayStore)

3218                ++NumMemRefs;

3219            } else {

3220              ++NumMemRefs;

3221            }

3222          }

3223 

3224          MachineSDNode::mmo_iterator MemRefs =

3225            MF->allocateMemRefsArray(NumMemRefs);

3226 

3227          MachineSDNode::mmo_iterator MemRefsPos = MemRefs;

3228          for (SmallVectorImpl<MachineMemOperand *>::const_iterator I =

3229                 MatchedMemRefs.begin(), E = MatchedMemRefs.end(); I != E; ++I) {

3230            if ((*I)->isLoad()) {

3231              if (mayLoad)

3232                *MemRefsPos++ = *I;

3233            } else if ((*I)->isStore()) {

3234              if (mayStore)

3235                *MemRefsPos++ = *I;

3236            } else {

3237              *MemRefsPos++ = *I;

3238            }

3239          }

3240 

3241          cast<MachineSDNode>(Res)                                                                                         <- v7.0删除

3242            ->setMemRefs(MemRefs, MemRefs + NumMemRefs);

        Res->setMemRefs(MemRefs, MemRefs + NumMemRefs);                                    <- v7.0增加

3243        }

3244 

3245        DEBUG(dbgs() << "  "

3246                     << (Opcode == OPC_MorphNodeTo ? "Morphed" : "Created")

3247                     << " node: "; Res->dump(CurDAG); dbgs() << "\n");

3248 

3249        // If this was a MorphNodeTo then we're completely done!

3250        if (Opcode == OPC_MorphNodeTo) {                                                                             <- v7.0删除

3241          // Update chain and glue uses.

3242          UpdateChainsAndGlue(NodeToMatch, InputChain, ChainNodesMatched,

3243                              InputGlue, GlueResultNodesMatched, true);

3244          return Res;

3245        }

 

      if (IsMorphNodeTo) {                                                                                                         <- v7.0增加

        // Update chain uses.

        UpdateChains(Res, InputChain, ChainNodesMatched, true);

        return;

      }

3246 

3247        continue;

3248      }

注意,OPC_MorphNodeTo从3244行退出SelectCodeCommon()。而OPC_EmitNode则仍然要继续前进,在3247行继续大循环。不过OPC_MorphNodeTo在退出前,先要执行下面的方法,更新Chain与glue操作数。

作为参数的容器ChainNodesMatched与GlueResultNodesMatched都是大循环里加入的使用当前匹配DAG的Chain或glue的SDNode对象。如果当前匹配DAG包含了链并修改标志寄存器,InputChain在上面3193及3195行,InputGlue在3191行产生,都是对Res结果的援引。否则,InputChain就是对ChainNodesMatched执行HandleMergeInputChains()的结果。InputGlue则来自OPC_CaptureGlueInput项(表示当前节点具有输入glue,因此InputGlue指向这个节点)。这里将InputChain与InputGlue更新到它们的使用者。

1983  void SelectionDAGISel::

1984  UpdateChainsAndGlue(SDNode *NodeToMatch, SDValue InputChain,

1985                      const SmallVectorImpl<SDNode*> &ChainNodesMatched,

1986                      SDValue InputGlue,

1987                      const SmallVectorImpl<SDNode*> &GlueResultNodesMatched,

1988                      bool isMorphNodeTo) {

1989    SmallVector<SDNode*, 4> NowDeadNodes;

1990 

1991    // Now that all the normal results are replaced, we replace the chain and

1992    // glue results if present.

1993    if (!ChainNodesMatched.empty()) {

1994      assert(InputChain.getNode() &&

1995             "Matched input chains but didn't produce a chain");

1996      // Loop over all of the nodes we matched that produced a chain result.

1997      // Replace all the chain results with the final chain we ended up with.

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

1999        SDNode *ChainNode = ChainNodesMatched[i];

2000 

2001        // If this node was already deleted, don't look at it.

2002        if (ChainNode->getOpcode() == ISD::DELETED_NODE)

2003          continue;

2004 

2005        // Don't replace the results of the root node if we're doing a

2006        // MorphNodeTo.

2007        if (ChainNode == NodeToMatch && isMorphNodeTo)

2008          continue;

2009 

2010        SDValue ChainVal = SDValue(ChainNode, ChainNode->getNumValues()-1);

2011        if (ChainVal.getValueType() == MVT::Glue)

2012          ChainVal = ChainVal.getValue(ChainVal->getNumValues()-2);

2013        assert(ChainVal.getValueType() == MVT::Other && "Not a chain?");

2014        CurDAG->ReplaceAllUsesOfValueWith(ChainVal, InputChain);

2015 

2016        // If the node became dead and we haven't already seen it, delete it.

2017        if (ChainNode->use_empty() &&

2018            !std::count(NowDeadNodes.begin(), NowDeadNodes.end(), ChainNode))

2019          NowDeadNodes.push_back(ChainNode);

2020      }

2021    }

2022 

2023    // If the result produces glue, update any glue results in the matched

2024    // pattern with the glue result.

2025    if (InputGlue.getNode()) {

2026      // Handle any interior nodes explicitly marked.

2027      for (unsigned i = 0, e = GlueResultNodesMatched.size(); i != e; ++i) {

2028        SDNode *FRN = GlueResultNodesMatched[i];

2029 

2030        // If this node was already deleted, don't look at it.

2031        if (FRN->getOpcode() == ISD::DELETED_NODE)

2032          continue;

2033 

2034        assert(FRN->getValueType(FRN->getNumValues()-1) == MVT::Glue &&

2035               "Doesn't have a glue result");

2036        CurDAG->ReplaceAllUsesOfValueWith(SDValue(FRN, FRN->getNumValues()-1),

2037                                          InputGlue);

2038 

2039        // If the node became dead and we haven't already seen it, delete it.

2040        if (FRN->use_empty() &&

2041            !std::count(NowDeadNodes.begin(), NowDeadNodes.end(), FRN))

2042          NowDeadNodes.push_back(FRN);

2043      }

2044    }

2045 

2046    if (!NowDeadNodes.empty())

2047      CurDAG->RemoveDeadNodes(NowDeadNodes);

2048 

2049    DEBUG(dbgs() << "ISEL: Match complete!\n");

2050  }

V7.0使用SelectionDAGISel::UpdateChains()替换了SelectionDAGISel::UpdateChainsAndGlue(),因为v7.0不需要支持OPC_MarkGlueResults类型的节点。但是,因为OPC_EmitMergeInputChains的存在,还需要支持公共链节点的替换。下面的容器ChainNodesMatched如果不为空,表明在当前的OPC_Scope中生成了公共链节点。

2431  void SelectionDAGISel::UpdateChains(

2432      SDNode *NodeToMatch, SDValue InputChain,

2433      SmallVectorImpl<SDNode *> &ChainNodesMatched, bool isMorphNodeTo) {

2434    SmallVector<SDNode*, 4> NowDeadNodes;

2435 

2436    // Now that all the normal results are replaced, we replace the chain and

2437    // glue results if present.

2438    if (!ChainNodesMatched.empty()) {

2439      assert(InputChain.getNode() &&

2440             "Matched input chains but didn't produce a chain");

2441      // Loop over all of the nodes we matched that produced a chain result.

2442      // Replace all the chain results with the final chain we ended up with.

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

2444        SDNode *ChainNode = ChainNodesMatched[i];

2445        // If ChainNode is null, it's because we replaced it on a previous

2446        // iteration and we cleared it out of the map. Just skip it.

2447        if (!ChainNode)

2448          continue;

2449 

2450        assert(ChainNode->getOpcode() != ISD::DELETED_NODE &&

2451               "Deleted node left in chain");

2452 

2453        // Don't replace the results of the root node if we're doing a

2454        // MorphNodeTo.

2455        if (ChainNode == NodeToMatch && isMorphNodeTo)

2456          continue;

2457 

2458        SDValue ChainVal = SDValue(ChainNode, ChainNode->getNumValues()-1);

2459        if (ChainVal.getValueType() == MVT::Glue)

2460          ChainVal = ChainVal.getValue(ChainVal->getNumValues()-2);

2461        assert(ChainVal.getValueType() == MVT::Other && "Not a chain?");

2462        SelectionDAG::DAGNodeDeletedListener NDL(

2463            *CurDAG, [&](SDNode *N, SDNode *E) {

2464              std::replace(ChainNodesMatched.begin(), ChainNodesMatched.end(), N,

2465                           static_cast<SDNode *>(nullptr));

2466            });

2467        if (ChainNode->getOpcode() != ISD::TokenFactor)

2468          ReplaceUses(ChainVal, InputChain);

2469 

2470        // If the node became dead and we haven't already seen it, delete it.

2471        if (ChainNode != NodeToMatch && ChainNode->use_empty() &&

2472            !std::count(NowDeadNodes.begin(), NowDeadNodes.end(), ChainNode))

2473          NowDeadNodes.push_back(ChainNode);

2474      }

2475    }

2476 

2477    if (!NowDeadNodes.empty())

2478      CurDAG->RemoveDeadNodes(NowDeadNodes);

2479 

2480    LLVM_DEBUG(dbgs() << "ISEL: Match complete!\n");

2481  }

下面的OPC_MarkGlueResults是由MarkGlueResultsMatcher对象输出的,这些对象用于标记会使用标志寄存器的节点(当然是通过序号)。我们已经看到在UpdateChainsAndGlue()里这些节点会被目标节点的值所替换(v7.0不再支持)。

SelectionDAGISel::SelectCodeCommon(续)

3250      case OPC_MarkGlueResults: {

3251        unsigned NumNodes = MatcherTable[MatcherIndex++];

3252 

3253        // Read and remember all the glue-result nodes.

3254        for (unsigned i = 0; i != NumNodes; ++i) {

3255          unsigned RecNo = MatcherTable[MatcherIndex++];

3256          if (RecNo & 128)

3257            RecNo = GetVBR(RecNo, MatcherTable, MatcherIndex);

3258 

3259          assert(RecNo < RecordedNodes.size() && "Invalid MarkGlueResults");

3260          GlueResultNodesMatched.push_back(RecordedNodes[RecNo].first.getNode());

3261        }

3262        continue;

3263      }

3264 

3265      case OPC_CompleteMatch: {

3266        // The match has been completed, and any new nodes (if any) have been

3267        // created.  Patch up references to the matched dag to use the newly

3268        // created nodes.

3269        unsigned NumResults = MatcherTable[MatcherIndex++];

3270 

3271        for (unsigned i = 0; i != NumResults; ++i) {

3272          unsigned ResSlot = MatcherTable[MatcherIndex++];

3273          if (ResSlot & 128)

3274            ResSlot = GetVBR(ResSlot, MatcherTable, MatcherIndex);

3275 

3276          assert(ResSlot < RecordedNodes.size() && "Invalid CompleteMatch");

3277          SDValue Res = RecordedNodes[ResSlot].first;

3278 

3279          assert(i < NodeToMatch->getNumValues() &&

3280                 NodeToMatch->getValueType(i) != MVT::Other &&

3281                 NodeToMatch->getValueType(i) != MVT::Glue &&

3282                 "Invalid number of results to complete!");

3283          assert((NodeToMatch->getValueType(i) == Res.getValueType() ||

3284                  NodeToMatch->getValueType(i) == MVT::iPTR ||

3285                  Res.getValueType() == MVT::iPTR ||

3286                  NodeToMatch->getValueType(i).getSizeInBits() ==

3287                      Res.getValueType().getSizeInBits()) &&

3288                 "invalid replacement");

3289          CurDAG->ReplaceAllUsesOfValueWith(SDValue(NodeToMatch, i), Res);          <- v7.0删除

        ReplaceUses(SDValue(NodeToMatch, i), Res);                                                        <- v7.0增加

3290        }

3291 

3292        // If the root node defines glue, add it to the glue nodes to update list.              <- v7.0删除

3293        if (NodeToMatch->getValueType(NodeToMatch->getNumValues()-1) == MVT::Glue)

3294          GlueResultNodesMatched.push_back(NodeToMatch);

3295 

3296        // Update chain and glue uses.

3297        UpdateChainsAndGlue(NodeToMatch, InputChain, ChainNodesMatched,

3298                            InputGlue, GlueResultNodesMatched, false);

 

      // Update chain uses.                                                                                                       <- v7.0增加

      UpdateChains(NodeToMatch, InputChain, ChainNodesMatched, false);

 

      // If the root node defines glue, we need to update it to the glue result.

      // TODO: This never happens in our tests and I think it can be removed /

      // replaced with an assert, but if we do it this the way the change is

      // NFC.

      if (NodeToMatch->getValueType(NodeToMatch->getNumValues() - 1) ==

              MVT::Glue &&

          InputGlue.getNode())

        ReplaceUses(SDValue(NodeToMatch, NodeToMatch->getNumValues() - 1),

                    InputGlue);

3299 

3300        assert(NodeToMatch->use_empty() &&

3301               "Didn't replace all uses of the node?");

      CurDAG->RemoveDeadNode(NodeToMatch);                                                         ß v7.0增加

3302 

3303        // FIXME: We just return here, which interacts correctly with SelectRoot

3304        // above.  We should fix this to not return an SDNode* anymore.

3305        return nullptr;

3306      }

3307      }

3308 

3309      // If the code reached this point, then the match failed.  See if there is

3310      // another child to try in the current 'Scope', otherwise pop it until we

3311      // find a case to check.

3312      DEBUG(dbgs() << "  Match failed at index " << CurrentOpcodeIndex << "\n");

3313      ++NumDAGIselRetries;

3314      while (1) {

3315        if (MatchScopes.empty()) {

3316          CannotYetSelect(NodeToMatch);

3317          return nullptr;

3318        }

3319 

3320        // Restore the interpreter state back to the point where the scope was

3321        // formed.

3322        MatchScope &LastScope = MatchScopes.back();

3323        RecordedNodes.resize(LastScope.NumRecordedNodes);

3324        NodeStack.clear();

3325        NodeStack.append(LastScope.NodeStack.begin(), LastScope.NodeStack.end());

3326        N = NodeStack.back();

3327 

3328        if (LastScope.NumMatchedMemRefs != MatchedMemRefs.size())

3329          MatchedMemRefs.resize(LastScope.NumMatchedMemRefs);

3330        MatcherIndex = LastScope.FailIndex;

3331 

3332        DEBUG(dbgs() << "  Continuing at " << MatcherIndex << "\n");

3333 

3334        InputChain = LastScope.InputChain;

3335        InputGlue = LastScope.InputGlue;

3336        if (!LastScope.HasChainNodesMatched)

3337          ChainNodesMatched.clear();

3338        if (!LastScope.HasGlueResultNodesMatched)                                                                <- v7.0删除

3339          GlueResultNodesMatched.clear();

3340 

3341        // Check to see what the offset is at the new MatcherIndex.  If it is zero

3342        // we have reached the end of this scope, otherwise we have another child

3343        // in the current scope to try.

3344        unsigned NumToSkip = MatcherTable[MatcherIndex++];

3345        if (NumToSkip & 128)

3346          NumToSkip = GetVBR(NumToSkip, MatcherTable, MatcherIndex);

3347 

3348        // If we have another child in this scope to match, update FailIndex and

3349        // try it.

3350        if (NumToSkip != 0) {

3351          LastScope.FailIndex = MatcherIndex+NumToSkip;

3350          break;

3351        }

3352 

3353        // End of this scope, pop it and try the next child in the containing

3354        // scope.

3355        MatchScopes.pop_back();

3356      }

3357    }

3358  }

至于标记OPC_CompleteMatch,它与OPC_EmitNode配合表示匹配完成。在前面OPC_EmitNode已经生成了一个MachineSDNode实例,并将它chain与glue以外的结果保存在RecordedNodes(3169 ~ 3176行)。在3281行的循环取出这些结果来替换原来值。在3303行,如果匹配DAG的根节点会修改标志寄存器(glue),也要记录在GlueResultNodesMatched里,随后在UpdateChainsAndGlue()里得到替换(这次调用的isMorphNodeTo是false)。

3312行至函数结束,是出错处理。每次匹配出错都会进入到这里,前进到同一个Scope的下一个分支,或者上一层Scope的下一个分支(如果当前Scope已到末尾)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值