kervinck / gigatron-rom

System, apps and tooling for the Gigatron TTL microcomputer
BSD 2-Clause "Simplified" License
229 stars 81 forks source link

lcc: compiler crash #73

Open kervinck opened 5 years ago

kervinck commented 5 years ago
$ cat test2.c
struct S {
  char c;                       // 'int c' works...
};
int f(int c, struct S *s)
{
  return s->c = c;              // just 's->c = c' without return works...
}
$ make test2.gt1
Utils/lcc/build/lcc -ILibs -c test2.c -o test2.o
Utils/lcc/build/lcc: fatal error in Utils/lcc/build/rcc
make: *** [test2.o] Error 1
$

Edit: see simplification below

kervinck commented 5 years ago

Crash happens in emitasm, before returning:

emitasm(0x7fc2a3012338, ASGNU1, (none)) (action)

In

        act = IR->x._actions[rulenum];
[...]
                act(p);

(Note: rulenum == 26)

Jumping to:

static void inst_strunc(Node p)
[...]
        unsigned to = p->kids[0]->syms[0]->x.regnode->number;

Was introduced with https://github.com/kervinck/gigatron-rom/commit/5916cb261b0b7aa866af4d381e29aca736bdd206

p->kids[0]->syms[0]->x.regnode is a null pointer.

(Note: p->kids[0]->syms[RX].x.regnode is a null pointer as well)

dumptree(p) after entering inst_strunc() gives:

ASGNU1(VREGP(1), CVUU1(INDIRI2(ADDRFP2(c))))
kervinck commented 5 years ago

Simplification of test program that crashes LCC:

char x;
int f(int c)
{
  return x = c;
}
kervinck commented 5 years ago

Interestingly, this was commented out in https://github.com/kervinck/gigatron-rom/commit/e58bf0c1c3e4b975875aedfb65f0398835d8d59e

Utils/lcc/src/gen.c:

//  case CVI: case CVU: case CVP:
//      if (optype(p->op) != F
//      &&  opsize(p->op) <= p->syms[0]->u.c.v.i)
//          p->op = LOAD + opkind(p->op);
//      break;

If we re-enable, the compilation completes without crashing LCC itself. Resulting output:

asm.defun('_f')
asm.push()
asm.ldwi(0xc0)
asm.call('enter')
asm.ldi(6)
asm.call('ldloc')
asm.stw('r7')
asm.ldwi('_x')
asm.stw('r6')
asm.ldw('r7')
asm.poke('r6')
asm.ldw('r7')
asm.stw('rv')
asm.label('.L1')
asm.ldwi(0x600)
asm.call('leave')
asm.ldi(2)
asm.addw('sp')
asm.stw('sp')
asm.ldw('rv')
asm.pop()
asm.ret()
asm.defun('_x')
asm.dx([0] * 1)

This looks correct to me and gttest passes. However......... Libs/Example.c doesn't work anymore. There are many changes in the emitted code (mostly ANDI $ff instructions are now gone) and, for example, __lookup/LUP is broken:

Before:
0cd3  21 48                    LDW   $48                |!H|
0cd5  7f 00                    LUP   $00                |..|
0cd7  82 ff                    ANDI  $ff                |..|
0cd9  f0 3c                    POKE  $3c                |.<|
0cdb  b4 cb                    SYS   134                |..|

After:
0cc2  21 48                    LDW   $48                |!H|
0cc4  7f 00                    LUP   $00                |..|
0cc6  21 3a                    LDW   $3a                |!:| <-- ???
0cc8  f0 3c                    POKE  $3c                |.<|
0cca  b4 cb                    SYS   134                |..|

Close, but no cigar.

kervinck commented 5 years ago

This would be a good point to ask @pgavlin for some insights :-)

pgavlin commented 5 years ago

This is the point at which I wish that I had gone back and commented things up a bit more.

I disabled the conversion of CVI/CVU/CVP to LOAD because it was breaking the backend's assumption that all LOADs are from vAC to a virtual register or vice-versa. We could probably tweak things such that the conversion works, but I'm not 100% certain what those tweaks would be offhand.

It's a bit strange that the register allocator appears not to be allocating those nodes... I'll try running cpp and rcc manually (rather than via the driver) to get debug output.

kervinck commented 5 years ago

I can work-around it in my C library and made a note in my updated Libs/stdio/fputc.c that found the issue.

kervinck commented 5 years ago

Fyi, I spent the best part of the last few days on the other issue: https://github.com/kervinck/gigatron-rom/issues/76 https://github.com/kervinck/gigatron-rom/issues/76

Basically: nested multiplicative expressions such as "a * (b / c)" don’t compile.

LCC gets in an infinite loop of spilling and reloading vAC but I’m stuck at understanding it. It spills vAC at some point, which is fine and understandable. Later it reloads, but at that point vAC is allocated, so it wants to spill it again. etc

(The message “inserting load from vAC to vAC” looks like a red herring.)

On 13 May 2019, at 22:24, Pat Gavlin notifications@github.com wrote:

This is the point at which I wish that I had gone back and commented things up a bit more.

I disabled the conversion of CVI/CVU/CVP to LOAD because it was breaking the backend's assumption that all LOADs are from vAC to a virtual register or vice-versa. We could probably tweak things such that the conversion works, but I'm not 100% certain what those tweaks would be offhand.

It's a bit strange that the register allocator appears not to be allocating those nodes... I'll try running cpp and rcc manually (rather than via the driver) to get debug output.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/kervinck/gigatron-rom/issues/73?email_source=notifications&email_token=AC5ZS3RQX5PESYR3DRMWR7DPVHFBDA5CNFSM4HMH77S2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODVJOQVI#issuecomment-491972693, or mute the thread https://github.com/notifications/unsubscribe-auth/AC5ZS3TAAZL7C6DWWHYZEUDPVHFBDANCNFSM4HMH77SQ.

lb3361 commented 1 year ago

This issue should be closed since glcc fixes it.