diff --git a/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp b/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp index 01a89bc2fc8a..535c0c93b1c4 100644 --- a/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp +++ b/llvm/lib/Target/TMS34010/TMS34010ISelLowering.cpp @@ -31,6 +31,11 @@ TMS34010TargetLowering::TMS34010TargetLowering(const TargetMachine &TM, : TargetLowering(TM, STI) { addRegisterClass(MVT::i32, &TMS34010::ARegsRegClass); + // The backend has no SEXT-as-field-width path that suits every width, so + // sign extension in register selects the SEXT8/SEXT16 pseudo and expands to + // a shift pair after instruction selection (see EmitInstrWithCustomInserter). + // DAGCombine forms these nodes from ordinary `short` shift pairs. + // MOVB is an 8-bit sign-extending load and an 8-bit truncating store. setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i8, Legal); setTruncStoreAction(MVT::i32, MVT::i8, Legal); @@ -45,6 +50,16 @@ TMS34010TargetLowering::TMS34010TargetLowering(const TargetMachine &TM, setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, MVT::i8, Custom); setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, MVT::i16, Custom); + // Multiply and divide are single register-register instructions (MPYS/DIVS/ + // DIVU) with an odd tied destination; see TMS34010InstrInfo.td. The + // remainder has no direct 32-bit form, so it is expanded from the quotient + // and a multiply in LowerOperation. + setOperationAction(ISD::MUL, MVT::i32, Legal); + setOperationAction(ISD::SDIV, MVT::i32, Legal); + setOperationAction(ISD::UDIV, MVT::i32, Legal); + setOperationAction(ISD::SREM, MVT::i32, Custom); + setOperationAction(ISD::UREM, MVT::i32, Custom); + // There is no conditional move or dedicated setcc result; let the generic // legalizer turn setcc into a select_cc over 1/0 and select into a // select_cc, then lower the compare and branch ourselves. @@ -476,6 +491,21 @@ SDValue TMS34010TargetLowering::LowerOperation(SDValue Op, return LowerBR_CC(Op, DAG); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); + case ISD::SREM: + case ISD::UREM: { + // The odd-destination DIVS/DIVU leaves only the quotient. Reconstruct the + // remainder in the C semantics (which truncates the quotient toward zero): + // rem = dividend - quotient * divisor + // signed and unsigned remainder both use the corresponding divide and the + // same low-32-bit product, so one expansion covers both. + SDLoc DL(Op); + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + unsigned DivOpc = Op.getOpcode() == ISD::SREM ? ISD::SDIV : ISD::UDIV; + SDValue Q = DAG.getNode(DivOpc, DL, MVT::i32, LHS, RHS); + SDValue P = DAG.getNode(ISD::MUL, DL, MVT::i32, Q, RHS); + return DAG.getNode(ISD::SUB, DL, MVT::i32, LHS, P); + } default: llvm_unreachable("unexpected TMS34010 custom lowering operation"); } @@ -486,6 +516,31 @@ MachineBasicBlock *TMS34010TargetLowering::EmitInstrWithCustomInserter( switch (MI.getOpcode()) { case TMS34010::SELECTCC: return emitSelectCC(MI, MBB); + case TMS34010::SEXT8: + case TMS34010::SEXT16: { + // dst = (src << K) >> K, arithmetic, with K = 32 - width. + MachineFunction *MF = MBB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo(); + const TargetRegisterClass *RC = &TMS34010::ARegsRegClass; + const DebugLoc &DL = MI.getDebugLoc(); + Register Dst = MI.getOperand(0).getReg(); + Register Src = MI.getOperand(1).getReg(); + int64_t Shift = MI.getOpcode() == TMS34010::SEXT8 ? 24 : 16; + // A machine virtual register has one definition before SSA is destroyed, + // so each step produces a fresh one. + Register T1 = MRI.createVirtualRegister(RC); + Register T2 = MRI.createVirtualRegister(RC); + BuildMI(*MBB, MI, DL, TII.get(TargetOpcode::COPY), T1).addReg(Src); + BuildMI(*MBB, MI, DL, TII.get(TMS34010::SLLK), T2) + .addReg(T1) + .addImm(Shift); + BuildMI(*MBB, MI, DL, TII.get(TMS34010::SRAK), Dst) + .addReg(T2) + .addImm(Shift); + MI.eraseFromParent(); + return MBB; + } default: return nullptr; } diff --git a/llvm/lib/Target/TMS34010/TMS34010InstrInfo.td b/llvm/lib/Target/TMS34010/TMS34010InstrInfo.td index 8c838c3d327d..76ecbece2187 100644 --- a/llvm/lib/Target/TMS34010/TMS34010InstrInfo.td +++ b/llvm/lib/Target/TMS34010/TMS34010InstrInfo.td @@ -154,6 +154,82 @@ def XOR : TMS34010Inst<(outs ARegs:$dst), (ins ARegs:$src, ARegs:$val), let Inst{3-0} = dst{3-0}; } +// MPYS Rs, Rd: 0101 110S SSSR DDDD (0x5C00). Signed multiply: Rd is the +// 32-bit multiplicand and the low 32 bits of the product are stored back in +// Rd when Rd is odd. The ABI keeps FS1 = 32, so Rs is a full 32-bit multiplier +// and the low half of the signed and unsigned products is identical. An even +// Rd would write the high half to Rd and the low half to Rd+1, clobbering the +// neighbouring register, so the tied destination is ARegsOdd. +def MPYS : TMS34010Inst<(outs ARegsOdd:$dst), (ins ARegs:$src, ARegsOdd:$val), + "MPYS $src, $dst", + [(set ARegsOdd:$dst, (mul ARegs:$src, + ARegsOdd:$val))]> { + let Constraints = "$val = $dst"; + let Defs = [ST]; + bits<5> src; + bits<5> val; + bits<5> dst; + let Inst{15-9} = 0b0101110; + let Inst{8-5} = src{3-0}; + let Inst{4} = dst{4}; + let Inst{3-0} = dst{3-0}; +} + +// MPYU Rs, Rd: 0101 111S SSSR DDDD (0x5E00). Unsigned multiply. A 16x16 +// unsigned product reaches the DAG as both operands masked to 16 bits, which +// is the natural place to select MPYU; the low 32 bits are identical to a +// signed multiply, so this is an encoding choice, not a different result. +def MPYU : TMS34010Inst<(outs ARegsOdd:$dst), (ins ARegs:$src, ARegsOdd:$val), + "MPYU $src, $dst", + [(set ARegsOdd:$dst, + (mul (and i32:$src, 65535), + (and ARegsOdd:$val, 65535)))]> { + let Constraints = "$val = $dst"; + let Defs = [ST]; + bits<5> src; + bits<5> val; + bits<5> dst; + let Inst{15-9} = 0b0101111; + let Inst{8-5} = src{3-0}; + let Inst{4} = dst{4}; + let Inst{3-0} = dst{3-0}; +} + +// DIVS Rs, Rd: 0101 100S SSSR DDDD (0x5800). Signed divide of the 32-bit +// dividend in Rd by Rs. With an odd Rd the quotient replaces Rd and no +// remainder is returned; the remainder is synthesised as dividend - +// quotient * divisor (the hardware only returns it with an even Rd pair). +def DIVS : TMS34010Inst<(outs ARegsOdd:$dst), (ins ARegs:$src, ARegsOdd:$val), + "DIVS $src, $dst", + [(set ARegsOdd:$dst, (sdiv ARegsOdd:$val, + ARegs:$src))]> { + let Constraints = "$val = $dst"; + let Defs = [ST]; + bits<5> src; + bits<5> val; + bits<5> dst; + let Inst{15-9} = 0b0101100; + let Inst{8-5} = src{3-0}; + let Inst{4} = dst{4}; + let Inst{3-0} = dst{3-0}; +} + +// DIVU Rs, Rd: 0101 101S SSSR DDDD (0x5A00). Unsigned divide, same form. +def DIVU : TMS34010Inst<(outs ARegsOdd:$dst), (ins ARegs:$src, ARegsOdd:$val), + "DIVU $src, $dst", + [(set ARegsOdd:$dst, (udiv ARegsOdd:$val, + ARegs:$src))]> { + let Constraints = "$val = $dst"; + let Defs = [ST]; + bits<5> src; + bits<5> val; + bits<5> dst; + let Inst{15-9} = 0b0101101; + let Inst{8-5} = src{3-0}; + let Inst{4} = dst{4}; + let Inst{3-0} = dst{3-0}; +} + // NEG Rd: 0000 0011 101R DDDD (0x03A0). def NEG : TMS34010Inst<(outs ARegs:$dst), (ins ARegs:$src), "NEG $dst", [(set ARegs:$dst, (ineg ARegs:$src))]> { @@ -570,6 +646,23 @@ def GETFI : TMS34010Inst<(outs ARegs:$dst), (ins i32imm:$off), "# GETFI", []> { let isPseudo = 1; } +// Sign extension in register. The ISA's SEXT reads the current field size, and +// the ABI pins FS0 at 16 for `short`, so a width-specific field extension is +// not available for every width. Expand to the verified shift pair +// (SLL K ; SRA K) instead. DAGCombine forms these nodes from shift pairs in +// ordinary `short` arithmetic, so they must select. +def SEXT8 : TMS34010Inst<(outs ARegs:$dst), (ins ARegs:$src), "# SEXT8", + [(set ARegs:$dst, (sext_inreg ARegs:$src, i8))]> { + let isPseudo = 1; + let usesCustomInserter = 1; +} + +def SEXT16 : TMS34010Inst<(outs ARegs:$dst), (ins ARegs:$src), "# SEXT16", + [(set ARegs:$dst, (sext_inreg ARegs:$src, i16))]> { + let isPseudo = 1; + let usesCustomInserter = 1; +} + def NOP : TMS34010Inst<(outs), (ins), "NOP", []> { let Inst{15-0} = 0x0300; } diff --git a/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.td b/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.td index d8f7bea19c7e..aa5d4d557b3f 100644 --- a/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.td +++ b/llvm/lib/Target/TMS34010/TMS34010RegisterInfo.td @@ -63,6 +63,14 @@ def ARegs : RegisterClass<"TMS34010", [i32], 32, (add A0, A1, A2, A3, A4, A5, A6, A7, A9, A10, A11, A12)>; +// MPYS/MPYU/DIVS/DIVU treat an even Rd as the first of a register pair: an +// even multiply writes Rd:Rd+1, and an even divide reads a 64-bit Rd:Rd+1 +// dividend and writes the quotient to Rd and the remainder to Rd+1. The +// 32-bit forms here always want the odd (single-register) encoding, so the +// tied destination operand is restricted to the odd allocatable A registers. +def ARegsOdd : RegisterClass<"TMS34010", [i32], 32, + (add A1, A3, A5, A7, A9, A11)>; + // ARegsAll names every A register. It is used only as the operand class of // the frame and system-stack instructions, which need to name the reserved // FP/STK/SP registers explicitly; it is never allocated. diff --git a/llvm/test/CodeGen/TMS34010/m4-mul.ll b/llvm/test/CodeGen/TMS34010/m4-mul.ll new file mode 100644 index 000000000000..9a4d08844b20 --- /dev/null +++ b/llvm/test/CodeGen/TMS34010/m4-mul.ll @@ -0,0 +1,80 @@ +; RUN: llc -march=tms34010 -O0 -filetype=asm < %s | FileCheck %s +; RUN: llc -march=tms34010 -O2 -filetype=asm < %s | FileCheck %s + +; M4 adds the register-file ALU multiply and divide instructions. MPYS and +; MPYU multiply the 32-bit Rd (the tied destination) by the multiplier field +; Rs; with an odd Rd the low 32 bits are stored back and no register pair is +; touched. The destination must be odd, so the tied operand uses the +; odd-only ARegsOdd class. +; +; DIVS/DIVU with an odd Rd divide the 32-bit Rd by Rs, leaving the quotient in +; Rd. The remainder is derived as dividend - quotient * divisor, because the +; hardware only returns the remainder with an even destination pair. + +; A 32x32 low product: one MPYS to an odd destination. +define i32 @mul32(i32 %a, i32 %b) { + %r = mul i32 %a, %b + ret i32 %r +} +; CHECK-LABEL: _mul32: +; CHECK: MPYS A{{[0-9]+}}, {{A([13579]|11)$}} +; CHECK: RETS 2 + +; A 16x16 signed product: the operands are truncated to 16 bits and +; sign-extended with a shift pair, then multiplied with MPYS. +define i32 @mul16s(i32 %a, i32 %b) { + %as = shl i32 %a, 16 + %bs = shl i32 %b, 16 + %ae = ashr i32 %as, 16 + %be = ashr i32 %bs, 16 + %r = mul i32 %ae, %be + ret i32 %r +} +; CHECK-LABEL: _mul16s: +; CHECK: MPYS + +; A 16x16 unsigned product, masked to 16 bits: MPYU. +define i32 @mul16u(i32 %a, i32 %b) { + %ae = and i32 %a, 65535 + %be = and i32 %b, 65535 + %r = mul i32 %ae, %be + ret i32 %r +} +; CHECK-LABEL: _mul16u: +; CHECK: MPYU + +; Signed and unsigned 32/32 division with an odd destination. +define i32 @sdiv32(i32 %a, i32 %b) { + %r = sdiv i32 %a, %b + ret i32 %r +} +; CHECK-LABEL: _sdiv32: +; CHECK: DIVS A{{[0-9]+}}, {{A([13579]|11)$}} +; CHECK: RETS 2 + +define i32 @udiv32(i32 %a, i32 %b) { + %r = udiv i32 %a, %b + ret i32 %r +} +; CHECK-LABEL: _udiv32: +; CHECK: DIVU A{{[0-9]+}}, {{A([13579]|11)$}} +; CHECK: RETS 2 + +; Remainder = dividend - quotient * divisor, using the same divide. +define i32 @srem32(i32 %a, i32 %b) { + %r = srem i32 %a, %b + ret i32 %r +} +; CHECK-LABEL: _srem32: +; CHECK: DIVS +; CHECK: MPYS +; CHECK: SUB + +define i32 @urem32(i32 %a, i32 %b) { + %r = urem i32 %a, %b + ret i32 %r +} +; CHECK-LABEL: _urem32: +; CHECK: DIVU +; CHECK: MPYS +; CHECK: SUB