From d7060781aec7f891a3615566e3ecd2a66f0c30d0 Mon Sep 17 00:00:00 2001 From: Forest Belton Date: Wed, 15 Sep 2021 13:07:04 -0400 Subject: [PATCH] Reorganize codebase and implement liveness check --- lib/compile.ts | 23 +-- lib/{ => data}/graph.ts | 16 +-- lib/data/set.ts | 25 ++++ lib/ir.ts | 143 ------------------- lib/ir/convert.ts | 72 ++++++++++ lib/ir/loc.ts | 43 ++++++ lib/ir/pretty.ts | 45 ++++++ lib/ir/ssa.d.ts | 17 +++ lib/live.ts | 33 +++++ lib/main.ts | 1 + package.json | 2 +- test/{ => data}/graph.spec.ts | 2 +- test/ir.spec.ts | 259 ---------------------------------- test/ir/convert.spec.ts | 133 +++++++++++++++++ test/ir/pretty.spec.ts | 66 +++++++++ test/live.spec.ts | 28 ++++ 16 files changed, 471 insertions(+), 437 deletions(-) rename lib/{ => data}/graph.ts (88%) create mode 100644 lib/data/set.ts delete mode 100644 lib/ir.ts create mode 100644 lib/ir/convert.ts create mode 100644 lib/ir/loc.ts create mode 100644 lib/ir/pretty.ts create mode 100644 lib/ir/ssa.d.ts create mode 100644 lib/live.ts rename test/{ => data}/graph.spec.ts (92%) delete mode 100644 test/ir.spec.ts create mode 100644 test/ir/convert.spec.ts create mode 100644 test/ir/pretty.spec.ts create mode 100644 test/live.spec.ts diff --git a/lib/compile.ts b/lib/compile.ts index 7093b9b..d96bb6d 100644 --- a/lib/compile.ts +++ b/lib/compile.ts @@ -1,7 +1,6 @@ -// import { convertASM } from "./asm" -import { convertIR, prettyPrintIR } from "./ir" +import { convertIR } from "./ir/convert" +import { prettyPrintBlock } from "./ir/pretty" import { parse } from "./parser" -import { inspect } from "util" import type { Attr, Decl, Stmt, Type, VarDecl } from "./ast" @@ -36,25 +35,9 @@ export const compile = (fileName: string, source: string): string => { const ir = convertIR(stmts) console.log("=== IR === ") - console.log(ir.map(prettyPrintIR).join("\n")) + console.log(prettyPrintBlock(ir)) // 5. Generate code - /* const insns = convertASM(ir) - - let output = '' - if (asmDecls.length > 0) { - output += `SECTION "${fileName} Data", WRAM0\n\n` - output += asmDecls.join("\n") - output += "\n\n" - } - - if (insns.length > 0) { - output += `SECTION "${fileName} Code", ROM0\n\n` - output += insns.join("\n") - } - - console.log("=== ASM === ") - return output */ return '' } diff --git a/lib/graph.ts b/lib/data/graph.ts similarity index 88% rename from lib/graph.ts rename to lib/data/graph.ts index 8ecb880..c26ac53 100644 --- a/lib/graph.ts +++ b/lib/data/graph.ts @@ -1,3 +1,5 @@ +import { intersect } from "./set" + export type Graph = { vertices: { [v: string]: V @@ -55,7 +57,7 @@ export const maxCardinalitySearch = (g: Graph): Array => { const v = findMaxWeight(weights, W) ordering.push(v) - setIntersect(W, neighbors(g, v)).forEach(x => + intersect(W, neighbors(g, v)).forEach(x => weights[x] = (weights[x] || 0) + 1 ) @@ -83,15 +85,3 @@ const findMaxWeight = (weights: { [s: string]: number }, W: Set): string return maxV } - -const setIntersect = (xs: Set, ys: Set): Set => { - const intersection: Set = new Set() - - xs.forEach(x => { - if (ys.has(x)) { - intersection.add(x) - } - }) - - return intersection -} diff --git a/lib/data/set.ts b/lib/data/set.ts new file mode 100644 index 0000000..668dc93 --- /dev/null +++ b/lib/data/set.ts @@ -0,0 +1,25 @@ +export const intersect = (xs: Set, ys: Set): Set => { + const out: Set = new Set() + + xs.forEach(x => { + if (ys.has(x)) { + out.add(x) + } + }) + + return out +} + +export const setEquals = (xs: Set, ys: Set): boolean => { + if (xs.size != ys.size) { + return false + } + + for (const x of xs) { + if (!ys.has(x)) { + return false + } + } + + return true +} diff --git a/lib/ir.ts b/lib/ir.ts deleted file mode 100644 index 65cbb3b..0000000 --- a/lib/ir.ts +++ /dev/null @@ -1,143 +0,0 @@ -import type { AssignStmt, Expr, Stmt, UnaryOp, BinaryOp } from "./ast" - -type LocationType = "register" | "temporary" | "variable" - -type Location = { - type: LocationType, - name: string, -} - -type Operand = Location | number - -type ASSA = { dest: Location, source: Operand } & Data - -export type SSACopy = ASSA<{}> // dest = source - -export type SSAUnary = ASSA<{ op: UnaryOp }> // dest = op(source) - -export type SSABinary = ASSA<{ op: BinaryOp, source1: Operand }> // dest = op(source, source1) - -export type SSA = SSACopy | SSAUnary | SSABinary - -type IRState = { - nextID: number - ssa_stmts: Array -} - -const temp = (state: IRState): Location => ({ - type: "temporary", - name: `t${state.nextID++}`, -}) - -const vari = (name: string): Location => ({ - type: "variable", - name, -}) - -const reg = (name: string): Location => ({ - type: "register", - name, -}) - -export const convertIR = (stmts: Array): Array => { - const state: IRState = { - nextID: 0, - ssa_stmts: [], - } - - stmts.forEach(stmt => { - const ssa_stmts = convertAssignStmt(state, stmt) - state.ssa_stmts.push(...ssa_stmts) - }) - - return state.ssa_stmts -} - -export const convertAssignStmt = (state: IRState, stmt: AssignStmt): Array => { - return convertExpr(state, vari(stmt.args.name), stmt.args.expr) -} - -export const convertExpr = (state: IRState, dest: Location, expr: Expr): Array => { - let expr_stmts = [] - - if (typeof expr === "number") { - expr_stmts = [{ dest, source: expr }] - } else if (typeof expr === "string") { - expr_stmts = [{ dest, source: vari(expr) }] - } else if (expr.type === "unary") { - const [source, stmts] = getSource(state, expr.arg) - stmts.push({ - dest, - op: expr.op, - source, - }) - - expr_stmts = stmts - } else { - const [left_source, left_stmts] = getSource(state, expr.left) - const [right_source, right_stmts] = getSource(state, expr.right) - - const stmts = [...left_stmts, ...right_stmts] - stmts.push({ - dest, - op: expr.op, - source: left_source, - source1: right_source, - }) - - expr_stmts = stmts - } - - return expr_stmts -} - -const getSource = (state: IRState, expr: Expr): [Operand, Array] => { - if (typeof expr === "number") { - return [expr, []] - } else if (typeof expr === "string") { - return [vari(expr), []] - } - - const source = temp(state) - const stmts = convertExpr(state, source, expr) - return [source, stmts] -} - -export const prettyPrintIR = (ssa: SSA): string => { - let output = "" - - if ("source1" in ssa) { - output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)}, ${ppOp(ssa.source1)})` - } else if ("op" in ssa) { - output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)})` - } else { - output = `${ppLoc(ssa.dest)} = ${ppOp(ssa.source)}` - } - - return output -} - -const ppOp = (op: Operand): string => - typeof op === "number" - ? op.toString() - : ppLoc(op) - -const ppLoc = (loc: Location): string => { - let output = '' - - switch (loc.type) { - case "register": - output = `%${loc.name}` - break - - case "temporary": - output = `#${loc.name}` - break - - case "variable": - output = loc.name - break - } - - return output -} diff --git a/lib/ir/convert.ts b/lib/ir/convert.ts new file mode 100644 index 0000000..f94a7ea --- /dev/null +++ b/lib/ir/convert.ts @@ -0,0 +1,72 @@ +import type { AssignStmt, Expr, Stmt } from "../ast" +import { Loc } from "./loc" +import type { Operand, SSA } from "./ssa" + +type IRState = { + nextID: number + ssa_stmts: Array +} + +export const convertIR = (stmts: Array): Array => { + const state: IRState = { + nextID: 0, + ssa_stmts: [], + } + + stmts.forEach(stmt => { + const ssa_stmts = convertAssignStmt(state, stmt) + state.ssa_stmts.push(...ssa_stmts) + }) + + return state.ssa_stmts +} + +export const convertAssignStmt = (state: IRState, stmt: AssignStmt): Array => { + return convertExpr(state, Loc.vari(stmt.args.name), stmt.args.expr) +} + +export const convertExpr = (state: IRState, dest: Loc, expr: Expr): Array => { + let expr_stmts: Array = [] + + if (typeof expr === "number") { + expr_stmts = [{ dest, source: expr }] + } else if (typeof expr === "string") { + expr_stmts = [{ dest, source: Loc.vari(expr) }] + } else if (expr.type === "unary") { + const [source, stmts] = getSource(state, expr.arg) + stmts.push({ + dest, + op: expr.op, + source, + }) + + expr_stmts = stmts + } else { + const [left_source, left_stmts] = getSource(state, expr.left) + const [right_source, right_stmts] = getSource(state, expr.right) + + const stmts = [...left_stmts, ...right_stmts] + stmts.push({ + dest, + op: expr.op, + source: left_source, + source1: right_source, + }) + + expr_stmts = stmts + } + + return expr_stmts +} + +const getSource = (state: IRState, expr: Expr): [Operand, Array] => { + if (typeof expr === "number") { + return [expr, []] + } else if (typeof expr === "string") { + return [Loc.vari(expr), []] + } + + const source = Loc.temp(`t${state.nextID++}`) + const stmts = convertExpr(state, source, expr) + return [source, stmts] +} diff --git a/lib/ir/loc.ts b/lib/ir/loc.ts new file mode 100644 index 0000000..33bc68d --- /dev/null +++ b/lib/ir/loc.ts @@ -0,0 +1,43 @@ +export enum LocType { + REGISTER = "register", + TEMPORARY = "temporary", + VARIABLE = "variable", +} + +export class Loc { + type: LocType + name: string + + constructor(type: LocType, name: string) { + this.type = type + this.name = name + } + + toString(): string { + let sigil = '' + + switch (this.type) { + case 'register': + sigil = '%' + break + + case 'temporary': + sigil = '#' + break + } + + return sigil + this.name + } + + static vari(name: string): Loc { + return new Loc(LocType.VARIABLE, name) + } + + static temp(name: string): Loc { + return new Loc(LocType.TEMPORARY, name) + } + + static reg(name: string): Loc { + return new Loc(LocType.REGISTER, name) + } +} diff --git a/lib/ir/pretty.ts b/lib/ir/pretty.ts new file mode 100644 index 0000000..7679a79 --- /dev/null +++ b/lib/ir/pretty.ts @@ -0,0 +1,45 @@ +import type { Loc } from "./loc" +import type { Operand, SSA } from "./ssa" + +export const prettyPrintBlock = (block: Array): string => { + return block.map(prettyPrintSSA).join("\n") +} + +export const prettyPrintSSA = (ssa: SSA): string => { + let output = "" + + if ("source1" in ssa) { + output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)}, ${ppOp(ssa.source1)})` + } else if ("op" in ssa) { + output = `${ppLoc(ssa.dest)} = ${ssa.op}(${ppOp(ssa.source)})` + } else { + output = `${ppLoc(ssa.dest)} = ${ppOp(ssa.source)}` + } + + return output +} + +const ppOp = (op: Operand): string => + typeof op === "number" + ? op.toString() + : ppLoc(op) + +const ppLoc = (loc: Loc): string => { + let output = '' + + switch (loc.type) { + case "register": + output = `%${loc.name}` + break + + case "temporary": + output = `#${loc.name}` + break + + case "variable": + output = loc.name + break + } + + return output +} diff --git a/lib/ir/ssa.d.ts b/lib/ir/ssa.d.ts new file mode 100644 index 0000000..3e9b08d --- /dev/null +++ b/lib/ir/ssa.d.ts @@ -0,0 +1,17 @@ +import type { BinaryOp, UnaryOp } from "../ast" +import type { Loc } from "./loc" + +export type Operand = Loc | number + +type ASSA = { dest: Loc, source: Operand } & Data + +// dest = source +export type SSACopy = ASSA<{}> + +// dest = op(source) +export type SSAUnary = ASSA<{ op: UnaryOp }> + +// dest = op(source, source1) +export type SSABinary = ASSA<{ op: BinaryOp, source1: Operand }> + +export type SSA = SSACopy | SSAUnary | SSABinary diff --git a/lib/live.ts b/lib/live.ts new file mode 100644 index 0000000..ac5c6a0 --- /dev/null +++ b/lib/live.ts @@ -0,0 +1,33 @@ +import type { Loc } from "./ir/loc" +import type { SSA } from "./ir/ssa" + +export type LivenessInfo = Array> + +export const liveness = (block: Array): LivenessInfo => { + const info: LivenessInfo = [] + + for (let i = block.length - 1; i >= 0; --i) { + const insn = block[i] + const last = info[i + 1] || new Set() + + info[i] = new Set() + + if (typeof insn.source !== "number") { + info[i].add(insn.source) + } + + if ("source1" in insn && typeof insn.source1 !== "number") { + info[i].add(insn.source1) + } + + last.forEach(loc => { + if (loc === insn.dest) { + return + } + + info[i].add(loc) + }) + } + + return info +} diff --git a/lib/main.ts b/lib/main.ts index 4db74b6..10ff261 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -5,6 +5,7 @@ import { compile } from "./compile" const { readFile } = promises +// TODO: Proper command-line argument support if (process.argv.length !== 3) { console.error("usage: gbuoy ") process.exit(1) diff --git a/package.json b/package.json index 7c24a84..5a4f8c6 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "scripts": { "build": "mkdir -p build && peggy -o build/parser.js lib/parser.pegjs && tsc", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "ts-mocha" }, "author": "Forest Belton ", "license": "MIT", diff --git a/test/graph.spec.ts b/test/data/graph.spec.ts similarity index 92% rename from test/graph.spec.ts rename to test/data/graph.spec.ts index 369f52e..4850bd1 100644 --- a/test/graph.spec.ts +++ b/test/data/graph.spec.ts @@ -1,6 +1,6 @@ import { expect } from "chai" -import { createGraph, neighbors, vertices } from "../lib/graph" +import { createGraph, neighbors, vertices } from "../../lib/data/graph" const g = createGraph((v, e) => { v("a", true) diff --git a/test/ir.spec.ts b/test/ir.spec.ts deleted file mode 100644 index 303a0f2..0000000 --- a/test/ir.spec.ts +++ /dev/null @@ -1,259 +0,0 @@ -import { expect } from "chai" -import { convertAssignStmt, prettyPrintIR, SSA } from "../lib/ir" - -describe("ir", () => { - describe("convertExpr", () => { - it("load with immediate", () => { - const state = { nextID: 0, ssa_stmts: [] } - const ir = convertAssignStmt(state, { - type: "stmt", - stmt_type: "assign", - args: { - name: "x", - expr: 42, - }, - }) - - expect(ir).to.deep.equal([ - { - dest: { - type: "variable", - name: "x", - }, - source: 42, - }, - ]) - }) - - it("load with variable", () => { - const state = { nextID: 0, ssa_stmts: [] } - const ir = convertAssignStmt(state, { - type: "stmt", - stmt_type: "assign", - args: { - name: "x", - expr: "y", - }, - }) - - expect(ir).to.deep.equal([ - { - dest: { - type: "variable", - name: "x", - }, - source: { - type: "variable", - name: "y", - }, - }, - ]) - }) - - it("unary op", () => { - const state = { nextID: 0, ssa_stmts: [] } - const ir = convertAssignStmt(state, { - type: "stmt", - stmt_type: "assign", - args: { - name: "x", - expr: { - type: "unary", - op: "arith_negate", - arg: "y" - }, - }, - }) - - expect(ir).to.deep.equal([ - { - dest: { - type: "variable", - name: "x", - }, - source: { - type: "variable", - name: "y", - }, - op: "arith_negate", - }, - ]) - }) - - it("binary op", () => { - const state = { nextID: 0, ssa_stmts: [] } - const ir = convertAssignStmt(state, { - type: "stmt", - stmt_type: "assign", - args: { - name: "x", - expr: { - type: "binary", - op: "add", - left: "y", - right: 42, - }, - }, - }) - - expect(ir).to.deep.equal([ - { - dest: { - type: "variable", - name: "x", - }, - source: { - type: "variable", - name: "y", - }, - source1: 42, - op: "add", - }, - ]) - }) - - it("nested binary op", () => { - const state = { nextID: 0, ssa_stmts: [] } - const ir = convertAssignStmt(state, { - type: "stmt", - stmt_type: "assign", - args: { - name: "x", - expr: { - type: "binary", - op: "add", - left: "y", - right: { - type: "binary", - op: "subtract", - left: "z", - right: 42, - }, - }, - }, - }) - - expect(ir).to.deep.equal([ - { - dest: { - type: "temporary", - name: "t0", - }, - source: { - type: "variable", - name: "z", - }, - op: "subtract", - source1: 42, - }, - { - dest: { - type: "variable", - name: "x", - }, - source: { - type: "variable", - name: "y", - }, - op: "add", - source1: { - type: "temporary", - name: "t0", - }, - }, - ]) - }) - }) - - describe("prettyPrintIR", () => { - it("load with immediate", () => { - const ssa: SSA = { - dest: { - type: "variable", - name: "x", - }, - source: 42, - } - - expect(prettyPrintIR(ssa)).to.equal("x = 42") - }) - - it("load with register", () => { - const ssa: SSA = { - dest: { - type: "variable", - name: "x", - }, - source: { - type: "register", - name: "A" - }, - } - - expect(prettyPrintIR(ssa)).to.equal("x = %A") - }) - - it("load with temporary", () => { - const ssa: SSA = { - dest: { - type: "variable", - name: "x", - }, - source: { - type: "temporary", - name: "t0" - }, - } - - expect(prettyPrintIR(ssa)).to.equal("x = #t0") - }) - - it("load with variable", () => { - const ssa: SSA = { - dest: { - type: "variable", - name: "x", - }, - source: { - type: "variable", - name: "y" - }, - } - - expect(prettyPrintIR(ssa)).to.equal("x = y") - }) - - it("unary op", () => { - const ssa: SSA = { - dest: { - type: "variable", - name: "x", - }, - source: { - type: "variable", - name: "y" - }, - op: "arith_negate", - } - - expect(prettyPrintIR(ssa)).to.equal("x = arith_negate(y)") - }) - - it("binary op", () => { - const ssa: SSA = { - dest: { - type: "variable", - name: "x", - }, - source: { - type: "variable", - name: "y" - }, - source1: 42, - op: "add", - } - - expect(prettyPrintIR(ssa)).to.equal("x = add(y, 42)") - }) - }) -}) diff --git a/test/ir/convert.spec.ts b/test/ir/convert.spec.ts new file mode 100644 index 0000000..e024e4c --- /dev/null +++ b/test/ir/convert.spec.ts @@ -0,0 +1,133 @@ +import { expect } from "chai" + +import { convertAssignStmt } from "../../lib/ir/convert" +import { Loc } from "../../lib/ir/loc" + +describe("ir", () => { + describe("convertExpr", () => { + it("load with immediate", () => { + const state = { nextID: 0, ssa_stmts: [] } + const ir = convertAssignStmt(state, { + type: "stmt", + stmt_type: "assign", + args: { + name: "x", + expr: 42, + }, + }) + + expect(ir).to.deep.equal([ + { + dest: Loc.vari("x"), + source: 42, + }, + ]) + }) + + it("load with variable", () => { + const state = { nextID: 0, ssa_stmts: [] } + const ir = convertAssignStmt(state, { + type: "stmt", + stmt_type: "assign", + args: { + name: "x", + expr: "y", + }, + }) + + expect(ir).to.deep.equal([ + { + dest: Loc.vari("x"), + source: Loc.vari("y"), + }, + ]) + }) + + it("unary op", () => { + const state = { nextID: 0, ssa_stmts: [] } + const ir = convertAssignStmt(state, { + type: "stmt", + stmt_type: "assign", + args: { + name: "x", + expr: { + type: "unary", + op: "arith_negate", + arg: "y" + }, + }, + }) + + expect(ir).to.deep.equal([ + { + dest: Loc.vari("x"), + source: Loc.vari("y"), + op: "arith_negate", + }, + ]) + }) + + it("binary op", () => { + const state = { nextID: 0, ssa_stmts: [] } + const ir = convertAssignStmt(state, { + type: "stmt", + stmt_type: "assign", + args: { + name: "x", + expr: { + type: "binary", + op: "add", + left: "y", + right: 42, + }, + }, + }) + + expect(ir).to.deep.equal([ + { + dest: Loc.vari("x"), + source: Loc.vari("y"), + source1: 42, + op: "add", + }, + ]) + }) + + it("nested binary op", () => { + const state = { nextID: 0, ssa_stmts: [] } + const ir = convertAssignStmt(state, { + type: "stmt", + stmt_type: "assign", + args: { + name: "x", + expr: { + type: "binary", + op: "add", + left: "y", + right: { + type: "binary", + op: "subtract", + left: "z", + right: 42, + }, + }, + }, + }) + + expect(ir).to.deep.equal([ + { + dest: Loc.temp("t0"), + source: Loc.vari("z"), + op: "subtract", + source1: 42, + }, + { + dest: Loc.vari("x"), + source: Loc.vari("y"), + op: "add", + source1: Loc.temp("t0"), + }, + ]) + }) + }) +}) diff --git a/test/ir/pretty.spec.ts b/test/ir/pretty.spec.ts new file mode 100644 index 0000000..e344cd2 --- /dev/null +++ b/test/ir/pretty.spec.ts @@ -0,0 +1,66 @@ +import { expect } from "chai" + +import { Loc } from "../../lib/ir/loc" +import { prettyPrintSSA } from "../../lib/ir/pretty" +import type { SSA } from "../../lib/ir/ssa" + +describe("ir", () => { + describe("prettyPrintSSA", () => { + it("load with immediate", () => { + const ssa: SSA = { + dest: Loc.vari("x"), + source: 42, + } + + expect(prettyPrintSSA(ssa)).to.equal("x = 42") + }) + + it("load with register", () => { + const ssa: SSA = { + dest: Loc.vari("x"), + source: Loc.reg("A"), + } + + expect(prettyPrintSSA(ssa)).to.equal("x = %A") + }) + + it("load with temporary", () => { + const ssa: SSA = { + dest: Loc.vari("x"), + source: Loc.temp("t0"), + } + + expect(prettyPrintSSA(ssa)).to.equal("x = #t0") + }) + + it("load with variable", () => { + const ssa: SSA = { + dest: Loc.vari("x"), + source: Loc.vari("y"), + } + + expect(prettyPrintSSA(ssa)).to.equal("x = y") + }) + + it("unary op", () => { + const ssa: SSA = { + dest: Loc.vari("x"), + source: Loc.vari("y"), + op: "arith_negate", + } + + expect(prettyPrintSSA(ssa)).to.equal("x = arith_negate(y)") + }) + + it("binary op", () => { + const ssa: SSA = { + dest: Loc.vari("x"), + source: Loc.vari("y"), + source1: 42, + op: "add", + } + + expect(prettyPrintSSA(ssa)).to.equal("x = add(y, 42)") + }) + }) +}) diff --git a/test/live.spec.ts b/test/live.spec.ts new file mode 100644 index 0000000..f998cdc --- /dev/null +++ b/test/live.spec.ts @@ -0,0 +1,28 @@ +import { expect } from "chai" + +import { Loc } from "../lib/ir/loc" +import type { SSA } from "../lib/ir/ssa" +import { liveness } from "../lib/live" + +describe("liveness", () => { + it("computes liveness", () => { + const x = [0, 1, 2].map(i => Loc.vari("x" + i)) + const y = [0, 1].map(i => Loc.vari("y" + i)) + + const block: Array = [ + { dest: x[0], source: 1 }, + { dest: x[1], source: x[0], op: "add", source1: x[0] }, + { dest: x[2], source: x[1], op: "add", source1: x[0] }, + { dest: y[0], source: x[0], op: "add", source1: x[1] }, + { dest: y[1], source: y[0], op: "add", source1: x[2] }, + ] + + const info = liveness(block) + + expect(info[0]).to.deep.equal(new Set()) + expect(info[1]).to.deep.equal(new Set([x[0]])) + expect(info[2]).to.deep.equal(new Set([x[0], x[1]])) + expect(info[3]).to.deep.equal(new Set([x[0], x[1], x[2]])) + expect(info[4]).to.deep.equal(new Set([y[0], x[2]])) + }) +})