vivier / qemu-m68k

Other
40 stars 6 forks source link

Long-long register shuffling. #12

Closed rdebath closed 7 years ago

rdebath commented 8 years ago

https://gist.github.com/rdebath/67d37e192f88e27d4993e84ab0eb85b0

I'm running: Branch: 680x0-v2.6.0 Commit: 82c8f6b2c46b67e8e25098288c47afc0981dbce3

The above is a piece of C code using long-longs and compiled without optimisation. I've compiled it on x86 for the control and two minor variations on m68k. If I compile it WITH optimisation it runs successfully, if I add in the call to the empty 'f()' function it runs successfully. If I leave the register shuffling in the unmodified the code it is unsuccessful.

As GCC generates the same code for the two m68k versions (except for the single jsr to the empty function) it would appear that this bug is in the emulator.

Placing the call to 'f()' between any two C statements in this section of the code seems to prevent the problem occurring.

 .L21:
        .loc 1 120 0
        move.l %a2,-(%sp)
        pea 120.w
        jsr memdump
        addq.l #8,%sp
        .loc 1 121 0
        lea (48,%a2),%a0
        move.l 56(%a2),%d0
        move.l 60(%a2),%d1
        move.l %d0,(%a0)
        move.l %d1,4(%a0)
+       .loc 1 123 0
+       jsr f
        .loc 1 125 0
        lea (56,%a2),%a0
        clr.l (%a0)
        clr.l 4(%a0)
        .loc 1 126 0
        lea (48,%a2),%a3
        lea (48,%a2),%a0
        move.l 4(%a0),%a1
        move.l (%a0),%a0
        lea (64,%a2),%a4
        move.l (%a4),%d2
        move.l 4(%a4),%d3
        move.l %d2,%d0
        move.l %d3,%d1
        move.l %d0,%d2
        move.l %d1,%d3
        add.l %d3,%d3
        addx.l %d2,%d2
        move.l %d2,%d0
        move.l %d3,%d1
        move.l %d0,%d2
        move.l %d1,%d3
        add.l %d3,%d3
        addx.l %d2,%d2
        add.l %d3,%d3
        addx.l %d2,%d2
        add.l %d3,%d1
        addx.l %d2,%d0
        move.l %a0,%d3
        add.l %a1,%d1
        addx.l %d3,%d0
        clr.l %d4
        subq.l #1,%d1
        subx.l %d4,%d0
        move.l %d0,(%a3)
        move.l %d1,4(%a3)
        .loc 1 127 0
        lea (64,%a2),%a0
        clr.l (%a0)
        clr.l 4(%a0)
        .loc 1 128 0
        lea (40,%a2),%a0
        move.l (%a0),%d0
        move.l 4(%a0),%d1
        clr.l %d5
        subq.l #1,%d1
        subx.l %d5,%d0
        move.l %d0,(%a0)
        move.l %d1,4(%a0)
 .L20:
        .loc 1 113 0
        lea (40,%a2),%a0
        move.l (%a0),%d0
        move.l 4(%a0),%d1
        sub.l %d2,%d2
        tst.l %d1
        subx.l %d2,%d0
        jne .L22
        .loc 1 130 0
        move.l %a2,-(%sp)
        pea 130.w
        jsr memdump
vivier commented 7 years ago

Seems fixed in m68k-dev branch.

The result is now: "This interpreter has 32bit cells".

I have compared cellsize-bug.out and cellsize-nobug.out (and the result from a real machine), and they are equal now.

rdebath commented 7 years ago

Good news, I assume you meant to say "64bit cells", 'cause "32" would be really wrong.

vivier commented 7 years ago

No it's "32". But I have the same result on my Quadra 800.

rdebath commented 7 years ago

No, no...

The loop at lines 97..100 of the C source (316..388 of the assembler) is a very simple doubling loop that counts the number of bits in the (unsigned) integer type used as a 'cell' (The C define). Standard ints on the m68k are 32bits but gcc is using addx and friends to double this to 64bits.

The bug wasn't in this part of the code, but in the crazy decimal number printing routine between lines 109 and 155 of the C source. So you should get this "dump" at the start of the stderr log.

__LINE__=108
000000:  00 00 00 00(00)01 40 00  40 00 00 00 01 01 01 01  ......@.@.......
000010:  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
*

If the two "40"s are "20"s I think this would mean that the assembler has been regenerated without the unsigned long long C type and so it's using plain 32bit ints. There was nothing wrong with ints (AFAIK).

You can use -DC='unsigned long long' and similar to override the search for the biggest unsigned type it can find. This will let you regenerated the expected results on processors with 64bit registers that gcc can double up to 128bit.

vivier commented 7 years ago

LINE=108 000000: 00 00 00 00(00)01 20 00 20 00 00 00 01 01 01 01 ................ 000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ But with -DC='unsigned long long': "This interpreter has 64bit cells." LINE=108.out (press RETURN) 000000: 00 00 00 00(00)01 40 00 40 00 00 00 01 01 01 01 ......@.@....... 000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................