diff options
author | Vladimir Azarov <avm@intermediate-node.net> | 2025-08-08 19:07:58 +0200 |
---|---|---|
committer | Vladimir Azarov <avm@intermediate-node.net> | 2025-08-08 19:07:58 +0200 |
commit | a417225089fd78d53d73ad63cd79f57d1a4a8ff1 (patch) | |
tree | d9da68b0414fdaf08ddccbae20bd0e2977cdca25 | |
parent | b0cb85edf2b60f6f0909355db717376f435ab312 (diff) |
Register allocation
-rw-r--r-- | emit.fun | 697 | ||||
-rw-r--r-- | il.fun | 225 | ||||
-rw-r--r-- | il.sig | 3 | ||||
-rw-r--r-- | parser.fun | 11 | ||||
-rw-r--r-- | parser.sig | 1 |
5 files changed, 837 insertions, 100 deletions
@@ -5,8 +5,54 @@ functor Emit(I: IL) = struct structure D = P.D structure PP = P.P + val ip = I + val file = ref NONE + datatype reg = + Rax | Rbx | Rcx | Rdx | Rsi | Rdi | Rbp | Rsp | R8 | + R9 | R10 | R11 | R12 | R13 | R14 | R15 + + datatype vConst = VConst of word | VAddrConst of int * word + datatype vrType = + VtConst of vConst | VtReg of reg | VtStack of int | VtUnk + + datatype affinity = AfHard of reg | AfSoft of int list | AfUnk + + val regs = [ + (Rax, 0), + (Rdx, 1), + (Rsp, 2), + (Rbp, 3), + + (Rcx, 4), + (Rsi, 5), + (Rdi, 6), + (R8, 7), + (R9, 8), + (R10, 9), + (R11, 10), + + (Rbx, 11), + (R12, 12), + (R13, 13), + (R14, 14), + (R15, 15) + ] + + val firstUsedReg = 4 + val usedRegNum = 12 + + fun reg2idx reg = + case List.find (fn (r, _) => r = reg) regs of + NONE => raise Unreachable + | SOME (_, idx) => idx + + fun idx2reg idx = + case List.find (fn (_, i) => i = idx) regs of + NONE => raise Unreachable + | SOME (r, _) => r + local fun output s = let @@ -120,24 +166,6 @@ functor Emit(I: IL) = struct D.appi f P.iniLayouts end - fun getVarsForAlloc vregs = - let - fun loop idx acc = - if idx = D.length vregs then - rev acc - else - let - val { t, ... } = D.get vregs idx - in - if t = I.RtReg then - loop (idx + 1) (idx :: acc) - else - loop (idx + 1) acc - end - in - loop 0 [] - end - fun extendEnd (iStart, iEnd) ops labels = let fun loop idx iEnd = @@ -145,7 +173,7 @@ functor Emit(I: IL) = struct iEnd else let - val ins = D.get ops idx + val (ins, _) = D.get ops idx in case ins of SOME (I.IrJmp lid) | SOME (I.IrJz (_, lid)) | @@ -167,11 +195,24 @@ functor Emit(I: IL) = struct loop iEnd iEnd end - fun computeIntLocal (s, e) ops labels = + fun computeIntLocal (s, e) firstDef ops labels = let val e = extendEnd (s, e) ops labels + + val (_, li) = D.get ops firstDef in - (s, e) + case li of + SOME (startL, endL) => + let + val (startLoop, endLoop) = + (valOf $ D.get labels startL, valOf $ D.get labels endL) + + val s = if s < startLoop then s else startLoop + val e = if e > endLoop then e else endLoop + in + (s, e) + end + | _ => (s, e) end fun getBasicInt [] _ = raise Unreachable @@ -194,33 +235,629 @@ functor Emit(I: IL) = struct val (iStart, iEnd) = if var < localBound then - computeIntLocal (iStart, iEnd) ops labels + computeIntLocal (iStart, iEnd) (List.last defs) ops labels else (iStart, iEnd) in (var, iStart, iEnd) end - fun computeInts (F as I.Fi { vregs, ... }) vars = - List.map (computeInt F) vars + fun computeInts F vars = List.map (computeInt F) vars fun printInts ints = let - val () = printfn `"\nintervals:\n" % + val () = printfn `"\nsorted intervals:\n" % fun p (id, s, e) = printfn `"id: %" I id `" {" I s `", " I e `"}" % in List.app p ints end + fun updAff arr idx aff = + let + val (_, vt) = Array.sub (arr, idx) + in + Array.update (arr, idx, (aff, vt)) + end + + datatype insAff = IaNone | IaHard of (int * reg) list + | IaSoft of int * int list + + fun parNum2reg pr = + case pr of + 0 => Rdi + | 1 => Rsi + | 2 => Rdx + | 3 => Rcx + | 5 => R8 + | 6 => R9 + | _ => raise Unreachable + + fun getInsAff (SOME ins) = + let + fun tr (rd, rs1, rs2) = IaSoft (rd, [rs1, rs2]) + + fun setAff (rd, I.SaVReg rs) = IaSoft (rd, [rs]) + | setAff _ = IaNone + + fun fcallAff args = + let + fun collect idx (arg :: args) acc = + collect (idx + 1) args ((arg, parNum2reg idx) :: acc) + | collect _ [] acc = rev acc + in + IaHard $ collect 0 args [] + end + in + case ins of + I.IrSet p => setAff p + | I.IrAdd t => tr t + | I.IrSub t => tr t + | I.IrMul t => tr t + | I.IrIMul t => tr t + | I.IrDiv t => tr t + | I.IrIDiv t => tr t + | I.IrMod t => tr t + | I.IrIMod t => tr t + | I.IrShl t => tr t + | I.IrShr t => tr t + | I.IrSar t => tr t + | I.IrAnd t => tr t + | I.IrOr t => tr t + | I.IrXor t => tr t + | I.IrEq t => tr t + | I.IrNeq t => tr t + | I.IrCmpul t => tr t + | I.IrCmpug t => tr t + | I.IrCmpule t => tr t + | I.IrCmpuge t => tr t + | I.IrCmpsl t => tr t + | I.IrCmpsg t => tr t + | I.IrCmpsle t => tr t + | I.IrCmpsge t => tr t + + | I.IrExtZero _ | I.IrExtSign _ + | I.IrLoad _ | I.IrStore _ | I.IrJmp _ + | I.IrJz _ | I.IrJnz _ | I.IrNopLabel _ + | I.IrNop _ | I.IrRet _ | I.IrAlloc _ + | I.IrCopy _ => IaNone + | I.IrFcall (_, _, args) => fcallAff args + end + | getInsAff NONE = IaNone + + fun updateSoftAff rinfo rd rss = + let + fun sort [r] = [r] + | sort [rs1, rs2] = if rs1 < rs2 then [rs1, rs2] else [rs2, rs1] + | sort _ = raise Unreachable + + fun isNotConst rv = + let + val (_, vt) = Array.sub (rinfo, rv) + in + case vt of + VtConst _ => false + | _ => true + end + + val (aff, vt) = Array.sub (rinfo, rd) + val rss = List.filter isNotConst $ sort rss + + fun insertSorted ins [] = ins + | insertSorted [] acc = acc + | insertSorted (x :: xs) (y :: ys) = + if x < y then + x :: insertSorted xs (y :: ys) + else + y :: insertSorted (x :: xs) ys + + val aff = + case aff of + AfUnk => AfSoft rss + | AfSoft affs => AfSoft $ insertSorted rss affs + | AfHard _ => aff + in + Array.update (rinfo, rd, (aff, vt)) + end + + fun updateHardAff rinfo hards = + let + fun f (rd, reg) = + let + val (aff, vt) = Array.sub (rinfo, rd) + + val aff = + case aff of + AfUnk | AfSoft _ => AfHard reg + | AfHard _ => raise Unreachable + in + Array.update (rinfo, rd, (aff, vt)) + end + in + List.app f hards + end + + fun compAffinity rinfo ops paramNum = + let + fun compParams idx = + if idx = paramNum then + () + else + let + val reg = parNum2reg idx + in + updAff rinfo idx (AfHard reg); + compParams (idx + 1) + end + val () = compParams 0 + + fun loop idx = + if idx = D.length ops then + () + else + let + val (ins, _) = D.get ops idx + in + case getInsAff ins of + IaNone => () + | IaSoft (rd, rss) => updateSoftAff rinfo rd rss + | IaHard hards => updateHardAff rinfo hards; + loop (idx + 1) + end + in + loop 0 + end + + fun prepareRegInfo paramNum ops vregs = + let + val rinfo = Array.array (D.length vregs, (AfUnk, VtUnk)) + + fun transfer idx acc = + if idx = D.length vregs then + rev acc + else + let + val (vt, cand) = + case #t $ D.get vregs idx of + I.RtRem => (VtUnk, NONE) + | I.RtConst w => (VtConst (VConst w), NONE) + | I.RtAddrConst (id, w) => (VtConst (VAddrConst (id, w)), NONE) + | I.RtReg => (VtUnk, SOME idx) + in + Array.update (rinfo, idx, (AfUnk, vt)); + transfer (idx + 1) (if isSome cand then valOf cand :: acc else acc) + end + + val toAlloc = transfer 0 [] + in + compAffinity rinfo ops paramNum; + (toAlloc, rinfo) + end + + fun preg reg out = + let + val s = + case reg of + Rax => "rax" + | Rbx => "rbx" + | Rcx => "rcx" + | Rdx => "rdx" + | Rsi => "rsi" + | Rdi => "rdi" + | Rbp => "rbp" + | Rsp => "rsp" + | R8 => "r8" + | R9 => "r9" + | R10 => "r10" + | R11 => "r11" + | R12 => "r12" + | R13 => "r13" + | R14 => "r14" + | R15 => "r15" + in + Printf out `s % + end + + val Preg = fn z => bind A1 preg z + + fun affPrint rinfo = + let + fun pv idx out = Printf out `"%" I idx % + + fun p (idx, (aff, _)) = + let + val () = printf `"%" I idx % + in + case aff of + AfUnk => printfn `" = unk" % + | AfHard reg => printfn `" <- " Preg reg % + | AfSoft rss => printfn `" <- " Plist pv rss (", ", true, 1) % + end + in + Array.appi p rinfo + end + + fun sort _ [] = [] + | sort _ [x] = [x] + | sort le l = + let + fun divide [] accp = accp + | divide [x] (acc1, acc2) = (x :: acc1, acc2) + | divide (x :: y :: tail) (acc1, acc2) = + divide tail (x :: acc1, y :: acc2) + val (part1, part2) = divide l ([], []) + val part1 = sort le part1 + val part2 = sort le part2 + + fun merge [] [] acc = acc + | merge [] ys acc = rev $ List.revAppend (ys, acc) + | merge xs [] acc = rev $ List.revAppend (xs, acc) + | merge (x :: xs) (y :: ys) acc = + if le (x, y) then + merge xs (y :: ys) (x :: acc) + else + merge (x :: xs) ys (y :: acc) + in + merge part1 part2 [] + end + + fun updateI i = fn z => + let + fun from rinfo active pool intervals stackCand = + { rinfo, active, pool, intervals, stackCand } + fun to f { rinfo, active, pool, intervals, stackCand } = + f rinfo active pool intervals stackCand + in + FRU.makeUpdate5 (from, from, to) i + end z + + fun returnToPool pool reg = + let + val idx = reg2idx reg - firstUsedReg + in + Array.update (pool, idx, NONE) + end + + fun expireOne { rinfo, active, pool, ... } (_, start, _) = + case !active of + [] => false + | (j, startp, endp) :: acts => + if endp > start then + false + else + let + val (_, vt) = Array.sub (rinfo, j) + val reg = case vt of VtReg reg => reg | _ => raise Unreachable + + val () = printfn `"III!!! interval %" + ip j `"(" ip startp `", " ip endp `") " + `"with " Preg reg `" has expired" % + in + returnToPool pool reg; + active := acts; + true + end + + fun expireOld (I as { active, ... }) int = + let + fun loop I = + case expireOne I int of + false => () + | true => loop I + in + case !active of + [] => () + | _ => loop I + end + + fun addToActive int [] = [int] + | addToActive (I as (_, _, e1)) (act :: acts) = + if e1 < #3 act then + (I :: act :: acts) + else + act :: addToActive I acts + + fun updReg arr idx reg = + let + val (aff, _) = Array.sub (arr, idx) + in + Array.update (arr, idx, (aff, reg)) + end + + fun assignFirstReg poff { rinfo, pool, ... } vr = + let + fun loop idx = + if idx = Array.length pool then + raise Unreachable + else + let + val user = Array.sub (pool, idx) + in + case user of + SOME _ => loop (idx + 1) + | NONE => + let + val () = Array.update (pool, idx, SOME vr); + val reg = idx2reg (firstUsedReg + idx) + + val () = printfn R poff + `"assigned (first) reg " Preg reg `" to %" ip vr % + in + updReg rinfo vr (VtReg reg) + end + end + in + loop 0 + end + + fun freeRegList pool = + let + fun loop idx acc = + if idx = Array.length pool then + rev acc + else + case Array.sub (pool, idx) of + NONE => loop (idx + 1) (idx2reg (idx + firstUsedReg) :: acc) + | SOME _ => loop (idx + 1) acc + in + loop 0 [] + end + + fun getAffRegList rinfo affs = + let + fun loop [] acc = rev acc + | loop (vr :: vrs) acc = + let + val (_, vt) = Array.sub (rinfo, vr) + in + case vt of + VtReg r => loop vrs (r :: acc) + | _ => loop vrs acc + end + in + loop affs [] + end + + fun findCommonRegs l1 l2 = + let + val l1 = sort (fn (r1, r2) => reg2idx r1 <= reg2idx r2) l1 + val l2 = sort (fn (r1, r2) => reg2idx r1 <= reg2idx r2) l2 + + fun intersection [] _ = [] + | intersection _ [] = [] + | intersection (x :: xs) (y :: ys) = + case Int.compare (reg2idx x, reg2idx y) of + LESS => intersection xs (y :: ys) + | EQUAL => x :: intersection xs ys + | GREATER => intersection (x :: xs) ys + in + intersection l1 l2 + end + + fun assignSoftReg poff affs (I as { rinfo, pool, ... }) vr = + let + val () = printfn R poff + `"trying to assign register (by affinity) to %" ip vr % + + val regs = freeRegList pool + val affRegs = getAffRegList rinfo affs + val common = findCommonRegs regs affRegs + + val () = printfn R (poff + 1) + `"free registers: " Plist preg regs (", ", true, 0) % + val () = printfn R (poff + 1) + `"affinity registers: " Plist preg affRegs (", ", true, 0) % + in + case common of + [] => + let + val () = printfn R (poff + 1) `"affinity was not satisfied" % + in + assignFirstReg (poff + 2) I vr + end + | (reg :: _) => + let + in + updReg rinfo vr (VtReg reg); + Array.update (pool, reg2idx reg - firstUsedReg, SOME vr); + printfn R (poff + 1) + `"assigned (by affinity) reg " Preg reg `" to %" ip vr %; + printfn R (poff + 1) + `"free registers: " Plist preg (freeRegList pool) (", ", true, 0) % + end + end + + fun putToStack poff { rinfo, stackCand, ... } vr = + let + val () = printfn R poff + `"puting %" ip vr `" to stack: " ip (!stackCand) % + in + updReg rinfo vr (VtStack (!stackCand)); + stackCand := !stackCand - 8 + end + + fun assignHardReg poff (I as { rinfo, pool, ... }) vr reg = + let + val () = printfn R poff + `"trying to assign hard reg " A1 preg reg `" to %" ip vr % + + val regIdx = reg2idx reg - firstUsedReg + val user = Array.sub (pool, regIdx) + + fun setOurReg () = + let + val () = printfn R (poff + 1) `"reg assigned" % + in + Array.update (pool, regIdx, SOME vr); + updReg rinfo vr (VtReg reg) + end + in + case user of + NONE => setOurReg () + | SOME u => + let + val () = printfn R (poff + 1) `"reg is taken by %" ip u % + val (aff, _) = Array.sub (rinfo, u) + in + case aff of + AfHard _ => raise Unreachable + | AfSoft affs => assignSoftReg poff affs I u + | AfUnk => assignFirstReg poff I u + ; + setOurReg () + end + end + + fun assignReg (I as { rinfo, ... }) (vr, _, _) = + let + val (aff, _) = Array.sub (rinfo, vr) + in + case aff of + AfUnk => assignFirstReg 0 I vr + | AfSoft affs => assignSoftReg 0 affs I vr + | AfHard reg => assignHardReg 0 I vr reg + end + + fun getPool () = Array.array (usedRegNum, NONE) + + fun changeInActive active newInt oldVr = + let + val a = !active + val a = List.filter (fn (v, _, _) => v <> oldVr) a + in + active := addToActive newInt a + end + + fun expropriateReg (I as { rinfo, pool, active, ... }) int reg = + let + val vr = #1 int + + val regIdx = reg2idx reg - firstUsedReg + val u = valOf $ Array.sub (pool, regIdx) + + val (uAff, _) = Array.sub (rinfo, u) + val () = + case uAff of + AfHard _ => raise Unreachable + | _ => () + + val () = putToStack 1 I u + val () = Array.update (pool, regIdx, SOME vr) + val () = updReg rinfo vr (VtReg reg) + in + changeInActive active int u + end + + fun userIdx pool vr = + let + fun loop idx = + if idx = Array.length pool then + raise Unreachable + else + case Array.sub (pool, idx) of + SOME u => + if u = vr then + idx + else + loop (idx + 1) + | NONE => loop (idx + 1) + in + loop 0 + end + + fun spillAtInterval (I as { rinfo, active, pool, ... }) int = + let + val spill = List.last (!active) + + val vr = #1 int + val (ourAff, _) = Array.sub (rinfo, vr) + + fun isNotHard vr = + case #1 $ Array.sub (rinfo, vr) of + AfHard _ => false + | _ => true + + val () = printfn `"SpilAtInt" % + val () = printfn R 0 + `"free registers: " Plist preg (freeRegList pool) (", ", true, 0) % + in + case ourAff of + AfHard reg => expropriateReg I int reg + | _ => + if #3 spill > #3 int andalso isNotHard (#1 spill) then + let + val idx = userIdx pool (#1 spill) + val () = printfn `"spilling!!!" % + in + Array.update (pool, idx, SOME vr); + updReg rinfo vr (VtReg $ idx2reg (idx + firstUsedReg)); + putToStack 1 I (#1 spill); + changeInActive active int (#1 spill) + end + else + putToStack 0 I vr + end + + fun linearscan rinfo ints = + let + fun incStart ((_, start1, _), (_, start2, _)) = start1 <= start2 + val ints = sort incStart ints + + val () = printInts ints + + fun loop _ [] = () + | loop (I as { active, ... }) (int :: ints) = + let + val () = printfn `"\n\ninspectiing interval " + ip (#1 int) `": (" ip (#2 int) `", " ip (#3 int) `")" % + + val () = expireOld I int + + val () = + if length (!active) = usedRegNum then + spillAtInterval I int + else + let + val () = assignReg I int + in + active := addToActive int (!active) + end + in + loop I ints + end + in + loop { active = ref [], pool = getPool (), rinfo, + stackCand = ref (~8) } ints + end - fun regAlloc (F as I.Fi { vregs, labels, ... }) = + fun printAllocVar rinfo v = let - val varsForAlloc = getVarsForAlloc vregs - val () = printfn `"for alloc: " Plist i varsForAlloc (", ", true, 0) % + val () = printf `"%" I v `": " % + val (_, vt) = Array.sub (rinfo, v) + in + case vt of + VtStack off => printfn `"stack " I off % + | VtReg reg => printfn `"reg " A1 preg reg % + | VtConst _ | VtUnk => raise Unreachable + end + + fun printAlloced rinfo toAlloc = + let + val () = printfn `"\nallocated:\n" % + in + List.app (printAllocVar rinfo) toAlloc + end + + fun regAlloc (F as I.Fi { vregs, ops, paramNum, ... }) = + let + val (toAlloc, regInfo) = prepareRegInfo paramNum ops vregs + val () = printfn `"for alloc: " Plist i toAlloc (", ", true, 0) % + + val () = affPrint regInfo - val intervals = computeInts F varsForAlloc + val intervals = computeInts F toAlloc - val () = printInts intervals + val () = linearscan regInfo intervals + val () = printAlloced regInfo toAlloc in raise Unimplemented end @@ -75,22 +75,28 @@ functor IL(P: PARSER) = struct t: regType } + datatype scopeInfo = + SiLoop of { breakL: label, contL: label, startL: label, endL: label } | + SiIf + datatype localCtx = Lctx of { - localVars: { onStack: bool, t: P.ctype } vector, + fname: int, + localVars: { onStack: bool, t: P.ctype, name: int } vector, paramNum: int, vregs: regInfo D.t, - ops: (irIns option) D.t, + ops: (irIns option * (label * label) option) D.t, - loopLabels: { break: label, continue: label } D.t, + scopes: scopeInfo list ref, labels: (int option * int) D.t } datatype funcInfo = Fi of { name: int, + paramNum: int, localBound: int, vregs: regInfo D.t, - ops: (irIns option) D.t, + ops: (irIns option * (label * label) option) D.t, labels: int option D.t } @@ -105,10 +111,10 @@ functor IL(P: PARSER) = struct fun updateLctx (Lctx ctx) = fn z => let - fun from localVars paramNum vregs ops loopLabels labels = - { localVars, paramNum, vregs, ops, loopLabels, labels } - fun to f { localVars, paramNum, vregs, ops, loopLabels, labels } = - f localVars paramNum vregs ops loopLabels labels + fun from fname localVars paramNum vregs ops scopes labels = + { fname, localVars, paramNum, vregs, ops, scopes, labels } + fun to f { fname, localVars, paramNum, vregs, ops, scopes, labels } = + f fname localVars paramNum vregs ops scopes labels in FRU.makeUpdate6 (from, from, to) ctx (fn (a, f) => z (a, Lctx o f)) end @@ -139,9 +145,9 @@ functor IL(P: PARSER) = struct Vector.fromList (rev acc) else let - val { onStack: bool, t: P.ctype, ... } = Vector.sub (localVars, idx) + val { onStack, t, name, ... } = Vector.sub (localVars, idx) in - setup (idx + 1) ({ onStack, t } :: acc) + setup (idx + 1) ({ onStack, t, name } :: acc) end in setup 0 [] @@ -172,7 +178,7 @@ functor IL(P: PARSER) = struct let val { t, onStack, ... } = Vector.sub (localVars, idx) val class = if onStack then VR8 else getClassForType t - val defs = if idx < paramNum then [~1] else [] + val defs = if idx < paramNum then [0] else [] in D.push vregs ({ class, defs, use = [], t = RtReg }); loop (idx + 1) @@ -260,12 +266,30 @@ functor IL(P: PARSER) = struct List.app updateUse use end - fun ctxPutOp (C as Lctx { ops, labels, ... }) op' = + fun getOutermostLoopIfNeeded scopes = + let + fun skipToIf [] = NONE + | skipToIf (SiLoop _ :: tail) = skipToIf tail + | skipToIf (SiIf :: tail) = SOME tail + + fun tryGetFirstLoop (SiIf :: tail) = tryGetFirstLoop tail + | tryGetFirstLoop (SiLoop { startL, endL, ... } :: _) = + SOME (startL, endL) + | tryGetFirstLoop [] = NONE + in + case skipToIf scopes of + NONE => NONE + | SOME tail => tryGetFirstLoop (rev tail) + end + + fun ctxPutOp (C as Lctx { ops, labels, scopes, ... }) op' = let val { defs, use } = getInsInfo op' val insPos = D.length ops val () = updateDefsUse C defs use insPos - val () = D.push ops (SOME op') + + val li = getOutermostLoopIfNeeded (!scopes) + val () = D.push ops (SOME op', li) fun setPos (NONE, use) = (SOME insPos, use) | setPos (SOME _, _) = raise Unreachable @@ -297,17 +321,19 @@ functor IL(P: PARSER) = struct fun getLabel (Lctx { labels, ... }) = D.pushAndGetId labels (NONE, 0) - fun createLocalCtx localVars paramNum = + fun createLocalCtx fname localVars paramNum = let val localVars = setupLocalVars localVars val vregs = setupVregs localVars paramNum val labels = D.create0 () val ctx = Lctx { + fname, localVars, paramNum, vregs, ops = D.create0 (), - loopLabels = D.create0 (), labels + scopes = ref [], labels } + val () = ctxPutOp ctx (IrNop "") val _ = getLabel ctx (* label before ret *) val () = copyArgs ctx in @@ -929,7 +955,6 @@ functor IL(P: PARSER) = struct fun genArgs [] acc = let - fun loop _ [] acc2 = rev acc2 | loop idx (vArg :: acc) acc2 = let @@ -941,7 +966,7 @@ functor IL(P: PARSER) = struct val () = ctxPutOp ctx (IrNop "here") in - loop 0 acc [] + loop 0 (rev acc) [] end | genArgs (arg :: args) acc = let @@ -1022,8 +1047,15 @@ functor IL(P: PARSER) = struct end | NONE => ctxPutOp ctx (IrRet NONE) + fun beginIfScope (Lctx { scopes, ... }) = scopes := SiIf :: !scopes + fun endIfScope (Lctx { scopes, ... }) = + case hd (!scopes) of + SiLoop _ => raise Unreachable + | SiIf => scopes := tl (!scopes) + fun convIf ctx (cond, thenPart, elsePart) = let + val () = beginIfScope ctx val v = genLogPart ctx cond val (elseL, endL) = getLabelPair ctx in @@ -1037,63 +1069,94 @@ functor IL(P: PARSER) = struct convStmt ctx elsePart; ctxPutOp ctx (IrNopLabel endL) ) - | NONE => () + | NONE => (); + endIfScope ctx end - and ctxGetLoopLabels (C as Lctx { loopLabels, ... }) = + and getLabelsWhile (C as Lctx { scopes, ... }) = let - val (l1, l2) = getLabelPair C - - val () = D.push loopLabels { break = l1, continue = l2 } + val (startL, endL) = getLabelPair C + val scope = SiLoop { startL, endL, contL = startL, breakL = endL } in - (l1, l2) + scopes := scope :: !scopes; + { startL, endL } end - and ctxLoopExit (Lctx { loopLabels, ... }) = ignore $ D.pop loopLabels + and ctxLoopExit (Lctx { scopes, ... }) = + let + val top = hd $ !scopes + in + case top of + SiLoop _ => scopes := tl (!scopes) + | _ => raise Unreachable + end and convWhile ctx (cond, body) = let - val (breakL, contL) = ctxGetLoopLabels ctx - val () = ctxPutOp ctx (IrNopLabel contL) + val { startL, endL } = getLabelsWhile ctx + val () = ctxPutOp ctx (IrNopLabel startL) val cond = genLogPart ctx cond in - ctxPutOp ctx (IrJz (cond, breakL)); + ctxPutOp ctx (IrJz (cond, endL)); convStmt ctx body; - ctxPutOp ctx (IrJmp contL); - ctxPutOp ctx (IrNopLabel breakL); + ctxPutOp ctx (IrJmp startL); + ctxPutOp ctx (IrNopLabel endL); ctxLoopExit ctx end + and getLabelsDoWhile (C as Lctx { scopes, ... }) = + let + val startL = getLabel C + val (contL, endL) = getLabelPair C + val scope = SiLoop { startL, endL, contL, breakL = endL } + in + scopes := scope :: !scopes; + { startL, contL, endL } + end + and convDoWhile ctx (body, cond) = let - val (breakL, contL) = ctxGetLoopLabels ctx - val startL = getLabel ctx + val { startL, contL, endL } = getLabelsDoWhile ctx val () = ctxPutOp ctx (IrNopLabel startL) val () = convStmt ctx body val () = ctxPutOp ctx (IrNopLabel contL) val cond = genLogPart ctx cond in ctxPutOp ctx (IrJnz (cond, startL)); - ctxPutOp ctx (IrNopLabel breakL); + ctxPutOp ctx (IrNopLabel endL); ctxLoopExit ctx end - and convBreakOrCont isBreak (C as Lctx { loopLabels, ... }) = + and convBreakOrCont isBreak (C as Lctx { scopes, ... }) = let - val { break, continue } = D.last loopLabels + fun getFirstLoopInfo [] = raise Unreachable + | getFirstLoopInfo (SiLoop { breakL, contL, ... } :: _) = + (breakL, contL) + | getFirstLoopInfo (SiIf :: tail) = getFirstLoopInfo tail + + val (break, continue) = getFirstLoopInfo $ !scopes val label = if isBreak then break else continue in ctxPutOp C (IrJmp label) end + and getLabelsFor (C as Lctx { scopes, ... }) = + let + val startL = getLabel C + val (endL, contL) = getLabelPair C + val scope = SiLoop { startL, endL, contL, breakL = endL } + in + scopes := scope :: !scopes; + { startL, contL, endL } + end + and convFor ctx (pre, cond, post, stmt) = let val () = case pre of NONE => () | SOME ea => ignore $ convExpr ctx ea - val startL = getLabel ctx - val (breakL, contL) = ctxGetLoopLabels ctx + val { startL, contL, endL } = getLabelsFor ctx val () = ctxPutOp ctx (IrNopLabel startL) val () = @@ -1103,7 +1166,7 @@ functor IL(P: PARSER) = struct let val cond = genLogPart ctx cond in - ctxPutOp ctx (IrJz (cond, breakL)) + ctxPutOp ctx (IrJz (cond, endL)) end val () = convStmt ctx stmt val () = ctxPutOp ctx (IrNopLabel contL) @@ -1112,9 +1175,9 @@ functor IL(P: PARSER) = struct NONE => () | SOME post => ignore $ convExpr ctx post val () = ctxPutOp ctx (IrJmp startL) - val () = ctxPutOp ctx (IrNopLabel breakL) + val () = ctxPutOp ctx (IrNopLabel endL) in - () + ctxLoopExit ctx end and convStmt ctx stmt: unit = @@ -1131,6 +1194,7 @@ functor IL(P: PARSER) = struct | P.StmtDoWhile pair => convDoWhile ctx pair | P.StmtBreak => convBreakOrCont true ctx | P.StmtContinue => convBreakOrCont false ctx + | P.StmtNone => raise Unreachable val Pl = fn z => let @@ -1185,12 +1249,6 @@ functor IL(P: PARSER) = struct fun preg (C as Lctx { vregs, ... }) id out = let val rt = getRegType vregs id - - val () = - if id = 10 then - printfn `"printing 10" % - else - () in case rt of RtReg => Printf out `"%" I id % @@ -1210,10 +1268,20 @@ functor IL(P: PARSER) = struct | SaAddr (id, w) => (printf PP.? id %; printConst VR8 w) end - fun printOp ctx (idx, SOME op') = + fun printOp ctx (idx, (SOME op', li)) = let + fun printTail NONE = printf `"\n" % + | printTail (SOME (startL, endL)) = + case op' of + IrNopLabel _ => printf `"\n" % + | _ => printf `" ; (l" I startL `", l" I endL `")\n" % + val () = printf I idx `":" % + val () = + case op' of + IrNopLabel _ => () + | _ => printf `"\t" % fun pt (reg1, reg2, reg3) op' = printf `"\t" Preg ctx reg1 `" " Pt ctx reg1 `" = " `op' `" " Preg ctx reg2 `", " Preg ctx reg3 % @@ -1224,7 +1292,6 @@ functor IL(P: PARSER) = struct fun pj (r, l) op' = printf `"\t" `op' `" " Preg ctx r `", " Pl l % - fun printRet NONE = printf `"\tret" % | printRet (SOME reg) = printf `"\tret " Pt ctx reg `" " Preg ctx reg % @@ -1296,9 +1363,9 @@ functor IL(P: PARSER) = struct | IrCopy t => printCopy t | IrFcall t => printFcall t ; - printf `"\n" % + printTail li end - | printOp _ (_, NONE) = () + | printOp _ (_, (NONE, _)) = () fun printIns (C as Lctx { ops, ... }) = D.appi (printOp C) ops @@ -1351,8 +1418,11 @@ functor IL(P: PARSER) = struct | RtAddrConst (id, w) => RtAddrConst (id, w) | RtReg | RtRem => raise Unreachable val () = D.set vregs vid { class, defs, use, t = v } + + fun f (SOME _, li) = (NONE, li) + | f (NONE, _) = raise Unreachable in - D.set ops insId NONE + D.update ops f insId end fun getFirstConstants @@ -1379,7 +1449,7 @@ functor IL(P: PARSER) = struct case defs of [def] => let - val ins = valOf $ D.get ops def + val ins = valOf o #1 $ D.get ops def in case ins of IrSet(_, arg as SaConst _ | arg as SaAddr _) => @@ -1595,7 +1665,7 @@ functor IL(P: PARSER) = struct fun loop (insId :: tail) acc = let - val ins = D.get ops insId + val (ins, li) = D.get ops insId (* val () = printfn `"v: " I v `", Ins: " I insId % @@ -1620,7 +1690,7 @@ functor IL(P: PARSER) = struct | _ => raise Unreachable val ins = IrSet (vd, vl) in - D.set ops insId (SOME ins); + D.set ops insId (SOME ins, li); NONE end in @@ -1685,12 +1755,19 @@ functor IL(P: PARSER) = struct let val () = printfn `"removing %" I rs % + val { class, ... } = D.get vregs rs val () = D.set vregs rs { defs = [], use = [], class, t = RtRem } - val ins = valOf $ D.get ops (idx - 1) + val ins = valOf o #1 $ D.get ops (idx - 1) val ir = changeDest rd ins - val () = D.set ops (idx - 1) (SOME ir) - val () = D.set ops idx NONE + + fun f1 (SOME _, v) = (SOME ir, v) + | f1 (NONE, _) = raise Unreachable + fun f2 (SOME _, v) = (NONE, v) + | f2 (NONE, _) = raise Unreachable + + val () = D.update ops f1 (idx - 1) + val () = D.update ops f2 idx val { defs, use, class, t } = D.get vregs rd @@ -1703,7 +1780,7 @@ functor IL(P: PARSER) = struct end fun optSet (C as Lctx { vregs, localVars, paramNum, ... }) - (idx, SOME (IrSet (rd, SaVReg rs))) + (idx, (SOME (IrSet (rd, SaVReg rs)), _)) = if getCS vregs rd <> getCS vregs rs then () @@ -1731,15 +1808,16 @@ functor IL(P: PARSER) = struct fun removeUnusedLabels (Lctx { ops, labels, ... }) = let - fun f (insId, op') = + fun rem (insId, (op', _)) = case op' of SOME (IrNopLabel lid) => let val (_, usage) = D.get labels lid in - if usage = 0 then - (printfn `"removing label: " I lid %; D.set ops insId NONE) - else + if usage = 0 then ( + printfn `"removing label: " I lid %; + D.set ops insId (NONE, NONE) + ) else () end | _ => () @@ -1748,15 +1826,22 @@ functor IL(P: PARSER) = struct if idx = D.length ops then () else ( - f (idx, D.get ops idx); + rem (idx, D.get ops idx); loop (idx + 1) ) in loop 0 end - fun removeUnusedVars (Lctx { vregs, ... }) = + fun removeUnusedVars (Lctx { fname, vregs, localVars, ... }) = let + fun die' idx = + let + val varName = #name $ Vector.sub (localVars, idx) + in + die 1 PP.? fname `": " PP.? varName + `": variable is used uninitialized" % + end fun loop idx = if idx = D.length vregs then () @@ -1764,8 +1849,14 @@ functor IL(P: PARSER) = struct let val { defs, use, t, class } = D.get vregs idx val t = - if t = RtReg andalso defs = [] andalso use = [] then - RtRem + if t = RtReg andalso defs = [] then + case use of + [] => RtRem + | _ => + if idx < Vector.length localVars then + die' idx + else + raise Unreachable else t in @@ -1779,7 +1870,7 @@ functor IL(P: PARSER) = struct fun translateFn (F as { localVars, stmt, paramNum, name, ... }) = let val () = P.printDef (P.Definition F) - val ctx = createLocalCtx localVars paramNum + val ctx = createLocalCtx name localVars paramNum val () = convStmt ctx stmt val () = ctxPutOp ctx (IrNopLabel 0) @@ -1807,7 +1898,7 @@ functor IL(P: PARSER) = struct val Lctx { vregs, ops, labels, ... } = ctx in Fi { name, localBound = Vector.length localVars + paramNum, - vregs, ops, labels = D.copy labels (fn (v, _) => v) } + paramNum, vregs, ops, labels = D.copy labels (fn (v, _) => v) } end fun createCtx ({ ext, glob, objsZI, objs, funcs, strlits }) = @@ -77,9 +77,10 @@ signature IL = sig datatype funcInfo = Fi of { name: int, + paramNum: int, localBound: int, vregs: regInfo D.t, - ops: (irIns option) D.t, + ops: (irIns option * (label * label) option) D.t, labels: int option D.t } @@ -178,6 +178,7 @@ functor Parser(structure Tree: TREE; structure P: PPC; StmtDoWhile of stmt * exprAug | StmtReturn of exprAug option | StmtBreak | + StmtNone | StmtContinue datatype parseBinopRes = BRbinop of exprPart | BRfinish of int @@ -3046,7 +3047,7 @@ functor Parser(structure Tree: TREE; structure P: PPC; lx end) - | _ => raise Unimplemented + | _ => raise Unreachable end fun printOffsets (LcAux (offset, l)) out = @@ -3467,6 +3468,7 @@ functor Parser(structure Tree: TREE; structure P: PPC; | Tk T.kwBreak => parseJmp StmtBreak | Tk T.kwContinue => parseJmp StmtContinue | Tk T.kwReturn => parseReturn ctx + | Tk T.Semicolon => (StmtNone, #3 $ getTokenCtx ctx) | _ => parseStmtExpr ctx end @@ -3670,8 +3672,12 @@ functor Parser(structure Tree: TREE; structure P: PPC; | _ => let val (stmt, ctx) = parseStmt ctx + val acc = + case stmt of + StmtNone => acc + | _ => stmt :: acc in - collectStmts (stmt :: acc) ctx + collectStmts acc ctx end end @@ -3723,6 +3729,7 @@ functor Parser(structure Tree: TREE; structure P: PPC; Printf out `"return " Popt pea ea `";" % | pstmt' _ StmtBreak out = Printf out `"break;" % | pstmt' _ StmtContinue out = Printf out `"continue;" % + | pstmt' _ StmtNone _ = raise Unreachable and pCompBody off (S as (StmtCompound _)) out = Printf out A2 pstmt' (off - 1) S % @@ -126,6 +126,7 @@ signature PARSER = sig StmtDoWhile of stmt * exprAug | StmtReturn of exprAug option | StmtBreak | + StmtNone | StmtContinue type funcInfo = { |