Compilation 2015 Instruction Selection for Tiger Aslan Askarov aslan@cs.au.dk Based on slides by E. Ernst
Instruction Selection for Tiger • The algorithms, e.g., Maximal Munch, did not show which registers were used to carry results MEM EBX • Ex: typical memory access ➜ + • We must handle: e CONST FP • choice of registers c • consistency across tiling • explicit representation (needed during static analysis)
Register Allocation Timing • Register allocation: Choosing concrete registers for assembly instructions • Possible timing: • before tiling (imprecise!! – don’t even know tile roots) • during tiling (not impossible – somewhat imprecise) • after tiling (most powerful model; portable, too) • Requires abstract assembly instructions: • very flexible representation of actual assembly code • generic, externally accessible representation of temps • encoding both explicit and implicit usage
Abstract Assembly for Tiger datatype instr = • New module ‘Assem’ OPER of { assem:string , dst: temp list • Instructions datatype: , src: temp list • allows arbitrary syntax , jump: label list option} in assem : a string | LABEL of { assem: string , lab: label} • assem actually has structure: | MOVE of { assem: string backquote marks “parameters” , dst: temp , src: temp} • `si `di `ji marks source number i , destination i , jump i , in fields src , dst , jump ( NONE : fall through, SOME _ : all targets) • MOVE just a special case of OPER : analyzable! • Independent of CPU, registers
Example Instr • A single tile IR tree: MEM + TEMP FP CONST 8 • Corresponding instr : OPER { assem = "LOAD `d0 <- M[`s0+8]" , dst = [Temp.newtemp()] , src = [Frame.FP] , jump = NONE} • Note: • dst/src/jump index selects list element • jump NONE means fall through
Example Instr • A multi tile IR tree: * MEM + TEMP t92 • Corresponding instr s: TEMP t87 CONST 3 assem dst src "ADDI `d0 <- `s0+3" t908 t87 "LOAD `d0 <- M[`s0+0]" t909 t92 "MUL `d0 <- `s0*`s1" t910 t908,t909 • Note: t908, t909, t910 fresh, t910 returned
Two-address Instructions • CISC format, think "+=" etc. MOVE + TEMP t1 TEMP t1 TEMP t2 • Corresponding instr : assem dst src "ADD `d0,`s1" t1 t1,t2 • Notation similar to Jouette: ADD t1 ⃪ t1 + t2 • Realistic assembly syntax: ADD t1,t2
Maximal Munch • Register aware Maximal Munch algorithm, munchStm: Tree.stm -> unit fun munchStm (SEQ(a,b)) = (munchStm a; munchStm b) | munchStm (MOVE(MEM(BINOP(PLUS,e1,CONST i)),e2)) = emit (A.OPER{ assem = "STORE M[`s0+" ^ int i ^ "] <- `s1\n" , src = [munchExp e1, munchExp e2] , dst = [], jump = NONE} | munchStm (MOVE(MEM(BINOP(PLUS,CONST i,e1)),e2)) = emit (A.OPER{ assem = "STORE M[`s0+" ^ int i ^ "] <- `s1\n" , src = [munchExp e1, munchExp e2] , dst = [], jump = NONE} | munchStm (MOVE(MEM e1,MEM e2)) = emit (A.OPER{ assem = "MOVE M[`s0] <- M[`s1]\n" , src = [munchExp e1, munchExp e2] , dst = [], jump = NONE} ... | munchStm (LABEL lab) = emit (A.LABEL {assem = lab ^ ":\n", lab = lab}) ...
Maximal Munch • Note that CALL case involves “artificial” src/dest ... | munchStm (EXP(CALL(e,args))) = emit (A.OPER{ assem = "CALL `s0\n" , src = munchExp e :: munchArgs (0,args) , dst = calldefs , jump = NONE} ... • munchArgs returns registers used during call; depends on parameter passing mechanism (arguments, static link, frame pointer, …) • 0 is argument number of hd args
Maximal Munch • munchExp: Tree.stm -> Temp.temp and munchExp (MEM(BINOP(PLUS,e1,CONST i))) = result (fn r => emit (A.OPER { assem = "LOAD `d0 <- M[`s0+" ^ int i ^ "]\n" , src = [munchExp e1], dst = [r], jump = NONE} | munchExp (MEM(BINOP(PLUS,CONST i,e1))) = result (fn r => emit (A.OPER { assem = "LOAD `d0 <- M[`s0+" ^ int i ^ "]\n" , src = [munchExp e1], dst = [r], jump = NONE} | munchExp (MEM(CONST i)) = result (fn r => emit (A.OPER { assem = "LOAD `d0 <- M[r0+" ^ int i ^ "]\n" , src = [munchExp e1], dst = [r], jump = NONE} ... | munchExp (BINOP(PLUS,e1,e2)) = result (fn r => emit (A.OPER { assem = "ADD `d0 <-`s0+`s1\n" , src = [munchExp e1, munchExp e2] , dst = [r], jump = NONE} | munchExp (TEMP t) = t Note the use of result
Maximal Munch • codegen: frame -> stm -> instr list fun codegen frame (stm: Tree.stm): Assem.instr list = let val ilist = ref (nil: instr list) fun emit x = (ilist := x::ilist) fun result gen = let val t = newtemp() in gen t; t end fun munchStm ... fun munchExp ... in munchStm stm; rev (!ilist) end Note definition of result and use of side-e ff ects
Be Careful… • Note that some instructions a ff ect registers not mentioned explicitly (!) ... | munchExp (BINOP(MUL,e1,e2)) = result (fn r => ... emit (A.OPER{ assem = "IMUL `s1" , src = [F.EAX, r] , dst = [F.EAX, F.EDX] , jump = NONE}) ... High bits used for 32*32->64 bit computation, rarely Common view: it “trashes” EDX
Be Careful… • Tempting approach to handling returned value ... emit (A.OPER { assem = "CALL " ^S.name lab^ "\n" (* result: EAX *) , src = munchArgs args , dst = F.calldefs , jump = NONE}); emit (... (* clean up stack *)); emit (A.OPER { assem = "STORE M[`s0+0] <- `s1\n" , src = [munchExp e1, F.EAX] (* overwrite EAX! *) , dst = [] , jump = NONE}) ... Problem: generated code destroys fixed register
Being Careful… • Working approach to handle returned value ... val t = newtemp() ... emit (A.OPER { assem = "CALL " ^S.name lab^ "\n" (* result: EAX *) , src = munchArgs args , dst = F.calldefs , jump = NONE}); emit (... (* clean up stack *)); emit (A.MOVE { assem = "MOVE `d0 <- `s0\n" (* result: t *) , src = F.EAX , dst = t}); emit (A.OPER { assem = "STORE M[`s0+0] <- `s1\n" , src = [munchExp e1, t] (* no overwrite *) , dst = [] , jump = NONE}) ... Trick: fresh temp protects value
Whither Frame Pointer? • Fixed size activation record possible • must consider entire body: all function calls • no alloca(…) • Frame pointer then derived: FP ≡ SP+c • Omitting frame pointer saves one register at zero cost • Historically, this is the trend
Summary • Instruction selection algorithms omitted registers • Needs abstract assembly (flexible location spec) • Module Assem: OPER/LABEL/MOVE • `s0, `d1, `j2, matching src/dst/jump • Register aware Maximal Munch (Stm,Exp) • MUL trashes EDX ; overwriting CALL/EAX/t • Frame pointer may be omitted
Recommend
More recommend