Index: lib/Target/NDS32/NDS32ISelLowering.h =================================================================== --- lib/Target/NDS32/NDS32ISelLowering.h +++ lib/Target/NDS32/NDS32ISelLowering.h @@ -141,10 +141,24 @@ const SmallVectorImpl &Ins, const SDLoc &dl, SelectionDAG &DAG, SmallVectorImpl &InVals) const override; + + typedef SmallVector, 8> RegsToPassVector; + SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl &InVals) const override; + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, + const SDLoc &dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + + SDValue LowerMemOpCallTo(SDValue Chain, SDValue StackPtr, SDValue Arg, + const SDLoc &dl, SelectionDAG &DAG, + const CCValAssign &VA, + ISD::ArgFlagsTy Flags) const; + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, Index: lib/Target/NDS32/NDS32ISelLowering.cpp =================================================================== --- lib/Target/NDS32/NDS32ISelLowering.cpp +++ lib/Target/NDS32/NDS32ISelLowering.cpp @@ -368,7 +368,6 @@ std::advance(FuncArg, Ins[i].getOrigArgIndex() - CurArgIdx); CurArgIdx = Ins[i].getOrigArgIndex(); } - ISD::ArgFlagsTy Flags = Ins[i].Flags; bool IsRegLoc = VA.isRegLoc(); // Arguments stored on registers if (IsRegLoc) { @@ -460,11 +459,180 @@ return DAG.getNode(Opc, dl, MVT::Other, RetOps); } +/// LowerMemOpCallTo - Store the argument to the stack. +SDValue NDS32TargetLowering::LowerMemOpCallTo(SDValue Chain, SDValue StackPtr, + SDValue Arg, const SDLoc &dl, + SelectionDAG &DAG, + const CCValAssign &VA, + ISD::ArgFlagsTy Flags) const { + unsigned LocMemOffset = VA.getLocMemOffset(); + SDValue PtrOff = DAG.getIntPtrConstant(LocMemOffset, dl); + PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(DAG.getDataLayout()), + StackPtr, PtrOff); + return DAG.getStore( + Chain, dl, Arg, PtrOff, + MachinePointerInfo::getStack(DAG.getMachineFunction(), LocMemOffset)); +} + // LowerCall - Specify how caller passing arguments SDValue NDS32TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { - SDValue Chain; + SelectionDAG &DAG = CLI.DAG; + SDLoc &DL = CLI.DL; + SmallVectorImpl &Outs = CLI.Outs; + SmallVectorImpl &OutVals = CLI.OutVals; + SmallVectorImpl &Ins = CLI.Ins; + SDValue Chain = CLI.Chain; + SDValue Callee = CLI.Callee; + bool &IsTailCall = CLI.IsTailCall; + CallingConv::ID CallConv = CLI.CallConv; + bool IsVarArg = CLI.IsVarArg; + + // NDS32 target does not support tail call optimization yet. + IsTailCall = false; + + const TargetFrameLowering *TFL = Subtarget->getFrameLowering(); + + // Analyze operands of the call, assigning locations to each operand. + SmallVector ArgLocs; + + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, + *DAG.getContext()); + + CCInfo.AnalyzeCallOperands(Outs, CC_NDS32); + + // Get a count of how many bytes are to be pushed on the stack. + unsigned NextStackOffset = CCInfo.getNextStackOffset(); + + // Chain is the output chain of the last Load/Store or CopyToReg node. + unsigned StackAlignment = TFL->getStackAlignment(); + NextStackOffset = alignTo(NextStackOffset, StackAlignment); + SDValue NextStackOffsetVal = DAG.getIntPtrConstant(NextStackOffset, DL, true); + + if (!IsTailCall) + Chain = DAG.getCALLSEQ_START(Chain, NextStackOffsetVal, DL); + + RegsToPassVector RegsToPass; + SmallVector MemOpChains; + + SDValue StackPtr = DAG.getCopyFromReg(Chain, DL, NDS32::SP, + getPointerTy(DAG.getDataLayout())); + + // Walk the register/memloc assignments, inserting copies/loads. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + SDValue Arg = OutVals[i]; + CCValAssign &VA = ArgLocs[i]; + ISD::ArgFlagsTy Flags = Outs[i].Flags; + + // Promote the value if needed. + switch (VA.getLocInfo()) { + default: llvm_unreachable("Unknown loc info!"); + case CCValAssign::Full: break; + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::AExt: + Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::BCvt: + Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg); + break; + } + + if (VA.isRegLoc()) { + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + } else { + assert(VA.isMemLoc()); + MemOpChains.push_back(LowerMemOpCallTo(Chain, StackPtr, Arg, + DL, DAG, VA, Flags)); + } + } + + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); + + // Build a sequence of copy-to-reg nodes chained together with token chain and + // flag operands which copy the outgoing args into registers. The InFlag in + // necessary since all emitted instructions must be stuck together. + SDValue InFlag; + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, DL, RegsToPass[i].first, + RegsToPass[i].second, InFlag); + InFlag = Chain.getValue(1); + } + + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + // Likewise ExternalSymbol -> TargetExternalSymbol. + if (GlobalAddressSDNode *G = dyn_cast(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, MVT::i32); + else if (ExternalSymbolSDNode *E = dyn_cast(Callee)) + Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32); + + std::vector Ops; + Ops.push_back(Chain); + Ops.push_back(Callee); + + // Add argument registers to the end of the list so that they are + // known live into the call. + for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) + Ops.push_back(DAG.getRegister(RegsToPass[i].first, + RegsToPass[i].second.getValueType())); + + // Add a register mask operand representing the call-preserved(callee saved) + // registers. Let register allocator could get correct register live time + // cross call. + const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); + const uint32_t *Mask = + TRI->getCallPreservedMask(DAG.getMachineFunction(), CLI.CallConv); + assert(Mask && "Missing call preserved mask for calling convention"); + Ops.push_back(DAG.getRegisterMask(Mask)); + + if (InFlag.getNode()) + Ops.push_back(InFlag); + + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); + Chain = DAG.getNode(NDS32ISD::CALL, DL, NodeTys, Ops); + InFlag = Chain.getValue(1); + + // Create the CALLSEQ_END node. + Chain = DAG.getCALLSEQ_END(Chain, NextStackOffsetVal, + DAG.getIntPtrConstant(0, DL, true), InFlag, DL); + InFlag = Chain.getValue(1); + + // Handle result values, copying them out of physregs into vregs that we + // return. + return LowerCallResult(Chain, InFlag, CallConv, IsVarArg, Ins, DL, + DAG, InVals); +} + +/// LowerCallResult - Lower the result values of a call into the +/// appropriate copies out of appropriate physical registers. +/// Specify how caller get return value +SDValue NDS32TargetLowering::LowerCallResult( + SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, const SDLoc &dl, + SelectionDAG &DAG, SmallVectorImpl &InVals) const { + + // Assign locations to each value returned by this call. + SmallVector RVLocs; + CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs, + *DAG.getContext()); + + CCInfo.AnalyzeCallResult(Ins, RetCC_NDS32); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { + Chain = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(), + RVLocs[i].getValVT(), InFlag).getValue(1); + InFlag = Chain.getValue(2); + InVals.push_back(Chain.getValue(0)); + } + return Chain; } Index: lib/Target/NDS32/NDS32InstrInfo.cpp =================================================================== --- lib/Target/NDS32/NDS32InstrInfo.cpp +++ lib/Target/NDS32/NDS32InstrInfo.cpp @@ -56,6 +56,15 @@ MachineBasicBlock::iterator I, const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, bool KillSrc) const { + unsigned Opc; + + if (NDS32::GPRRegClass.contains(DestReg, SrcReg)) { + Opc = NDS32::ADDI; + } else + llvm_unreachable("Impossible reg-to-reg copy"); + + BuildMI(MBB, I, DL, get(Opc), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)).addImm(0); } //===----------------------------------------------------------------------===// Index: lib/Target/NDS32/NDS32InstrInfo.td =================================================================== --- lib/Target/NDS32/NDS32InstrInfo.td +++ lib/Target/NDS32/NDS32InstrInfo.td @@ -17,6 +17,7 @@ //===----------------------------------------------------------------------===// // Type Profiles. //===----------------------------------------------------------------------===// +def SDT_NDS32Call : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>; def SDT_NDS32CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>; def SDT_NDS32CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; @@ -25,6 +26,8 @@ //===----------------------------------------------------------------------===// def NDS32ret : SDNode<"NDS32ISD::RET", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; +def NDS32call : SDNode<"NDS32ISD::CALL", SDT_NDS32Call, + [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; def NDS32callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_NDS32CallSeqStart, [SDNPHasChain, SDNPOutGlue]>; @@ -507,6 +510,32 @@ def BNEC : CondBranchConstant<"bnec", setne, 1>; +class JREG_call pat, bits<2> dt_it, + bits<5> sub_opcode> : + JREGForm<(outs), (ins GPR:$Rb), + !strconcat(opstr, "\t$Rb"), pat> { + bits<5> Rb; + let Inst{24-20} = 30; // LP register number + let Inst{19-15} = 0; + let Inst{14-10} = Rb; + let Inst{9-8} = dt_it; + let Inst{7-5} = 0; + let Inst{4-0} = sub_opcode; +} + +let isCall = 1, + Defs = [LP] in { + def JAL : JIForm<(outs), (ins nds32_jal_target:$func), + "jal\t$func", + [(NDS32call tglobaladdr:$func)]> { + bits<24> func; + let Inst{24} = 1; + let Inst{23-0} = func; + } + def JRAL : JREG_call<"jral", [(NDS32call GPR:$Rb)], 0b00, 0b00001>; +} + + //===----------------------------------------------------------------------===// // Pattern Transformation //===----------------------------------------------------------------------===// Index: test/CodeGen/NDS32/call.ll =================================================================== --- /dev/null +++ test/CodeGen/NDS32/call.ll @@ -0,0 +1,29 @@ +; RUN: llc < %s | FileCheck %s +target datalayout = "e-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "nds32le---elf" + +; Function Attrs: noinline nounwind +define i32 @foo(i32 %a) #0 { +entry: + %a.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + ret i32 %0 +} + +; Function Attrs: noinline nounwind +define i32 @bar(i32 %a) #0 { +entry: + %a.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %call = call i32 @foo(i32 %0) +; CHECK: jal foo + %1 = load i32, i32* %a.addr, align 4 + %call1 = call i32 @f1(i32 %1) +; CHECK: jal f1 + %add = add nsw i32 %call, %call1 + ret i32 %add +} + +declare i32 @f1(i32) #1