[LLVMdev] RFC: Tail call optimization X86

Evan Cheng evan.cheng at apple.com
Fri Oct 5 10:41:46 PDT 2007


On Oct 5, 2007, at 2:42 AM, Arnold Schwaighofer wrote:

> Hi Evan,
> I incoporated the changes you request but to the following i have got
> a question:
>
>> Also, moving the option
>> there will allow us to change fastcc ABI (callee popping arguments)
>> only when this option is on. See Chris' email:
>
> I am not to sure on that. because that would make modules compiled
> with the flag on incompatible with ones compiled without the flag off
> as stack behaviour would mismatch.
> It would be no problem to make the behaviour dependent on the -tail-
> call-opt flag. i am not sure that this is a good idea?

In theory, any function can be marked fastcc. But llvm-gcc c / c++  
frontend does *not* mark any external functions fastcc. Also, the  
optimizer only changes the calling convention of internal functions  
to fastcc. We can set a policy of treating fastcc external functions  
as c functions. Then there is no chance of introducing ABI  
incompatibility.

>
> pseudocode:
>
> module 1: with -tailcallopt enabled
> fastcc int callee(int arg1, int arg2) {
> ...
> -> onreturn: pops 8 byte
> }
>
> module 2: no -tailcallopt
> fastcc int caller() {
> 	int x= call fastcc callee();
> 	//!! caller pops the arguments => stack mismatch
>
> callee pops the arguments but caller also wants to pop the arguments
> of the stack
>
> Apparently i forgot to send the answer email to chris reponse. sorry
> for that.
>>
>>> Hmmm. Ok. So this is due to X86CallingConv.td changes? Unfortunately
>>> that's not controlled by options. Ok then.
>>>
>>
>> Sure it can be, you can set up custom predicates, for example the
>> X86CallingConv.td file has:
>>
>> class CCIfSubtarget<string F, CCAction A>
>>   : CCIf<!strconcat("State.getTarget().getSubtarget<X86Subtarget>
>> ().", F), A>;
>>
>> It would be straight-forward to have a CCIf defined to check some
>> command
>> line argument.  I think enabling this as llcbeta for a few nights
>> makes
>> sense before turning it on by default.
> No not directly. The code related to "caller/callee cleans arguments
> off the stack" is not controlled by the .td. It's controlled in code
> by the operands of CALLSEQ_END.

Ok, that's even easier to have it be controlled by the command line  
option.

Evan

>
> for example in SDOperand X86TargetLowering::LowerCCCCallTo:
> ...
>    if (CC == CallingConv::X86_StdCall || CC == CallingConv::Fast) {
>      if (isVarArg)
>        NumBytesForCalleeToPush = isSRet ? 4 : 0;
>      else
>        NumBytesForCalleeToPush = NumBytes;
>      assert(!(isVarArg && CC==CallingConv::Fast) &&
>              "CallingConv::Fast does not support varargs.");
>    } else {
>      // If this is is a call to a struct-return function, the callee
>      // pops the hidden struct pointer, so we have to push it back.
>      // This is common for Darwin/X86, Linux & Mingw32 targets.
>      NumBytesForCalleeToPush = isSRet ? 4 : 0;
>    }
>
>    NodeTys = DAG.getVTList(MVT::Other, MVT::Flag);
>    Ops.clear();
>    Ops.push_back(Chain);
>    Ops.push_back(DAG.getConstant(NumBytes, getPointerTy()));
>    Ops.push_back(DAG.getConstant(NumBytesForCalleeToPush, getPointerTy
> ()));
>    Ops.push_back(InFlag);
>    Chain = DAG.getNode(ISD::CALLSEQ_END, NodeTys, &Ops[0], Ops.size 
> ());
>    InFlag = Chain.getValue(1);
>
>    The third operand is the number of bytes the callee pops of the
> stack on return (on x86). This gets lowered to a ADJCALLSTACKUP
> pseudo machineinstruction.
>
> Later when X86RegisterInfo::eliminateCallFramePseudoInstr is called
> and framepointerelimination is enabled the following code gets called:
> ...
>    else if (I->getOpcode() == X86::ADJCALLSTACKUP) {
>      // If we are performing frame pointer elimination and if the
> callee pops
>      // something off the stack pointer, add it back.  We do this
> until we have
>      // more advanced stack pointer tracking ability.
>      if (uint64_t CalleeAmt = I->getOperand(1).getImm()) {
>        unsigned Opc = (CalleeAmt < 128) ?
>          (Is64Bit ? X86::SUB64ri8 : X86::SUB32ri8) :
>          (Is64Bit ? X86::SUB64ri32 : X86::SUB32ri);
>        MachineInstr *New =
>          BuildMI(TII.get(Opc), StackPtr).addReg(StackPtr).addImm
> (CalleeAmt);
>        MBB.insert(I, New);
>      }
>    }
>
> I am not sure about a command line switch would toggling the stack
> adjusting behaviour of a function. Because if the function is called
> from a different module which was compiled with the opposite command
> line switch all hell would break loose (because it assumes callee
> pops arguments when it does not).
> _______________________________________________
> LLVM Developers mailing list
> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev




More information about the llvm-dev mailing list