Index: lib/Target/Mips/MicroMips32r6InstrInfo.td =================================================================== --- lib/Target/Mips/MicroMips32r6InstrInfo.td +++ lib/Target/Mips/MicroMips32r6InstrInfo.td @@ -1709,8 +1709,6 @@ def : MipsPat<(store GPRMM16:$src, addrimm4lsl2:$addr), (SW16_MMR6 GPRMM16:$src, addrimm4lsl2:$addr)>, ISA_MICROMIPS32R6; -def : MipsPat<(subc GPR32:$lhs, GPR32:$rhs), - (SUBU_MMR6 GPR32:$lhs, GPR32:$rhs)>, ISA_MICROMIPS32R6; def : MipsPat<(select i32:$cond, i32:$t, i32:$f), (OR_MM (SELNEZ_MMR6 i32:$t, i32:$cond), Index: lib/Target/Mips/MicroMipsInstrInfo.td =================================================================== --- lib/Target/Mips/MicroMipsInstrInfo.td +++ lib/Target/Mips/MicroMipsInstrInfo.td @@ -1201,8 +1201,6 @@ (LW16_MM addrimm4lsl2:$addr)>; def : MipsPat<(load addr:$addr), (LW_MM addr:$addr)>; - def : MipsPat<(subc GPR32:$lhs, GPR32:$rhs), - (SUBu_MM GPR32:$lhs, GPR32:$rhs)>; def : MipsPat<(i32 (extloadi1 addr:$src)), (LBu_MM addr:$src)>, ISA_MICROMIPS; Index: lib/Target/Mips/Mips64InstrInfo.td =================================================================== --- lib/Target/Mips/Mips64InstrInfo.td +++ lib/Target/Mips/Mips64InstrInfo.td @@ -740,16 +740,6 @@ // bswap MipsPattern def : MipsPat<(bswap GPR64:$rt), (DSHD (DSBH GPR64:$rt))>, ISA_MIPS64R2; -// Carry pattern -let AdditionalPredicates = [NotInMicroMips] in { - def : MipsPat<(subc GPR64:$lhs, GPR64:$rhs), - (DSUBu GPR64:$lhs, GPR64:$rhs)>; - def : MipsPat<(addc GPR64:$lhs, GPR64:$rhs), - (DADDu GPR64:$lhs, GPR64:$rhs)>, ASE_NOT_DSP; - def : MipsPat<(addc GPR64:$lhs, immSExt16:$imm), - (DADDiu GPR64:$lhs, imm:$imm)>, ASE_NOT_DSP; -} - // Octeon bbit0/bbit1 MipsPattern def : MipsPat<(brcond (i32 (seteq (and i64:$lhs, PowerOf2LO:$mask), 0)), bb:$dst), (BBIT0 i64:$lhs, (Log2LO PowerOf2LO:$mask), bb:$dst)>, ASE_MIPS64_CNMIPS; Index: lib/Target/Mips/MipsDSPInstrInfo.td =================================================================== --- lib/Target/Mips/MipsDSPInstrInfo.td +++ lib/Target/Mips/MipsDSPInstrInfo.td @@ -1359,9 +1359,7 @@ def : DSPBinPat; def : DSPBinPat; def : DSPBinPat; -def : DSPBinPat; def : DSPBinPat; -def : DSPBinPat; // Shift immediate patterns. class DSPShiftPat; -// Carry MipsPatterns -let AdditionalPredicates = [NotInMicroMips] in { - def : MipsPat<(subc GPR32:$lhs, GPR32:$rhs), - (SUBu GPR32:$lhs, GPR32:$rhs)>; -} -def : MipsPat<(addc GPR32:$lhs, GPR32:$rhs), - (ADDu GPR32:$lhs, GPR32:$rhs)>, ASE_NOT_DSP; -def : MipsPat<(addc GPR32:$src, immSExt16:$imm), - (ADDiu GPR32:$src, imm:$imm)>, ASE_NOT_DSP; - // Support multiplication for pre-Mips32 targets that don't have // the MUL instruction. def : MipsPat<(mul GPR32:$lhs, GPR32:$rhs), Index: lib/Target/Mips/MipsSEISelDAGToDAG.h =================================================================== --- lib/Target/Mips/MipsSEISelDAGToDAG.h +++ lib/Target/Mips/MipsSEISelDAGToDAG.h @@ -41,7 +41,7 @@ const SDLoc &dl, EVT Ty, bool HasLo, bool HasHi); - void selectAddE(SDNode *Node, const SDLoc &DL) const; + void selectADDCARRY(SDNode *Node, const SDLoc &DL); bool selectAddrFrameIndex(SDValue Addr, SDValue &Base, SDValue &Offset) const; bool selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, SDValue &Offset, Index: lib/Target/Mips/MipsSEISelDAGToDAG.cpp =================================================================== --- lib/Target/Mips/MipsSEISelDAGToDAG.cpp +++ lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -245,64 +245,73 @@ } } -void MipsSEDAGToDAGISel::selectAddE(SDNode *Node, const SDLoc &DL) const { - SDValue InFlag = Node->getOperand(2); - unsigned Opc = InFlag.getOpcode(); - SDValue LHS = Node->getOperand(0), RHS = Node->getOperand(1); - EVT VT = LHS.getValueType(); - - // In the base case, we can rely on the carry bit from the addsc - // instruction. - if (Opc == ISD::ADDC) { - SDValue Ops[3] = {LHS, RHS, InFlag}; - CurDAG->SelectNodeTo(Node, Mips::ADDWC, VT, MVT::Glue, Ops); - return; - } - - assert(Opc == ISD::ADDE && "ISD::ADDE not in a chain of ADDE nodes!"); - - // The more complex case is when there is a chain of ISD::ADDE nodes like: - // (adde (adde (adde (addc a b) c) d) e). - // - // The addwc instruction does not write to the carry bit, instead it writes - // to bit 20 of the dsp control register. To match this series of nodes, each - // intermediate adde node must be expanded to write the carry bit before the - // addition. - - // Start by reading the overflow field for addsc and moving the value to the - // carry field. The usage of 1 here with MipsISD::RDDSP / Mips::WRDSP - // corresponds to reading/writing the entire control register to/from a GPR. - - SDValue CstOne = CurDAG->getTargetConstant(1, DL, MVT::i32); +static SDValue extractCarryFlag(SDNode *N, unsigned Position, + SelectionDAG *DAG) { + SDLoc DL(N); - SDValue OuFlag = CurDAG->getTargetConstant(20, DL, MVT::i32); + SDValue CstOne = DAG->getTargetConstant(1, DL, MVT::i32); + SDValue OuFlag = DAG->getTargetConstant(Position, DL, MVT::i32); + // Extract the value of the carry flag. The usage of 1 here with + // MipsISD::RDDSP corresponds to reading/writing the entire control + // register to a GPR. SDNode *DSPCtrlField = - CurDAG->getMachineNode(Mips::RDDSP, DL, MVT::i32, MVT::Glue, CstOne, InFlag); + DAG->getMachineNode(Mips::RDDSP, DL, MVT::i32, MVT::Glue, CstOne, + SDValue(N, 1)); - SDNode *Carry = CurDAG->getMachineNode( - Mips::EXT, DL, MVT::i32, SDValue(DSPCtrlField, 0), OuFlag, CstOne); + SDNode *CarryNode = + DAG->getMachineNode(Mips::EXT, DL, MVT::i32, SDValue(DSPCtrlField, 0), + OuFlag, CstOne); + return SDValue(CarryNode, 0); +} - SDValue Ops[4] = {SDValue(DSPCtrlField, 0), - CurDAG->getTargetConstant(6, DL, MVT::i32), CstOne, - SDValue(Carry, 0)}; - SDNode *DSPCFWithCarry = CurDAG->getMachineNode(Mips::INS, DL, MVT::i32, Ops); +void MipsSEDAGToDAGISel::selectADDCARRY(SDNode *Node, const SDLoc &DL) { + SDValue LHS = Node->getOperand(0); + SDValue RHS = Node->getOperand(1); + SDValue CarryIn = Node->getOperand(2); - // My reading of the MIPS DSP 3.01 specification isn't as clear as I - // would like about whether bit 20 always gets overwritten by addwc. - // Hence take an extremely conservative view and presume it's sticky. We - // therefore need to clear it. + EVT VT = LHS.getValueType(); - SDValue Zero = CurDAG->getRegister(Mips::ZERO, MVT::i32); + SDNode *CarryNode; + if (CarryIn.getOpcode() == ISD::UADDO && CarryIn.getResNo() == 1 && + CarryIn.hasOneUse()) { + // In the base case, we can rely on the carry bit from the addsc + // instruction. + SDValue CarryLHS = CarryIn.getOperand(0); + SDValue CarryRHS = CarryIn.getOperand(1); + + CarryNode = + CurDAG->getMachineNode(Mips::ADDSC, SDLoc(CarryIn), + CarryIn.getValueType(), MVT::Glue, + CarryLHS, CarryRHS); + + // Also replace add result to avoid selecting that node twice. + SDValue UAddOResult = CarryIn.getValue(0); + if (!UAddOResult.use_empty()) + ReplaceUses(UAddOResult, SDValue(CarryNode, 0)); + } else { + // In more coplex cases, we recreate the carry using (ADDSC Carry, -1). + EVT CarryVT = CarryIn.getValueType(); + SDValue CstAllOnes = CurDAG->getTargetConstant(-1, DL, CarryVT); + CarryNode = CurDAG->getMachineNode(Mips::ADDSC, DL, CarryVT, MVT::Glue, + CarryIn, CstAllOnes); + } - SDValue InsOps[4] = {Zero, OuFlag, CstOne, SDValue(DSPCFWithCarry, 0)}; - SDNode *DSPCtrlFinal = CurDAG->getMachineNode(Mips::INS, DL, MVT::i32, InsOps); + SDValue Ops[3] = {LHS, RHS, SDValue(CarryNode, 1)}; + SDNode *Result = + CurDAG->getMachineNode(Mips::ADDWC, DL, VT, MVT::Glue, Ops); - SDNode *WrDSP = CurDAG->getMachineNode(Mips::WRDSP, DL, MVT::Glue, - SDValue(DSPCtrlFinal, 0), CstOne); + if (!SDValue(Node, 0).use_empty()) + ReplaceUses(SDValue(Node, 0), SDValue(Result, 0)); - SDValue Operands[3] = {LHS, RHS, SDValue(WrDSP, 0)}; - CurDAG->SelectNodeTo(Node, Mips::ADDWC, VT, MVT::Glue, Operands); + if (!SDValue(Node, 1).use_empty()) { + // The addwc instruction does not write to the carry bit, instead it writes + // to bit 20 of the dsp control register. + ReplaceUses(SDValue(Node, 1), extractCarryFlag(Result, 20, CurDAG)); + } + + CurDAG->RemoveDeadNode(Node); + return; } /// Match frameindex @@ -783,8 +792,30 @@ switch(Opcode) { default: break; - case ISD::ADDE: { - selectAddE(Node, DL); + case ISD::UADDO: { + SDValue LHS = Node->getOperand(0); + SDValue RHS = Node->getOperand(1); + + EVT VT = LHS.getValueType(); + + SDNode *Result = + CurDAG->getMachineNode(Mips::ADDSC, DL, VT, MVT::Glue, LHS, RHS); + + if (!SDValue(Node, 0).use_empty()) + ReplaceUses(SDValue(Node, 0), SDValue(Result, 0)); + + if (!SDValue(Node, 1).use_empty()) { + // The addsc instruction does write to the carry bit, namely, it writes + // to bit 6 of the dsp control register. + ReplaceUses(SDValue(Node, 1), extractCarryFlag(Result, 6, CurDAG)); + } + + CurDAG->RemoveDeadNode(Node); + return true; + } + + case ISD::ADDCARRY: { + selectADDCARRY(Node, DL); return true; } Index: lib/Target/Mips/MipsSEISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsSEISelLowering.cpp +++ lib/Target/Mips/MipsSEISelLowering.cpp @@ -106,8 +106,8 @@ setTargetDAGCombine(ISD::VSELECT); if (Subtarget.hasMips32r2()) { - setOperationAction(ISD::ADDC, MVT::i32, Legal); - setOperationAction(ISD::ADDE, MVT::i32, Legal); + setOperationAction(ISD::UADDO, MVT::i32, Legal); + setOperationAction(ISD::ADDCARRY, MVT::i32, Legal); } }