[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 <mateusz.belicki@intel.com>
llvm-svn: 322069
This commit is contained in:
Nikolai Bozhenov 2018-01-09 11:15:08 +00:00
parent 6db41e608f
commit eededdade9
8 changed files with 210 additions and 11 deletions

View 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);
}

View 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
@ -150,6 +180,27 @@ class FJ<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern,
let Inst{31-6} = addr;
}
//===----------------------------------------------------------------------===//
// 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

View 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));
}

View 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

View 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>;

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}