f



misc, OT: C compiler, x86-64 or not x86-64...

well, I have my C compiler, for now, for the most part, it is working (and 
being used in my projects for its amazing scripting powers).

but, now, there is a new mystery:
do for now, I count my blessings, and just continue using it for plain x86, 
or partly branch my lower compiler and make an x86-64 version as well?...

before, I had thought, well, x86-64 would very likely require nearly 
completely rewriting my lower compiler. now, maybe, maybe not (could be able 
to get by just with minor modifications...).

me now thinking, as it is structured, it would be less work than it would 
have been before. could just cruft over a few things.


the rest of the post is me thinking of how I could structure things...

another minor issue:
support just the linux calling convention, or attempt both the linux and MS 
conventions?...

main changes:
well, the regs have different names (rax vs eax, ...);
need to maintain even stack alignment;
some regs are used for arg passing;
....

so, assuming for now the linux convention:
need to preserve: RBX and RBP, R12-15;
args passed in: RDI, RSI, RDX, RCX, R8, R9, and XMM0-7.

this leaves free ('true' scratch):
RAX, R10, R11, XMM8-15

so, as I may adjust my compiler:
Top Of Stack is stored in RAX, potentially with R10 and R11 as a secondary 
and tertiary TOS values (or, I could stick to only having 2 TOS values, 
maybe in RAX and R10, or R10 and R11).

these regs may be, as before, flushed for intermediate calculations.

R12-R15 will be used by the register allocator (for holding variables).

within the main body, the args will be allocated space for a "backing-store" 
(this mechanism would require reworking how I currently manage args and 
locals, assigning various offsets for vars, rather than the current dynamic 
lookup/offset-calculation approach).

as such, flushing a register for an arg (when holding an arg), will return 
it to the backing store (initially, the backing store will be created, and 
the register allocator set up as if the args had been pulled from these 
locations).

when constructing a function call, regs will be flushed into the "red zone", 
and will be periodically restored (not good: it is unclear how to apply this 
to nested-calls). in x86, there is always the stack. one option is, when a 
nested mark is done, any intermediate args are forced to the stack.

the 'call' function is likely to detect this case, and generate code to pop 
the values back off the stack.


a much simpler, though less efficient approach is that of always generating 
args on the stack (as in x86), and popping them off just prior to the call. 
in this case, I have a lot more scratch registers (this would make the port 
a lot easier).

the only real issue then in this case is the need to preserve proper stack 
alignment (probably a special hack in the 'mark' function, will check the 
size of the args and the stack pos and potentially insert a 'dummy' stack 
item). this would be more difficult for vararg functions...


as such, the internal convention would be more an adaptation of my current 
x86 convention:
RAX and RDX, are often used as the primary and secondary TOS;
RCX, RSI, RDI, special, used for pointers, ... in intermediate calculations;
R8, R9, R10, R11, termporary (flushed without worry);
R12, R13, R14, R15, used by register allocator for vars.

potentially, RCX/RSI/RDI could be 'semi-volatile', aka: they will not be 
modified implicitly by psuedo-ops, but are not required to be preseved 
between RIL ops;
R8-11 could be 'very volatile', aka, it is not even needed to flush them, 
and may be used freely by psuedo-ops (nothing similar exists in my current 
x86 target).

or such...



0
cr88192
7/31/2007 12:08:25 AM
comp.lang.misc 1780 articles. 1 followers. Post Follow

2 Replies
473 Views

Similar Articles

[PageSpeed] 42

On Jul 30, 7:08 pm, "cr88192" <cr88...@hotmail.com> wrote:
> well, I have my C compiler, for now, for the most part, it is working (and
> being used in my projects for its amazing scripting powers).
>
> but, now, there is a new mystery:
> do for now, I count my blessings, and just continue using it for plain x86,
> or partly branch my lower compiler and make an x86-64 version as well?...

If you wish to take advantage of the extra registers and what-not...
then yes. Otherwise, just take advantage of the fact that most 32-bit
apps will still run and concentrate on producing a solid 32-bit
version.

0
SpooK
7/31/2007 1:50:23 AM
"SpooK" <keith@dynatos.net> wrote in message 
news:1185846623.051293.105650@i13g2000prf.googlegroups.com...
> On Jul 30, 7:08 pm, "cr88192" <cr88...@hotmail.com> wrote:
>> well, I have my C compiler, for now, for the most part, it is working 
>> (and
>> being used in my projects for its amazing scripting powers).
>>
>> but, now, there is a new mystery:
>> do for now, I count my blessings, and just continue using it for plain 
>> x86,
>> or partly branch my lower compiler and make an x86-64 version as well?...
>
> If you wish to take advantage of the extra registers and what-not...
> then yes. Otherwise, just take advantage of the fact that most 32-bit
> apps will still run and concentrate on producing a solid 32-bit
> version.
>

mostly, I want to be able to compile code on 64-bit linux and similar absent 
having to force my app to be 32-bit on account of the dynamic compiler. some 
loss of efficiency is tolerable, but the ability to link with the code 
directly is important.

if I could ignore calling external functions, I could get by pretending 
x86-64 was just x86 with more regs, but otherwise, I would have to support 
the native calling conventions (annoyingly, different between windows and 
linux).

the current considered approach (dumping out stuff on the stack and 
reloading into regs at function call time) should be simpler than supporting 
the convention 'natively', albeit is less efficient...

(would have been nice had windows and linux used the same calling 
convention...).


the other option, is not to bother for the time being (after all, my primary 
development target is plain-old 32 bit code).

in any case, this may be a 'longer term' decision...

another route may be to work on generalizing and breaking up some of the 
cruft in my current lower compiler, so that later on, if needed, such a 
change would be less drastic (much more like how my assembler works, same 
basic mechanics generate all of 16, 32, and 64 bit code).

the current lower compiler was largely written under the assumption that it 
would likely be simply replaced for the 64-bit target, but has ended up 
being a somewhat larger piece of machinery than was originally intended (and 
has a lot more potentially reusable mechanics).

it recieves as input a language I call RPNIL, or a kind of 
psuedo-declarative RPN-style language. for the most part, things like 
constant folding, code reorganization, decomposing various syntactic forms 
into basic abstact operations, "pre-cooking" the typesystem, ... is done in 
the upper compiler.


however, at present, the lower compiler is a little ad-hoc and inflexible 
(simply getting it working, and to a lesser extent producing clean output, 
being a much higher priority than making it nice or flexible...).

worse case, it may be needed to rework it and or split it (upper-lower 
compiler and lower-lower compiler). in this case, the upper-lower compiler 
would be primarily responsible for tasks of managing type/value propagation, 
data representation, stack layout, ... and the lower-lower compiler spitting 
out a sensible instruction sequence. however, such a division point should 
start to occure naturally, so at present there is little real need to force 
it.

at present, it is a single process (done as 2 essentially nearly identical 
passes), where the more abstract operations working in terms of an abstract 
stack model (with little direct relation to the x86 stack, aka: full 
structs, long longs, symbols, ... being regarded as single stack items), are 
further decomposed into "psuedo-ops", which handle a lot more of the 
mechanics (doing some things, generating more p-ops, and spitting out raw 
x86-instructions).

the 2 passes are used to resolve certain pieces of info up front (such as, 
whether or not certain variables will need to be used, ...), with the first 
pass essentially having output disabled.

all more of an elaborate mess right now....


or such...


0
cr88192
7/31/2007 3:00:48 AM
Reply: