From eededdade956e057d099bea20b769d25374d89c5 Mon Sep 17 00:00:00 2001 From: Nikolai Bozhenov Date: Tue, 9 Jan 2018 11:15:08 +0000 Subject: [PATCH] [Nios2] Arithmetic instructions for R1 and R2 ISA. Summary: This commit enables some of the arithmetic instructions for Nios2 ISA (for both R1 and R2 revisions), implements facilities required to emit those instructions and provides LIT tests for added instructions. Reviewed By: hfinkel Differential Revision: https://reviews.llvm.org/D41236 Author: belickim llvm-svn: 322069 --- llvm/lib/Target/Nios2/Nios2ISelLowering.cpp | 29 +++++++++ llvm/lib/Target/Nios2/Nios2InstrFormats.td | 66 ++++++++++++++++++--- llvm/lib/Target/Nios2/Nios2InstrInfo.cpp | 11 ++++ llvm/lib/Target/Nios2/Nios2InstrInfo.h | 4 ++ llvm/lib/Target/Nios2/Nios2InstrInfo.td | 39 ++++++++++-- llvm/test/CodeGen/Nios2/add-sub.ll | 19 ++++++ llvm/test/CodeGen/Nios2/mul-div.ll | 27 +++++++++ llvm/test/CodeGen/Nios2/shift-rotate.ll | 26 ++++++++ 8 files changed, 210 insertions(+), 11 deletions(-) create mode 100644 llvm/test/CodeGen/Nios2/add-sub.ll create mode 100644 llvm/test/CodeGen/Nios2/mul-div.ll create mode 100644 llvm/test/CodeGen/Nios2/shift-rotate.ll diff --git a/llvm/lib/Target/Nios2/Nios2ISelLowering.cpp b/llvm/lib/Target/Nios2/Nios2ISelLowering.cpp index 99aa43f960c1..008ce1570722 100644 --- a/llvm/lib/Target/Nios2/Nios2ISelLowering.cpp +++ b/llvm/lib/Target/Nios2/Nios2ISelLowering.cpp @@ -32,9 +32,38 @@ Nios2TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const { + // CCValAssign - represent the assignment of + // the return value to a location + SmallVector RVLocs; + MachineFunction &MF = DAG.getMachineFunction(); + // CCState - Info about the registers and stack slot. + CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); + // Analyze return values. + CCInfo.CheckReturn(Outs, RetCC_Nios2EABI); + + SDValue Flag; SmallVector RetOps(1, Chain); + // Copy the result values into the output registers. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + SDValue Val = OutVals[i]; + CCValAssign &VA = RVLocs[i]; + assert(VA.isRegLoc() && "Can only return in registers!"); + + if (RVLocs[i].getValVT() != RVLocs[i].getLocVT()) + Val = DAG.getNode(ISD::BITCAST, DL, RVLocs[i].getLocVT(), Val); + + Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Flag); + + // Guarantee that all emitted copies are stuck together with flags. + Flag = Chain.getValue(1); + RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); + } + + if (Flag.getNode()) + RetOps.push_back(Flag); + return DAG.getNode(Nios2ISD::Ret, DL, MVT::Other, RetOps); } diff --git a/llvm/lib/Target/Nios2/Nios2InstrFormats.td b/llvm/lib/Target/Nios2/Nios2InstrFormats.td index 58578501d804..f57bf03bba3c 100644 --- a/llvm/lib/Target/Nios2/Nios2InstrFormats.td +++ b/llvm/lib/Target/Nios2/Nios2InstrFormats.td @@ -20,14 +20,44 @@ class Format val> { bits<6> Value = val; } -def Pseudo : Format<0>; -def FrmI : Format<1>; -def FrmR : Format<2>; -def FrmJ : Format<3>; -def FrmOther : Format<4>; // Instruction w/ a custom format +def Pseudo : Format<0>; +// Nios2 R1 instr formats: +def FrmI : Format<1>; +def FrmR : Format<2>; +def FrmJ : Format<3>; +def FrmOther : Format<4>; // Instruction w/ a custom format +// Nios2 R2 instr 32-bit formats: +def FrmL26 : Format<5>; // corresponds to J format in R1 +def FrmF2I16 : Format<6>; // corresponds to I format in R1 +def FrmF2X4I12 : Format<7>; +def FrmF1X4I12 : Format<8>; +def FrmF1X4L17 : Format<9>; +def FrmF3X6L5 : Format<10>; // corresponds to R format in R1 +def FrmF2X6L10 : Format<11>; +def FrmF3X6 : Format<12>; // corresponds to R format in R1 +def FrmF3X8 : Format<13>; // corresponds to custom format in R1 +// Nios2 R2 instr 16-bit formats: +def FrmI10 : Format<14>; +def FrmT1I7 : Format<15>; +def FrmT2I4 : Format<16>; +def FrmT1X1I6 : Format<17>; +def FrmX1I7 : Format<18>; +def FrmL5I4X1 : Format<19>; +def FrmT2X1L3 : Format<20>; +def FrmT2X1I3 : Format<21>; +def FrmT3X1 : Format<22>; +def FrmT2X3 : Format<23>; +def FrmF1X1 : Format<24>; +def FrmX2L5 : Format<25>; +def FrmF1I5 : Format<26>; +def FrmF2 : Format<27>; -def isNios2r1 : Predicate<"Subtarget->isNios2r1()">; -def isNios2r2 : Predicate<"Subtarget->isNios2r2()">; +//===----------------------------------------------------------------------===// +// Instruction Predicates: +//===----------------------------------------------------------------------===// + +def isNios2r1 : Predicate<"Subtarget->isNios2r1()">; +def isNios2r2 : Predicate<"Subtarget->isNios2r2()">; class PredicateControl { // Predicates related to specific target CPU features @@ -150,6 +180,27 @@ class FJ op, dag outs, dag ins, string asmstr, list pattern, let Inst{31-6} = addr; } +//===----------------------------------------------------------------------===// +// Format F3X6 (R2) instruction : <|opx|RSV|C|B|A|opcode|> +//===----------------------------------------------------------------------===// + +class F3X6 opx, dag outs, dag ins, string asmstr, list pattern, + InstrItinClass itin>: + Nios2R2Inst32 { + bits<5> rC; + bits<5> rB; + bits<5> rA; + bits<5> rsv = 0; + + let Opcode = 0x20; /* opcode is always 0x20 (OPX group) for F3X6 instr. */ + + let Inst{31-26} = opx; /* opx stands for opcode extension */ + let Inst{25-21} = rsv; + let Inst{20-16} = rC; + let Inst{15-11} = rB; + let Inst{10-6} = rA; +} + //===----------------------------------------------------------------------===// // Multiclasses for common instructions of both R1 and R2: //===----------------------------------------------------------------------===// @@ -160,6 +211,7 @@ multiclass CommonInstr_R_F3X6_opx opxR1, bits<6> opxR2, dag outs, dag ins, string asmstr, list pattern, InstrItinClass itin> { def NAME#_R1 : FR; + def NAME#_R2 : F3X6; } // Multiclass for instructions that have R format in R1 and F3X6 format in R2 diff --git a/llvm/lib/Target/Nios2/Nios2InstrInfo.cpp b/llvm/lib/Target/Nios2/Nios2InstrInfo.cpp index df435d2715d7..9700cba3595b 100644 --- a/llvm/lib/Target/Nios2/Nios2InstrInfo.cpp +++ b/llvm/lib/Target/Nios2/Nios2InstrInfo.cpp @@ -41,3 +41,14 @@ bool Nios2InstrInfo::expandPostRAPseudo(MachineInstr &MI) const { MBB.erase(MI); return true; } + +void Nios2InstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + const DebugLoc &DL, unsigned DestReg, + unsigned SrcReg, bool KillSrc) const { + unsigned opc = Subtarget.hasNios2r2() ? Nios2::ADD_R2 : Nios2::ADD_R1; + BuildMI(MBB, I, DL, get(opc)) + .addReg(DestReg, RegState::Define) + .addReg(Nios2::ZERO) + .addReg(SrcReg, getKillRegState(KillSrc)); +} diff --git a/llvm/lib/Target/Nios2/Nios2InstrInfo.h b/llvm/lib/Target/Nios2/Nios2InstrInfo.h index a994d3662db2..52f6e7e9c7c8 100644 --- a/llvm/lib/Target/Nios2/Nios2InstrInfo.h +++ b/llvm/lib/Target/Nios2/Nios2InstrInfo.h @@ -39,6 +39,10 @@ public: const Nios2RegisterInfo &getRegisterInfo() const { return RI; }; bool expandPostRAPseudo(MachineInstr &MI) const override; + + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, + bool KillSrc) const override; }; } // namespace llvm diff --git a/llvm/lib/Target/Nios2/Nios2InstrInfo.td b/llvm/lib/Target/Nios2/Nios2InstrInfo.td index 7a39b31a25a8..dee84f74bcbe 100644 --- a/llvm/lib/Target/Nios2/Nios2InstrInfo.td +++ b/llvm/lib/Target/Nios2/Nios2InstrInfo.td @@ -30,6 +30,10 @@ def simm16 : Operand { // e.g. addi, andi def immSExt16 : PatLeaf<(imm), [{ return isInt<16>(N->getSExtValue()); }]>; +// Custom return SDNode +def Nios2Ret : SDNode<"Nios2ISD::Ret", SDTNone, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + //===----------------------------------------------------------------------===// // Instructions specific format //===----------------------------------------------------------------------===// @@ -45,6 +49,16 @@ multiclass ArithLogicRegImm16 op, string mnemonic, SDNode opNode, (opNode CPURegs:$rA, immType:$imm))], IIAlu>; +// Arithmetic and logical instructions with 3 register operands. +// Defines R1 and R2 instruction at the same time. +multiclass ArithLogicReg opx, string mnemonic, + SDNode opNode>: + CommonInstr_R_F3X6; + multiclass Return opx, dag outs, dag ins, string mnemonic> { let rB = 0, rC = 0, isReturn = 1, @@ -55,14 +69,31 @@ multiclass Return opx, dag outs, dag ins, string mnemonic> { } } -// Custom return SDNode -def Nios2Ret : SDNode<"Nios2ISD::Ret", SDTNone, - [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; - //===----------------------------------------------------------------------===// // Nios2 Instructions //===----------------------------------------------------------------------===// +/// Arithmetic instructions operating on registers. +let isCommutable = 1 , + isReMaterializable = 1 in { + defm ADD : ArithLogicReg<0x31, "add", add>; + defm AND : ArithLogicReg<0x0e, "and", and>; + defm OR : ArithLogicReg<0x16, "or", or>; + defm XOR : ArithLogicReg<0x1e, "xor", xor>; + defm MUL : ArithLogicReg<0x27, "mul", mul>; +} + +let isReMaterializable = 1 in { + defm SUB : ArithLogicReg<0x39, "sub", sub>; +} + +defm DIVU : ArithLogicReg<0x24, "divu", udiv>; +defm DIV : ArithLogicReg<0x25, "div", sdiv>; + +defm SLL : ArithLogicReg<0x13, "sll", shl>; +defm SRL : ArithLogicReg<0x1b, "srl", srl>; +defm SRA : ArithLogicReg<0x3b, "sra", sra>; + /// Arithmetic Instructions (ALU Immediate) defm ADDI : ArithLogicRegImm16<0x04, "addi", add, simm16, immSExt16>; diff --git a/llvm/test/CodeGen/Nios2/add-sub.ll b/llvm/test/CodeGen/Nios2/add-sub.ll new file mode 100644 index 000000000000..7c9a2896ed9f --- /dev/null +++ b/llvm/test/CodeGen/Nios2/add-sub.ll @@ -0,0 +1,19 @@ +; RUN: llc < %s -march=nios2 2>&1 | FileCheck %s +; RUN: llc < %s -march=nios2 -target-abi=nios2r2 2>&1 | FileCheck %s + +define i32 @add_reg(i32 %a, i32 %b) nounwind { +entry: +; CHECK: add_reg: +; CHECK: add r2, r4, r5 + %c = add i32 %a, %b + ret i32 %c +} + +define i32 @sub_reg(i32 %a, i32 %b) nounwind { +entry: +; CHECK: sub_reg: +; CHECK: sub r2, r4, r5 + %c = sub i32 %a, %b + ret i32 %c +} + diff --git a/llvm/test/CodeGen/Nios2/mul-div.ll b/llvm/test/CodeGen/Nios2/mul-div.ll new file mode 100644 index 000000000000..8327823cf141 --- /dev/null +++ b/llvm/test/CodeGen/Nios2/mul-div.ll @@ -0,0 +1,27 @@ +; RUN: llc < %s -march=nios2 2>&1 | FileCheck %s +; RUN: llc < %s -march=nios2 -target-abi=nios2r2 2>&1 | FileCheck %s + +define i32 @mul_reg(i32 %a, i32 %b) nounwind { +entry: +; CHECK: mul_reg: +; CHECK: mul r2, r4, r5 + %c = mul i32 %a, %b + ret i32 %c +} + +define i32 @div_signed(i32 %a, i32 %b) nounwind { +entry: +; CHECK: div_signed: +; CHECK: div r2, r4, r5 + %c = sdiv i32 %a, %b + ret i32 %c +} + +define i32 @div_unsigned(i32 %a, i32 %b) nounwind { +entry: +; CHECK: div_unsigned: +; CHECK: divu r2, r4, r5 + %c = udiv i32 %a, %b + ret i32 %c +} + diff --git a/llvm/test/CodeGen/Nios2/shift-rotate.ll b/llvm/test/CodeGen/Nios2/shift-rotate.ll new file mode 100644 index 000000000000..d3084b5fb597 --- /dev/null +++ b/llvm/test/CodeGen/Nios2/shift-rotate.ll @@ -0,0 +1,26 @@ +; RUN: llc < %s -march=nios2 2>&1 | FileCheck %s +; RUN: llc < %s -march=nios2 -target-abi=nios2r2 2>&1 | FileCheck %s + +define i32 @sll_reg(i32 %a, i32 %b) nounwind { +entry: +; CHECK: sll_reg: +; CHECK: sll r2, r4, r5 + %c = shl i32 %a, %b + ret i32 %c +} + +define i32 @srl_reg(i32 %a, i32 %b) nounwind { +entry: +; CHECK: srl_reg: +; CHECK: srl r2, r4, r5 + %c = lshr i32 %a, %b + ret i32 %c +} + +define i32 @sra_reg(i32 %a, i32 %b) nounwind { +entry: +; CHECK: sra_reg: +; CHECK: sra r2, r4, r5 + %c = ashr i32 %a, %b + ret i32 %c +}