Index: lib/Target/NDS32/NDS32ISelLowering.h =================================================================== --- lib/Target/NDS32/NDS32ISelLowering.h +++ lib/Target/NDS32/NDS32ISelLowering.h @@ -67,6 +67,8 @@ /// LowerOperation - Provide custom lowering hooks for some operations. SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + SDValue LowerDIVREM(SDValue Op, SelectionDAG &DAG) const; + /// getTargetNodeName - This method returns the name of a target specific /// DAG node. const char *getTargetNodeName(unsigned Opcode) const override; Index: lib/Target/NDS32/NDS32ISelLowering.cpp =================================================================== --- lib/Target/NDS32/NDS32ISelLowering.cpp +++ lib/Target/NDS32/NDS32ISelLowering.cpp @@ -143,11 +143,24 @@ SDValue NDS32TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { + case ISD::UDIVREM: return LowerDIVREM(Op, DAG); + case ISD::SDIVREM: return LowerDIVREM(Op, DAG); default: llvm_unreachable("unimplemented operand"); } } +SDValue NDS32TargetLowering::LowerDIVREM(SDValue Op, SelectionDAG &DAG) const { + SDLoc dl(Op); + EVT VT = Op.getValueType(); + SDVTList vts = DAG.getVTList(VT, VT); + SDValue Ra = Op.getOperand(0); + SDValue Rb = Op.getOperand(1); + unsigned Opc = (Op->getOpcode() == ISD::SDIVREM) + ? NDS32ISD::SDIVREM : NDS32ISD::UDIVREM; + return DAG.getNode(Opc, dl, vts, Ra, Rb); +} + //===----------------------------------------------------------------------===// // NDS32 Addressing Mode Support //===----------------------------------------------------------------------===// Index: lib/Target/NDS32/NDS32InstrInfo.td =================================================================== --- lib/Target/NDS32/NDS32InstrInfo.td +++ lib/Target/NDS32/NDS32InstrInfo.td @@ -32,6 +32,9 @@ SDNode<"ISD::CALLSEQ_END", SDT_NDS32CallSeqEnd, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; +def NDS32sdivrem : SDNode<"NDS32ISD::SDIVREM", SDTIntBinHiLoOp>; +def NDS32udivrem : SDNode<"NDS32ISD::UDIVREM", SDTIntBinHiLoOp>; + //===----------------------------------------------------------------------===// // ADJCALLSTACKDOWN/UP implicitly use/def SP because they may be expanded into // a stack adjustment and the codegen must know that they may modify the stack @@ -210,6 +213,44 @@ def XOR_SRLI : ALU_shift<"xor_srli", xor, srl, 0b11111>; +//===----------------------------------------------------------------------===// +// Division Instructions +// +// In NDS32 ISA, quotient and remainder register set to same register +// will only set quotient value to the register which match the semantic +// udiv/sdiv in dags. +class DIVrr subop_encode> : + ALU_1Form<(outs GPR:$Rt), (ins GPR:$Ra, GPR:$Rb), + !strconcat(opstr, "\t$Rt, $Rt, $Ra, $Rb"), + [(set GPR:$Rt, (Op GPR:$Ra, GPR:$Rb))]> { + bits<5> Rt; + bits<5> Ra; + bits<5> Rb; + let Inst{24-20} = Rt; + let Inst{19-15} = Ra; + let Inst{14-10} = Rb; + let Inst{9-5} = Rt; + let Inst{4-0} = subop_encode; +} + +class DIVREM subop_encode> : + ALU_1Form<(outs GPR:$Rt, GPR:$Rs), (ins GPR:$Ra, GPR:$Rb), + !strconcat(opstr, "\t$Rt, $Rs, $Ra, $Rb"), []> { + bits<5> Rt; + bits<5> Rs; + bits<5> Ra; + bits<5> Rb; + let Inst{24-20} = Rt; + let Inst{19-15} = Ra; + let Inst{14-10} = Rb; + let Inst{9-5} = Rs; + let Inst{4-0} = subop_encode; +} + +def UDIVREM : DIVREM< "divr", 0b10111>; +def SDIVREM : DIVREM< "divsr", 0b10110>; + + class JREG_ret pat, bits<2> dt_it> : JREGForm<(outs), (ins), opstr, pat> { let Inst{24-15} = 0; @@ -223,3 +264,15 @@ let isReturn = 1, isTerminator = 1, isBarrier = 1 in { def RET : JREG_ret<"ret", [(NDS32ret)], 0b00>; } + + +//===----------------------------------------------------------------------===// +// Pattern Transformation +//===----------------------------------------------------------------------===// + +// division patterns +def : Pat<(NDS32sdivrem i32:$Ra, i32:$Rb), + (SDIVREM i32:$Ra, i32:$Rb)>; +def : Pat<(NDS32udivrem i32:$Ra, i32:$Rb), + (UDIVREM i32:$Ra, i32:$Rb)>; + Index: test/CodeGen/NDS32/div.ll =================================================================== --- /dev/null +++ test/CodeGen/NDS32/div.ll @@ -0,0 +1,19 @@ +; RUN: llc < %s | FileCheck %s +target datalayout = "e-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "nds32le---elf" + +; Function Attrs: norecurse nounwind readnone +define i32 @divsr(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %div = sdiv i32 %a, %b +; CHECK: divsr $r0, $r1, $r0, $r1 + ret i32 %div +} + +; Function Attrs: norecurse nounwind readnone +define i32 @divr(i32 %a, i32 %b) local_unnamed_addr #0 { +entry: + %div = udiv i32 %a, %b +; CHECK: divr $r0, $r1, $r0, $r1 + ret i32 %div +}