Front End --- Middle --- Back End AST <---> IR <---> ASM
- Calling convention
- Size and properties of register file
- List of supported instructions TableGen tool is used by LLVM.
- Code format (heap, stack, data & code section)
- Memory mapping c++ heap -> DDR OpenCL __local -> stack/scratchpad, __global -> DDR
- Instruction selection (LLVM: Legalization for backend) (NxM, NP-complete)
- Target architecture legalization
IR {abstract ISA, virtual registers} -> IR {target ISA, virtual registers}
NxM problem
while abstract isa is not fully converted to target isa
Ex 1:1:
add %r2, %r0, %r1=>add r2, r, r1Ex N:1:a[i*width+j]mul t0 i width add t1 t0 j add t2 a t1 mul t3 t2 4 load t4 t3=> if address model supportsa*x+bassumingj1 = j * 4mul t0 i width add t1 a t0 load t2 t1 4 j1=> if target supports mla (multiply-accumulate)
mla a i width
load t2 a 4 j1
```
Ex 1:M:
a = (b < c)
=> if compare writes to register file
cmp.lt a, b, c
or if compare branches
br.lt b, c, L0 a = 0 br L1 L0: a = 1 L1:
- calling convention compliance
- register allocation (NxM, NP-complete)
- ISA compliance, if any rules
- IR {target ISA, virtual registers} in SSA -> IR {target ISA, physical registers}, no
SSA - register spilling minimization
- Instruction scheduling (NxM, NP-complete)
- Stale minimization
- Hiding latency Ex:
2 load a
2 load b
3 fma c a b
1 store c
=>
2 load a
2 load b
inc i 1// use this slot
3 fma c a b
// use 2 slots
1 store c
Simplifications
- Problems are solved independently
- Problems are solved heuristically (correct & profitable)
Ex:
a = *b + *c * 3
=>
load @b b
load @c c
load r0 @b
load r1 @c
load r2 3
mul r3 r1 r2
add a r1 r2
or
- less instructions
- less registers
- bigger code size due to immediate codding
load @b b
load @c c
load r0 @b
load r1 @c
mul r3 r1 3
add a r1 r2
[stack] dynamic <- high address v ... ^ [heap] dynamic [data] static [code] static <- low address
[code] instructions [data] statically allocated data, global variables, string literals, global arrays static size [stack] function calls, local variables fixed size, register spilling [heap] new/malloc
Ex:
char c; // data
int arr[4]; // data
void foo() {
int arr2[4]; // stack
int* ptr = new int[4]; // heap
bar("hello"); // data
}- Calling convention
- Stack handling
- stack pointer SP
- frame pointer FP FP = SP and work on FP inside a function LLVM's omit frame pointer pass optimizes extra stack management