lcc: compiler crash
kervinck opened this issue · comments
$ 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
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 5916cb2
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))))
Simplification of test program that crashes LCC:
char x;
int f(int c)
{
return x = c;
}
Interestingly, this was commented out in e58bf0c
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.
This would be a good point to ask @pgavlin for some insights :-)
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.
I can work-around it in my C library and made a note in my updated Libs/stdio/fputc.c that found the issue.
This issue should be closed since glcc fixes it.