import type { BinaryOp, UnaryOp } from "../ast"
|
|
import type { Loc } from "./loc"
|
|
|
|
export type Operand = Loc | number
|
|
|
|
export type AbsInsnCopy = {
|
|
type: "copy",
|
|
dest: Loc,
|
|
source: Operand,
|
|
}
|
|
|
|
export type AbsInsnGoto = {
|
|
type: "goto",
|
|
dest: string,
|
|
}
|
|
|
|
export type AbsInsnLabel = {
|
|
type: "label",
|
|
dest: string,
|
|
}
|
|
|
|
type UnaryInsn<Op> = {
|
|
type: "unary",
|
|
dest: Loc,
|
|
op: Op,
|
|
source: Operand,
|
|
}
|
|
|
|
// NOTE: We convert binary -> unary when going SSA3 -> SSA2
|
|
export type AbsInsn2Unary = UnaryInsn<UnaryOp | BinaryOp>
|
|
|
|
// Abstract instruction in two-address form
|
|
export type AbsInsn2 = AbsInsnCopy | AbsInsnLabel | AbsInsnGoto | AbsInsn2Unary
|
|
|
|
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 UnaryFn2<A> = UnaryFn<UnaryOp | BinaryOp, A>
|
|
|
|
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 AbsInsnBinary = {
|
|
type: "binary",
|
|
dest: Loc,
|
|
source: Operand,
|
|
op: BinaryOp,
|
|
source1: Operand
|
|
}
|
|
|
|
// Abstract instruction in three-address form
|
|
export type AbsInsn3 = AbsInsnCopy | AbsInsnLabel | AbsInsnGoto | AbsInsn3Unary | AbsInsnBinary
|
|
|
|
export const CopyInsn = (dest: Loc, source: Operand): AbsInsnCopy => ({
|
|
type: 'copy',
|
|
dest,
|
|
source,
|
|
})
|
|
|
|
export const UnaryInsn = <Op>(dest: Loc, op: Op, source: Operand): UnaryInsn<Op> => ({
|
|
type: 'unary',
|
|
dest,
|
|
op,
|
|
source,
|
|
})
|
|
|
|
export const BinaryInsn = (dest: Loc, source: Operand, op: BinaryOp, source1: Operand): AbsInsnBinary => ({
|
|
type: 'binary',
|
|
dest,
|
|
source,
|
|
op,
|
|
source1,
|
|
})
|
|
|
|
export const LabelInsn = (dest: string): AbsInsnLabel => ({
|
|
type: 'label',
|
|
dest,
|
|
})
|
|
|
|
export const GotoInsn = (dest: string): AbsInsnGoto => ({
|
|
type: 'goto',
|
|
dest,
|
|
})
|