Index: clang/test/CodeGen/mips16-mult.c =================================================================== --- /dev/null +++ clang/test/CodeGen/mips16-mult.c @@ -0,0 +1,9 @@ +// REQUIRES: mips-registered-target +// RUN: %clang --target=mipsel-unknown-linux -mips16 -c -o %t %s + +// Check for BugZilla bug 49146 "Crash with MIPS16 Multiply". +// The bug does not manifest when using the "-S" or "-emit-llvm" options. + +unsigned do_mult(unsigned n, unsigned m) { + return n * m; +} Index: llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp +++ llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp @@ -191,6 +191,13 @@ default: break; + case ISD::MUL: { + MultOpc = Mips::MultRxRy16; + auto LoHi = selectMULT(Node, MultOpc, DL, NodeTy, true, false); + ReplaceNode(Node, LoHi.first); + return true; + } + /// Mul with two results case ISD::SMUL_LOHI: case ISD::UMUL_LOHI: { Index: llvm/lib/Target/Mips/Mips16InstrInfo.td =================================================================== --- llvm/lib/Target/Mips/Mips16InstrInfo.td +++ llvm/lib/Target/Mips/Mips16InstrInfo.td @@ -298,25 +298,6 @@ FI8_MOV32R16<(outs GPR32:$r32), (ins CPU16Regs:$rz), !strconcat(asmstr, "\t$r32, $rz"), [], itin>; -// -// This are pseudo formats for multiply -// This first one can be changed to non-pseudo now. -// -// MULT -// -class FMULT16_ins : - MipsPseudo16<(outs), (ins CPU16Regs:$rx, CPU16Regs:$ry), - !strconcat(asmstr, "\t$rx, $ry"), []>; - -// -// MULT-LO -// -class FMULT16_LO_ins : - MipsPseudo16<(outs CPU16Regs:$rz), (ins CPU16Regs:$rx, CPU16Regs:$ry), - !strconcat(asmstr, "\t$rx, $ry\n\tmflo\t$rz"), []> { - let isCodeGenOnly=1; -} - // // RR-type instruction format // @@ -347,6 +328,10 @@ FRR16 ; +class FRR16_mult_ins f, string asmstr, InstrItinClass itin> : + FRR16 ; + class FUnaryRR16_ins f, string asmstr, InstrItinClass itin> : FRR16 ; @@ -731,6 +716,7 @@ def DivuRxRy16: FRR16_div_ins<0b11011, "divu", IIM16Alu> { let Defs = [HI0, LO0]; } + // // Format: JAL target MIPS16e // Purpose: Jump and Link @@ -892,29 +878,12 @@ let isMoveReg = 0; } -// -// Pseudo Instruction for mult -// -def MultRxRy16: FMULT16_ins<"mult", IIM16Alu> { - let isCommutable = 1; - let hasSideEffects = 0; - let Defs = [HI0, LO0]; -} - -def MultuRxRy16: FMULT16_ins<"multu", IIM16Alu> { - let isCommutable = 1; - let hasSideEffects = 0; - let Defs = [HI0, LO0]; -} - // // Format: MULT rx, ry MIPS16e // Purpose: Multiply Word // To multiply 32-bit signed integers. // -def MultRxRyRz16: FMULT16_LO_ins<"mult", IIM16Alu> { - let isCommutable = 1; - let hasSideEffects = 0; +def MultRxRy16: FRR16_mult_ins<0b11000, "mult", IIM16Alu> { let Defs = [HI0, LO0]; } @@ -923,12 +892,11 @@ // Purpose: Multiply Unsigned Word // To multiply 32-bit unsigned integers. // -def MultuRxRyRz16: FMULT16_LO_ins<"multu", IIM16Alu> { - let isCommutable = 1; - let hasSideEffects = 0; +def MultuRxRy16: FRR16_mult_ins<0b11001, "multu", IIM16Alu> { let Defs = [HI0, LO0]; } + // // Format: NEG rx, ry MIPS16e // Purpose: Negate @@ -1313,7 +1281,6 @@ def: ArithLogic16_pat; def: ArithLogic16_pat; -def: ArithLogic16_pat; def: ArithLogic16_pat; def: ArithLogic16_pat; def: ArithLogic16_pat; @@ -1557,6 +1524,20 @@ <(MipsDivRemU16 CPU16Regs:$rx, CPU16Regs:$ry), (DivuRxRy16 CPU16Regs:$rx, CPU16Regs:$ry)>; +// +// MipsMult +// +def: Mips16Pat + <(MipsMult16 CPU16Regs:$rx, CPU16Regs:$ry), + (MultRxRy16 CPU16Regs:$rx, CPU16Regs:$ry)>; + +// +// MipsMultu +// +def: Mips16Pat + <(MipsMultu16 CPU16Regs:$rx, CPU16Regs:$ry), + (MultuRxRy16 CPU16Regs:$rx, CPU16Regs:$ry)>; + // signed a,b // x = (a>=b)?x:y // Index: llvm/lib/Target/Mips/MipsISelLowering.h =================================================================== --- llvm/lib/Target/Mips/MipsISelLowering.h +++ llvm/lib/Target/Mips/MipsISelLowering.h @@ -54,203 +54,205 @@ namespace MipsISD { - enum NodeType : unsigned { - // Start the numbering from where ISD NodeType finishes. - FIRST_NUMBER = ISD::BUILTIN_OP_END, + enum NodeType : unsigned { + // Start the numbering from where ISD NodeType finishes. + FIRST_NUMBER = ISD::BUILTIN_OP_END, - // Jump and link (call) - JmpLink, + // Jump and link (call) + JmpLink, - // Tail call - TailCall, + // Tail call + TailCall, - // Get the Highest (63-48) 16 bits from a 64-bit immediate - Highest, + // Get the Highest (63-48) 16 bits from a 64-bit immediate + Highest, - // Get the Higher (47-32) 16 bits from a 64-bit immediate - Higher, + // Get the Higher (47-32) 16 bits from a 64-bit immediate + Higher, - // Get the High 16 bits from a 32/64-bit immediate - // No relation with Mips Hi register - Hi, + // Get the High 16 bits from a 32/64-bit immediate + // No relation with Mips Hi register + Hi, - // Get the Lower 16 bits from a 32/64-bit immediate - // No relation with Mips Lo register - Lo, + // Get the Lower 16 bits from a 32/64-bit immediate + // No relation with Mips Lo register + Lo, - // Get the High 16 bits from a 32 bit immediate for accessing the GOT. - GotHi, + // Get the High 16 bits from a 32 bit immediate for accessing the GOT. + GotHi, - // Get the High 16 bits from a 32-bit immediate for accessing TLS. - TlsHi, + // Get the High 16 bits from a 32-bit immediate for accessing TLS. + TlsHi, - // Handle gp_rel (small data/bss sections) relocation. - GPRel, - - // Thread Pointer - ThreadPointer, - - // Vector Floating Point Multiply and Subtract - FMS, - - // Floating Point Branch Conditional - FPBrcond, - - // Floating Point Compare - FPCmp, - - // Floating point select - FSELECT, - - // Node used to generate an MTC1 i32 to f64 instruction - MTC1_D64, - - // Floating Point Conditional Moves - CMovFP_T, - CMovFP_F, - - // FP-to-int truncation node. - TruncIntFP, - - // Return - Ret, - - // Interrupt, exception, error trap Return - ERet, - - // Software Exception Return. - EH_RETURN, - - // Node used to extract integer from accumulator. - MFHI, - MFLO, - - // Node used to insert integers to accumulator. - MTLOHI, - - // Mult nodes. - Mult, - Multu, - - // MAdd/Sub nodes - MAdd, - MAddu, - MSub, - MSubu, - - // DivRem(u) - DivRem, - DivRemU, - DivRem16, - DivRemU16, - - BuildPairF64, - ExtractElementF64, - - Wrapper, - - DynAlloc, - - Sync, - - Ext, - Ins, - CIns, - - // EXTR.W instrinsic nodes. - EXTP, - EXTPDP, - EXTR_S_H, - EXTR_W, - EXTR_R_W, - EXTR_RS_W, - SHILO, - MTHLIP, - - // DPA.W intrinsic nodes. - MULSAQ_S_W_PH, - MAQ_S_W_PHL, - MAQ_S_W_PHR, - MAQ_SA_W_PHL, - MAQ_SA_W_PHR, - DPAU_H_QBL, - DPAU_H_QBR, - DPSU_H_QBL, - DPSU_H_QBR, - DPAQ_S_W_PH, - DPSQ_S_W_PH, - DPAQ_SA_L_W, - DPSQ_SA_L_W, - DPA_W_PH, - DPS_W_PH, - DPAQX_S_W_PH, - DPAQX_SA_W_PH, - DPAX_W_PH, - DPSX_W_PH, - DPSQX_S_W_PH, - DPSQX_SA_W_PH, - MULSA_W_PH, - - MULT, - MULTU, - MADD_DSP, - MADDU_DSP, - MSUB_DSP, - MSUBU_DSP, - - // DSP shift nodes. - SHLL_DSP, - SHRA_DSP, - SHRL_DSP, - - // DSP setcc and select_cc nodes. - SETCC_DSP, - SELECT_CC_DSP, - - // Vector comparisons. - // These take a vector and return a boolean. - VALL_ZERO, - VANY_ZERO, - VALL_NONZERO, - VANY_NONZERO, - - // These take a vector and return a vector bitmask. - VCEQ, - VCLE_S, - VCLE_U, - VCLT_S, - VCLT_U, - - // Vector Shuffle with mask as an operand - VSHF, // Generic shuffle - SHF, // 4-element set shuffle. - ILVEV, // Interleave even elements - ILVOD, // Interleave odd elements - ILVL, // Interleave left elements - ILVR, // Interleave right elements - PCKEV, // Pack even elements - PCKOD, // Pack odd elements - - // Vector Lane Copy - INSVE, // Copy element from one vector to another - - // Combined (XOR (OR $a, $b), -1) - VNOR, - - // Extended vector element extraction - VEXTRACT_SEXT_ELT, - VEXTRACT_ZEXT_ELT, - - // Load/Store Left/Right nodes. - LWL = ISD::FIRST_TARGET_MEMORY_OPCODE, - LWR, - SWL, - SWR, - LDL, - LDR, - SDL, - SDR - }; + // Handle gp_rel (small data/bss sections) relocation. + GPRel, + + // Thread Pointer + ThreadPointer, + + // Vector Floating Point Multiply and Subtract + FMS, + + // Floating Point Branch Conditional + FPBrcond, + + // Floating Point Compare + FPCmp, + + // Floating point select + FSELECT, + + // Node used to generate an MTC1 i32 to f64 instruction + MTC1_D64, + + // Floating Point Conditional Moves + CMovFP_T, + CMovFP_F, + + // FP-to-int truncation node. + TruncIntFP, + + // Return + Ret, + + // Interrupt, exception, error trap Return + ERet, + + // Software Exception Return. + EH_RETURN, + + // Node used to extract integer from accumulator. + MFHI, + MFLO, + + // Node used to insert integers to accumulator. + MTLOHI, + + // Mult nodes. + Mult, + Multu, + Mult16, + Multu16, + + // MAdd/Sub nodes + MAdd, + MAddu, + MSub, + MSubu, + + // DivRem(u) + DivRem, + DivRemU, + DivRem16, + DivRemU16, + + BuildPairF64, + ExtractElementF64, + + Wrapper, + + DynAlloc, + + Sync, + + Ext, + Ins, + CIns, + + // EXTR.W instrinsic nodes. + EXTP, + EXTPDP, + EXTR_S_H, + EXTR_W, + EXTR_R_W, + EXTR_RS_W, + SHILO, + MTHLIP, + + // DPA.W intrinsic nodes. + MULSAQ_S_W_PH, + MAQ_S_W_PHL, + MAQ_S_W_PHR, + MAQ_SA_W_PHL, + MAQ_SA_W_PHR, + DPAU_H_QBL, + DPAU_H_QBR, + DPSU_H_QBL, + DPSU_H_QBR, + DPAQ_S_W_PH, + DPSQ_S_W_PH, + DPAQ_SA_L_W, + DPSQ_SA_L_W, + DPA_W_PH, + DPS_W_PH, + DPAQX_S_W_PH, + DPAQX_SA_W_PH, + DPAX_W_PH, + DPSX_W_PH, + DPSQX_S_W_PH, + DPSQX_SA_W_PH, + MULSA_W_PH, + + MULT, + MULTU, + MADD_DSP, + MADDU_DSP, + MSUB_DSP, + MSUBU_DSP, + + // DSP shift nodes. + SHLL_DSP, + SHRA_DSP, + SHRL_DSP, + + // DSP setcc and select_cc nodes. + SETCC_DSP, + SELECT_CC_DSP, + + // Vector comparisons. + // These take a vector and return a boolean. + VALL_ZERO, + VANY_ZERO, + VALL_NONZERO, + VANY_NONZERO, + + // These take a vector and return a vector bitmask. + VCEQ, + VCLE_S, + VCLE_U, + VCLT_S, + VCLT_U, + + // Vector Shuffle with mask as an operand + VSHF, // Generic shuffle + SHF, // 4-element set shuffle. + ILVEV, // Interleave even elements + ILVOD, // Interleave odd elements + ILVL, // Interleave left elements + ILVR, // Interleave right elements + PCKEV, // Pack even elements + PCKOD, // Pack odd elements + + // Vector Lane Copy + INSVE, // Copy element from one vector to another + + // Combined (XOR (OR $a, $b), -1) + VNOR, + + // Extended vector element extraction + VEXTRACT_SEXT_ELT, + VEXTRACT_ZEXT_ELT, + + // Load/Store Left/Right nodes. + LWL = ISD::FIRST_TARGET_MEMORY_OPCODE, + LWR, + SWL, + SWR, + LDL, + LDR, + SDL, + SDR + }; } // ene namespace MipsISD Index: llvm/lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- llvm/lib/Target/Mips/MipsISelLowering.cpp +++ llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -205,6 +205,10 @@ case MipsISD::MTLOHI: return "MipsISD::MTLOHI"; case MipsISD::Mult: return "MipsISD::Mult"; case MipsISD::Multu: return "MipsISD::Multu"; + case MipsISD::Mult16: + return "MipsISD::Mult16"; + case MipsISD::Multu16: + return "MipsISD::Multu16"; case MipsISD::MAdd: return "MipsISD::MAdd"; case MipsISD::MAddu: return "MipsISD::MAddu"; case MipsISD::MSub: return "MipsISD::MSub"; Index: llvm/lib/Target/Mips/MipsInstrInfo.td =================================================================== --- llvm/lib/Target/Mips/MipsInstrInfo.td +++ llvm/lib/Target/Mips/MipsInstrInfo.td @@ -30,7 +30,7 @@ def SDT_MipsMAddMSub : SDTypeProfile<1, 3, [SDTCisVT<0, untyped>, SDTCisSameAs<0, 3>, SDTCisVT<1, i32>, SDTCisSameAs<1, 2>]>; -def SDT_MipsDivRem16 : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>]>; +def SDT_MipsMultDiv16 : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>]>; def SDT_MipsThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>; @@ -100,8 +100,10 @@ def MipsMTLOHI : SDNode<"MipsISD::MTLOHI", SDT_MTLOHI>; // Mult nodes. -def MipsMult : SDNode<"MipsISD::Mult", SDT_MipsMultDiv>; -def MipsMultu : SDNode<"MipsISD::Multu", SDT_MipsMultDiv>; +def MipsMult : SDNode<"MipsISD::Mult", SDT_MipsMultDiv>; +def MipsMultu : SDNode<"MipsISD::Multu", SDT_MipsMultDiv>; +def MipsMult16 : SDNode<"MipsISD::Mult16", SDT_MipsMultDiv16>; +def MipsMultu16 : SDNode<"MipsISD::Multu16", SDT_MipsMultDiv16>; // MAdd*/MSub* nodes def MipsMAdd : SDNode<"MipsISD::MAdd", SDT_MipsMAddMSub>; @@ -112,9 +114,9 @@ // DivRem(u) nodes def MipsDivRem : SDNode<"MipsISD::DivRem", SDT_MipsMultDiv>; def MipsDivRemU : SDNode<"MipsISD::DivRemU", SDT_MipsMultDiv>; -def MipsDivRem16 : SDNode<"MipsISD::DivRem16", SDT_MipsDivRem16, +def MipsDivRem16 : SDNode<"MipsISD::DivRem16", SDT_MipsMultDiv16, [SDNPOutGlue]>; -def MipsDivRemU16 : SDNode<"MipsISD::DivRemU16", SDT_MipsDivRem16, +def MipsDivRemU16 : SDNode<"MipsISD::DivRemU16", SDT_MipsMultDiv16, [SDNPOutGlue]>; // Target constant nodes that are not part of any isel patterns and remain Index: llvm/lib/Target/Mips/MipsScheduleGeneric.td =================================================================== --- llvm/lib/Target/Mips/MipsScheduleGeneric.td +++ llvm/lib/Target/Mips/MipsScheduleGeneric.td @@ -203,8 +203,7 @@ // MIPS16e // ======= -def : InstRW<[GenericWriteHILO], (instrs MultRxRy16, MultuRxRy16, - MultRxRyRz16, MultuRxRyRz16)>; +def : InstRW<[GenericWriteHILO], (instrs MultRxRy16, MultuRxRy16)>; def : InstRW<[GenericWriteDIV], (instrs DivRxRy16)>;