-
Notifications
You must be signed in to change notification settings - Fork 149
Description
Description
Currently, shecc cannot correctly handle large structure instances, causing operations such as large structure assignment and passing a large structure instance as a function argument to behave incorrect.
Current Bug
typedef struct {
int a, b, c, d, e;
} large_struct_t;
void test(large_struct_t s)
{
printf("test(s) = %d %d %d %d %d\n", s.a, s.b, s.c, s.d, s.e);
}
int main(void)
{
large_struct_t s;
s.a = 10;
s.b = 20;
s.c = 30;
s.d = 40;
s.e = 50;
printf("s = %d %d %d %d %d\n", s.a, s.b, s.c, s.d, s.e);
/* Bug 1: assignment is incorrect. */
large_struct_t s2 = s;
printf("s2 = %d %d %d %d %d\n", s2.a, s2.b, s2.c, s2.d, s2.e);
/* Bug 2: pass a large instance as an argument is also incorrect. */
test(s);
return 0;
}$ qemu-arm out/shecc-stage2.elf -o test test.c
$ qemu-arm test
s = 10 20 30 40 50
s2 = 10 0 0 0 0
test(s) = 10 1082129836 1082129828 1082129596 4
Root Cause
One of potential root causes is that the current register allocator lacks proper considerations about "physical storage". Consider the following structure definition in shecc's source code:
typedef struct {
var_t *var;
int polluted;
} regfile_t;shecc uses instances of regfile_t to perform register allocation. Although a register may conceptually hold a variable (var_t), each register on Arm32 and RISC-V can store only a 4 byte object and thus cannot hold large objects.
However, during register allocation, shecc directly assigns each variable to a register even if the variable is a large structure whose size exceeds 4 bytes. Since no additional handling is performed, the code generator ultimately treats every register as if it always stores small objects when generating instructions, which leads to the aforementioned bugs.