static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value) { if (shouldPrintInline(*Value.getNode())) { OS << Value->getOperationName(G) << ':'; Value->print_types(OS, G); Value->print_details(OS, G); return true; } else { OS << PrintNodeId(*Value.getNode()); if (unsigned RN = Value.getResNo()) OS << ':' << RN; return false; } }
/// getVR - Return the virtual register corresponding to the specified result /// of the specified node. unsigned ScheduleDAGSDNodes::getVR(SDValue Op, DenseMap<SDValue, unsigned> &VRBaseMap) { if (Op.isMachineOpcode() && Op.getMachineOpcode() == TargetInstrInfo::IMPLICIT_DEF) { // Add an IMPLICIT_DEF instruction before every use. unsigned VReg = getDstOfOnlyCopyToRegUse(Op.getNode(), Op.getResNo()); // IMPLICIT_DEF can produce any type of result so its TargetInstrDesc // does not include operand register class info. if (!VReg) { const TargetRegisterClass *RC = TLI->getRegClassFor(Op.getValueType()); VReg = MRI.createVirtualRegister(RC); } BuildMI(BB, Op.getDebugLoc(), TII->get(TargetInstrInfo::IMPLICIT_DEF),VReg); return VReg; } DenseMap<SDValue, unsigned>::iterator I = VRBaseMap.find(Op); assert(I != VRBaseMap.end() && "Node emitted out of order - late"); return I->second; }
/// EmitCopyFromReg - Generate machine code for an CopyFromReg node or an /// implicit physical register output. void InstrEmitter:: EmitCopyFromReg(SDNode *Node, unsigned ResNo, bool IsClone, bool IsCloned, unsigned SrcReg, DenseMap<SDValue, unsigned> &VRBaseMap) { unsigned VRBase = 0; if (TargetRegisterInfo::isVirtualRegister(SrcReg)) { // Just use the input register directly! SDValue Op(Node, ResNo); if (IsClone) VRBaseMap.erase(Op); bool isNew = VRBaseMap.insert(std::make_pair(Op, SrcReg)).second; (void)isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); return; } // If the node is only used by a CopyToReg and the dest reg is a vreg, use // the CopyToReg'd destination register instead of creating a new vreg. bool MatchReg = true; const TargetRegisterClass *UseRC = nullptr; MVT VT = Node->getSimpleValueType(ResNo); // Stick to the preferred register classes for legal types. if (TLI->isTypeLegal(VT)) UseRC = TLI->getRegClassFor(VT); if (!IsClone && !IsCloned) for (SDNode *User : Node->uses()) { bool Match = true; if (User->getOpcode() == ISD::CopyToReg && User->getOperand(2).getNode() == Node && User->getOperand(2).getResNo() == ResNo) { unsigned DestReg = cast<RegisterSDNode>(User->getOperand(1))->getReg(); if (TargetRegisterInfo::isVirtualRegister(DestReg)) { VRBase = DestReg; Match = false; } else if (DestReg != SrcReg) Match = false; } else { for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i) { SDValue Op = User->getOperand(i); if (Op.getNode() != Node || Op.getResNo() != ResNo) continue; MVT VT = Node->getSimpleValueType(Op.getResNo()); if (VT == MVT::Other || VT == MVT::Glue) continue; Match = false; if (User->isMachineOpcode()) { const MCInstrDesc &II = TII->get(User->getMachineOpcode()); const TargetRegisterClass *RC = nullptr; if (i+II.getNumDefs() < II.getNumOperands()) { RC = TRI->getAllocatableClass( TII->getRegClass(II, i+II.getNumDefs(), TRI, *MF)); } if (!UseRC) UseRC = RC; else if (RC) { const TargetRegisterClass *ComRC = TRI->getCommonSubClass(UseRC, RC, VT.SimpleTy); // If multiple uses expect disjoint register classes, we emit // copies in AddRegisterOperand. if (ComRC) UseRC = ComRC; } } } } MatchReg &= Match; if (VRBase) break; } const TargetRegisterClass *SrcRC = nullptr, *DstRC = nullptr; SrcRC = TRI->getMinimalPhysRegClass(SrcReg, VT); // Figure out the register class to create for the destreg. if (VRBase) { DstRC = MRI->getRegClass(VRBase); } else if (UseRC) { assert(TRI->isTypeLegalForClass(*UseRC, VT) && "Incompatible phys register def and uses!"); DstRC = UseRC; } else { DstRC = TLI->getRegClassFor(VT); } // If all uses are reading from the src physical register and copying the // register is either impossible or very expensive, then don't create a copy. if (MatchReg && SrcRC->getCopyCost() < 0) { VRBase = SrcReg; } else { // Create the reg, emit the copy. VRBase = MRI->createVirtualRegister(DstRC); BuildMI(*MBB, InsertPos, Node->getDebugLoc(), TII->get(TargetOpcode::COPY), VRBase).addReg(SrcReg); } SDValue Op(Node, ResNo); if (IsClone) VRBaseMap.erase(Op); bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second; (void)isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); }
/// EmitCopyFromReg - Generate machine code for an CopyFromReg node or an /// implicit physical register output. void ScheduleDAGSDNodes::EmitCopyFromReg(SDNode *Node, unsigned ResNo, bool IsClone, bool IsCloned, unsigned SrcReg, DenseMap<SDValue, unsigned> &VRBaseMap) { unsigned VRBase = 0; if (TargetRegisterInfo::isVirtualRegister(SrcReg)) { // Just use the input register directly! SDValue Op(Node, ResNo); if (IsClone) VRBaseMap.erase(Op); bool isNew = VRBaseMap.insert(std::make_pair(Op, SrcReg)).second; isNew = isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); return; } // If the node is only used by a CopyToReg and the dest reg is a vreg, use // the CopyToReg'd destination register instead of creating a new vreg. bool MatchReg = true; const TargetRegisterClass *UseRC = NULL; if (!IsClone && !IsCloned) for (SDNode::use_iterator UI = Node->use_begin(), E = Node->use_end(); UI != E; ++UI) { SDNode *User = *UI; bool Match = true; if (User->getOpcode() == ISD::CopyToReg && User->getOperand(2).getNode() == Node && User->getOperand(2).getResNo() == ResNo) { unsigned DestReg = cast<RegisterSDNode>(User->getOperand(1))->getReg(); if (TargetRegisterInfo::isVirtualRegister(DestReg)) { VRBase = DestReg; Match = false; } else if (DestReg != SrcReg) Match = false; } else { for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i) { SDValue Op = User->getOperand(i); if (Op.getNode() != Node || Op.getResNo() != ResNo) continue; MVT VT = Node->getValueType(Op.getResNo()); if (VT == MVT::Other || VT == MVT::Flag) continue; Match = false; if (User->isMachineOpcode()) { const TargetInstrDesc &II = TII->get(User->getMachineOpcode()); const TargetRegisterClass *RC = getInstrOperandRegClass(TRI, II, i+II.getNumDefs()); if (!UseRC) UseRC = RC; else if (RC) { if (UseRC->hasSuperClass(RC)) UseRC = RC; else assert((UseRC == RC || RC->hasSuperClass(UseRC)) && "Multiple uses expecting different register classes!"); } } } } MatchReg &= Match; if (VRBase) break; } MVT VT = Node->getValueType(ResNo); const TargetRegisterClass *SrcRC = 0, *DstRC = 0; SrcRC = TRI->getPhysicalRegisterRegClass(SrcReg, VT); // Figure out the register class to create for the destreg. if (VRBase) { DstRC = MRI.getRegClass(VRBase); } else if (UseRC) { assert(UseRC->hasType(VT) && "Incompatible phys register def and uses!"); DstRC = UseRC; } else { DstRC = TLI->getRegClassFor(VT); } // If all uses are reading from the src physical register and copying the // register is either impossible or very expensive, then don't create a copy. if (MatchReg && SrcRC->getCopyCost() < 0) { VRBase = SrcReg; } else { // Create the reg, emit the copy. VRBase = MRI.createVirtualRegister(DstRC); bool Emitted = TII->copyRegToReg(*BB, InsertPos, VRBase, SrcReg, DstRC, SrcRC); // If the target didn't handle the copy with different register // classes and the destination is a subset of the source, // try a normal same-RC copy. if (!Emitted && DstRC->hasSuperClass(SrcRC)) Emitted = TII->copyRegToReg(*BB, InsertPos, VRBase, SrcReg, SrcRC, SrcRC); assert(Emitted && "Unable to issue a copy instruction!\n"); } SDValue Op(Node, ResNo); if (IsClone) VRBaseMap.erase(Op); bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second; isNew = isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); }
SDNode *HSAILDAGToDAGISel::SelectImageIntrinsic(SDNode *Node) { SDValue Chain = Node->getOperand(0); SDNode *ResNode; unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); bool hasSampler = false; if (IntNo == HSAILIntrinsic::HSAIL_rd_imgf_1d_s32) { SDLoc SL; const SDValue Ops[] = { CurDAG->getTargetConstant(1, SL, MVT::i1), // v4 CurDAG->getTargetConstant(BRIG_TYPE_ROIMG, SL, MVT::i32), // imageType CurDAG->getTargetConstant(BRIG_TYPE_S32, SL, MVT::i32), // coordType CurDAG->getTargetConstant(BRIG_GEOMETRY_1D, SL, MVT::i32), // geometry CurDAG->getTargetConstant(0, SL, MVT::i32), // equiv Node->getOperand(2), // image Node->getOperand(3), // sampler Node->getOperand(4), // coordWidth CurDAG->getTargetConstant(BRIG_TYPE_F32, SL, MVT::i32), // destType Chain }; return CurDAG->SelectNodeTo(Node, HSAIL::RDIMAGE, Node->getVTList(), Ops); } if (HSAILIntrinsicInfo::isReadImage((HSAILIntrinsic::ID)IntNo)) { hasSampler = true; } else if (!HSAILIntrinsicInfo::isLoadImage((HSAILIntrinsic::ID)IntNo)) { return SelectCode(Node); } if (((HSAILIntrinsic::ID)IntNo) == (HSAILIntrinsic::HSAIL_rd_imgf_2ddepth_f32) || ((HSAILIntrinsic::ID)IntNo) == (HSAILIntrinsic::HSAIL_rd_imgf_2ddepth_s32) || ((HSAILIntrinsic::ID)IntNo) == (HSAILIntrinsic::HSAIL_ld_imgf_2ddepth_u32) || ((HSAILIntrinsic::ID)IntNo) == (HSAILIntrinsic::HSAIL_rd_imgf_2dadepth_f32) || ((HSAILIntrinsic::ID)IntNo) == (HSAILIntrinsic::HSAIL_rd_imgf_2dadepth_s32) || ((HSAILIntrinsic::ID)IntNo) == (HSAILIntrinsic::HSAIL_ld_imgf_2dadepth_u32)) { assert(Node->getNumValues() == 2); } else { assert(Node->getNumValues() == 5); } SmallVector<SDValue, 6> NewOps; unsigned OpIndex = 2; SDValue Img = Node->getOperand(OpIndex++); int ResNo = Img.getResNo(); SDValue ImgHandle = Img.getValue(ResNo); NewOps.push_back(ImgHandle); if (hasSampler) { SDValue Smp = Node->getOperand(OpIndex++); SDValue SmpHandle = Smp.getValue(Smp.getResNo()); NewOps.push_back(SmpHandle); } while (OpIndex < Node->getNumOperands()) { SDValue Coord = Node->getOperand(OpIndex++); NewOps.push_back(Coord); } NewOps.push_back(Chain); ResNode = CurDAG->SelectNodeTo(Node, getImageInstr((HSAILIntrinsic::ID)IntNo), Node->getVTList(), NewOps); return ResNode; }
SDNode *CoffeeDAGToDAGISel::SelectBRCONDOp(SDNode *N) { SDValue Chain = N->getOperand(0); // Chain SDValue N1 = N->getOperand(1); // Destination SDValue N2 = N->getOperand(2); // CondCode as constant SDValue N3 = N->getOperand(3); // CC regsiter to check --> CR0 SDValue InFlag = N->getOperand(4); // glue assert(N1.getOpcode() == ISD::BasicBlock); assert(N2.getOpcode() == ISD::Constant); assert(N3.getOpcode() == ISD::Register); DebugLoc dl = N->getDebugLoc(); ISD::CondCode cc = (ISD::CondCode)cast<ConstantSDNode>(N2)->getZExtValue(); // The main logic here follows ARM implementation but unlike ARM, // Coffee has dedicated branch instructions for each situations while // ARM has one instruction which take CondCode as operands. unsigned Opc = 0; switch (cc) { default: llvm_unreachable("coffee:: unexpected condition code"); break; case ISD::SETEQ: case ISD::SETUEQ: case ISD::SETOEQ: Opc = Coffee::BEQ; break; case ISD::SETGT: case ISD::SETUGT: case ISD::SETOGT: Opc = Coffee::BGT; break; case ISD::SETGE: case ISD::SETUGE: case ISD::SETOGE: Opc = Coffee::BEGT; break; case ISD::SETLT: case ISD::SETULT: case ISD::SETOLT: Opc = Coffee::BLT; break; case ISD::SETLE: case ISD::SETULE: case ISD::SETOLE: Opc = Coffee::BELT; break; case ISD::SETNE: case ISD::SETUNE: case ISD::SETONE: Opc = Coffee::BNE; break; } SDValue Ops[] = { N3, N1, Chain, InFlag }; // TODO: do we need output glue here ? SDNode *ResNode = CurDAG->getMachineNode(Opc, dl, MVT::Other, MVT::Glue, Ops, 4); /***NOTE**/ // Is replaceUses function meant for Chain Node ? Chain = SDValue(ResNode, 0); ReplaceUses(SDValue(N, 0), SDValue(Chain.getNode(), Chain.getResNo())); return NULL; }
/// LowerCCCCallTo - functions arguments are copied from virtual regs to /// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. /// TODO: sret. SDValue MSP430TargetLowering::LowerCCCCallTo(SDValue Op, SelectionDAG &DAG, unsigned CC) { CallSDNode *TheCall = cast<CallSDNode>(Op.getNode()); SDValue Chain = TheCall->getChain(); SDValue Callee = TheCall->getCallee(); bool isVarArg = TheCall->isVarArg(); DebugLoc dl = Op.getDebugLoc(); // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs); CCInfo.AnalyzeCallOperands(TheCall, CC_MSP430); // Get a count of how many bytes are to be pushed on the stack. unsigned NumBytes = CCInfo.getNextStackOffset(); Chain = DAG.getCALLSEQ_START(Chain ,DAG.getConstant(NumBytes, getPointerTy(), true)); SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass; SmallVector<SDValue, 12> MemOpChains; SDValue StackPtr; // Walk the register/memloc assignments, inserting copies/loads. for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; // Arguments start after the 5 first operands of ISD::CALL SDValue Arg = TheCall->getArg(i); // Promote the value if needed. switch (VA.getLocInfo()) { default: assert(0 && "Unknown loc info!"); case CCValAssign::Full: break; case CCValAssign::SExt: Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); break; case CCValAssign::ZExt: Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg); break; case CCValAssign::AExt: Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); break; } // Arguments that can be passed on register must be kept at RegsToPass // vector if (VA.isRegLoc()) { RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); } else { assert(VA.isMemLoc()); if (StackPtr.getNode() == 0) StackPtr = DAG.getCopyFromReg(Chain, dl, MSP430::SPW, getPointerTy()); SDValue PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(), StackPtr, DAG.getIntPtrConstant(VA.getLocMemOffset())); MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, PseudoSourceValue::getStack(), VA.getLocMemOffset())); } } // Transform all store nodes into one single node because all store nodes are // independent of each other. if (!MemOpChains.empty()) Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &MemOpChains[0], MemOpChains.size()); // Build a sequence of copy-to-reg nodes chained together with token chain and // flag operands which copy the outgoing args into registers. The InFlag in // necessary since all emited instructions must be stuck together. SDValue InFlag; for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first, RegsToPass[i].second, InFlag); InFlag = Chain.getValue(1); } // If the callee is a GlobalAddress node (quite common, every direct call is) // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. // Likewise ExternalSymbol -> TargetExternalSymbol. if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i16); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i16); // Returns a chain & a flag for retval copy to use. SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Flag); SmallVector<SDValue, 8> Ops; Ops.push_back(Chain); Ops.push_back(Callee); // Add argument registers to the end of the list so that they are // known live into the call. for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) Ops.push_back(DAG.getRegister(RegsToPass[i].first, RegsToPass[i].second.getValueType())); if (InFlag.getNode()) Ops.push_back(InFlag); Chain = DAG.getNode(MSP430ISD::CALL, dl, NodeTys, &Ops[0], Ops.size()); InFlag = Chain.getValue(1); // Create the CALLSEQ_END node. Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, getPointerTy(), true), DAG.getConstant(0, getPointerTy(), true), InFlag); InFlag = Chain.getValue(1); // Handle result values, copying them out of physregs into vregs that we // return. return SDValue(LowerCallResult(Chain, InFlag, TheCall, CC, DAG), Op.getResNo()); }
/// LowerCCCArguments - transform physical registers into virtual registers and /// generate load operations for arguments places on the stack. // FIXME: struct return stuff // FIXME: varargs SDValue MSP430TargetLowering::LowerCCCArguments(SDValue Op, SelectionDAG &DAG) { MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo *MFI = MF.getFrameInfo(); MachineRegisterInfo &RegInfo = MF.getRegInfo(); SDValue Root = Op.getOperand(0); bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getZExtValue() != 0; unsigned CC = MF.getFunction()->getCallingConv(); DebugLoc dl = Op.getDebugLoc(); // Assign locations to all of the incoming arguments. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs); CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_MSP430); assert(!isVarArg && "Varargs not supported yet"); SmallVector<SDValue, 16> ArgValues; for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; if (VA.isRegLoc()) { // Arguments passed in registers MVT RegVT = VA.getLocVT(); switch (RegVT.getSimpleVT()) { default: cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: " << RegVT.getSimpleVT() << "\n"; abort(); case MVT::i16: unsigned VReg = RegInfo.createVirtualRegister(MSP430::GR16RegisterClass); RegInfo.addLiveIn(VA.getLocReg(), VReg); SDValue ArgValue = DAG.getCopyFromReg(Root, dl, VReg, RegVT); // If this is an 8-bit value, it is really passed promoted to 16 // bits. Insert an assert[sz]ext to capture this, then truncate to the // right size. if (VA.getLocInfo() == CCValAssign::SExt) ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue, DAG.getValueType(VA.getValVT())); else if (VA.getLocInfo() == CCValAssign::ZExt) ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue, DAG.getValueType(VA.getValVT())); if (VA.getLocInfo() != CCValAssign::Full) ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); ArgValues.push_back(ArgValue); } } else { // Sanity check assert(VA.isMemLoc()); // Load the argument to a virtual register unsigned ObjSize = VA.getLocVT().getSizeInBits()/8; if (ObjSize > 2) { cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: " << VA.getLocVT().getSimpleVT() << "\n"; } // Create the frame index object for this incoming parameter... int FI = MFI->CreateFixedObject(ObjSize, VA.getLocMemOffset()); // Create the SelectionDAG nodes corresponding to a load //from this parameter SDValue FIN = DAG.getFrameIndex(FI, MVT::i16); ArgValues.push_back(DAG.getLoad(VA.getLocVT(), dl, Root, FIN, PseudoSourceValue::getFixedStack(FI), 0)); } } ArgValues.push_back(Root); // Return the new list of results. return DAG.getNode(ISD::MERGE_VALUES, dl, Op.getNode()->getVTList(), &ArgValues[0], ArgValues.size()).getValue(Op.getResNo()); }
// selectMSUB - // Transforms a subgraph in CurDAG if the following pattern is found: // (addc Lo0, multLo), (sube Hi0, multHi), // where, // multHi/Lo: product of multiplication // Lo0: initial value of Lo register // Hi0: initial value of Hi register // Return true if pattern matching was successful. static bool selectMSUB(SDNode *SUBENode, SelectionDAG *CurDAG) { // SUBENode's second operand must be a flag output of an SUBC node in order // for the matching to be successful. SDNode *SUBCNode = SUBENode->getOperand(2).getNode(); if (SUBCNode->getOpcode() != ISD::SUBC) return false; SDValue MultHi = SUBENode->getOperand(1); SDValue MultLo = SUBCNode->getOperand(1); SDNode *MultNode = MultHi.getNode(); unsigned MultOpc = MultHi.getOpcode(); // MultHi and MultLo must be generated by the same node, if (MultLo.getNode() != MultNode) return false; // and it must be a multiplication. if (MultOpc != ISD::SMUL_LOHI && MultOpc != ISD::UMUL_LOHI) return false; // MultLo amd MultHi must be the first and second output of MultNode // respectively. if (MultHi.getResNo() != 1 || MultLo.getResNo() != 0) return false; // Transform this to a MSUB only if SUBENode and SUBCNode are the only users // of the values of MultNode, in which case MultNode will be removed in later // phases. // If there exist users other than SUBENode or SUBCNode, this function returns // here, which will result in MultNode being mapped to a single MULT // instruction node rather than a pair of MULT and MSUB instructions being // produced. if (!MultHi.hasOneUse() || !MultLo.hasOneUse()) return false; SDLoc DL(SUBENode); // Initialize accumulator. SDValue ACCIn = CurDAG->getNode(MipsISD::InsertLOHI, DL, MVT::Untyped, SUBCNode->getOperand(0), SUBENode->getOperand(0)); // create MipsSub(u) node MultOpc = MultOpc == ISD::UMUL_LOHI ? MipsISD::MSubu : MipsISD::MSub; SDValue MSub = CurDAG->getNode(MultOpc, DL, MVT::Glue, MultNode->getOperand(0),// Factor 0 MultNode->getOperand(1),// Factor 1 ACCIn); // replace uses of sube and subc here if (!SDValue(SUBCNode, 0).use_empty()) { SDValue LoIdx = CurDAG->getConstant(Mips::sub_lo, MVT::i32); SDValue LoOut = CurDAG->getNode(MipsISD::ExtractLOHI, DL, MVT::i32, MSub, LoIdx); CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBCNode, 0), LoOut); } if (!SDValue(SUBENode, 0).use_empty()) { SDValue HiIdx = CurDAG->getConstant(Mips::sub_hi, MVT::i32); SDValue HiOut = CurDAG->getNode(MipsISD::ExtractLOHI, DL, MVT::i32, MSub, HiIdx); CurDAG->ReplaceAllUsesOfValueWith(SDValue(SUBENode, 0), HiOut); } return true; }