From 98d1378343c0e38b29dee4eba085230f81cb7ca2 Mon Sep 17 00:00:00 2001 From: Duraid Madina Date: Thu, 22 Dec 2005 04:07:40 +0000 Subject: [PATCH] I shoulda done this a *long* time ago (tm): implement calls properly, i.e. r1/r12/rp are saved/restored regardless of scheduling/luck TODO: calls to external symbols, indirect (function descriptor) calls, performance (we're being paranoid right now) BUG: the code for handling calls to vararg functions breaks if FP args are passed (this will make printf() go haywire so a bunch of tests will fail) BUG: this seems to trigger some legalize nastiness git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24942 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/IA64/IA64ISelLowering.cpp | 178 ++++++++++++++++++++++++--- 1 file changed, 160 insertions(+), 18 deletions(-) diff --git a/lib/Target/IA64/IA64ISelLowering.cpp b/lib/Target/IA64/IA64ISelLowering.cpp index 6bfa7931988..009a337155d 100644 --- a/lib/Target/IA64/IA64ISelLowering.cpp +++ b/lib/Target/IA64/IA64ISelLowering.cpp @@ -282,13 +282,25 @@ IA64TargetLowering::LowerCallTo(SDOperand Chain, MF.getInfo()->outRegsUsed= std::max(outRegsUsed, MF.getInfo()->outRegsUsed); + // keep stack frame 16-byte aligned + //assert(NumBytes==((NumBytes+15) & ~15) && "stack frame not 16-byte aligned!"); + NumBytes = (NumBytes+15) & ~15; + Chain = DAG.getNode(ISD::CALLSEQ_START, MVT::Other, Chain, DAG.getConstant(NumBytes, getPointerTy())); - std::vector args_to_use; + SDOperand StackPtr, NullSV; + std::vector Stores; + std::vector RegValuesToPass; + unsigned ArgOffset = 16; + for (unsigned i = 0, e = Args.size(); i != e; ++i) { - switch (getValueType(Args[i].second)) { + SDOperand Val = Args[i].first; + MVT::ValueType ObjectVT = Val.getValueType(); + SDOperand ValToStore; + unsigned ObjSize=8; + switch (ObjectVT) { default: assert(0 && "unexpected argument type!"); case MVT::i1: case MVT::i8: @@ -297,34 +309,164 @@ IA64TargetLowering::LowerCallTo(SDOperand Chain, //promote to 64-bits, sign/zero extending based on type //of the argument if(Args[i].second->isSigned()) - Args[i].first = DAG.getNode(ISD::SIGN_EXTEND, MVT::i64, - Args[i].first); + Val = DAG.getNode(ISD::SIGN_EXTEND, MVT::i64, Val); else - Args[i].first = DAG.getNode(ISD::ZERO_EXTEND, MVT::i64, - Args[i].first); + Val = DAG.getNode(ISD::ZERO_EXTEND, MVT::i64, Val); + // XXX: fall through + case MVT::i64: + //ObjSize = 8; + if(RegValuesToPass.size() >= 8) { + ValToStore = Val; + } else { + RegValuesToPass.push_back(Val); + } break; case MVT::f32: //promote to 64-bits - Args[i].first = DAG.getNode(ISD::FP_EXTEND, MVT::f64, Args[i].first); + Val = DAG.getNode(ISD::FP_EXTEND, MVT::f64, Val); + // XXX: fall through case MVT::f64: - case MVT::i64: + if(RegValuesToPass.size() >= 8) { + ValToStore = Val; + } else { + RegValuesToPass.push_back(Val); + } break; } - args_to_use.push_back(Args[i].first); + + if(ValToStore.Val) { + if(!StackPtr.Val) { + StackPtr = DAG.getRegister(IA64::r12, MVT::i64); + NullSV = DAG.getSrcValue(NULL); + } + SDOperand PtrOff = DAG.getConstant(ArgOffset, getPointerTy()); + PtrOff = DAG.getNode(ISD::ADD, MVT::i64, StackPtr, PtrOff); + Stores.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain, + ValToStore, PtrOff, NullSV)); + } + ArgOffset += ObjSize; } - std::vector RetVals; - MVT::ValueType RetTyVT = getValueType(RetTy); - if (RetTyVT != MVT::isVoid) - RetVals.push_back(RetTyVT); - RetVals.push_back(MVT::Other); + // Emit all stores, make sure they occur before any copies into physregs. + if (!Stores.empty()) + Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, Stores); - SDOperand TheCall = SDOperand(DAG.getCall(RetVals, Chain, - Callee, args_to_use), 0); - Chain = TheCall.getValue(RetTyVT != MVT::isVoid); + static const unsigned IntArgRegs[] = { + IA64::out0, IA64::out1, IA64::out2, IA64::out3, + IA64::out4, IA64::out5, IA64::out6, IA64::out7 + }; + + static const unsigned FPArgRegs[] = { + IA64::F8, IA64::F9, IA64::F10, IA64::F11, + IA64::F12, IA64::F13, IA64::F14, IA64::F15 + }; + + SDOperand InFlag; + + // save the current GP, SP and RP : FIXME: do we need to do all 3 always? + SDOperand GPBeforeCall = DAG.getCopyFromReg(Chain, IA64::r1, MVT::i64, InFlag); + Chain = GPBeforeCall; + InFlag = Chain.getValue(1); + SDOperand SPBeforeCall = DAG.getCopyFromReg(Chain, IA64::r12, MVT::i64, InFlag); + Chain = SPBeforeCall; + InFlag = Chain.getValue(1); + SDOperand RPBeforeCall = DAG.getCopyFromReg(Chain, IA64::rp, MVT::i64, InFlag); + Chain = RPBeforeCall; + InFlag = Chain.getValue(1); + + // Build a sequence of copy-to-reg nodes chained together with token chain + // and flag operands which copy the outgoing integer args into regs out[0-7] + // mapped 1:1 and the FP args into regs F8-F15 "lazily" + // TODO: for performance, we should only copy FP args into int regs when we + // know this is required (i.e. for varardic or external (unknown) functions) + unsigned usedFPArgs = 0; + for (unsigned i = 0, e = RegValuesToPass.size(); i != e; ++i) { + Chain = DAG.getCopyToReg(Chain, + MVT::isInteger(RegValuesToPass[i].getValueType()) ? + IntArgRegs[i] : FPArgRegs[usedFPArgs++], + RegValuesToPass[i], InFlag); + InFlag = Chain.getValue(1); + + //FIXME: for performance, only do the following when required + + // if we have just copied an FP arg, copy its in-memory representation + // to the appropriate integer register +/* if(MVT::isFloatingPoint(RegValuesToPass[i].getValueType())) { + Chain = DAG.getTargetNode(IA64::GETFD, MVT::i64, RegValuesToPass[i], Chain, InFlag); + InFlag = Chain.getValue(0); // XXX + Chain = DAG.getCopyToReg(Chain, IntArgRegs[i], Chain, InFlag); // ...thrice! + InFlag = Chain.getValue(1); + } */ + + } + + std::vector RetVals; + RetVals.push_back(MVT::Other); + RetVals.push_back(MVT::Flag); + + // 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. + if (GlobalAddressSDNode *G = dyn_cast(Callee)) + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), MVT::i64); + + std::vector NodeTys; + NodeTys.push_back(MVT::Other); // Returns a chain + NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use. + if (InFlag.Val) + Chain = SDOperand(DAG.getCall(NodeTys, Chain, Callee, InFlag), 0); + else + Chain = SDOperand(DAG.getCall(NodeTys, Chain, Callee), 0); + InFlag = Chain.getValue(1); + + // restore the GP, SP and RP after the call + Chain = DAG.getCopyToReg(Chain, IA64::r1, GPBeforeCall, InFlag); + InFlag = Chain.getValue(1); + Chain = DAG.getCopyToReg(Chain, IA64::r12, SPBeforeCall, InFlag); + InFlag = Chain.getValue(1); + Chain = DAG.getCopyToReg(Chain, IA64::rp, RPBeforeCall, InFlag); + InFlag = Chain.getValue(1); + + MVT::ValueType RetTyVT = getValueType(RetTy); + SDOperand RetVal; + if (RetTyVT != MVT::isVoid) { + switch (RetTyVT) { + default: assert(0 && "Unknown value type to return!"); + case MVT::i1:/* { // bools are just like other integers (returned in r8) + SDOperand boolInR8 = DAG.getCopyFromReg(Chain, IA64::r8, MVT::i64, InFlag); + RetVal = DAG.getTargetNode(IA64::CMPNE, MVT::i1, // FIXME: is this flagged correctly? + DAG.getRegister(IA64::r0, MVT::i64), boolInR8, Chain, InFlag); + Chain = RetVal.getValue(1); + // Add a note to keep track of whether it is sign or zero extended - TODO: bools + RetVal = DAG.getNode(RetTy->isSigned() ? ISD::AssertSext :ISD::AssertZext, + MVT::i64, RetVal, DAG.getValueType(RetTyVT)); + RetVal = DAG.getNode(ISD::TRUNCATE, RetTyVT, RetVal); + break; + }*/ + case MVT::i8: + case MVT::i16: + case MVT::i32: + RetVal = DAG.getCopyFromReg(Chain, IA64::r8, MVT::i64, InFlag); + Chain = RetVal.getValue(1); + + // Add a note to keep track of whether it is sign or zero extended - TODO: bools + RetVal = DAG.getNode(RetTy->isSigned() ? ISD::AssertSext :ISD::AssertZext, + MVT::i64, RetVal, DAG.getValueType(RetTyVT)); + RetVal = DAG.getNode(ISD::TRUNCATE, RetTyVT, RetVal); + case MVT::i64: + RetVal = DAG.getCopyFromReg(Chain, IA64::r8, MVT::i64, InFlag); + Chain = RetVal.getValue(1); + break; + case MVT::f64: + RetVal = DAG.getCopyFromReg(Chain, IA64::F8, MVT::f64, InFlag); + Chain = RetVal.getValue(1); + break; + } + } + Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain, DAG.getConstant(NumBytes, getPointerTy())); - return std::make_pair(TheCall, Chain); + + return std::make_pair(RetVal, Chain); } SDOperand