SDValue SparcTargetLowering::LowerCall(SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool isVarArg, bool &isTailCall, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<ISD::InputArg> &Ins, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { // Sparc target does not yet support tail call optimization. isTailCall = false; #if 0 // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, isVarArg, DAG.getTarget(), ArgLocs); CCInfo.AnalyzeCallOperands(Outs, CC_Sparc32); // Get the size of the outgoing arguments stack space requirement. unsigned ArgsSize = CCInfo.getNextStackOffset(); // FIXME: We can't use this until f64 is known to take two GPRs. #else (void)CC_Sparc32; // Count the size of the outgoing arguments. unsigned ArgsSize = 0; for (unsigned i = 0, e = Outs.size(); i != e; ++i) { switch (Outs[i].Val.getValueType().getSimpleVT().SimpleTy) { default: llvm_unreachable("Unknown value type!"); case MVT::i1: case MVT::i8: case MVT::i16: case MVT::i32: case MVT::f32: ArgsSize += 4; break; case MVT::i64: case MVT::f64: ArgsSize += 8; break; } } if (ArgsSize > 4*6) ArgsSize -= 4*6; // Space for first 6 arguments is prereserved. else ArgsSize = 0; #endif // Keep stack frames 8-byte aligned. ArgsSize = (ArgsSize+7) & ~7; Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true)); SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass; SmallVector<SDValue, 8> MemOpChains; #if 0 // Walk the register/memloc assignments, inserting copies/loads. for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; SDValue Arg = Outs[i].Val; // 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, VA.getLocVT(), Arg); break; case CCValAssign::ZExt: Arg = DAG.getNode(ISD::ZERO_EXTEND, VA.getLocVT(), Arg); break; case CCValAssign::AExt: Arg = DAG.getNode(ISD::ANY_EXTEND, VA.getLocVT(), Arg); break; } // Arguments that can be passed on register must be kept at // RegsToPass vector if (VA.isRegLoc()) { RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); continue; } assert(VA.isMemLoc()); // Create a store off the stack pointer for this argument. SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); // FIXME: VERIFY THAT 68 IS RIGHT. SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset()+68); PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff); MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0, false, false, 0)); } #else static const unsigned ArgRegs[] = { SP::I0, SP::I1, SP::I2, SP::I3, SP::I4, SP::I5 }; unsigned ArgOffset = 68; for (unsigned i = 0, e = Outs.size(); i != e; ++i) { SDValue Val = Outs[i].Val; EVT ObjectVT = Val.getValueType(); SDValue ValToStore(0, 0); unsigned ObjSize; switch (ObjectVT.getSimpleVT().SimpleTy) { default: llvm_unreachable("Unhandled argument type!"); case MVT::i32: ObjSize = 4; if (RegsToPass.size() >= 6) { ValToStore = Val; } else { RegsToPass.push_back(std::make_pair(ArgRegs[RegsToPass.size()], Val)); } break; case MVT::f32: ObjSize = 4; if (RegsToPass.size() >= 6) { ValToStore = Val; } else { // Convert this to a FP value in an int reg. Val = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, Val); RegsToPass.push_back(std::make_pair(ArgRegs[RegsToPass.size()], Val)); } break; case MVT::f64: { ObjSize = 8; if (RegsToPass.size() >= 6) { ValToStore = Val; // Whole thing is passed in memory. break; } // Break into top and bottom parts by storing to the stack and loading // out the parts as integers. Top part goes in a reg. SDValue StackPtr = DAG.CreateStackTemporary(MVT::f64, MVT::i32); SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Val, StackPtr, NULL, 0, false, false, 0); // Sparc is big-endian, so the high part comes first. SDValue Hi = DAG.getLoad(MVT::i32, dl, Store, StackPtr, NULL, 0, false, false, 0); // Increment the pointer to the other half. StackPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), StackPtr, DAG.getIntPtrConstant(4)); // Load the low part. SDValue Lo = DAG.getLoad(MVT::i32, dl, Store, StackPtr, NULL, 0, false, false, 0); RegsToPass.push_back(std::make_pair(ArgRegs[RegsToPass.size()], Hi)); if (RegsToPass.size() >= 6) { ValToStore = Lo; ArgOffset += 4; ObjSize = 4; } else { RegsToPass.push_back(std::make_pair(ArgRegs[RegsToPass.size()], Lo)); } break; } case MVT::i64: { ObjSize = 8; if (RegsToPass.size() >= 6) { ValToStore = Val; // Whole thing is passed in memory. break; } // Split the value into top and bottom part. Top part goes in a reg. SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Val, DAG.getConstant(1, MVT::i32)); SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Val, DAG.getConstant(0, MVT::i32)); RegsToPass.push_back(std::make_pair(ArgRegs[RegsToPass.size()], Hi)); if (RegsToPass.size() >= 6) { ValToStore = Lo; ArgOffset += 4; ObjSize = 4; } else { RegsToPass.push_back(std::make_pair(ArgRegs[RegsToPass.size()], Lo)); } break; } } if (ValToStore.getNode()) { SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); SDValue PtrOff = DAG.getConstant(ArgOffset, MVT::i32); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); MemOpChains.push_back(DAG.getStore(Chain, dl, ValToStore, PtrOff, NULL, 0, false, false, 0)); } ArgOffset += ObjSize; } #endif // Emit all stores, make sure the occur before any copies into physregs. if (!MemOpChains.empty()) Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &MemOpChains[0], MemOpChains.size()); // 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 emited instructions must be // stuck together. SDValue InFlag; for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { unsigned Reg = RegsToPass[i].first; // Remap I0->I7 -> O0->O7. if (Reg >= SP::I0 && Reg <= SP::I7) Reg = Reg-SP::I0+SP::O0; Chain = DAG.getCopyToReg(Chain, dl, Reg, 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<GlobalAddressSDNode>(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i32); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32); std::vector<EVT> NodeTys; NodeTys.push_back(MVT::Other); // Returns a chain NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use. SDValue Ops[] = { Chain, Callee, InFlag }; Chain = DAG.getNode(SPISD::CALL, dl, NodeTys, Ops, InFlag.getNode() ? 3 : 2); InFlag = Chain.getValue(1); Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true), DAG.getIntPtrConstant(0, true), InFlag); InFlag = Chain.getValue(1); // Assign locations to each value returned by this call. SmallVector<CCValAssign, 16> RVLocs; CCState RVInfo(CallConv, isVarArg, DAG.getTarget(), RVLocs, *DAG.getContext()); RVInfo.AnalyzeCallResult(Ins, RetCC_Sparc32); // Copy all of the result registers out of their specified physreg. for (unsigned i = 0; i != RVLocs.size(); ++i) { unsigned Reg = RVLocs[i].getLocReg(); // Remap I0->I7 -> O0->O7. if (Reg >= SP::I0 && Reg <= SP::I7) Reg = Reg-SP::I0+SP::O0; Chain = DAG.getCopyFromReg(Chain, dl, Reg, RVLocs[i].getValVT(), InFlag).getValue(1); InFlag = Chain.getValue(2); InVals.push_back(Chain.getValue(0)); } return Chain; }
SDValue SparcTargetLowering::LowerCall(SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool isVarArg, bool &isTailCall, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, const SmallVectorImpl<ISD::InputArg> &Ins, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { // Sparc target does not yet support tail call optimization. isTailCall = false; // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, isVarArg, DAG.getTarget(), ArgLocs, *DAG.getContext()); CCInfo.AnalyzeCallOperands(Outs, CC_Sparc32); // Get the size of the outgoing arguments stack space requirement. unsigned ArgsSize = CCInfo.getNextStackOffset(); // Keep stack frames 8-byte aligned. ArgsSize = (ArgsSize+7) & ~7; MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); //Create local copies for byval args. SmallVector<SDValue, 8> ByValArgs; for (unsigned i = 0, e = Outs.size(); i != e; ++i) { ISD::ArgFlagsTy Flags = Outs[i].Flags; if (!Flags.isByVal()) continue; SDValue Arg = OutVals[i]; unsigned Size = Flags.getByValSize(); unsigned Align = Flags.getByValAlign(); int FI = MFI->CreateStackObject(Size, Align, false); SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy()); SDValue SizeNode = DAG.getConstant(Size, MVT::i32); Chain = DAG.getMemcpy(Chain, dl, FIPtr, Arg, SizeNode, Align, false, //isVolatile, (Size <= 32), //AlwaysInline if size <= 32 MachinePointerInfo(), MachinePointerInfo()); ByValArgs.push_back(FIPtr); } Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true)); SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass; SmallVector<SDValue, 8> MemOpChains; const unsigned StackOffset = 92; bool hasStructRetAttr = false; // Walk the register/memloc assignments, inserting copies/loads. for (unsigned i = 0, realArgIdx = 0, byvalArgIdx = 0, e = ArgLocs.size(); i != e; ++i, ++realArgIdx) { CCValAssign &VA = ArgLocs[i]; SDValue Arg = OutVals[realArgIdx]; ISD::ArgFlagsTy Flags = Outs[realArgIdx].Flags; //Use local copy if it is a byval arg. if (Flags.isByVal()) Arg = ByValArgs[byvalArgIdx++]; // 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 (Flags.isSRet()) { assert(VA.needsCustom()); // store SRet argument in %sp+64 SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); SDValue PtrOff = DAG.getIntPtrConstant(64); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo(), false, false, 0)); hasStructRetAttr = true; continue; } if (VA.needsCustom()) { assert(VA.getLocVT() == MVT::f64); if (VA.isMemLoc()) { unsigned Offset = VA.getLocMemOffset() + StackOffset; //if it is double-word aligned, just store. if (Offset % 8 == 0) { SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); SDValue PtrOff = DAG.getIntPtrConstant(Offset); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo(), false, false, 0)); continue; } } SDValue StackPtr = DAG.CreateStackTemporary(MVT::f64, MVT::i32); SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Arg, StackPtr, MachinePointerInfo(), false, false, 0); // Sparc is big-endian, so the high part comes first. SDValue Hi = DAG.getLoad(MVT::i32, dl, Store, StackPtr, MachinePointerInfo(), false, false, 0); // Increment the pointer to the other half. StackPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), StackPtr, DAG.getIntPtrConstant(4)); // Load the low part. SDValue Lo = DAG.getLoad(MVT::i32, dl, Store, StackPtr, MachinePointerInfo(), false, false, 0); if (VA.isRegLoc()) { RegsToPass.push_back(std::make_pair(VA.getLocReg(), Hi)); assert(i+1 != e); CCValAssign &NextVA = ArgLocs[++i]; if (NextVA.isRegLoc()) { RegsToPass.push_back(std::make_pair(NextVA.getLocReg(), Lo)); } else { //Store the low part in stack. unsigned Offset = NextVA.getLocMemOffset() + StackOffset; SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); SDValue PtrOff = DAG.getIntPtrConstant(Offset); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); MemOpChains.push_back(DAG.getStore(Chain, dl, Lo, PtrOff, MachinePointerInfo(), false, false, 0)); } } else { unsigned Offset = VA.getLocMemOffset() + StackOffset; // Store the high part. SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); SDValue PtrOff = DAG.getIntPtrConstant(Offset); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); MemOpChains.push_back(DAG.getStore(Chain, dl, Hi, PtrOff, MachinePointerInfo(), false, false, 0)); // Store the low part. PtrOff = DAG.getIntPtrConstant(Offset+4); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); MemOpChains.push_back(DAG.getStore(Chain, dl, Lo, PtrOff, MachinePointerInfo(), false, false, 0)); } continue; } // Arguments that can be passed on register must be kept at // RegsToPass vector if (VA.isRegLoc()) { if (VA.getLocVT() != MVT::f32) { RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); continue; } Arg = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Arg); RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); continue; } assert(VA.isMemLoc()); // Create a store off the stack pointer for this argument. SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset()+StackOffset); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo(), false, false, 0)); } // Emit all stores, make sure the occur before any copies into physregs. if (!MemOpChains.empty()) Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &MemOpChains[0], MemOpChains.size()); // 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) { unsigned Reg = RegsToPass[i].first; // Remap I0->I7 -> O0->O7. if (Reg >= SP::I0 && Reg <= SP::I7) Reg = Reg-SP::I0+SP::O0; Chain = DAG.getCopyToReg(Chain, dl, Reg, RegsToPass[i].second, InFlag); InFlag = Chain.getValue(1); } unsigned SRetArgSize = (hasStructRetAttr)? getSRetArgSize(DAG, Callee):0; // 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<GlobalAddressSDNode>(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32); // Returns a chain & a flag for retval copy to use SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); SmallVector<SDValue, 8> Ops; Ops.push_back(Chain); Ops.push_back(Callee); if (hasStructRetAttr) Ops.push_back(DAG.getTargetConstant(SRetArgSize, MVT::i32)); for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) { unsigned Reg = RegsToPass[i].first; if (Reg >= SP::I0 && Reg <= SP::I7) Reg = Reg-SP::I0+SP::O0; Ops.push_back(DAG.getRegister(Reg, RegsToPass[i].second.getValueType())); } if (InFlag.getNode()) Ops.push_back(InFlag); Chain = DAG.getNode(SPISD::CALL, dl, NodeTys, &Ops[0], Ops.size()); InFlag = Chain.getValue(1); Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true), DAG.getIntPtrConstant(0, true), InFlag); InFlag = Chain.getValue(1); // Assign locations to each value returned by this call. SmallVector<CCValAssign, 16> RVLocs; CCState RVInfo(CallConv, isVarArg, DAG.getTarget(), RVLocs, *DAG.getContext()); RVInfo.AnalyzeCallResult(Ins, RetCC_Sparc32); // Copy all of the result registers out of their specified physreg. for (unsigned i = 0; i != RVLocs.size(); ++i) { unsigned Reg = RVLocs[i].getLocReg(); // Remap I0->I7 -> O0->O7. if (Reg >= SP::I0 && Reg <= SP::I7) Reg = Reg-SP::I0+SP::O0; Chain = DAG.getCopyFromReg(Chain, dl, Reg, RVLocs[i].getValVT(), InFlag).getValue(1); InFlag = Chain.getValue(2); InVals.push_back(Chain.getValue(0)); } return Chain; }