compiler constructie - activatierecords en intermediaire code
TRANSCRIPT
CompilerConstructie / Les 3 Activatierecords & Intermediaire Code
Christophe Van Ginneken
les 3 in 1 [slide|minuut]
Front End Back End
(intermediaire code)*broncode machine code
mov edx,len ;message length Mov ecx,msg ;message to write mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel
Java
ML
Pascal
C
C++
Sparc
MIPS
Pentium
Alpha
CJUMP(LT,x,CONST(5), t, F) MEM(+(TEMP fp, CONST kn), S) SEQ(label z, s2(t, f)) CALL(NAME z, [sl,e1, e2,...,en])
... argument n
... argument 2 argument 1
statische link
locale variabelen terugkeer adres
tijdelijke variabelen opgeslagen registers
argument n ...
argument 2 argument 1
statische link
locale variabelen ...
stack
vrij geheugen
heap
statische gegevens
code
CALL(NAME z, [sl,e1, e2,...,en])
procedure-oproep- en keer-terug-model oproep == activatie
activatierecord == stack frame
89 minuten te vullen ;-)
Proloog: jij && CC
• 38 jaar + vrouw & 2 kinderen
• (ex-)software consultant
• Open{Source,Mind}
!
• 1999 gbasic
• 2006 UML model “compiler”
• 2012 foo-lang
Proloog: jij && CC
Les 3 Activatierecords & Intermediaire Code
EN ➔ NL
EN ➔ NL
EN ➔ NL
EN ➔ NL
Intermediaire Code
Intermediaire Voorstelling
Les 3 Activatierecords & Intermediaire Code
Situering
Structuur van een compiler
Front End Back End
intermediaire code
fouten
broncode machine code
mov edx,len ;message length Mov ecx,msg ;message to write mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel !mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel
Front End
Scanner & Parser
Semantisch Analyse &
IC generatie
tokens
fouten
broncode intermediaire code
CJUMP(LT,x,CONST(5), t, F) MEM(+(TEMP fp, CONST kn), S) SEQ(label z, s2(t, f) CALL(NAME z, [sl,e1, e2,...,en])
AST
CJUMP(LT,x,CONST(5), t, F) MEM(+(TEMP fp, CONST kn), S) SEQ(label z, s2(t, f) CALL(NAME z, [sl,e1, e2,...,en])
mov edx,len ;message length Mov ecx,msg ;message to write mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel !mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel
Back End
Instructie Selectie &
Flow Analyse
Register Allocatie &
Code Emissie
fouten
intermediaire code
machine code
Optimizer Optimizer
{code generatie
Waarom intermediaire code ?
Java
ML
Pascal
C
C++
Sparc
MIPS
Pentium
Alpha
Java
ML
Pascal
C
C++
Sparc
MIPS
Pentium
Alpha
IC
Intermediaire code
• IC = “abstracte machine” code
• moet handig zijn
• genereren (door front-end)
• om te zetten (door back-end)
• eenvoudig en duidelijk
CJUMP(LT,x,CONST(5), t, F) MEM(+(TEMP fp, CONST kn), S) SEQ(label z, s2(t, f) CALL(NAME z, [sl,e1, e2,...,en])
!
Back End!
Front End
Situering IC
Semantisch Analyse &
IC generatie
Code Generatie
Activatierecords ?
broncode
Acties @
run-time
broncode
Acties @
run-timenamen data
objecten
Terminologieprogram sort(input, output);! var a : array [0..10] of integer;! ! procedure readarray;! var i : integer;! begin! for i := 1 to 9 do read(a[i])! end;! ! function partition(y, z: integer) : integer;! var i, j, x, v: integer;! begin ... end;! ! procedure quicksort(m, n : integer);! var a : integer;! begin! if( n > m ) then begin! a := partition(m, n);! quicksort(m, a-1);! quicksort(a+1, n);! end! end;! ! begin! a[0] := -9999; a[10] := 9999;! readarray;! quicksort(1,9);! end.
formele parameters
actuele parameters
procedure body
procedure naam
niet-lokale scope & geneste diepte
niveau 1
niveau 2
lokale scope
Procedure-verloop & levensduur
1. sequentieel: uitvoeringsstappen 2. procedureel: oproep - uitvoering - terugkeer
procedure A
procedure B
procedure A
procedure B
procedure A
procedure A
procedure A
procedure BXactivatie
recursief
Activatiesboomsort
readarray qs(1, 9)
part(1, 9) qs(1, 3) qs(5, 9)
part(1, 3) qs(1, 0) qs(2, 3) part(5, 9) qs(5, 5) qs(7, 9)
part(7, 9) qs(7, 7) qs(9, 9)part(2, 3) qs(2, 1) qs(3, 3)
Controlestack
sort
readarray qs(1, 9)
part(1, 9) qs(1, 3)
part(1, 3) qs(1, 0) qs(2, 3) sort
qs(1, 9)
qs(1, 3)
qs(2, 3)
Scope van een declaratie
• zelfde naam op meerdere plaatsen➔ scope regels: lokaal, niet-lokaal
• “de scope van x”➔ “de scope van de declaratie van naam x die van toepassing is voor dit voorkomen van x”
• compilatie ➔ symbolen tabel voorkomen ➔ declaratie
program sort(input, output);! var a : array [0..10] of integer;! ! procedure readarray;! var i : integer;! begin! for i := 1 to 9 do read(a[i])! end;!...! procedure quicksort(m, n : integer);! var a : integer;! begin! if( n > m ) then begin! a := partition(m, n);! quicksort(m, a-1);! quicksort(a+1, n);! end! end;!...
Naambinding
naam plaats waardeomgeving status
pi 100 0
binding
pi:=3.14;pi 100 3.14
statisch / in code dynamisch / tijdens uitvoering
definitie van een procedure activatie van de procedure
declaratie van een naam binding van de naam
scope van een declaratie levensduur van de binding
status
“l-value” “r-value”
Organisatie van geheugen
stack
vrij geheugen
heap
statische gegevens
code
(voorbeeld MIPS)
hoge adressen
lage adressen
controlestack met activatierecords
“malloc”
Activatierecords
• Stack Frame
• procedure oproep == “activatie”
• alle info gaat op de stack in een “frame”
• ligt bijna volledig vast bij compilatie
• conventionele layout
Activatierecords...
argument n ...
argument 2 argument 1
statische link
lokale variabelen terugkeer adres
tijdelijke variabelen opgeslagen registers
argument n ...
argument 2 argument 1
statische link
locale variabelen ...
frame pointer
stack pointer
vorig frame
huidig frame
volgend frame
Intermezzo: Registers
• 32
• lokale variabelen ➔ snelheid
• caller-save / callee-save
• doorgeven van parameters (4, 6)
http://en.wikipedia.org/wiki/Processor_register
Parameters & terugkeeradres
• Calling convention
• Call-by-reference
!
• CALL()
• stack / register
... argument n
... argument 2 argument 1 statische link
lokale variabelen terugkeer adres
tijdelijke variabelen opgeslagen registers
argument n ...
argument 2 argument 1
statische link
Variabelen in het activatierecord
• register !
• by-reference
• geneste procedures
• > 1 register
• rij
• veel
!
• “escapes”
... argument n
... argument 2 argument 1
statische link
lokale variabelen terugkeer adres
tijdelijke variabelen opgeslagen registers
argument n ...
argument 2 argument 1
statische link
Statische link
• blok structuur
• statische link
• “display”
• “lambda lifting”
sort
qs(1, 9)
qs(1, 3)
part()
program sort(input, output);! var a : array [0..10] of integer;! ...! procedure quicksort(m, n : integer);! var i : integer;! function partition() : integer;! var i, j, x, v: integer;! begin ... a[x] ... end;! begin! if( n > m ) then begin! i := partition();! quicksort(m, i-1);! quicksort(i+1, n);! end! end;
Display
• blok structuur
• statische link
• “display”
• “lambda lifting”
sort
qs(1, 9)
qs(1, 3)
part()
program sort(input, output);! var a : array [0..10] of integer;! ...! procedure quicksort(m, n : integer);! var i : integer;! function partition() : integer;! var i, j, x, v: integer;! begin ... a[x] ... end;! begin! if( n > m ) then begin! i := partition();! quicksort(m, i-1);! quicksort(i+1, n);! end! end;
d[3]d[2]d[1]
Lambda Lifting
• blok structuur
• statische link
• “display”
• “lambda lifting”
program sort(input, output);! var a : array [0..10] of integer;! ! procedure readarray(a : array[0..10] of integer);! var i : integer;! begin! for i := 1 to 9 do read(a[i])! end;! ! function partition(y, z: integer,! a : array[0..10] of integer)! : integer;! var i, j, x, v: integer;! begin ... end;! ! procedure quicksort(m, n : integer,! a : array[0..10] of integer);! var i : integer;! begin! if( n > m ) then begin! i := partition(m,n,a);! quicksort(m,i-1,a);! quicksort(i+1,n,a);! end! end;! ! begin! a[0] := -9999; a[10] := 9999;! readarray(a);! quicksort(1,9,a);! end.
Intermezzo: Hogere orde functies
fun f(x) = let fun g(y) = x+y in g
end !val h = f(3) val j = f(4) !val z = h(5) (* 8 *) val w = j(7) (* 11 *)
Kan niet op een stack !
geneste functiesresultaat = functie+hogere orde functie
Intermediaire Code Generatie
IC generatie
• meerdere iteraties
• optimaliserende algoritmes één per één
• onderlinge afhankelijkheid
!
AST !
boom
IC !
sequentieel
IC statements
• SEQ( stm, stm )
• LABEL( label )
• JUMP( exp )
• CJUMP( op, exp, exp, label, label )
• MOVE( exp, exp )
• EXP( exp )
IC expressies
• BINOP( binop, exp, exp )
• MEM( exp )
• TEMP( temp )
• ESEQ( stm, exp )
• NAME( label )
• CONST( int )
• CALL( exp, args )
Intermezzo: Expressies & Statements
“Expressies” = “evalueert” tot een waarde 1 + 2 ⇒ 3
“Statements” = “doet iets” x = 2 doSomething() !
Pascal expliciet function, procedure C* verwaterd doSomething(x = 2) Haskell géén statements, alleen expressies
AST ➔ IC
• AST expressie
• 3 soorten IC expressies
• expressie 2 + 1 Ex
• statement procedure Nx
• boolse expr. a < b Cx
Enkelvoudige variabeleMEM(BINOP(PLUS, TEMP(fp), CONST(k)))MEM
BINOP
PLUS TEMP fp CONST k MEM(+(TEMP(fp), CONST(k)))
... argument n
... argument 2 argument 1
statische link
locale variabelen terugkeer adres
tijdelijke variabelen opgeslagen registers
argument n ...
argument 2 argument 1
statische link
locale variabelen ...
stack
vrij geheugen
heap
statische gegevens
code
stack pointerframe pointer
frame pointer
TEMP(fp)
MEM(...)variabele
CONST(k)+
=
+ statische link
uitwerken
Rijenvar a,b : array[1..12] of integer begin b := a;
end;
{ int a[12], b[12]; b = a;
}
{ int a[12], *b; b = a;
}
let type intArray = array of int var a := intArray[12] of 0 var b := intArray[12] of 7
in b := a
end
X ➔
Pascal
C
Tiger
RijenMEM(+(MEM(e),BINOP(MUL,i,CONST(W)))
MEM
BINOP
MUL i CONST W
MEM e
+
locale variabelen terugkeer adres
tijdelijke variabelen opgeslagen registers
argument n ...
argument 2 argument 1
statische link
a’= MEM(+(TEMP(fp),CONST(ka)))
MEM(a’)
stack
vrij geheugen
heap
statische gegevens
code
MEM(a’+(i*W))
a[i]
Integers & Strings
• Integer IntExp(i) ➔ CONST(i)
• Operaties OpExp(i,...) ➔ BINOP(i,...)
!
• Strings lengte + “rij” van karakters
e l l o h w o r l d11
Boolse expressiesa>b | c<d
SEQ
CJUMP
GT a zb null t
SEQ
CJUMP
LT c d null t
LABEL(z)
null f
if a > b goto lbl_true goto z z: if c < d goto lbl_true goto lbl_false
Intermezzo: Conversie van IC expr.
• a < b boolse expressie CJUMP(LT, a, b, ..., ...)
• var x = a < b expressie MOVE(TEMP(x), ? )
0
1
expressie boolse
statement
unCx
unNx
unEx
Conditionele Expressiesif e1 then e2 else e3
if e1 goto t goto f t: r = e2 goto join f: r = e3 join:
unCx unEx unEx
SEQ
CJUMP
“e1” ft
SEQ
LABEL(t) MOVE
TEMP(r) “e3”
SEQ
LABEL(f)MOVE
TEMP(r) “e2”
SEQ
SEQ
LABEL(join)
join
SEQ
join
SEQ
Lussen
test: if not(condition) goto done <body> goto test done:
for i := low to high do <body>
let var i := low in while i <= high do <body> i := i + 1
end
while
maxint !
Functieoproepen
CALL(NAME(lf), [sl,e1,e2,...,en])
f(a1,a2,...,an)
lf LABEL voor f sl statische link ex adres voor ax
Functiedefinitiesfunction partition(y, z: integer) : integer;! var i, j, x, v: integer;! begin ... end;
FunctionDec
Symbol(“partition”) FieldList
Symbol(“y”)
Symbol(“integer”)
Symbol(“z”)
Symbol(“integer”)
Symbol(“integer”) LetExp
VarDec
Symbol(“i”)
Symbol(“integer”)
... DecList
...
AST
IC fragment
PROC(label “partition”, <IC code for body>, <frame layout info>)
Proloog / Epiloog• proloog
• aankondiging begin functie
• label voor functie naam
• aanpassen stack pointer
• escaping argumenten + statische link bewaren niet-escaping in registers
• callee-save registers & terugkeer adres
• epiloog
• resultaat naar register
• callee-save registers
• terugzetten stack pointer
• terugkeer instructie
• aankondiging einde functie
exacte grootte frame
is pas gekend NA register
allocatie
Managed - Unmanaged
Managed - Unmanaged
• IC == Java Bytecode ?
• .NET Common Intermediate Language ?
• javac == Front-End ?
• java == Back-End ?
Managed - Unmanaged
• Java, .NET, Perl 6,...
• Heeft unmanaged nog zin ?
• Run-Time optimalisaties verder dan machine code optimalisaties in compiler ?
Managed - UnmanagedConclusies groepsgesprek:
• Intermediare Code staat nog ver van Java bytecode:bvb. veel details (exacte adressering, machineafhankelijke constanten,...) ontbreken nog
• Unmanaged code kan zeker nog betekenis behouden in kader van bvb. embedded systemen.
• Tendens naar managed is zeker waar te nemen en wordt bvb. ondersteund door processoren die rechtstreeks Java bytecode kunnen uitvoeren. De vraag wordt dan wel of deze dan nog verschillend van klassieke machine code kan/moet gezien worden.
Wat hebben we geleerd vandaag ?
COMPILEERPLEZIER
CC
Front End Back End
(intermediaire code)*broncode machine code
mov edx,len ;message length Mov ecx,msg ;message to write mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel
Java
ML
Pascal
C
C++
Sparc
MIPS
Pentium
Alpha
CJUMP(LT,x,CONST(5), t, F) MEM(+(TEMP fp, CONST kn), S) SEQ(label z, s2(t, f)) CALL(NAME z, [sl,e1, e2,...,en])
... argument n
... argument 2 argument 1
statische link
locale variabelen terugkeer adres
tijdelijke variabelen opgeslagen registers
argument n ...
argument 2 argument 1
statische link
locale variabelen ...
stack
vrij geheugen
heap
statische gegevens
code
CALL(NAME z, [sl,e1, e2,...,en])
procedure-oproep- en keer-terug-model oproep == activatie
activatierecord == stack frame
Optimale Code Generatie is een onbeslisbaar probleem
• Doe het zo goed mogelijk
• correct
• gebruik machine architectuur
• efficiënte uitvoering
EndOfPresentationException
Mogelijke Examenvragen
• Wat is een “standaard activatierecord-layout” en waarom zou je dit al dan niet volgen ?
• Kan het FP register niet eenvoudig vervangen worden door en/of gebaseerd worden op het SP register ? Bespreek aan de hand van het principe van activatierecords en een stack.
• Wat is een “dangling reference” ? Geef een voorbeeld hoe deze kan ontstaan vanuit een activatierecord.
• Wat zijn de beperkingen van activatierecords en een stack ?
• Waarom gebruik je wel of niet één of meerdere intermediare codes ? Wat zijn de voordelen/nadelen ?
• Welke eigenschappen vertoont een goede intermediaire code ?