[LLVMdev] Destination register needs to be valid after callee saved register restore when tail calling

Evan Cheng evan.cheng at apple.com
Thu Aug 9 02:06:29 PDT 2007



Sent from my iPhone

On Aug 8, 2007, at 10:46 AM, Arnold Schwaighofer <arnold.schwaighofer at gmail.com 
 > wrote:

> Hi Anton and Dale
> first thanks for your answers.
>
> On 8 Aug 2007, at 16:43, Anton Korobeynikov wrote:
>
>> Hello, Arnold.
>>
>>> Is there a way to indicate that the register the tail call
>>> instruction uses as destination needs to be valid after the callee
>>> saved registers have been restored? (some X86InstrInfo.td foo magic
>>> maybe ?)
>> It's wrong way to do the things. Because in this case you either
>> violate
>> the ABI for callee, or you're restricted to do tail call lowering  
>> only
>> for internal functions, making all stuff inpractical. . Only
>> call-clobbered registers can be used to store pointer to callee (I'd
>> suggest %ecx on x86/32, btw).
>>
>
> yes i cannot use the calleesaved registers for calling. i realized
> that. likely i did not express myself clearly. (sorry for that)
> it is not me who is loading the target address to the callee saved
> register but the register allocator
> decides to load the function pointer  to esi because it assumes it is
> safe to do so. normally this is the case because
> if you do a regular function call the code to restore registers would
> be inserted after the function call. so register esi is
> still valid.

Hmm. Seems like somthing else is wrong. The register allocator is free  
to use a callee saved register to store the function ptr provided it's  
not live. It's likely your lowering code isn't setting up things  
properly.

Anyway, I am pretty sure target specific dag combiner isn't the right  
way to implement tail call. We wanted something more general. Since  
there seems to be interests in this. Perhaps this is a good time to  
formula a plan. I'll talk to Chris about this.

Thx

Evan

>
> with the sentence i tried to express the question whether there is a
> way to persuade the code generator to use
> another register to load (or move) the function pointer to (right
> before the callee saved register restore) but thinking a little
> further that's nonsense.
>
> something like
> let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1,
> noResults = 1,
>    ifDestRegisterisCalleeSavedEmitAMoveToECXAndJumpToThat=1
>   in
>   def TAILJMPr : I<0xFF, MRM4r, (ops GR32:$dst), "jmp {*}$dst  #
> TAIL CALL jmpr",
>                  []>;
>
> On 8 Aug 2007, at 18:27, Dale Johannesen wrote:
>> Inserting a pseudo before your tail call that defines all the callee-
>> saved
>> registers should work.  See FP_REG_KILL.
>
> the trick of dale seems to work with the downside that all registers
> are safed (and in llvm-2.0 the epilogue inserter ignoring
> the isTerminator instruction - note to myself: should move to trunk
> soon!)
>
> another option would be to do the move from the register holding the
> function pointer to a register like ECX myself (as you say),
>
>>> Or do i have to insert code into PEI::saveCalleeSavedRegisters to
>>> detect that there is a tail called function that uses a callee saved
>>> register and move it to another (EAX).
>> You shouldn't use call-saved registers at all. Only call-clobbered.  
>> It
>> seems, that you can use the trick similar to eh_return lowering (that
>> case is somehow special, because %eax and %edx should be preserved
>> there
>> too). You can see it in TOT for x86 target (also, prologue/epilogue
>> emission code changed on TOT, you might want to check, whether your
>> code
>> works for it).
>>
>
> Sorry i was under the misconception that eax is call-clobbered too
> since it contains the function result.
>
> TOT means trunk of today (funny because in german, my native language
> it means death)?
>
> So what i will be trying then is to emit a copytoreg from the virtual
> register holding the
> function pointer to ecx before the tailcall node.
>
> So where i approximately had this before (assuming that RetNode.getOp
> (1) is not a TargetGlobalAddress or the like)
>
> SDOperand OpsTailCall [] = {AdjStackChain, RetNode.getOperand(1),
> RetNode.getOperand(2)};
> RetNode = DCI.DAG.getNode(X86ISD::TAILCALL, TCVTs, OpsTailCall,3);
>
> would then be replaced by
>
> Chain = DAG.getCopyToReg(AdjStackChain, X86::ECX, RetNode.getOperand
> (1));
> SDOperand OpsTailCall [] = {Chain,DAG.getRegister(X86::ECX,
> getPointerTy())), RetNode.getOperand(2)};
> RetNode = DCI.DAG.getNode(X86ISD::TAILCALL, TCVTs, OpsTailCall, 3);
>
> the downside here is that ECX is no longer free for passing function
> arguments. (i am using the x86_fastcall semantics at the moment with
> first
> two arguments stored in ecx,edx)
>
> does that sound sane?
>
> yes i will try against the trunk soon when i am in a masochistic
> deathly mood ;). maybe tonight.
> and sorry if i am bothering you with questions whose answer should be
> obvious. i am really a total newbie greenhorn :)
>
>
> regards arnold
>> PS: Feel free to contact me in case of any related questions. In
>> fact, I
>> planned to start tail call lowering within next 2-3 weeks :)
>>
>> --
>> WBR, Anton Korobeynikov
>> _______________________________________________
>> LLVM Developers mailing list
>> LLVMdev at cs.uiuc.edu         http://llvm.cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
>
> _______________________________________________
> 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