/// Transform physical registers into virtual registers, and generate load /// operations for argument places on the stack. SDValue ARCTargetLowering::LowerCallArguments( SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); MachineRegisterInfo &RegInfo = MF.getRegInfo(); auto *AFI = MF.getInfo<ARCFunctionInfo>(); // Assign locations to all of the incoming arguments. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, *DAG.getContext()); CCInfo.AnalyzeFormalArguments(Ins, CC_ARC); unsigned StackSlotSize = 4; if (!IsVarArg) AFI->setReturnStackOffset(CCInfo.getNextStackOffset()); // All getCopyFromReg ops must precede any getMemcpys to prevent the // scheduler clobbering a register before it has been copied. // The stages are: // 1. CopyFromReg (and load) arg & vararg registers. // 2. Chain CopyFromReg nodes into a TokenFactor. // 3. Memcpy 'byVal' args & push final InVals. // 4. Chain mem ops nodes into a TokenFactor. SmallVector<SDValue, 4> CFRegNode; SmallVector<ArgDataPair, 4> ArgData; SmallVector<SDValue, 4> MemOps; // 1a. CopyFromReg (and load) arg registers. for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; SDValue ArgIn; if (VA.isRegLoc()) { // Arguments passed in registers EVT RegVT = VA.getLocVT(); switch (RegVT.getSimpleVT().SimpleTy) { default: { DEBUG(errs() << "LowerFormalArguments Unhandled argument type: " << RegVT.getSimpleVT().SimpleTy << "\n"); llvm_unreachable("Unhandled LowerFormalArguments type."); } case MVT::i32: unsigned VReg = RegInfo.createVirtualRegister(&ARC::GPR32RegClass); RegInfo.addLiveIn(VA.getLocReg(), VReg); ArgIn = DAG.getCopyFromReg(Chain, dl, VReg, RegVT); CFRegNode.push_back(ArgIn.getValue(ArgIn->getNumValues() - 1)); } } else { // sanity check assert(VA.isMemLoc()); // Load the argument to a virtual register unsigned ObjSize = VA.getLocVT().getStoreSize(); assert((ObjSize <= StackSlotSize) && "Unhandled argument"); // Create the frame index object for this incoming parameter... int FI = MFI.CreateFixedObject(ObjSize, VA.getLocMemOffset(), true); // Create the SelectionDAG nodes corresponding to a load // from this parameter SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); ArgIn = DAG.getLoad(VA.getLocVT(), dl, Chain, FIN, MachinePointerInfo::getFixedStack(MF, FI)); } const ArgDataPair ADP = {ArgIn, Ins[i].Flags}; ArgData.push_back(ADP); } // 1b. CopyFromReg vararg registers. if (IsVarArg) { // Argument registers static const MCPhysReg ArgRegs[] = {ARC::R0, ARC::R1, ARC::R2, ARC::R3, ARC::R4, ARC::R5, ARC::R6, ARC::R7}; auto *AFI = MF.getInfo<ARCFunctionInfo>(); unsigned FirstVAReg = CCInfo.getFirstUnallocated(ArgRegs); if (FirstVAReg < array_lengthof(ArgRegs)) { int Offset = 0; // Save remaining registers, storing higher register numbers at a higher // address // There are (array_lengthof(ArgRegs) - FirstVAReg) registers which // need to be saved. int VarFI = MFI.CreateFixedObject((array_lengthof(ArgRegs) - FirstVAReg) * 4, CCInfo.getNextStackOffset(), true); AFI->setVarArgsFrameIndex(VarFI); SDValue FIN = DAG.getFrameIndex(VarFI, MVT::i32); for (unsigned i = FirstVAReg; i < array_lengthof(ArgRegs); i++) { // Move argument from phys reg -> virt reg unsigned VReg = RegInfo.createVirtualRegister(&ARC::GPR32RegClass); RegInfo.addLiveIn(ArgRegs[i], VReg); SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32); CFRegNode.push_back(Val.getValue(Val->getNumValues() - 1)); SDValue VAObj = DAG.getNode(ISD::ADD, dl, MVT::i32, FIN, DAG.getConstant(Offset, dl, MVT::i32)); // Move argument from virt reg -> stack SDValue Store = DAG.getStore(Val.getValue(1), dl, Val, VAObj, MachinePointerInfo()); MemOps.push_back(Store); Offset += 4; } } else { llvm_unreachable("Too many var args parameters."); } } // 2. Chain CopyFromReg nodes into a TokenFactor. if (!CFRegNode.empty()) Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, CFRegNode); // 3. Memcpy 'byVal' args & push final InVals. // Aggregates passed "byVal" need to be copied by the callee. // The callee will use a pointer to this copy, rather than the original // pointer. for (const auto &ArgDI : ArgData) { if (ArgDI.Flags.isByVal() && ArgDI.Flags.getByValSize()) { unsigned Size = ArgDI.Flags.getByValSize(); unsigned Align = std::max(StackSlotSize, ArgDI.Flags.getByValAlign()); // Create a new object on the stack and copy the pointee into it. int FI = MFI.CreateStackObject(Size, Align, false); SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); InVals.push_back(FIN); MemOps.push_back(DAG.getMemcpy( Chain, dl, FIN, ArgDI.SDV, DAG.getConstant(Size, dl, MVT::i32), Align, false, false, false, MachinePointerInfo(), MachinePointerInfo())); } else { InVals.push_back(ArgDI.SDV); } } // 4. Chain mem ops nodes into a TokenFactor. if (!MemOps.empty()) { MemOps.push_back(Chain); Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps); } return Chain; }