300 likes | 416 Views
Lecture #15, May 22, 2007. Project 3 C calling convention The IA32 module Translating. Project #3. In class today we describe project #3 It is due Thursday, June 7, 2007 at 5:00 PM this is in 17 days. In order to get the course graded, there will be no extensions
E N D
Lecture #15, May 22, 2007 • Project 3 • C calling convention • The IA32 module • Translating
Project #3 • In class today we describe project #3 • It is due Thursday, June 7, 2007 at 5:00 PM • this is in 17 days. • In order to get the course graded, there will be no extensions • Final exam will be week of June 11 • Monday June 11
Properties of the X86 translation • In project 3 we translate IR1 to x86 assembly. • Because of the sparseness of the X86 register set we assume variables all live in memory. • We have a number of types of variables • local variables (VAR n) • instance variables (MEMBER(address,n)) • parameters (PARAM n) • temporaries (TEMP n) • How do we access these variables? • Where in memory do they live?
C calling convention • Callers Job • Before the call • Save any registers that might be needed later • push the n arguments in reverse order • call the function • after the call • remove the arguments from the stack • restore any saved registers • return value is in register %eax • Callees Job • Set up the framepointer (%ebp) • allocate space for local variables on the stack • reset the old framepointer • put return value in %eax • return
. . . arg0 higher addresses → return address argn arg1 The X86 stack • Our translation is faithful to the calling convention of the GNU compiler. • The stack on entry to a function looks as follows: %esp
return address var1 argn old %ebp var0 . . . temp1 arg0 higher addresses → Allocating room for locals and temps • Temporaries and locals are treated identically • One exception locals may have some initialization code • Everything is reachable via the frame pointer (%ebp) %ebp %esp return address 4(%ebp) arg0 8(%ebp) arg1 12(%ebp) var0 -4(%ebp) var1 -8(%ebp)
prolog Call prolog precall postcall Return epilog epilog Procedure Call • Has 4 parts • Precall • Postreturn • Prolog • Epilog
Caller - Precall • Save registers that need it • write them to memory • save them on the stack • Push arguments on the stack • pushL arg2 • pushL arg1 • pushL arg0 • call the function • call _malloc
Caller - Postcall • Remove n arguments from stack • addl $(4*n), %esp • Pop saved registers if any
. . . arg0 higher addresses → return address argn arg1 Callee -- Prolog • Set up the framepointer (%ebx) • pushL %ebp # save the old framepointer • movl %esp,%ebp # initialize new framepointer • allocate space for local variables on the stack • subl $(n*4),%esp #subtract from spackpointer %esp
return address var2 argn old %ebp var1 . . . temp1 arg0 higher addresses → Callee -- Epilog • put return value in %eax • movL ans,%eax • reset the old framepointer • movl %ebp,%esp • popl %ebp • return • return %esp %ebp
The IA32 module • We build some data structures to represent IA32 code as SML data. • Registers • represent the machine registers • Modes • represent the addressing modes • Instructions • represent instructions • every instruction has room for a label and a comment
Registers datatype Register = eax (* Accumulator *) | ebx (* Base *) | ecx (* Count *) | edx (* Data *) | esi (* Source index *) | edi (* Destination index *) | ebp (* Base pointer *) | esp (* Stack Pointer *) | eip (* Instruction pointer *) | eflag (* Flags *)
Modes type Label = string; datatype Mode = Mem of string (* top *) | % of Register (* %eax *) | $ of int (* $12 *) | & of (int * Mode); (& n(%eax) *)
Instructions datatype IA32 = Movl of (Label * Mode * Mode * string) | Xchgl of (Label * Mode * Mode * string) | Addl of (Label * Mode * Mode * string) | Subl of (Label * Mode * Mode * string) | Imull of (Label * Mode * Mode * string) | Andl of (Label * Mode * Mode * string) | Orl of (Label * Mode * Mode * string) | Xorl of (Label * Mode * Mode * string) | Cmpl of (Label * Mode * Mode * string) | Idivl of (Label * Mode * string) | Negl of (Label * Mode * string) | Notl of (Label * Mode * string) | Incl of (Label * Mode * string) | Decl of (Label * Mode * string) | Pushl of (Label * Mode * string) | Popl of (Label * Mode * string) | Jmp of (Label * Label * string) | Jz of (Label * Label * string) | Jnz of (Label * Label * string) | Jl of (Label * Label * string) | Jnl of (Label * Label * string) | Jg of (Label * Label * string) | Jng of (Label * Label * string)
lower case instuctions fun movl (m1,m2) = Movl("",m1,m2,""); fun xchgl(m1,m2) = Xchgl("",m1,m2,""); fun addl (m1,m2) = Addl("",m1,m2,""); fun subl (m1,m2) = Subl("",m1,m2,""); fun imull(m1,m2) = Imull("",m1,m2,""); fun andl (m1,m2) = Andl("",m1,m2,""); fun orl (m1,m2) = Orl("",m1,m2,""); fun xorl (m1,m2) = Xorl("",m1,m2,""); fun cmpl (m1,m2) = Cmpl("",m1,m2,""); fun idivl(m1) = Idivl("",m1,""); • etc
Adding Labels fun addLabel l x = case x of Movl (_,m1,m2,s) => Movl (l,m1,m2,s) | Xchgl(_,m1,m2,s) => Xchgl(l,m1,m2,s) | Addl (_,m1,m2,s) => Addl (l,m1,m2,s) | Subl (_,m1,m2,s) => Subl (l,m1,m2,s) | Imull(_,m1,m2,s) => Imull(l,m1,m2,s) | Andl (_,m1,m2,s) => Andl (l,m1,m2,s) | Orl (_,m1,m2,s) => Orl (l,m1,m2,s) | Xorl (_,m1,m2,s) => Xorl (l,m1,m2,s) | Cmpl (_,m1,m2,s) => Cmpl (l,m1,m2,s)
Adding Comments fun addComment s x = case x of Movl (l,m1,m2,_) => Movl (l,m1,m2,s) | Xchgl(l,m1,m2,_) => Xchgl(l,m1,m2,s) | Addl (l,m1,m2,_) => Addl (l,m1,m2,s) | Subl (l,m1,m2,_) => Subl (l,m1,m2,s) | Imull(l,m1,m2,_) => Imull(l,m1,m2,s) | Andl (l,m1,m2,_) => Andl (l,m1,m2,s) | Orl (l,m1,m2,_) => Orl (l,m1,m2,s) | Xorl (l,m1,m2,_) => Xorl (l,m1,m2,s) | Cmpl (l,m1,m2,_) => Cmpl (l,m1,m2,s)
Translation scheme • Translate every IR.Exp into a IA32 list • Simple translation scheme • Every translation of an Expression leaves the answer in the %eax register.
Getting started fun compileE exp = case exp of BINOP(ADD,x,y) => let val xCode = compileE x val yCode = compileE y in xCode @ [ pushl(%eax) ] @ yCode @ [ popl(%ebx), addl(%ebx,%eax) ] end | CONST(s,typ) => let val n = valOf(Int.fromString s) in [ movl($n,%eax) ] end | NAME s => [ movl(Mem s,%eax) ]
Translating function calls fun compileE exp = case exp of | CALL(NAME f,args) => let fun pushargs [] = [] | pushargs (x::xs) = (pushargs xs) @ (compileE x) @ [ pushl (%eax) ] val n = length args in (pushargs args) @ [call f] @ [addl($(wdsize*n),%esp)] end
Translating Statements fun compileS x = case x of MOVE(dest,src) => (compileE src)@ [pushl (%eax)]@ (address dest)@ [popl (%ebx),Movl("",%ebx,&(0,%eax), sSTMT x)] | JUMP n => [Jmp("",label32 n,"")]
return address var2 argn old %ebp var1 . . . temp1 arg0 higher addresses → Translating addresses fun address (VAR n) = [movl(%ebp,%eax) , addl ($(~(n + wdsize)),%eax)] | address (PARAM n) = [movl(%ebp,%eax) ,addl ($( 2*wdsize + n),%eax) ] %esp %ebp
Translating Function definitions fun compileFunc (FUNC(nm,_,vs,ss)) = let fun size((typ),x) = ProgramTypes.typeSize typ + x val n = foldr size 0 vs in [ Pushl(nm,%ebp,"Entering "^nm) , movl (%esp,%ebp) , subl($ n, %esp) ] @ (compileSS ss) @ [ Movl("",%ebp,%esp,"Default Epilog") , popl (%ebp) , return() ] end; Prolog Epilog
Example class T { int instance2 = 0; public int f(int j) { int k = 1; return (j+k); } }
IR1 code ================================= The Class Table with inherited instance variables: class Object has vars: class T has vars: 0: int instance2 := 0 ================================= T_f(int P1) int V0; V0 := 1 return MEM(P1) + MEM(V0)
IA32 code T_f: pushl %ebp # Entering T_f movl %esp,%ebp subl $4,%esp movl $1,%eax pushl %eax movl %ebp,%eax addl $-4,%eax popl %ebx movl %ebx,0(%eax) # V0 := 1 movl %ebp,%eax addl $12,%eax movl 0(%eax),%eax # P1 pushl %eax movl %ebp,%eax addl $-4,%eax movl 0(%eax),%eax # V0 popl %ebx addl %ebx,%eax movl %ebp,%esp # Epilog popl %ebp return movl %ebp,%esp # Default Epilog popl %ebp return
Using the assembler • We will write some code in class.
What to turn in • You should hand in the module Phase3.sml • It should include a function • compileFunc :: IR1.FUNC list -> IA32.IA32 list • You should also write a function • toplevel :: string -> string -> unit • toplevel src dest • parses and compiles src to IA32 list • Then prints it out as assembly code to file dest
The template • I will supply a template. • The template will provide drivers and a complete solution to projects 1 and 2. • I will supply a file runtime.c • you will link your code with this file • You may ask for the template by emailing me. • I have posted the IA32 code on the web page.