[Openmcl-devel] CCL LAP info...
R. Matthew Emerson
rme at clozure.com
Sat Feb 13 21:41:06 UTC 2010
On Feb 13, 2010, at 2:01 PM, Jon S. Anthony wrote:
> I've been hacking some LAP functions (x86 only). I've looked/googled
> around but don't see any basic description (or detailed for that matter)
> of the "proper" protocol for writing and using them. The earlier
> comments about toggle tagging temps as immediates/nodes in X8632 was
> very useful!
> And I have found some small bits of information (for
> example, what the various @ $ %, etc forms are for operand defs) in the
> source. And looking over various example LAPs in the code base (and
> using a few x86 ref manuals) I have been able to get a decent enough
> idea to get some things working.
> So, any overview on this stuff available?
Well, not really.
> I suppose my major concerns
> are about proper protocol of using registers.
> BTW, are all registers
> saved on the stack at point of call?
On x8664, the registers save0 through save3 must be saved by the callee. And on some ports (win64, darwin), save3 (aka r11) is the TCR pointer, so you shouldn't mess with that.
Another register you don't mess with is %fn. An instruction to "establish fn" is automatically inserted at the beginning of a LAP function.
We also don't try to use ebp for anything other than the frame pointer.
Otherwise, you can use the registers as you please.
> I suppose that is an x86 question
> more than a CCL lap question, but if you know the answer, that would be
> cool! Also, any info on return results from function. I have been able
> (by reading, getting an idea and then cribbing some example code) to
> return single values in arg_z, but don't know if that is the standard
> return reg or what.
Yes, arg_z is where a single value is returned.
If your LAP function has more than 2 args (or 3 on x8664), then some of the args will be passed on the stack, and when you return, you need to pop those off the stack. Another probably non-obvious thing is that when a function takes args on the stack, the *caller* pushes space for a frame. Many LAP functions don't bother to set up a stack frame, though. That's why (on x8632) you'll see (single-value-return 3) when a function takes 1 stack arg. The 3 is the number of extra words to discard from the stack (the arg, and the two reserved words for the stack frame).
(defx8632lapfunction 3-arg-taker ((stack-arg1 4) #|(ra 0)|#
(arg2 arg_y) (arg3 arg_z))
;; last two args passed in registers, others are on the stack
(movl (@ stack-arg1 (% esp)) (% temp0))
(movl (% temp0) (% arg_z))
? (defun 3-arg-caller ()
(3-arg-taker 1 2 3)
? (df *)
;;; (defun 3-arg-caller () (3-arg-taker 1 2 3) 'foo)
 (testl (% temp1) (% temp1))
 (jne L66)
 (pushl (% ebp))
 (movl (% esp) (% ebp))
;;; (3-arg-taker 1 2 3)
;; here the caller reserves space for a frame
 (pushl ($ -21))
 (pushl ($ -21))
;; pass the first parameter on the stack
;; (the number 4 represents fixnum 1)
 (pushl ($ 4))
;; pass last two parameters in registers
 (movl ($ 8) (% arg_y))
 (movl ($ 12) (% arg_z))
;; number of arguments, as a fixnum
;; on x8632, temp1 doubles as nargs
 (movl ($ 12) (% temp1))
 (movl (@ '3-ARG-TAKER (% fn)) (% temp0))
;; nops for proper alignment of return address
 (leal (@ 0 (% arg_y)) (% arg_y))
 (calll (@ 6 (% temp0)))
 (movl (@ 'FOO (% fn)) (% arg_z))
;;; #<no source text>
Multiple values are more complicated: you save the current stack pointer in temp0, push your values on the stack, set nargs to the (fixnum) number of values you pushed, and then do (jmp-subprim .SPvalues). Look at %fixnum-truncate for a fairly simple example of doing this.
More information about the Openmcl-devel