I have installed Debian GNU/Linux on my Amiga 3000. That, along with NetBSD
on the HP425, allows me to compare Linux and NetBSD calling conventions.
Linux and NetBSD use different assembly language syntax. This is best
illustrated with the following C program:
double foo(double a)
{
return a * a + 1.0;
}
Under Linux, the resulting assembly code (gcc -S test.c) is:
.file "test.c"
.version "01.01"
gcc2_compiled.:
.text
.align 2
.globl foo
.type foo,@function
foo:
link.w %a6,#0
fmove.d 8(%a6),%fp0
fmul.d 8(%a6),%fp0
fmovecr #0x32,%fp1
fadd.x %fp1,%fp0
unlk %a6
rts
.Lfe1:
.size foo,.Lfe1-foo
.ident "GCC: (GNU) 2.7.2.3"
Under NetBSD:
#NO_APP
gcc2_compiled.:
___gnu_compiled_c:
.text
.even
.globl _foo
.type _foo,@function
_foo:
link a6,#0
fmoved a6@(8),fp0
fmuld a6@(8),fp0
fmovecr #0x32,fp1
faddx fp0,fp1
fmoved fp1,sp@-
movel sp@+,d0
movel sp@+,d1
unlk a6
rts
Lfe1:
.size _foo,Lfe1-_foo
Some things to note:
1. NetBSD uses the "MIT syntax", whereas Linux uses a more traditional M68K
syntax. With the exception of the '%' before register names, the Linux
assembler conforms to the assembly language format used in the Motorola
manuals.
The NetBSD syntax must not use a '%' in register names, and the addressing
modes are written somewhat differently.
2. Linux returns floating point values in fp0. NetBSD uses d0/d1.
All this creates problems for us, of course. Kiyo has tried to unify
the sysdepCallMethod for Linux and NetBSD. Unfortunately, the differing
syntax makes this all but impossible. For this reason, I recommend that
trampolines.c and common.h be split into Linux- and NetBSD-specific versions,
each using the proper syntax. As well, a comment should be added to each
piece of code noting that it is the same as its counterpart except for the
syntax, and that any bug found in one segment of code must also be fixed
in its counterpart.
The next problem to resolve is how to return floating-point values.
Since Kaffe's JIT is not compatible at the moment with the C calling
conventions, we have the freedom to take a definitive decision. There are
two logical ways to proceed:
1. Use the OS native calling convention. This will require separate code
for Linux and NetBSD.
2. Pick a convention and use it throughout. This will impact one of the OSes,
in that some translation may be necessary.
There are two cases to consider: returning a value from Java code into Java
code, and returning a value from Java code into native code.
Returning into native code is accomplished by sysdepCallMethod(). Right now,
Kiyo has this OS-dependent (approach #1).
Returning into Java code is accomplished by returnarg_double(). Right now,
this works with the Linux calling convention only. There is only one
definition of define_insn(returnarg_double, ...) in jit-m68k.def, and it
refers only to fp0. The same code for the return_double code that picks
up the value from fp0 on the caller's side.
As it currently stands, the code will work only on Linux, because that is
the only system in which the two return methods are consistent.
I propose that we adopt the Linux convention of returning floating-point
results in fp0 throughout. I say this even though I'm a NetBSD bigot because
the Linux method is simply more efficient to a good JIT: the return value
is in a floating-point register, waiting for use without further ado.
Also, this requires no changes to the JIT itself. The only change required
is to sysdepCallMethod(), to always use fp0.
To summarize:
1. Re-write sysdepCallMethod() for m68k to always pick up floating point
results from fp0, and to not clobber registers.
2. Provide separate (syntax changes only) NetBSD and Linux versions of
all assembly code.
I am willing to do this for both NetBSD and Linux, testing on my 425 and
Amiga as appropriate. Are there any comments before I do so?