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);
}
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
}
//===----------------------------------------------------------------------===//
+// 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:
//===----------------------------------------------------------------------===//
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
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));
+}
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
// 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
//===----------------------------------------------------------------------===//
(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,
}
}
-// 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>;
--- /dev/null
+; 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
+}
+
--- /dev/null
+; 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
+}
+
--- /dev/null
+; 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
+}