From 4129a30c13e403d26e44cf2104b540b59ec30486 Mon Sep 17 00:00:00 2001 From: Forest Belton Date: Sat, 18 Sep 2021 00:11:57 -0400 Subject: [PATCH] Start working on branch support --- example.gby | 2 ++ lib/ast.d.ts | 10 ++++++++- lib/codegen/allocate.ts | 4 +++- lib/ir/convert.ts | 18 ++++++++++------ lib/ir/insn.ts | 47 +++++++++++++++++++++++++++++++++++------ lib/ir/pretty.ts | 6 ++++++ lib/parser.pegjs | 28 +++++++++++++----------- lib/regalloc.ts | 17 +++++++++++---- lib/sm83/realize.ts | 16 +++++++++++++- 9 files changed, 117 insertions(+), 31 deletions(-) diff --git a/example.gby b/example.gby index ba7531b..d82a6f0 100644 --- a/example.gby +++ b/example.gby @@ -4,6 +4,8 @@ u8 x; u8 y; +loop: x <- -y + j; z <- w + 7; z <- z << 1; +goto loop; diff --git a/lib/ast.d.ts b/lib/ast.d.ts index 6f87d58..6057dde 100644 --- a/lib/ast.d.ts +++ b/lib/ast.d.ts @@ -16,7 +16,15 @@ type ADecl = { } // Statements -export type Stmt = AssignStmt +export type Stmt = LabelStmt | GotoStmt | AssignStmt + +export type LabelStmt = AStmt<"label", { + name: string, +}> + +export type GotoStmt = AStmt<"goto", { + name: string, +}> export type AssignStmt = AStmt<"assign", { name: string, diff --git a/lib/codegen/allocate.ts b/lib/codegen/allocate.ts index 24cdbe2..572922c 100644 --- a/lib/codegen/allocate.ts +++ b/lib/codegen/allocate.ts @@ -1,5 +1,5 @@ import type { RegAlloc } from '../regalloc' -import { AbsInsn2, CopyInsn, insnReduce2, Operand, UnaryInsn } from '../ir/insn' +import { AbsInsn2, CopyInsn, GotoInsn, insnReduce2, LabelInsn, Operand, UnaryInsn } from '../ir/insn' import { Loc, LocType } from '../ir/loc' import { UnaryOp, BinaryOp } from '../ast' @@ -11,6 +11,8 @@ export const allocateInsn = (alloc: RegAlloc, insn: AbsInsn2): AbsInsn2 => insnR allocateInsnDest(alloc, dest), typeof source === 'number' ? source : allocateInsnDest(alloc, source), ), + (name: string) => LabelInsn(name), + (name: string) => GotoInsn(name), (dest: Loc, op: UnaryOp | BinaryOp, source: Operand) => UnaryInsn( allocateInsnDest(alloc, dest), op, diff --git a/lib/ir/convert.ts b/lib/ir/convert.ts index baafbfe..619e1e4 100644 --- a/lib/ir/convert.ts +++ b/lib/ir/convert.ts @@ -1,7 +1,7 @@ import type { AssignStmt, Expr, Stmt } from "../ast" import { R8 } from "../sm83/cpu" import { Loc, LocType } from "./loc" -import { Operand, AbsInsn2, AbsInsn3, CopyInsn, UnaryInsn, BinaryInsn } from "./insn" +import { Operand, AbsInsn2, AbsInsn3, CopyInsn, GotoInsn, UnaryInsn, BinaryInsn, LabelInsn } from "./insn" export class IRState { nextID: number @@ -21,16 +21,22 @@ export const convertIR = (stmts: Array): Array => { const state: IRState = new IRState() stmts.forEach(stmt => { - convertAssignStmt(state, stmt) + switch (stmt.stmt_type) { + case 'assign': + convertExpr(state, Loc.vari(stmt.args.name), stmt.args.expr) + break + case 'label': + state.insns.push(LabelInsn(stmt.args.name)) + break + case 'goto': + state.insns.push(GotoInsn(stmt.args.name)) + break + } }) return state.insns } -export const convertAssignStmt = (state: IRState, stmt: AssignStmt): void => { - convertExpr(state, Loc.vari(stmt.args.name), stmt.args.expr) -} - export const convertExpr = (state: IRState, dest: Loc, expr: Expr): void => { const threeAddress = convertExpr3(state, dest, expr) diff --git a/lib/ir/insn.ts b/lib/ir/insn.ts index 4627cc7..05fc9f1 100644 --- a/lib/ir/insn.ts +++ b/lib/ir/insn.ts @@ -9,6 +9,16 @@ export type AbsInsnCopy = { source: Operand, } +export type AbsInsnGoto = { + type: "goto", + dest: string, +} + +export type AbsInsnLabel = { + type: "label", + dest: string, +} + type UnaryInsn = { type: "unary", dest: Loc, @@ -20,16 +30,31 @@ type UnaryInsn = { export type AbsInsn2Unary = UnaryInsn // Abstract instruction in two-address form -export type AbsInsn2 = AbsInsnCopy | AbsInsn2Unary +export type AbsInsn2 = AbsInsnCopy | AbsInsnLabel | AbsInsnGoto | AbsInsn2Unary type CopyFn = (dest: Loc, source: Operand) => A +type StringFn = (name: string) => A type UnaryFn = (dest: Loc, op: Op, source: Operand) => A type UnaryFn2 = UnaryFn -export const insnReduce2 = (copy: CopyFn, unary: UnaryFn2, insn: AbsInsn2): A => - insn.type === 'copy' - ? copy(insn.dest, insn.source) - : unary(insn.dest, insn.op, insn.source) +export const insnReduce2 = ( + copy: CopyFn, + label: StringFn, + goto: StringFn, + unary: UnaryFn2, + insn: AbsInsn2 +): A => { + switch (insn.type) { + case 'copy': + return copy(insn.dest, insn.source) + case 'label': + return label(insn.dest) + case 'goto': + return goto(insn.dest) + case 'unary': + return unary(insn.dest, insn.op, insn.source) + } +} export type AbsInsn3Unary = UnaryInsn @@ -42,7 +67,7 @@ export type AbsInsnBinary = { } // Abstract instruction in three-address form -export type AbsInsn3 = AbsInsnCopy | AbsInsn3Unary | AbsInsnBinary +export type AbsInsn3 = AbsInsnCopy | AbsInsnLabel | AbsInsnGoto | AbsInsn3Unary | AbsInsnBinary export const CopyInsn = (dest: Loc, source: Operand): AbsInsnCopy => ({ type: 'copy', @@ -64,3 +89,13 @@ export const BinaryInsn = (dest: Loc, source: Operand, op: BinaryOp, source1: Op op, source1, }) + +export const LabelInsn = (dest: string): AbsInsnLabel => ({ + type: 'label', + dest, +}) + +export const GotoInsn = (dest: string): AbsInsnGoto => ({ + type: 'goto', + dest, +}) diff --git a/lib/ir/pretty.ts b/lib/ir/pretty.ts index 8117cbe..f752637 100644 --- a/lib/ir/pretty.ts +++ b/lib/ir/pretty.ts @@ -18,6 +18,12 @@ export const prettyPrintInsn = (ssa: AbsInsn2 | AbsInsn3): string => { case 'binary': output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)}, ${ppOp(ssa.source1)})` break + case 'goto': + output = `goto(${ssa.dest})` + break + case 'label': + output = `${ssa.dest}:` + break } return output diff --git a/lib/parser.pegjs b/lib/parser.pegjs index 85ca7b5..e89ce3f 100644 --- a/lib/parser.pegjs +++ b/lib/parser.pegjs @@ -19,8 +19,10 @@ Decl = VarDecl VarDecl = attrs:Attrs? type:Type name:Ident SEMI { return decl("var", name, attrs, { type }) } // Statements -Stmt = @AssignStmt SEMI -AssignStmt = name:Ident ASSIGN expr:Expr { return stmt("assign", { name, expr }) } +Stmt = GotoStmt / LabelStmt / AssignStmt +GotoStmt = GOTO name:Ident SEMI { return stmt("goto", { name }) } +LabelStmt = name:Ident COLON { return stmt("label", { name }) } +AssignStmt = name:Ident ASSIGN expr:Expr SEMI { return stmt("assign", { name, expr }) } // Expressions Expr = BitOrExpr @@ -69,26 +71,28 @@ Number = digits:[0-9]+ WS { return parseInt(digits.join(''), 10) } / '0b' digits:[01]+ WS { return parseInt(digits.join(''), 2) } // Terminal keywords +GOTO = 'goto' WS S8 = @'s8' WS U8 = @'u8' WS U16 = @'u16' WS // Terminal symbols -PIPE = '|' WS -CARET = '^' WS AMPERSAND = '&' WS -LTLT = '<<' WS -GTGT = '>>' WS -PLUS = '+' WS -TILDE = '~' WS -MINUS = '-' WS -SEMI = ';' WS ASSIGN = '<-' WS -LPAREN = '(' WS -RPAREN = ')' WS +CARET = '^' WS +COLON = ':' WS COMMA = ',' WS +GTGT = '>>' WS LATTR = '[[' WS +LPAREN = '(' WS +LTLT = '<<' WS +MINUS = '-' WS +PIPE = '|' WS +PLUS = '+' WS RATTR = ']]' WS +RPAREN = ')' WS +SEMI = ';' WS +TILDE = '~' WS // Misc WS = [ \t\r\n]* diff --git a/lib/regalloc.ts b/lib/regalloc.ts index e60a483..502e58e 100644 --- a/lib/regalloc.ts +++ b/lib/regalloc.ts @@ -1,6 +1,6 @@ import { colorGreedy, createGraph, Graph, maxCardinalitySearch } from "./data/graph" import { R8, StackOffset } from "./sm83/cpu" -import type { Loc } from "./ir/loc" +import { Loc } from "./ir/loc" import type { AbsInsn2 } from "./ir/insn" export type LivenessInfo = Array> @@ -15,12 +15,17 @@ export const liveness = (block: Array): LivenessInfo => { info[i] = new Set() - if (typeof insn.source !== "number") { + // TODO: Add support for goto + if (insn.type === "goto") { + throw new Error("goto not supported in liveness analysis yet") + } + + if ("source" in insn && typeof insn.source !== "number") { info[i].add(insn.source) } last.forEach(loc => { - if (loc.ppName() === insn.dest.ppName()) { + if (insn.dest instanceof Loc && loc.ppName() === insn.dest.ppName()) { return } @@ -35,6 +40,10 @@ export const locations = (block: Array): Set => { const ls: Set = new Set() block.forEach(ssa => { + if (ssa.type === "goto" || ssa.type === "label") { + return + } + ls.add(ssa.dest) if (typeof ssa.source !== "number") { @@ -54,7 +63,7 @@ export const interference = (block: Array, live: LivenessInfo): Graph< block.forEach((insn, i) => live[i + 1].forEach(u => { - if (insn.dest.ppName() !== u.ppName()) { + if (insn.dest instanceof Loc && insn.dest.ppName() !== u.ppName()) { e(insn.dest.ppName(), u.ppName()) } }) diff --git a/lib/sm83/realize.ts b/lib/sm83/realize.ts index 0f2fadd..bcc1830 100644 --- a/lib/sm83/realize.ts +++ b/lib/sm83/realize.ts @@ -6,7 +6,13 @@ import type { SM83Insn } from "./insn" export const realizeBlock = (block: Array): Array => block.flatMap(realizeInsn) -export const realizeInsn = (insn: AbsInsn2): Array => insnReduce2(realizeCopy, realizeUnary, insn) +export const realizeInsn = (insn: AbsInsn2): Array => insnReduce2( + realizeCopy, + realizeLabel, + realizeGoto, + realizeUnary, + insn, +) const getSourceName = (source: Operand): string => typeof source === "number" ? source.toString() @@ -16,6 +22,14 @@ export const realizeCopy = (dest: Loc, source: Operand): Array => [ `LD ${dest.asmName()}, ${getSourceName(source)}` ] +export const realizeLabel = (name: string): Array => [ + `${name}:`, +] + +export const realizeGoto = (name: string): Array => [ + `JR ${name}`, +] + export const realizeUnary = (dest: Loc, op: UnaryOp | BinaryOp, source: Operand): Array => { if (!isA(dest)) { throw new Error("unexpected form for unary operation")