Re: Pascal compiler (was: Layout floating point numbers)

From: Ullrich von Bassewitz (uz_at_musoftware.de)
Date: 2002-10-08 13:21:02

On Tue, Oct 08, 2002 at 10:34:23AM +0200, ruud.baltissen@abp.nl wrote:
> U> using indirect pointers (pointers to pointers) which is
> U> slow and generates larger code.
>
> I completely agree. But this is a feature meant for low memory systems. The
> choice is either a slower program or a program that doesn't run at all.

What I meant was that using your approach will generate *larger* programs, not
smaller ones. The problem is, that using double indirection is expensive for
the 6502. Look at this pascal example:

        TYPE R = RECORD A, B, C, D: CHAR; END;
        VAR  X : ^R; D: CHAR;
        ...
        X := NEW(R);
        ...
        D := X^.D;

The access may translate into something like

        lda     X
        sta     zeropage
        lda     X+1
        sta     zeropage+1
        ldy     #3
        lda     (zeropage),y
        sta     D

An optimizer (if there is one) could even try to keep X in a zero page
location, because it's known to be a pointer, so the first four instructions
are not (always) needed.

With this pascal code using double indirection as needed with your allocation
routines:

        TYPE R = RECORD A, B, C, D: CHAR; END;
        VAR  X : ^^R; D: CHAR;
        ...
        X^ := NEW(R);
        ...
        D := X^^.D;

you get something like this as machine code:

        lda     X
        sta     zeropage
        lda     X+1
        sta     zeropage+1
        ldy     #0
        lda     (zeropage),y
        tax                     ; *
        iny                     ; *
        lda     (zeropage),y    ; *
        stx     zeropage        ; *
        sta     zeropage+1      ; *
        ldy     #3
        lda     (zeropage),y
        sta     D

The lines marked with an asterisk are the ones doing the double indirection,
and they are needed on each access, because the pointer cannot be cached (it
may change between two accesses)! So each access needs 8 bytes more code
(there are also examples that need more than these 8 bytes).

Add to this the additional code that moves heap blocks around, and you will
easily see, that your heap stuff will make many programs larger, not smaller.
Not to talk about the slowdown that is a consequence of all the additional
code...

> U> Without a really big effort, it is not possible to
> U> automatically generate code for a banked system like the
> U> 720 to use more than one bank.
>
> I agree. I already said that I will use 4 byte pointers for manipulating
> data on 64+ KB machines: two bytes for the address within any given 64 KB
> block, the other two to code which block is meant.

This does not help, because the pointers cannot be used for normal access.
Yes, you may include the bank and form a three byte pointer, but the compiler
will have to generate code that handles this additional bank. This means to
always use special addressing modes, even in the libraries, always switch to
the correct bank before using *any* pointer indirection and so on.

> All the above covers data manipulation. For one problem I still haven't
> found solution: what if the executable code doesn't fit inside the first
> bank? (The first thing that came to my mind: Use another computer !!!)

My suggestion is: Forget about all of this. Even writing a simple pascal
compiler without any optimization generating code for the 6502 is quite an
ambitious task. Then you will need lots of libraries to make it usable (as
mentioned before: cc65 comes with more than 180 small routines for runtime
support - and this does neither include the actual C library nor floating
point support!). While it may be usable, it's not really useful in this state.
To make it useful, you will have to add at least a small peephole optimizer,
otherwise code generated by such a simple compiler will just crawl. Plus
backend tools that support modularization and relocation. If you plan to
support more than one machine, remember that you have to write the library for
each machine (and of course, you will have to debug the machine specific code
on each target).

This alone will keep you busy for a very long time, without any need to worry
about supporting programs larger than 64K:-)

> P> it seems to have expression tree generation and constant
> P> expression evaluation.
>
> Would you mind explaining what this is? (but I have the vague idea that I
> already invented the wheel for the second time)

Don't generate code directly when parsing expressions. Generate an expression
tree in memory instead. When this tree is generated, let your code have a
thoroughful look at it, and rearrange this tree in memory to make expression
evaluation more efficient, or do even remove/replace parts of the tree that
can be evaluated at compile time. After that, walk along the tree and generate
code for it.

Regards


        Uz


-- 
Ullrich von Bassewitz                                  uz@musoftware.de

       Message was sent through the cbm-hackers mailing list

Archive generated by hypermail 2.1.4.