Browse Source

Start working on branch support

master
Forest Belton 3 years ago
parent
commit
4129a30c13
9 changed files with 117 additions and 31 deletions
  1. +2
    -0
      example.gby
  2. +9
    -1
      lib/ast.d.ts
  3. +3
    -1
      lib/codegen/allocate.ts
  4. +12
    -6
      lib/ir/convert.ts
  5. +41
    -6
      lib/ir/insn.ts
  6. +6
    -0
      lib/ir/pretty.ts
  7. +16
    -12
      lib/parser.pegjs
  8. +13
    -4
      lib/regalloc.ts
  9. +15
    -1
      lib/sm83/realize.ts

+ 2
- 0
example.gby View File

@ -4,6 +4,8 @@
u8 x; u8 x;
u8 y; u8 y;
loop:
x <- -y + j; x <- -y + j;
z <- w + 7; z <- w + 7;
z <- z << 1; z <- z << 1;
goto loop;

+ 9
- 1
lib/ast.d.ts View File

@ -16,7 +16,15 @@ type ADecl = {
} }
// Statements // 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", { export type AssignStmt = AStmt<"assign", {
name: string, name: string,

+ 3
- 1
lib/codegen/allocate.ts View File

@ -1,5 +1,5 @@
import type { RegAlloc } from '../regalloc' 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 { Loc, LocType } from '../ir/loc'
import { UnaryOp, BinaryOp } from '../ast' import { UnaryOp, BinaryOp } from '../ast'
@ -11,6 +11,8 @@ export const allocateInsn = (alloc: RegAlloc, insn: AbsInsn2): AbsInsn2 => insnR
allocateInsnDest(alloc, dest), allocateInsnDest(alloc, dest),
typeof source === 'number' ? source : allocateInsnDest(alloc, source), typeof source === 'number' ? source : allocateInsnDest(alloc, source),
), ),
(name: string) => LabelInsn(name),
(name: string) => GotoInsn(name),
(dest: Loc, op: UnaryOp | BinaryOp, source: Operand) => UnaryInsn( (dest: Loc, op: UnaryOp | BinaryOp, source: Operand) => UnaryInsn(
allocateInsnDest(alloc, dest), allocateInsnDest(alloc, dest),
op, op,

+ 12
- 6
lib/ir/convert.ts View File

@ -1,7 +1,7 @@
import type { AssignStmt, Expr, Stmt } from "../ast" import type { AssignStmt, Expr, Stmt } from "../ast"
import { R8 } from "../sm83/cpu" import { R8 } from "../sm83/cpu"
import { Loc, LocType } from "./loc" 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 { export class IRState {
nextID: number nextID: number
@ -21,16 +21,22 @@ export const convertIR = (stmts: Array): Array => {
const state: IRState = new IRState() const state: IRState = new IRState()
stmts.forEach(stmt => { 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 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 => { export const convertExpr = (state: IRState, dest: Loc, expr: Expr): void => {
const threeAddress = convertExpr3(state, dest, expr) const threeAddress = convertExpr3(state, dest, expr)

+ 41
- 6
lib/ir/insn.ts View File

@ -9,6 +9,16 @@ export type AbsInsnCopy = {
source: Operand, source: Operand,
} }
export type AbsInsnGoto = {
type: "goto",
dest: string,
}
export type AbsInsnLabel = {
type: "label",
dest: string,
}
type UnaryInsn<Op> = { type UnaryInsn<Op> = {
type: "unary", type: "unary",
dest: Loc, dest: Loc,
@ -20,16 +30,31 @@ type UnaryInsn = {
export type AbsInsn2Unary = UnaryInsn<UnaryOp | BinaryOp> export type AbsInsn2Unary = UnaryInsn<UnaryOp | BinaryOp>
// Abstract instruction in two-address form // Abstract instruction in two-address form
export type AbsInsn2 = AbsInsnCopy | AbsInsn2Unary
export type AbsInsn2 = AbsInsnCopy | AbsInsnLabel | AbsInsnGoto | AbsInsn2Unary
type CopyFn<A> = (dest: Loc, source: Operand) => A type CopyFn<A> = (dest: Loc, source: Operand) => A
type StringFn<A> = (name: string) => A
type UnaryFn<Op, A> = (dest: Loc, op: Op, source: Operand) => A type UnaryFn<Op, A> = (dest: Loc, op: Op, source: Operand) => A
type UnaryFn2<A> = UnaryFn<UnaryOp | BinaryOp, A> type UnaryFn2<A> = UnaryFn<UnaryOp | BinaryOp, A>
export const insnReduce2 = <A>(copy: CopyFn<A>, unary: UnaryFn2<A>, insn: AbsInsn2): A =>
insn.type === 'copy'
? copy(insn.dest, insn.source)
: unary(insn.dest, insn.op, insn.source)
export const insnReduce2 = <A>(
copy: CopyFn<A>,
label: StringFn<A>,
goto: StringFn<A>,
unary: UnaryFn2<A>,
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<UnaryOp> export type AbsInsn3Unary = UnaryInsn<UnaryOp>
@ -42,7 +67,7 @@ export type AbsInsnBinary = {
} }
// Abstract instruction in three-address form // 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 => ({ export const CopyInsn = (dest: Loc, source: Operand): AbsInsnCopy => ({
type: 'copy', type: 'copy',
@ -64,3 +89,13 @@ export const BinaryInsn = (dest: Loc, source: Operand, op: BinaryOp, source1: Op
op, op,
source1, source1,
}) })
export const LabelInsn = (dest: string): AbsInsnLabel => ({
type: 'label',
dest,
})
export const GotoInsn = (dest: string): AbsInsnGoto => ({
type: 'goto',
dest,
})

+ 6
- 0
lib/ir/pretty.ts View File

@ -18,6 +18,12 @@ export const prettyPrintInsn = (ssa: AbsInsn2 | AbsInsn3): string => {
case 'binary': case 'binary':
output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)}, ${ppOp(ssa.source1)})` output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)}, ${ppOp(ssa.source1)})`
break break
case 'goto':
output = `goto(${ssa.dest})`
break
case 'label':
output = `${ssa.dest}:`
break
} }
return output return output

+ 16
- 12
lib/parser.pegjs View File

@ -19,8 +19,10 @@ Decl = VarDecl
VarDecl = attrs:Attrs? type:Type name:Ident SEMI { return decl("var", name, attrs, { type }) } VarDecl = attrs:Attrs? type:Type name:Ident SEMI { return decl("var", name, attrs, { type }) }
// Statements // 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 // Expressions
Expr = BitOrExpr 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) } / '0b' digits:[01]+ WS { return parseInt(digits.join(''), 2) }
// Terminal keywords // Terminal keywords
GOTO = 'goto' WS
S8 = @'s8' WS S8 = @'s8' WS
U8 = @'u8' WS U8 = @'u8' WS
U16 = @'u16' WS U16 = @'u16' WS
// Terminal symbols // Terminal symbols
PIPE = '|' WS
CARET = '^' WS
AMPERSAND = '&' WS AMPERSAND = '&' WS
LTLT = '<<' WS
GTGT = '>>' WS
PLUS = '+' WS
TILDE = '~' WS
MINUS = '-' WS
SEMI = ';' WS
ASSIGN = '<-' WS ASSIGN = '<-' WS
LPAREN = '(' WS
RPAREN = ')' WS
CARET = '^' WS
COLON = ':' WS
COMMA = ',' WS COMMA = ',' WS
GTGT = '>>' WS
LATTR = '[[' WS LATTR = '[[' WS
LPAREN = '(' WS
LTLT = '<<' WS
MINUS = '-' WS
PIPE = '|' WS
PLUS = '+' WS
RATTR = ']]' WS RATTR = ']]' WS
RPAREN = ')' WS
SEMI = ';' WS
TILDE = '~' WS
// Misc // Misc
WS = [ \t\r\n]* WS = [ \t\r\n]*

+ 13
- 4
lib/regalloc.ts View File

@ -1,6 +1,6 @@
import { colorGreedy, createGraph, Graph, maxCardinalitySearch } from "./data/graph" import { colorGreedy, createGraph, Graph, maxCardinalitySearch } from "./data/graph"
import { R8, StackOffset } from "./sm83/cpu" import { R8, StackOffset } from "./sm83/cpu"
import type { Loc } from "./ir/loc"
import { Loc } from "./ir/loc"
import type { AbsInsn2 } from "./ir/insn" import type { AbsInsn2 } from "./ir/insn"
export type LivenessInfo = Array<Set<Loc>> export type LivenessInfo = Array<Set<Loc>>
@ -15,12 +15,17 @@ export const liveness = (block: Array): LivenessInfo => {
info[i] = new Set() 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) info[i].add(insn.source)
} }
last.forEach(loc => { last.forEach(loc => {
if (loc.ppName() === insn.dest.ppName()) {
if (insn.dest instanceof Loc && loc.ppName() === insn.dest.ppName()) {
return return
} }
@ -35,6 +40,10 @@ export const locations = (block: Array): Set => {
const ls: Set<Loc> = new Set() const ls: Set<Loc> = new Set()
block.forEach(ssa => { block.forEach(ssa => {
if (ssa.type === "goto" || ssa.type === "label") {
return
}
ls.add(ssa.dest) ls.add(ssa.dest)
if (typeof ssa.source !== "number") { if (typeof ssa.source !== "number") {
@ -54,7 +63,7 @@ export const interference = (block: Array, live: LivenessInfo): Graph<
block.forEach((insn, i) => block.forEach((insn, i) =>
live[i + 1].forEach(u => { 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()) e(insn.dest.ppName(), u.ppName())
} }
}) })

+ 15
- 1
lib/sm83/realize.ts View File

@ -6,7 +6,13 @@ import type { SM83Insn } from "./insn"
export const realizeBlock = (block: Array<AbsInsn2>): Array<SM83Insn> => block.flatMap(realizeInsn) export const realizeBlock = (block: Array<AbsInsn2>): Array<SM83Insn> => block.flatMap(realizeInsn)
export const realizeInsn = (insn: AbsInsn2): Array<SM83Insn> => insnReduce2(realizeCopy, realizeUnary, insn)
export const realizeInsn = (insn: AbsInsn2): Array<SM83Insn> => insnReduce2(
realizeCopy,
realizeLabel,
realizeGoto,
realizeUnary,
insn,
)
const getSourceName = (source: Operand): string => typeof source === "number" const getSourceName = (source: Operand): string => typeof source === "number"
? source.toString() ? source.toString()
@ -16,6 +22,14 @@ export const realizeCopy = (dest: Loc, source: Operand): Array => [
`LD ${dest.asmName()}, ${getSourceName(source)}` `LD ${dest.asmName()}, ${getSourceName(source)}`
] ]
export const realizeLabel = (name: string): Array<SM83Insn> => [
`${name}:`,
]
export const realizeGoto = (name: string): Array<SM83Insn> => [
`JR ${name}`,
]
export const realizeUnary = (dest: Loc, op: UnaryOp | BinaryOp, source: Operand): Array<SM83Insn> => { export const realizeUnary = (dest: Loc, op: UnaryOp | BinaryOp, source: Operand): Array<SM83Insn> => {
if (!isA(dest)) { if (!isA(dest)) {
throw new Error("unexpected form for unary operation") throw new Error("unexpected form for unary operation")

Loading…
Cancel
Save