OSDN Git Service

[Nios2] Arithmetic instructions for R1 and R2 ISA.
authorNikolai Bozhenov <nikolai.bozhenov@intel.com>
Tue, 9 Jan 2018 11:15:08 +0000 (11:15 +0000)
committerNikolai Bozhenov <nikolai.bozhenov@intel.com>
Tue, 9 Jan 2018 11:15:08 +0000 (11:15 +0000)
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 <mateusz.belicki@intel.com>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@322069 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/Nios2/Nios2ISelLowering.cpp
lib/Target/Nios2/Nios2InstrFormats.td
lib/Target/Nios2/Nios2InstrInfo.cpp
lib/Target/Nios2/Nios2InstrInfo.h
lib/Target/Nios2/Nios2InstrInfo.td
test/CodeGen/Nios2/add-sub.ll [new file with mode: 0644]
test/CodeGen/Nios2/mul-div.ll [new file with mode: 0644]
test/CodeGen/Nios2/shift-rotate.ll [new file with mode: 0644]

index 99aa43f..008ce15 100644 (file)
@@ -32,9 +32,38 @@ Nios2TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
                                  const SmallVectorImpl<ISD::OutputArg> &Outs,
                                  const SmallVectorImpl<SDValue> &OutVals,
                                  const SDLoc &DL, SelectionDAG &DAG) const {
+  // CCValAssign - represent the assignment of
+  // the return value to a location
+  SmallVector<CCValAssign, 16> 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<SDValue, 4> 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);
 }
 
index 5857850..f57bf03 100644 (file)
@@ -20,14 +20,44 @@ class Format<bits<6> 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
@@ -151,6 +181,27 @@ class FJ<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern,
 }
 
 //===----------------------------------------------------------------------===//
+// Format F3X6 (R2) instruction : <|opx|RSV|C|B|A|opcode|>
+//===----------------------------------------------------------------------===//
+
+class F3X6<bits<6> opx, dag outs, dag ins, string asmstr, list<dag> pattern,
+           InstrItinClass itin>:
+      Nios2R2Inst32<outs, ins, asmstr, pattern, itin, FrmF3X6> {
+  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<bits<6> opxR1, bits<6> opxR2, dag outs,
                                   dag ins, string asmstr, list<dag> pattern,
                                   InstrItinClass itin> {
   def NAME#_R1 : FR<opxR1, outs, ins, asmstr, pattern, itin>;
+  def NAME#_R2 : F3X6<opxR2, outs, ins, asmstr, pattern, itin>;
 }
 
 // Multiclass for instructions that have R format in R1 and F3X6 format in R2
index df435d2..9700cba 100644 (file)
@@ -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));
+}
index a994d36..52f6e7e 100644 (file)
@@ -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
 
index 7a39b31..dee84f7 100644 (file)
@@ -30,6 +30,10 @@ def simm16     : Operand<i32> {
 // 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<bits<6> 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<bits<6> opx, string mnemonic,
+                         SDNode opNode>:
+  CommonInstr_R_F3X6<opx, (outs CPURegs:$rC),
+                     (ins CPURegs:$rA, CPURegs:$rB),
+                     !strconcat(mnemonic, "\t$rC, $rA, $rB"),
+                     [(set CPURegs:$rC, (opNode CPURegs:$rA, CPURegs:$rB))],
+                     IIAlu>;
+
 multiclass Return<bits<6> opx, dag outs, dag ins, string mnemonic> {
   let rB = 0, rC = 0,
       isReturn = 1,
@@ -55,14 +69,31 @@ multiclass Return<bits<6> 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/test/CodeGen/Nios2/add-sub.ll b/test/CodeGen/Nios2/add-sub.ll
new file mode 100644 (file)
index 0000000..7c9a289
--- /dev/null
@@ -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/test/CodeGen/Nios2/mul-div.ll b/test/CodeGen/Nios2/mul-div.ll
new file mode 100644 (file)
index 0000000..8327823
--- /dev/null
@@ -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/test/CodeGen/Nios2/shift-rotate.ll b/test/CodeGen/Nios2/shift-rotate.ll
new file mode 100644 (file)
index 0000000..d3084b5
--- /dev/null
@@ -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
+}