I'm writing a toy compiler targeting on x86-64 machines. But I confront several problems when implementing register allocation with linear intermediate representation. I use NASM and GCC to generating executable file.
In intermediate representation of the origin code, we assume there are infinite registers(memory is regarded as a kind of virtual register). I divided them into two types:
Single registers: This kind of virtual register represent a typical variable.
Offset registers: This kind of virtual register is used to represent the access to an element of an array or a member of a struct. For example, when translating instructions such like
a.x = 3andb[i] = 3into intermediate representation, we may represent it asmov [$a + 0], 3andmov [$b + $i * 4], 3(4is the size of an integer), where$a,$band$iare single registers and[$a + 0]and[$b + $i * 4]are offset registers.
However, in x86-64 machine, memory access can only be represented as [$reg1 + $reg2 * imm1 + imm2], where $reg1 and $reg2 are physical registers and imm1 and imm2 are immediate number. I cannot understand how register allocation algorithms deal with the case that the algorithm marks $va and $vb as spilled node with instruction mov [$va + $vb * 4], 3. In other words, $va and $vb must be a physical register rather than memory access, but if a virtual register is marked as spilled node, it will be regarded as a memory access to the stack frame.
For example, I get the following origin C-like code:
int main() {
int [] a = new int[10];
int i = 3;
a[i] = 4;
}
And I translate it into following intermediate representation:
call malloc, 10
mov $a, $retval ; $retval is the return value of malloc
mov $i, 3
mov [$a + $i * 4], 4
However, after I have allocated registers, I find the final code becomes:
push rbp
mov rbp, rsp
sub rsp, 16
mov rdi, 10
call malloc
mov qword [rbp-8], rax
mov qword [rbp-16], 3
mov [qword [rbp-8] + qword [rbp-16] * 4], 3 <- Compliation error occurs here
I wonder if there is a nice implementation to solve this problem. Thanks in advance.
UPD: Basile-Starynkevitch gave me a paper showing how GCC solve this problem. And I'm looking for some (probably) simpler methods.
qword [rbp-8]is already inrax. forqword [rbp-16] * 4you need a temp. register, likerbx.=>
– rurban May 27 '17 at 15:42mov qword [rbp-16] * 4, rbx mov [rax + rbx], 3qword [rbp-16] * 4. And you know, In CISC-based machine, the number of registers is less than RISC, which means I cannot pick such temporary registers. – Kipsora Lawrence May 29 '17 at 15:09[rbp-24]instead ofrbx. Just the relative addressing will get tricky. If not possible you need to spill to get a free physical register. On 64bit you usually have a free register, just on x86 it will get tricky. – rurban May 29 '17 at 15:34