Index: lib/Target/Nios2/Nios2ISelLowering.h =================================================================== --- lib/Target/Nios2/Nios2ISelLowering.h +++ lib/Target/Nios2/Nios2ISelLowering.h @@ -57,6 +57,20 @@ const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &dl, SelectionDAG &DAG) const override; + + /// Nios2CC - This class provides methods used to analyze formal and call + /// arguments and inquire about calling convention information. + class Nios2CC { + public: + Nios2CC(CallingConv::ID CallConv, CCState &Info); + + void analyzeReturn(const SmallVectorImpl &Outs, + bool IsSoftFloat, const Type *RetTy) const; + + private: + CCState &CCInfo; + CallingConv::ID CallConv; + }; }; } // end namespace llvm Index: lib/Target/Nios2/Nios2ISelLowering.cpp =================================================================== --- lib/Target/Nios2/Nios2ISelLowering.cpp +++ lib/Target/Nios2/Nios2ISelLowering.cpp @@ -32,9 +32,39 @@ 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()); + Nios2CC Nios2CCInfo(CallConv, CCInfo); + // Analyze return values. + Nios2CCInfo.analyzeReturn(Outs, false, MF.getFunction()->getReturnType()); + 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); } @@ -157,3 +187,25 @@ } return nullptr; } + +//===----------------------------------------------------------------------===// +// TargetLowering Implementation +//===----------------------------------------------------------------------===// + +Nios2TargetLowering::Nios2CC::Nios2CC(CallingConv::ID CC, CCState &Info) + : CCInfo(Info), CallConv(CC) {} + +void Nios2TargetLowering::Nios2CC::analyzeReturn( + const SmallVectorImpl &RetVals, bool IsSoftFloat, + const Type *RetTy) const { + CCAssignFn *Fn; + Fn = RetCC_Nios2EABI; + + for (unsigned I = 0, E = RetVals.size(); I < E; ++I) { + MVT VT = RetVals[I].VT; + ISD::ArgFlagsTy Flags = RetVals[I].Flags; + if (Fn(I, VT, VT, CCValAssign::Full, Flags, this->CCInfo)) { + llvm_unreachable(nullptr); + } + } +} Index: lib/Target/Nios2/Nios2InstrFormats.td =================================================================== --- lib/Target/Nios2/Nios2InstrFormats.td +++ lib/Target/Nios2/Nios2InstrFormats.td @@ -20,14 +20,44 @@ 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 @@ } //===----------------------------------------------------------------------===// +// 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 @@ 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 Index: lib/Target/Nios2/Nios2InstrInfo.h =================================================================== --- lib/Target/Nios2/Nios2InstrInfo.h +++ lib/Target/Nios2/Nios2InstrInfo.h @@ -39,6 +39,10 @@ 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: lib/Target/Nios2/Nios2InstrInfo.cpp =================================================================== --- lib/Target/Nios2/Nios2InstrInfo.cpp +++ lib/Target/Nios2/Nios2InstrInfo.cpp @@ -41,3 +41,20 @@ 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; + // Build machine instruction based on selected op code. + MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(opc)); + + if (DestReg) + MIB.addReg(DestReg, RegState::Define); + + MIB.addReg(Nios2::ZERO); + + if (SrcReg) + MIB.addReg(SrcReg, getKillRegState(KillSrc)); +} Index: lib/Target/Nios2/Nios2InstrInfo.td =================================================================== --- lib/Target/Nios2/Nios2InstrInfo.td +++ lib/Target/Nios2/Nios2InstrInfo.td @@ -30,6 +30,10 @@ // 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 @@ (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,30 @@ } } -// 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>; Index: test/CodeGen/Nios2/add-sub.ll =================================================================== --- /dev/null +++ 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 {{r[0-9]+}}, {{r[0-9]+}}, {{r[0-9]+}} + %c = add i32 %a, %b + ret i32 %c +} + +define i32 @sub_reg(i32 %a, i32 %b) nounwind { +entry: +; CHECK: sub_reg: +; CHECK: sub {{r[0-9]+}}, {{r[0-9]+}}, {{r[0-9]+}} + %c = sub i32 %a, %b + ret i32 %c +} + Index: test/CodeGen/Nios2/mul-div.ll =================================================================== --- /dev/null +++ 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 {{r[0-9]+}}, {{r[0-9]+}}, {{r[0-9]+}} + %c = mul i32 %a, %b + ret i32 %c +} + +define i32 @div_signed(i32 %a, i32 %b) nounwind { +entry: +; CHECK: div_signed: +; CHECK: div {{r[0-9]+}}, {{r[0-9]+}}, {{r[0-9]+}} + %c = sdiv i32 %a, %b + ret i32 %c +} + +define i32 @div_unsigned(i32 %a, i32 %b) nounwind { +entry: +; CHECK: div_unsigned: +; CHECK: divu {{r[0-9]+}}, {{r[0-9]+}}, {{r[0-9]+}} + %c = udiv i32 %a, %b + ret i32 %c +} + Index: test/CodeGen/Nios2/shift-rotate.ll =================================================================== --- /dev/null +++ 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 {{r[0-9]+}}, {{r[0-9]+}}, {{r[0-9]+}} + %c = shl i32 %a, %b + ret i32 %c +} + +define i32 @srl_reg(i32 %a, i32 %b) nounwind { +entry: +; CHECK: srl_reg: +; CHECK: srl {{r[0-9]+}}, {{r[0-9]+}}, {{r[0-9]+}} + %c = lshr i32 %a, %b + ret i32 %c +} + +define i32 @sra_reg(i32 %a, i32 %b) nounwind { +entry: +; CHECK: sra_reg: +; CHECK: sra {{r[0-9]+}}, {{r[0-9]+}}, {{r[0-9]+}} + %c = ashr i32 %a, %b + ret i32 %c +}