@ -0,0 +1,25 @@ | |||||
export const intersect = <A>(xs: Set<A>, ys: Set<A>): Set<A> => { | |||||
const out: Set<A> = new Set() | |||||
xs.forEach(x => { | |||||
if (ys.has(x)) { | |||||
out.add(x) | |||||
} | |||||
}) | |||||
return out | |||||
} | |||||
export const setEquals = <A>(xs: Set<A>, ys: Set<A>): boolean => { | |||||
if (xs.size != ys.size) { | |||||
return false | |||||
} | |||||
for (const x of xs) { | |||||
if (!ys.has(x)) { | |||||
return false | |||||
} | |||||
} | |||||
return true | |||||
} |
@ -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<Data> = { 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<SSA> | |||||
} | |||||
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<Stmt>): Array<SSA> => { | |||||
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<SSA> => { | |||||
return convertExpr(state, vari(stmt.args.name), stmt.args.expr) | |||||
} | |||||
export const convertExpr = (state: IRState, dest: Location, expr: Expr): Array<SSA> => { | |||||
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<SSA>] => { | |||||
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 | |||||
} |
@ -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<SSA> | |||||
} | |||||
export const convertIR = (stmts: Array<Stmt>): Array<SSA> => { | |||||
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<SSA> => { | |||||
return convertExpr(state, Loc.vari(stmt.args.name), stmt.args.expr) | |||||
} | |||||
export const convertExpr = (state: IRState, dest: Loc, expr: Expr): Array<SSA> => { | |||||
let expr_stmts: Array<SSA> = [] | |||||
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<SSA>] => { | |||||
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] | |||||
} |
@ -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) | |||||
} | |||||
} |
@ -0,0 +1,45 @@ | |||||
import type { Loc } from "./loc" | |||||
import type { Operand, SSA } from "./ssa" | |||||
export const prettyPrintBlock = (block: Array<SSA>): 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 | |||||
} |
@ -0,0 +1,17 @@ | |||||
import type { BinaryOp, UnaryOp } from "../ast" | |||||
import type { Loc } from "./loc" | |||||
export type Operand = Loc | number | |||||
type ASSA<Data> = { 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 |
@ -0,0 +1,33 @@ | |||||
import type { Loc } from "./ir/loc" | |||||
import type { SSA } from "./ir/ssa" | |||||
export type LivenessInfo = Array<Set<Loc>> | |||||
export const liveness = (block: Array<SSA>): 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 | |||||
} |
@ -1,6 +1,6 @@ | |||||
import { expect } from "chai" | import { expect } from "chai" | ||||
import { createGraph, neighbors, vertices } from "../lib/graph" | |||||
import { createGraph, neighbors, vertices } from "../../lib/data/graph" | |||||
const g = createGraph((v, e) => { | const g = createGraph((v, e) => { | ||||
v("a", true) | v("a", true) |
@ -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)") | |||||
}) | |||||
}) | |||||
}) |
@ -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"), | |||||
}, | |||||
]) | |||||
}) | |||||
}) | |||||
}) |
@ -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)") | |||||
}) | |||||
}) | |||||
}) |
@ -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<SSA> = [ | |||||
{ 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]])) | |||||
}) | |||||
}) |