コード例 #1
0
static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) {
  SDNode *Node = Op.getNode();
  EVT VT = Node->getValueType(0);
  SDValue InChain = Node->getOperand(0);
  SDValue VAListPtr = Node->getOperand(1);
  const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
  DebugLoc dl = Node->getDebugLoc();
  SDValue VAList = DAG.getLoad(MVT::i32, dl, InChain, VAListPtr, SV, 0,
                               false, false, 0);
  // Increment the pointer, VAList, to the next vaarg
  SDValue NextPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, VAList,
                                  DAG.getConstant(VT.getSizeInBits()/8,
                                                  MVT::i32));
  // Store the incremented VAList to the legalized pointer
  InChain = DAG.getStore(VAList.getValue(1), dl, NextPtr,
                         VAListPtr, SV, 0, false, false, 0);
  // Load the actual argument out of the pointer VAList, unless this is an
  // f64 load.
  if (VT != MVT::f64)
    return DAG.getLoad(VT, dl, InChain, VAList, NULL, 0, false, false, 0);

  // Otherwise, load it as i64, then do a bitconvert.
  SDValue V = DAG.getLoad(MVT::i64, dl, InChain, VAList, NULL, 0,
                          false, false, 0);

  // Bit-Convert the value to f64.
  SDValue Ops[2] = {
    DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f64, V),
    V.getValue(1)
  };
  return DAG.getMergeValues(Ops, 2, dl);
}
コード例 #2
0
void ScheduleDAGLinearize::Schedule() {
  LLVM_DEBUG(dbgs() << "********** DAG Linearization **********\n");

  SmallVector<SDNode*, 8> Glues;
  unsigned DAGSize = 0;
  for (SDNode &Node : DAG->allnodes()) {
    SDNode *N = &Node;

    // Use node id to record degree.
    unsigned Degree = N->use_size();
    N->setNodeId(Degree);
    unsigned NumVals = N->getNumValues();
    if (NumVals && N->getValueType(NumVals-1) == MVT::Glue &&
        N->hasAnyUseOfValue(NumVals-1)) {
      SDNode *User = findGluedUser(N);
      if (User) {
        Glues.push_back(N);
        GluedMap.insert(std::make_pair(N, User));
      }
    }

    if (N->isMachineOpcode() ||
        (N->getOpcode() != ISD::EntryToken && !isPassiveNode(N)))
      ++DAGSize;
  }

  for (unsigned i = 0, e = Glues.size(); i != e; ++i) {
    SDNode *Glue = Glues[i];
    SDNode *GUser = GluedMap[Glue];
    unsigned Degree = Glue->getNodeId();
    unsigned UDegree = GUser->getNodeId();

    // Glue user must be scheduled together with the glue operand. So other
    // users of the glue operand must be treated as its users.
    SDNode *ImmGUser = Glue->getGluedUser();
    for (const SDNode *U : Glue->uses())
      if (U == ImmGUser)
        --Degree;
    GUser->setNodeId(UDegree + Degree);
    Glue->setNodeId(1);
  }

  Sequence.reserve(DAGSize);
  ScheduleNode(DAG->getRoot().getNode());
}
コード例 #3
0
// By default CONCAT_VECTORS is lowered by ExpandVectorBuildThroughStack()
// (see LegalizeDAG.cpp). This is slow and uses local memory.
// We use extract/insert/build vector just as what LegalizeOp() does in llvm 2.5
SDValue NVPTXTargetLowering::
LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) const {
  SDNode *Node = Op.getNode();
  DebugLoc dl = Node->getDebugLoc();
  SmallVector<SDValue, 8> Ops;
  unsigned NumOperands = Node->getNumOperands();
  for (unsigned i=0; i < NumOperands; ++i) {
    SDValue SubOp = Node->getOperand(i);
    EVT VVT = SubOp.getNode()->getValueType(0);
    EVT EltVT = VVT.getVectorElementType();
    unsigned NumSubElem = VVT.getVectorNumElements();
    for (unsigned j=0; j < NumSubElem; ++j) {
      Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, SubOp,
                                DAG.getIntPtrConstant(j)));
    }
  }
  return DAG.getNode(ISD::BUILD_VECTOR, dl, Node->getValueType(0),
                     &Ops[0], Ops.size());
}
コード例 #4
0
/// This is the main entry point for the type legalizer. This does a top-down
/// traversal of the dag, legalizing types as it goes. Returns "true" if it made
/// any changes.
bool DAGTypeLegalizer::run() {
  bool Changed = false;

  // Create a dummy node (which is not added to allnodes), that adds a reference
  // to the root node, preventing it from being deleted, and tracking any
  // changes of the root.
  HandleSDNode Dummy(DAG.getRoot());
  Dummy.setNodeId(Unanalyzed);

  // The root of the dag may dangle to deleted nodes until the type legalizer is
  // done.  Set it to null to avoid confusion.
  DAG.setRoot(SDValue());

  // Walk all nodes in the graph, assigning them a NodeId of 'ReadyToProcess'
  // (and remembering them) if they are leaves and assigning 'Unanalyzed' if
  // non-leaves.
  for (SDNode &Node : DAG.allnodes()) {
    if (Node.getNumOperands() == 0) {
      AddToWorklist(&Node);
    } else {
      Node.setNodeId(Unanalyzed);
    }
  }

  // Now that we have a set of nodes to process, handle them all.
  while (!Worklist.empty()) {
#ifndef EXPENSIVE_CHECKS
    if (EnableExpensiveChecks)
#endif
      PerformExpensiveChecks();

    SDNode *N = Worklist.back();
    Worklist.pop_back();
    assert(N->getNodeId() == ReadyToProcess &&
           "Node should be ready if on worklist!");

    if (IgnoreNodeResults(N))
      goto ScanOperands;

    // Scan the values produced by the node, checking to see if any result
    // types are illegal.
    for (unsigned i = 0, NumResults = N->getNumValues(); i < NumResults; ++i) {
      EVT ResultVT = N->getValueType(i);
      switch (getTypeAction(ResultVT)) {
      case TargetLowering::TypeLegal:
        break;
      // The following calls must take care of *all* of the node's results,
      // not just the illegal result they were passed (this includes results
      // with a legal type).  Results can be remapped using ReplaceValueWith,
      // or their promoted/expanded/etc values registered in PromotedIntegers,
      // ExpandedIntegers etc.
      case TargetLowering::TypePromoteInteger:
        PromoteIntegerResult(N, i);
        Changed = true;
        goto NodeDone;
      case TargetLowering::TypeExpandInteger:
        ExpandIntegerResult(N, i);
        Changed = true;
        goto NodeDone;
      case TargetLowering::TypeSoftenFloat:
        Changed = SoftenFloatResult(N, i);
        if (Changed)
          goto NodeDone;
        // If not changed, the result type should be legally in register.
        assert(isLegalInHWReg(ResultVT) &&
               "Unchanged SoftenFloatResult should be legal in register!");
        goto ScanOperands;
      case TargetLowering::TypeExpandFloat:
        ExpandFloatResult(N, i);
        Changed = true;
        goto NodeDone;
      case TargetLowering::TypeScalarizeVector:
        ScalarizeVectorResult(N, i);
        Changed = true;
        goto NodeDone;
      case TargetLowering::TypeSplitVector:
        SplitVectorResult(N, i);
        Changed = true;
        goto NodeDone;
      case TargetLowering::TypeWidenVector:
        WidenVectorResult(N, i);
        Changed = true;
        goto NodeDone;
      case TargetLowering::TypePromoteFloat:
        PromoteFloatResult(N, i);
        Changed = true;
        goto NodeDone;
      }
    }

ScanOperands:
    // Scan the operand list for the node, handling any nodes with operands that
    // are illegal.
    {
    unsigned NumOperands = N->getNumOperands();
    bool NeedsReanalyzing = false;
    unsigned i;
    for (i = 0; i != NumOperands; ++i) {
      if (IgnoreNodeResults(N->getOperand(i).getNode()))
        continue;

      EVT OpVT = N->getOperand(i).getValueType();
      switch (getTypeAction(OpVT)) {
      case TargetLowering::TypeLegal:
        continue;
      // The following calls must either replace all of the node's results
      // using ReplaceValueWith, and return "false"; or update the node's
      // operands in place, and return "true".
      case TargetLowering::TypePromoteInteger:
        NeedsReanalyzing = PromoteIntegerOperand(N, i);
        Changed = true;
        break;
      case TargetLowering::TypeExpandInteger:
        NeedsReanalyzing = ExpandIntegerOperand(N, i);
        Changed = true;
        break;
      case TargetLowering::TypeSoftenFloat:
        NeedsReanalyzing = SoftenFloatOperand(N, i);
        Changed = true;
        break;
      case TargetLowering::TypeExpandFloat:
        NeedsReanalyzing = ExpandFloatOperand(N, i);
        Changed = true;
        break;
      case TargetLowering::TypeScalarizeVector:
        NeedsReanalyzing = ScalarizeVectorOperand(N, i);
        Changed = true;
        break;
      case TargetLowering::TypeSplitVector:
        NeedsReanalyzing = SplitVectorOperand(N, i);
        Changed = true;
        break;
      case TargetLowering::TypeWidenVector:
        NeedsReanalyzing = WidenVectorOperand(N, i);
        Changed = true;
        break;
      case TargetLowering::TypePromoteFloat:
        NeedsReanalyzing = PromoteFloatOperand(N, i);
        Changed = true;
        break;
      }
      break;
    }

    // The sub-method updated N in place.  Check to see if any operands are new,
    // and if so, mark them.  If the node needs revisiting, don't add all users
    // to the worklist etc.
    if (NeedsReanalyzing) {
      assert(N->getNodeId() == ReadyToProcess && "Node ID recalculated?");

      N->setNodeId(NewNode);
      // Recompute the NodeId and correct processed operands, adding the node to
      // the worklist if ready.
      SDNode *M = AnalyzeNewNode(N);
      if (M == N)
        // The node didn't morph - nothing special to do, it will be revisited.
        continue;

      // The node morphed - this is equivalent to legalizing by replacing every
      // value of N with the corresponding value of M.  So do that now.
      assert(N->getNumValues() == M->getNumValues() &&
             "Node morphing changed the number of results!");
      for (unsigned i = 0, e = N->getNumValues(); i != e; ++i)
        // Replacing the value takes care of remapping the new value.
        ReplaceValueWith(SDValue(N, i), SDValue(M, i));
      assert(N->getNodeId() == NewNode && "Unexpected node state!");
      // The node continues to live on as part of the NewNode fungus that
      // grows on top of the useful nodes.  Nothing more needs to be done
      // with it - move on to the next node.
      continue;
    }

    if (i == NumOperands) {
      DEBUG(dbgs() << "Legally typed node: "; N->dump(&DAG); dbgs() << "\n");
    }
    }
NodeDone:

    // If we reach here, the node was processed, potentially creating new nodes.
    // Mark it as processed and add its users to the worklist as appropriate.
    assert(N->getNodeId() == ReadyToProcess && "Node ID recalculated?");
    N->setNodeId(Processed);

    for (SDNode::use_iterator UI = N->use_begin(), E = N->use_end();
         UI != E; ++UI) {
      SDNode *User = *UI;
      int NodeId = User->getNodeId();

      // This node has two options: it can either be a new node or its Node ID
      // may be a count of the number of operands it has that are not ready.
      if (NodeId > 0) {
        User->setNodeId(NodeId-1);

        // If this was the last use it was waiting on, add it to the ready list.
        if (NodeId-1 == ReadyToProcess)
          Worklist.push_back(User);
        continue;
      }

      // If this is an unreachable new node, then ignore it.  If it ever becomes
      // reachable by being used by a newly created node then it will be handled
      // by AnalyzeNewNode.
      if (NodeId == NewNode)
        continue;

      // Otherwise, this node is new: this is the first operand of it that
      // became ready.  Its new NodeId is the number of operands it has minus 1
      // (as this node is now processed).
      assert(NodeId == Unanalyzed && "Unknown node ID!");
      User->setNodeId(User->getNumOperands() - 1);

      // If the node only has a single operand, it is now ready.
      if (User->getNumOperands() == 1)
        Worklist.push_back(User);
    }
  }
コード例 #5
0
void ScheduleDAGSDNodes::BuildSchedUnits() {
  // During scheduling, the NodeId field of SDNode is used to map SDNodes
  // to their associated SUnits by holding SUnits table indices. A value
  // of -1 means the SDNode does not yet have an associated SUnit.
  unsigned NumNodes = 0;
  for (SelectionDAG::allnodes_iterator NI = DAG->allnodes_begin(),
       E = DAG->allnodes_end(); NI != E; ++NI) {
    NI->setNodeId(-1);
    ++NumNodes;
  }

  // Reserve entries in the vector for each of the SUnits we are creating.  This
  // ensure that reallocation of the vector won't happen, so SUnit*'s won't get
  // invalidated.
  // FIXME: Multiply by 2 because we may clone nodes during scheduling.
  // This is a temporary workaround.
  SUnits.reserve(NumNodes * 2);

  // Add all nodes in depth first order.
  SmallVector<SDNode*, 64> Worklist;
  SmallPtrSet<SDNode*, 64> Visited;
  Worklist.push_back(DAG->getRoot().getNode());
  Visited.insert(DAG->getRoot().getNode());

  SmallVector<SUnit*, 8> CallSUnits;
  while (!Worklist.empty()) {
    SDNode *NI = Worklist.pop_back_val();

    // Add all operands to the worklist unless they've already been added.
    for (unsigned i = 0, e = NI->getNumOperands(); i != e; ++i)
      if (Visited.insert(NI->getOperand(i).getNode()))
        Worklist.push_back(NI->getOperand(i).getNode());

    if (isPassiveNode(NI))  // Leaf node, e.g. a TargetImmediate.
      continue;

    // If this node has already been processed, stop now.
    if (NI->getNodeId() != -1) continue;

    SUnit *NodeSUnit = newSUnit(NI);

    // See if anything is glued to this node, if so, add them to glued
    // nodes.  Nodes can have at most one glue input and one glue output.  Glue
    // is required to be the last operand and result of a node.

    // Scan up to find glued preds.
    SDNode *N = NI;
    while (N->getNumOperands() &&
           N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Glue) {
      N = N->getOperand(N->getNumOperands()-1).getNode();
      assert(N->getNodeId() == -1 && "Node already inserted!");
      N->setNodeId(NodeSUnit->NodeNum);
      if (N->isMachineOpcode() && TII->get(N->getMachineOpcode()).isCall())
        NodeSUnit->isCall = true;
    }

    // Scan down to find any glued succs.
    N = NI;
    while (N->getValueType(N->getNumValues()-1) == MVT::Glue) {
      SDValue GlueVal(N, N->getNumValues()-1);

      // There are either zero or one users of the Glue result.
      bool HasGlueUse = false;
      for (SDNode::use_iterator UI = N->use_begin(), E = N->use_end();
           UI != E; ++UI)
        if (GlueVal.isOperandOf(*UI)) {
          HasGlueUse = true;
          assert(N->getNodeId() == -1 && "Node already inserted!");
          N->setNodeId(NodeSUnit->NodeNum);
          N = *UI;
          if (N->isMachineOpcode() && TII->get(N->getMachineOpcode()).isCall())
            NodeSUnit->isCall = true;
          break;
        }
      if (!HasGlueUse) break;
    }

    if (NodeSUnit->isCall)
      CallSUnits.push_back(NodeSUnit);

    // Schedule zero-latency TokenFactor below any nodes that may increase the
    // schedule height. Otherwise, ancestors of the TokenFactor may appear to
    // have false stalls.
    if (NI->getOpcode() == ISD::TokenFactor)
      NodeSUnit->isScheduleLow = true;

    // If there are glue operands involved, N is now the bottom-most node
    // of the sequence of nodes that are glued together.
    // Update the SUnit.
    NodeSUnit->setNode(N);
    assert(N->getNodeId() == -1 && "Node already inserted!");
    N->setNodeId(NodeSUnit->NodeNum);

    // Compute NumRegDefsLeft. This must be done before AddSchedEdges.
    InitNumRegDefsLeft(NodeSUnit);

    // Assign the Latency field of NodeSUnit using target-provided information.
    computeLatency(NodeSUnit);
  }

  // Find all call operands.
  while (!CallSUnits.empty()) {
    SUnit *SU = CallSUnits.pop_back_val();
    for (const SDNode *SUNode = SU->getNode(); SUNode;
         SUNode = SUNode->getGluedNode()) {
      if (SUNode->getOpcode() != ISD::CopyToReg)
        continue;
      SDNode *SrcN = SUNode->getOperand(2).getNode();
      if (isPassiveNode(SrcN)) continue;   // Not scheduled.
      SUnit *SrcSU = &SUnits[SrcN->getNodeId()];
      SrcSU->isCallOp = true;
    }
  }
}
コード例 #6
0
// Select - Convert the specified operand from a target-independent to a
// target-specific node if it hasn't already been changed.
SDNode *IA64DAGToDAGISel::Select(SDValue Op) {
    SDNode *N = Op.getNode();
    if (N->isMachineOpcode())
        return NULL;   // Already selected.
    DebugLoc dl = Op.getDebugLoc();

    switch (N->getOpcode()) {
    default:
        break;

    case IA64ISD::BRCALL: { // XXX: this is also a hack!
        SDValue Chain = N->getOperand(0);
        SDValue InFlag;  // Null incoming flag value.

        if(N->getNumOperands()==3) { // we have an incoming chain, callee and flag
            InFlag = N->getOperand(2);
        }

        unsigned CallOpcode;
        SDValue CallOperand;

        // if we can call directly, do so
        if (GlobalAddressSDNode *GASD =
                    dyn_cast<GlobalAddressSDNode>(N->getOperand(1))) {
            CallOpcode = IA64::BRCALL_IPREL_GA;
            CallOperand = CurDAG->getTargetGlobalAddress(GASD->getGlobal(), MVT::i64);
        } else if (isa<ExternalSymbolSDNode>(N->getOperand(1))) {
            // FIXME: we currently NEED this case for correctness, to avoid
            // "non-pic code with imm reloc.n against dynamic symbol" errors
            CallOpcode = IA64::BRCALL_IPREL_ES;
            CallOperand = N->getOperand(1);
        } else {
            // otherwise we need to load the function descriptor,
            // load the branch target (function)'s entry point and GP,
            // branch (call) then restore the GP
            SDValue FnDescriptor = N->getOperand(1);

            // load the branch target's entry point [mem] and
            // GP value [mem+8]
            SDValue targetEntryPoint=
                SDValue(CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, MVT::Other,
                                              FnDescriptor, CurDAG->getEntryNode()), 0);
            Chain = targetEntryPoint.getValue(1);
            SDValue targetGPAddr=
                SDValue(CurDAG->getTargetNode(IA64::ADDS, dl, MVT::i64,
                                              FnDescriptor,
                                              CurDAG->getConstant(8, MVT::i64)), 0);
            Chain = targetGPAddr.getValue(1);
            SDValue targetGP =
                SDValue(CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64,MVT::Other,
                                              targetGPAddr, CurDAG->getEntryNode()), 0);
            Chain = targetGP.getValue(1);

            Chain = CurDAG->getCopyToReg(Chain, dl, IA64::r1, targetGP, InFlag);
            InFlag = Chain.getValue(1);
            Chain = CurDAG->getCopyToReg(Chain, dl, IA64::B6,
                                         targetEntryPoint, InFlag); // FLAG these?
            InFlag = Chain.getValue(1);

            CallOperand = CurDAG->getRegister(IA64::B6, MVT::i64);
            CallOpcode = IA64::BRCALL_INDIRECT;
        }

        // Finally, once everything is setup, emit the call itself
        if (InFlag.getNode())
            Chain = SDValue(CurDAG->getTargetNode(CallOpcode, dl, MVT::Other,
                                                  MVT::Flag, CallOperand, InFlag), 0);
        else // there might be no arguments
            Chain = SDValue(CurDAG->getTargetNode(CallOpcode, dl, MVT::Other,
                                                  MVT::Flag, CallOperand, Chain), 0);
        InFlag = Chain.getValue(1);

        std::vector<SDValue> CallResults;

        CallResults.push_back(Chain);
        CallResults.push_back(InFlag);

        for (unsigned i = 0, e = CallResults.size(); i != e; ++i)
            ReplaceUses(Op.getValue(i), CallResults[i]);
        return NULL;
    }

    case IA64ISD::GETFD: {
        SDValue Input = N->getOperand(0);
        return CurDAG->getTargetNode(IA64::GETFD, dl, MVT::i64, Input);
    }

    case ISD::FDIV:
    case ISD::SDIV:
    case ISD::UDIV:
    case ISD::SREM:
    case ISD::UREM:
        return SelectDIV(Op);

    case ISD::TargetConstantFP: {
        SDValue Chain = CurDAG->getEntryNode(); // this is a constant, so..

        SDValue V;
        ConstantFPSDNode* N2 = cast<ConstantFPSDNode>(N);
        if (N2->getValueAPF().isPosZero()) {
            V = CurDAG->getCopyFromReg(Chain, dl, IA64::F0, MVT::f64);
        } else if (N2->isExactlyValue(N2->getValueType(0) == MVT::f32 ?
                                      APFloat(+1.0f) : APFloat(+1.0))) {
            V = CurDAG->getCopyFromReg(Chain, dl, IA64::F1, MVT::f64);
        } else
            assert(0 && "Unexpected FP constant!");

        ReplaceUses(SDValue(N, 0), V);
        return 0;
    }

    case ISD::FrameIndex: { // TODO: reduce creepyness
        int FI = cast<FrameIndexSDNode>(N)->getIndex();
        if (N->hasOneUse())
            return CurDAG->SelectNodeTo(N, IA64::MOV, MVT::i64,
                                        CurDAG->getTargetFrameIndex(FI, MVT::i64));
        else
            return CurDAG->getTargetNode(IA64::MOV, dl, MVT::i64,
                                         CurDAG->getTargetFrameIndex(FI, MVT::i64));
    }

    case ISD::ConstantPool: { // TODO: nuke the constant pool
        // (ia64 doesn't need one)
        ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(N);
        Constant *C = CP->getConstVal();
        SDValue CPI = CurDAG->getTargetConstantPool(C, MVT::i64,
                      CP->getAlignment());
        return CurDAG->getTargetNode(IA64::ADDL_GA, dl, MVT::i64, // ?
                                     CurDAG->getRegister(IA64::r1, MVT::i64), CPI);
    }

    case ISD::GlobalAddress: {
        GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal();
        SDValue GA = CurDAG->getTargetGlobalAddress(GV, MVT::i64);
        SDValue Tmp =
            SDValue(CurDAG->getTargetNode(IA64::ADDL_GA, dl, MVT::i64,
                                          CurDAG->getRegister(IA64::r1,
                                                  MVT::i64), GA), 0);
        return CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, MVT::Other, Tmp,
                                     CurDAG->getEntryNode());
    }

    /* XXX
       case ISD::ExternalSymbol: {
         SDValue EA = CurDAG->getTargetExternalSymbol(
           cast<ExternalSymbolSDNode>(N)->getSymbol(),
           MVT::i64);
         SDValue Tmp = CurDAG->getTargetNode(IA64::ADDL_EA, dl, MVT::i64,
                                               CurDAG->getRegister(IA64::r1,
                                                                   MVT::i64),
                                               EA);
         return CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, Tmp);
       }
    */

    case ISD::LOAD: { // FIXME: load -1, not 1, for bools?
        LoadSDNode *LD = cast<LoadSDNode>(N);
        SDValue Chain = LD->getChain();
        SDValue Address = LD->getBasePtr();

        MVT TypeBeingLoaded = LD->getMemoryVT();
        unsigned Opc;
        switch (TypeBeingLoaded.getSimpleVT()) {
        default:
#ifndef NDEBUG
            N->dump(CurDAG);
#endif
            assert(0 && "Cannot load this type!");
        case MVT::i1: { // this is a bool
            Opc = IA64::LD1; // first we load a byte, then compare for != 0
            if(N->getValueType(0) == MVT::i1) { // XXX: early exit!
                return CurDAG->SelectNodeTo(N, IA64::CMPNE, MVT::i1, MVT::Other,
                                            SDValue(CurDAG->getTargetNode(Opc, dl,
                                                    MVT::i64,
                                                    Address), 0),
                                            CurDAG->getRegister(IA64::r0, MVT::i64),
                                            Chain);
            }
            /* otherwise, we want to load a bool into something bigger: LD1
               will do that for us, so we just fall through */
        }
        case MVT::i8:
            Opc = IA64::LD1;
            break;
        case MVT::i16:
            Opc = IA64::LD2;
            break;
        case MVT::i32:
            Opc = IA64::LD4;
            break;
        case MVT::i64:
            Opc = IA64::LD8;
            break;

        case MVT::f32:
            Opc = IA64::LDF4;
            break;
        case MVT::f64:
            Opc = IA64::LDF8;
            break;
        }

        // TODO: comment this
        return CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other,
                                    Address, Chain);
    }

    case ISD::STORE: {
        StoreSDNode *ST = cast<StoreSDNode>(N);
        SDValue Address = ST->getBasePtr();
        SDValue Chain = ST->getChain();

        unsigned Opc;
        if (ISD::isNON_TRUNCStore(N)) {
            switch (N->getOperand(1).getValueType().getSimpleVT()) {
            default:
                assert(0 && "unknown type in store");
            case MVT::i1: { // this is a bool
                Opc = IA64::ST1; // we store either 0 or 1 as a byte
                // first load zero!
                SDValue Initial = CurDAG->getCopyFromReg(Chain, dl, IA64::r0, MVT::i64);
                Chain = Initial.getValue(1);
                // then load 1 into the same reg iff the predicate to store is 1
                SDValue Tmp = ST->getValue();
                Tmp =
                    SDValue(CurDAG->getTargetNode(IA64::TPCADDS, dl, MVT::i64, Initial,
                                                  CurDAG->getTargetConstant(1,
                                                          MVT::i64),
                                                  Tmp), 0);
                return CurDAG->SelectNodeTo(N, Opc, MVT::Other, Address, Tmp, Chain);
            }
            case MVT::i64:
                Opc = IA64::ST8;
                break;
            case MVT::f64:
                Opc = IA64::STF8;
                break;
            }
        } else { // Truncating store
            switch(ST->getMemoryVT().getSimpleVT()) {
            default:
                assert(0 && "unknown type in truncstore");
            case MVT::i8:
                Opc = IA64::ST1;
                break;
            case MVT::i16:
                Opc = IA64::ST2;
                break;
            case MVT::i32:
                Opc = IA64::ST4;
                break;
            case MVT::f32:
                Opc = IA64::STF4;
                break;
            }
        }

        SDValue N1 = N->getOperand(1);
        SDValue N2 = N->getOperand(2);
        return CurDAG->SelectNodeTo(N, Opc, MVT::Other, N2, N1, Chain);
    }

    case ISD::BRCOND: {
        SDValue Chain = N->getOperand(0);
        SDValue CC = N->getOperand(1);
        MachineBasicBlock *Dest =
            cast<BasicBlockSDNode>(N->getOperand(2))->getBasicBlock();
        //FIXME - we do NOT need long branches all the time
        return CurDAG->SelectNodeTo(N, IA64::BRLCOND_NOTCALL, MVT::Other, CC,
                                    CurDAG->getBasicBlock(Dest), Chain);
    }

    case ISD::CALLSEQ_START:
    case ISD::CALLSEQ_END: {
        int64_t Amt = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
        unsigned Opc = N->getOpcode() == ISD::CALLSEQ_START ?
                       IA64::ADJUSTCALLSTACKDOWN : IA64::ADJUSTCALLSTACKUP;
        SDValue N0 = N->getOperand(0);
        return CurDAG->SelectNodeTo(N, Opc, MVT::Other, getI64Imm(Amt), N0);
    }

    case ISD::BR:
        // FIXME: we don't need long branches all the time!
        SDValue N0 = N->getOperand(0);
        return CurDAG->SelectNodeTo(N, IA64::BRL_NOTCALL, MVT::Other,
                                    N->getOperand(1), N0);
    }

    return SelectCode(Op);
}
コード例 #7
0
SDValue AVM2TargetLowering::
LowerOperation(SDValue Op, SelectionDAG &DAG) const
{
    DebugLoc DL = Op.getDebugLoc();
    switch (Op.getOpcode()) {
    default: {
        assert(0 && "Shouldn't custom lower this");
    }
    // XXX TODO isn't this just Promote?
    case ISD::FADD:
    case ISD::FSUB:
    case ISD::FPOW:
    case ISD::FMUL:
    case ISD::FDIV:
    case ISD::FREM: {
        SDValue L = Op.getOperand(0);
        SDValue R = Op.getOperand(1);

        assert(L.getValueType() == R.getValueType() && L.getValueType() == MVT::f32);

        L = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, L);
        R = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, R);

        SDValue result = DAG.getNode(Op.getOpcode(), DL, MVT::f64, L, R);

        return DAG.getNode(ISD::FP_ROUND, DL, MVT::f32, result, DAG.getIntPtrConstant(0));
    }
    // XXX TODO isn't this just Promote?
    case ISD::FSIN:
    case ISD::FCOS:
    case ISD::FSQRT:
    case ISD::FNEG:
    case ISD::FABS: {
        SDValue L = Op.getOperand(0);

        assert(L.getValueType() == MVT::f32);

        L = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, L);

        SDValue result = DAG.getNode(Op.getOpcode(), DL, MVT::f64, L);

        return DAG.getNode(ISD::FP_ROUND, DL, MVT::f32, result, DAG.getIntPtrConstant(0));
    }
    case ISD::SELECT_CC: {
        ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
        SDValue L = Op.getOperand(0);
        SDValue R = Op.getOperand(1);
        SDValue A = Op.getOperand(2);
        SDValue B = Op.getOperand(3);

        // promote everything that is an f32
        if(L.getValueType() == MVT::f32) {
            L = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, L);
            R = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, R);
        }
        if(A.getValueType() == MVT::f32) {
            A = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, A);
            B = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, B);
        }

        bool IsFloat = L.getValueType() == MVT::f64;
        bool RIsFloat = A.getValueType() == MVT::f64;

        SDValue result = DAG.getNode(RIsFloat ? AVM2ISD::FSL : AVM2ISD::SL, DL, RIsFloat ? MVT::f64 : MVT::i32,
                                     DAG.getNode(IsFloat ? AVM2ISD::FCNOP: AVM2ISD::CNOP, DL, MVT::i32,
                                             DAG.getTargetConstant((int)CC, MVT::i32), L, R), A, B);
        if(Op.getValueType() == MVT::f32) {
            result = DAG.getNode(ISD::FP_ROUND, DL, MVT::f32, result, DAG.getIntPtrConstant(0));
        }
        return result;
    }

    // case ISD::BR_CC: { return LowerBR_CC(Op, DAG); }
    case ISD::BR_CC: {
        SDValue Chain = Op.getOperand(0);
        ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
        SDValue L = Op.getOperand(2);
        SDValue R = Op.getOperand(3);
        SDValue Dest = Op.getOperand(4);


        // If this is a br_cc of a "setcc", and if the setcc got lowered into
        // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values.
        if(L.getValueType() == MVT::f32) {
            L = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, L);
            R = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f64, R);
        } else if(L.getValueType() == MVT::i32 /*|| L.getValueType() == MVT::i64*/) {
            if(ConstantSDNode *node = dyn_cast<ConstantSDNode>(L)) {
                L = DAG.getTargetConstant((int)node->getSExtValue(), MVT::i32);
            }
            if(ConstantSDNode *node = dyn_cast<ConstantSDNode>(R)) {
                R = DAG.getTargetConstant((int)node->getSExtValue(), MVT::i32);
            }
        }


        int Opc;
        int Cmp;
        bool IsFloat = L.getValueType() == MVT::f64;
        if( IsFloat ) {
            Opc = AVM2ISD::FCBR;
            Cmp = AVM2ISD::FCNOP;
        } else {
            Opc = AVM2ISD::CBR;
            Cmp = AVM2ISD::CNOP;
        }

        SDValue NOP = DAG.getNode( Cmp, DL, MVT::i32, DAG.getTargetConstant(CC, MVT::i32), L, R);
        return DAG.getNode(Opc, DL, MVT::Other, Chain, NOP, Dest);
    }


    // XXX TODO can't this just be Legal?
    case ISD::ConstantFP: {
        union {
            double d;
            struct {
                unsigned a, b;
            } i;
        } u;

        APFloat apf(cast<ConstantFPSDNode>(Op)->getValueAPF());

        bool losesInfo = false;
        apf.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &losesInfo);
        u.d = apf.convertToDouble();
        SDValue result = DAG.getNode(AVM2ISD::FNOP, DL, MVT::f64,
                                     DAG.getNode(AVM2ISD::F64, DL, MVT::f64,
                                             DAG.getTargetConstant(u.i.a, MVT::i32),
                                             DAG.getTargetConstant(u.i.b, MVT::i32)));
        if(Op.getValueType() == MVT::f32) {
            result = DAG.getNode(ISD::FP_ROUND, DL, MVT::f32, result,DAG.getIntPtrConstant(0));
        }
        return result;
    }
    case ISD::ConstantPool: {
        const Constant *C = cast<ConstantPoolSDNode>(Op)->getConstVal();
        SDValue CP = DAG.getTargetConstantPool(C, MVT::i32,
                                               cast<ConstantPoolSDNode>(Op)->getAlignment());
        return CP;
    }
    case ISD::BRIND:  {
        return LowerBRIND(Op, DAG);
    }
    case ISD::BlockAddress:  {
        return LowerBlockAddress(Op, DAG);
    }
    case ISD::TRAMPOLINE:  {
        return LowerTRAMPOLINE(Op, DAG);
    }
    case ISD::GlobalAddress: {
        const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
        if(GV->isDeclaration()) {
            // TODO ok? probably a leak
            std::string Str = "\2" + GV->getNameStr();
            const char *N = strdup(Str.c_str());
            return DAG.getNode(AVM2ISD::INOP, DL, MVT::i32, DAG.getTargetExternalSymbol(N, MVT::i32));
        }
        EVT VT(MVT::i32);
        return DAG.getNode(AVM2ISD::INOP, DL, MVT::i32, DAG.getTargetGlobalAddress(GV, DL, VT));
    }
    case ISD::ExternalSymbol : {
        const char *N = cast<ExternalSymbolSDNode>(Op)->getSymbol();
        const Module *M = DAG.getMachineFunction().getFunction()->getParent();
        const GlobalValue *GV = M->getGlobalVariable(N);
        if(GV && !GV->isDeclaration()) {
            EVT VT(MVT::i32);
            return DAG.getNode(AVM2ISD::INOP, DL, MVT::i32, DAG.getTargetGlobalAddress(GV, DL, VT));
        }
        return DAG.getNode(AVM2ISD::INOP, DL, MVT::i32, DAG.getTargetExternalSymbol(N, MVT::i32));
    }
    case ISD::VASTART: {
        // vastart just stores the address of the VarArgsFrameIndex slot into the
        // memory location argument.
        SDValue Offset = DAG.getNode(ISD::ADD, DL, MVT::i32,
                                     DAG.getRegister(AVM2::EBP, MVT::i32),
                                     DAG.getConstant(DAG.getMachineFunction().getInfo<AVM2MachineFunctionInfo>()->getVarArgsFrameOffset(), MVT::i32));

        /*
         http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/SelectionDAGNodes.h?revision=46585&view=markup

         Create a new class, MemOperand, for describing memory references
         in the backend. Introduce a new SDNode type, MemOperandSDNode, for
         holding a MemOperand in the SelectionDAG IR, and add a MemOperand
         list to MachineInstr, and code to manage them. Remove the offset
         field from SrcValueSDNode; uses of SrcValueSDNode that were using
         it are all all using MemOperandSDNode now.

         Also, begin updating some getLoad and getStore calls to use the
         PseudoSourceValue objects.

         Most of this was written by Florian Brander, some
         reorganization and updating to TOT by me.
         */


        const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
        return DAG.getStore(Op.getOperand(0), DL, Offset,
                            Op.getOperand(1), MachinePointerInfo(SV), false, false, 0);

    }
    case ISD::VAARG: {
        SDNode *Node = Op.getNode();
        MVT::SimpleValueType VT = Node->getValueType(0).getSimpleVT().SimpleTy;
        SDValue InChain = Node->getOperand(0);
        SDValue VAListPtr = Node->getOperand(1);
        const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue();
        SDValue VAList = DAG.getLoad(getPointerTy(), DL, InChain, VAListPtr,
                                     MachinePointerInfo(SV), false, false, 0);
        // Increment the pointer, VAList, to the next vaarg
        SDValue NextPtr = DAG.getNode(ISD::ADD, DL, getPointerTy(), VAList,
                                      DAG.getConstant(Node->getValueType(0).getSizeInBits()/8,
                                              getPointerTy()));
        // Store the incremented VAList to the legalized pointer
        InChain = DAG.getStore(VAList.getValue(1), DL, NextPtr,
                               VAListPtr, MachinePointerInfo(SV), false, false, 0);
        // Load the actual argument out of the pointer VAList
        return DAG.getLoad(VT, DL, InChain, VAList, MachinePointerInfo(), false, false, 0);
    }
    case ISD::DYNAMIC_STACKALLOC: {
        SDValue Chain = Op.getOperand(0);  // Legalize the chain.
        SDValue Size  = Op.getOperand(1);  // Legalize the size.

        unsigned SPReg = AVM2::ESP;
        SDValue SP = DAG.getCopyFromReg(Chain, DL, SPReg, MVT::i32);
        SDValue NewSP = DAG.getNode(ISD::SUB, DL, MVT::i32, SP, Size);    // Value
        unsigned Align = getTargetMachine().getFrameLowering()->getStackAlignment();

        assert(!(Align & (Align - 1))); // must be power of 2
        SDValue NewSPAligned = DAG.getNode(ISD::AND, DL, MVT::i32, NewSP, DAG.getIntPtrConstant(~(Align - 1)));
        Chain = DAG.getCopyToReg(SP.getValue(1), DL, SPReg, NewSPAligned);      // Output chain

        std::vector<EVT> Tys;
        Tys.push_back(MVT::i32);
        Tys.push_back(MVT::Other);
        SDValue Ops[2] = { NewSPAligned, Chain };
        return DAG.getNode(ISD::MERGE_VALUES, DL, Tys, Ops, 2);
    }

    /*
     http://llvm.org/viewvc/llvm-project?view=rev&revision=78142
     Major calling convention code refactoring.

     Instead of awkwardly encoding calling-convention information with ISD::CALL,
     ISD::FORMAL_ARGUMENTS, ISD::RET, and ISD::ARG_FLAGS nodes, TargetLowering
     provides three virtual functions for targets to override:
     LowerFormalArguments, LowerCall, and LowerRet, which replace the custom
     lowering done on the special nodes. They provide the same information, but
     in a more immediately usable format.

     This also reworks much of the target-independent tail call logic. The
     decision of whether or not to perform a tail call is now cleanly split
     between target-independent portions, and the target dependent portion
     in IsEligibleForTailCallOptimization.

     This also synchronizes all in-tree targets, to help enable future
     refactoring and feature work.

     setOperationAction(ISD::RET               , MVT::Other, Custom);

     case ISD::RET: {
     SDValue Copy;

     switch(Op.getNumOperands()) {
     default:
     assert(0 && "Do not know how to return this many arguments!");
     abort();
     case 1:
     return DAG.getNode(AVM2ISD::RET_FLAG, DL, MVT::Other, Op.getOperand(0), DAG.getConstant(0, MVT::i32));
     case 3: {
     unsigned ArgReg;
     switch(Op.getOperand(1).getValueType()) {
     default: assert(0 && "Unknown type to return!");
     case MVT::i32: ArgReg = AVM2::EAX; break;
     case MVT::f32: ArgReg = AVM2::SST0; break;
     case MVT::f64: ArgReg = AVM2::ST0; break;
     }
     Copy = DAG.getCopyToReg(Op.getOperand(0), ArgReg, Op.getOperand(1),
     SDValue());
     break;
     }
     case 5:
     Copy = DAG.getCopyToReg(Op.getOperand(0), AVM2::EDX, Op.getOperand(3),
     SDValue());
     Copy = DAG.getCopyToReg(Copy, AVM2::EAX, Op.getOperand(1), Copy.getValue(1));
     break;
     }
     return DAG.getNode(AVM2ISD::RET_FLAG, DL, MVT::Other, Copy, Copy.getValue(1));
     }
     */
    case ISD::FRAMEADDR:
        return LowerFRAMEADDR(Op, DAG);
    case ISD::EH_SJLJ_SETJMP:
        return LowerEH_SJLJ_SETJMP(Op, DAG);
    case ISD::EH_SJLJ_LONGJMP:
        return LowerEH_SJLJ_LONGJMP(Op, DAG);
    case ISD::EH_SJLJ_DISPATCHSETUP:
        return LowerEH_SJLJ_DISPATCHSETUP(Op, DAG);
    case ISD::INTRINSIC_WO_CHAIN:
        return LowerINTRINSIC_WO_CHAIN(Op, DAG, SubTarget);
        // Return address.  Currently unimplemented
    case ISD::RETURNADDR:
        break;
    }
    return SDValue();
}
コード例 #8
0
void ScheduleDAGSDNodes::BuildSchedUnits() {
  // During scheduling, the NodeId field of SDNode is used to map SDNodes
  // to their associated SUnits by holding SUnits table indices. A value
  // of -1 means the SDNode does not yet have an associated SUnit.
  unsigned NumNodes = 0;
  for (SelectionDAG::allnodes_iterator NI = DAG->allnodes_begin(),
       E = DAG->allnodes_end(); NI != E; ++NI) {
    NI->setNodeId(-1);
    ++NumNodes;
  }

  // Reserve entries in the vector for each of the SUnits we are creating.  This
  // ensure that reallocation of the vector won't happen, so SUnit*'s won't get
  // invalidated.
  // FIXME: Multiply by 2 because we may clone nodes during scheduling.
  // This is a temporary workaround.
  SUnits.reserve(NumNodes * 2);
  
  // Check to see if the scheduler cares about latencies.
  bool UnitLatencies = ForceUnitLatencies();

  // Add all nodes in depth first order.
  SmallVector<SDNode*, 64> Worklist;
  SmallPtrSet<SDNode*, 64> Visited;
  Worklist.push_back(DAG->getRoot().getNode());
  Visited.insert(DAG->getRoot().getNode());
  
  while (!Worklist.empty()) {
    SDNode *NI = Worklist.pop_back_val();
    
    // Add all operands to the worklist unless they've already been added.
    for (unsigned i = 0, e = NI->getNumOperands(); i != e; ++i)
      if (Visited.insert(NI->getOperand(i).getNode()))
        Worklist.push_back(NI->getOperand(i).getNode());
  
    if (isPassiveNode(NI))  // Leaf node, e.g. a TargetImmediate.
      continue;
    
    // If this node has already been processed, stop now.
    if (NI->getNodeId() != -1) continue;
    
    SUnit *NodeSUnit = NewSUnit(NI);
    
    // See if anything is flagged to this node, if so, add them to flagged
    // nodes.  Nodes can have at most one flag input and one flag output.  Flags
    // are required to be the last operand and result of a node.
    
    // Scan up to find flagged preds.
    SDNode *N = NI;
    while (N->getNumOperands() &&
           N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Flag) {
      N = N->getOperand(N->getNumOperands()-1).getNode();
      assert(N->getNodeId() == -1 && "Node already inserted!");
      N->setNodeId(NodeSUnit->NodeNum);
    }
    
    // Scan down to find any flagged succs.
    N = NI;
    while (N->getValueType(N->getNumValues()-1) == MVT::Flag) {
      SDValue FlagVal(N, N->getNumValues()-1);
      
      // There are either zero or one users of the Flag result.
      bool HasFlagUse = false;
      for (SDNode::use_iterator UI = N->use_begin(), E = N->use_end(); 
           UI != E; ++UI)
        if (FlagVal.isOperandOf(*UI)) {
          HasFlagUse = true;
          assert(N->getNodeId() == -1 && "Node already inserted!");
          N->setNodeId(NodeSUnit->NodeNum);
          N = *UI;
          break;
        }
      if (!HasFlagUse) break;
    }
    
    // If there are flag operands involved, N is now the bottom-most node
    // of the sequence of nodes that are flagged together.
    // Update the SUnit.
    NodeSUnit->setNode(N);
    assert(N->getNodeId() == -1 && "Node already inserted!");
    N->setNodeId(NodeSUnit->NodeNum);

    // Assign the Latency field of NodeSUnit using target-provided information.
    if (UnitLatencies)
      NodeSUnit->Latency = 1;
    else
      ComputeLatency(NodeSUnit);
  }
}
コード例 #9
0
SDNode *XCoreDAGToDAGISel::Select(SDValue Op) {
  SDNode *N = Op.getNode();
  DebugLoc dl = N->getDebugLoc();
  EVT NVT = N->getValueType(0);
  if (NVT == MVT::i32) {
    switch (N->getOpcode()) {
      default: break;
      case ISD::Constant: {
        if (Predicate_immMskBitp(N)) {
          SDValue MskSize = Transform_msksize_xform(N);
          return CurDAG->getTargetNode(XCore::MKMSK_rus, dl, MVT::i32, MskSize);
        }
        else if (! Predicate_immU16(N)) {
          unsigned Val = cast<ConstantSDNode>(N)->getZExtValue();
          SDValue CPIdx =
            CurDAG->getTargetConstantPool(ConstantInt::get(
                                  Type::getInt32Ty(*CurDAG->getContext()), Val),
                                          TLI.getPointerTy());
          return CurDAG->getTargetNode(XCore::LDWCP_lru6, dl, MVT::i32, 
                                       MVT::Other, CPIdx, 
                                       CurDAG->getEntryNode());
        }
        break;
      }
      case ISD::SMUL_LOHI: {
        // FIXME fold addition into the macc instruction
        if (!Subtarget.isXS1A()) {
          SDValue Zero(CurDAG->getTargetNode(XCore::LDC_ru6, dl, MVT::i32,
                                  CurDAG->getTargetConstant(0, MVT::i32)), 0);
          SDValue Ops[] = { Zero, Zero, Op.getOperand(0), Op.getOperand(1) };
          SDNode *ResNode = CurDAG->getTargetNode(XCore::MACCS_l4r, dl,
                                                  MVT::i32, MVT::i32, Ops, 4);
          ReplaceUses(SDValue(N, 0), SDValue(ResNode, 1));
          ReplaceUses(SDValue(N, 1), SDValue(ResNode, 0));
          return NULL;
        }
        break;
      }
      case ISD::UMUL_LOHI: {
        // FIXME fold addition into the macc / lmul instruction
        SDValue Zero(CurDAG->getTargetNode(XCore::LDC_ru6, dl, MVT::i32,
                                  CurDAG->getTargetConstant(0, MVT::i32)), 0);
        SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1),
                            Zero, Zero };
        SDNode *ResNode = CurDAG->getTargetNode(XCore::LMUL_l6r, dl, MVT::i32,
                                                MVT::i32, Ops, 4);
        ReplaceUses(SDValue(N, 0), SDValue(ResNode, 1));
        ReplaceUses(SDValue(N, 1), SDValue(ResNode, 0));
        return NULL;
      }
      case XCoreISD::LADD: {
        if (!Subtarget.isXS1A()) {
          SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1),
                              Op.getOperand(2) };
          return CurDAG->getTargetNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
                                       Ops, 3);
        }
        break;
      }
      case XCoreISD::LSUB: {
        if (!Subtarget.isXS1A()) {
          SDValue Ops[] = { Op.getOperand(0), Op.getOperand(1),
                              Op.getOperand(2) };
          return CurDAG->getTargetNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
                                       Ops, 3);
        }
        break;
      }
      // Other cases are autogenerated.
    }
  }
  return SelectCode(Op);
}