add lir
Some checks failed
Check / Explore-Gitea-Actions (push) Failing after 12s

This commit is contained in:
sfja 2026-04-28 02:01:02 +02:00
parent ec84b385d3
commit e09e1ea8f6
2 changed files with 237 additions and 0 deletions

236
src/middle/lir.ts Normal file
View File

@ -0,0 +1,236 @@
export class Mod {
public fns: Fn[] = [];
constructor() {}
createFn(): Fn {
return new Fn(this);
}
}
export class Fn {
public bbs: BasicBlock[] = [];
constructor(
public mod: Mod,
) {}
createBasicBlock(): BasicBlock {
return new BasicBlock(this);
}
pushBasicBlock(bb: BasicBlock) {
this.bbs.push(bb);
}
}
export class BasicBlock {
public insts: Inst[] = [];
constructor(
public fn: Fn,
) {}
}
export class Inst {
constructor(
public bb: BasicBlock,
public ty: Ty,
public kind: InstKind,
) {}
}
export type InstKind =
| { tag: "Int"; value: number }
| { tag: "Bool"; value: boolean }
| { tag: "Fn"; fn: Fn }
| { tag: "Param"; idx: number }
| { tag: "GetElemPtr"; base: Inst; offset: number }
| { tag: "Call"; callee: Inst; args: Inst[] }
| { tag: "Alloca" }
| { tag: "Load"; source: Inst }
| { tag: "Store"; target: Inst; source: Inst }
| { tag: "ReturnVoid" }
| { tag: "Return"; source: Inst }
| { tag: "Jump"; target: BasicBlock }
| { tag: "Branch"; cond: Inst; truthy: BasicBlock; falsy: BasicBlock }
| { tag: "Select"; cond: Inst; truthy: Inst; falsy: Inst }
| { tag: "Trunc"; source: Inst }
| { tag: "ZeroExt"; source: Inst }
| { tag: "SignExt"; source: Inst }
| { tag: UnaryOp; source: Inst; signed: boolean }
| { tag: BinaryOp; left: Inst; right: Inst; signed: boolean };
export type UnaryOp = "Not" | "Neg";
export type BinaryOp =
| "Eq"
| "Ne"
| "Lt"
| "Gt"
| "Lte"
| "Gte"
| "Or"
| "Xor"
| "And"
| "Shl"
| "Shr"
| "Add"
| "Sub"
| "Mul"
| "Div"
| "Rem";
export class Ty {
constructor(
public kind: TyKind,
) {}
hash(): string {
return JSON.stringify(this.kind);
}
}
export type TyKind =
| { tag: "I8" | "I16" | "I32" | "I64" }
| { tag: "Ptr" }
| { tag: "Array"; ty: Ty; length: number };
export class Context {
private tys = new Map<string, Ty>();
private instsHashIds = new Map<Inst, number>();
private fnHashIds = new Map<Fn, number>();
private bbHashIds = new Map<BasicBlock, number>();
private insts = new Map<string, Inst>();
createTy<
Tag extends TyKind["tag"],
>(
tag: Tag,
kind: Omit<TyKind & { tag: Tag }, "tag">,
): Ty {
const ty = new Ty({ ...kind, tag } as TyKind);
const key = ty.hash();
const found = this.tys.get(key);
if (found) {
return found;
}
this.tys.set(key, ty);
return ty;
}
createInst(
bb: BasicBlock,
ty: Ty,
kind: InstKind,
): Inst {
const newId = this.instsHashIds.size;
const inst = new Inst(bb, ty, kind);
const key = this.hashInst(inst);
const found = this.insts.get(key);
if (found) {
return found;
}
this.insts.set(key, inst);
this.instsHashIds.set(inst, newId);
return inst;
}
hashInst(inst: Inst): string {
const id = this.instsHashIds.get(inst);
if (id) {
return `%${id}`;
}
const i = (inst: Inst) => this.hashInst(inst);
const fn = (fn: Fn): string => {
let id = this.fnHashIds.get(fn);
if (!id) {
id = this.fnHashIds.size;
this.fnHashIds.set(fn, id);
}
return `%${id}`;
};
const bb = (bb: BasicBlock): string => {
let id = this.bbHashIds.get(bb);
if (!id) {
id = this.bbHashIds.size;
this.bbHashIds.set(bb, id);
}
return `%${id}`;
};
const k = inst.kind;
switch (k.tag) {
case "Int":
case "Bool":
return `${k.tag}-${k.value}`;
case "Fn":
return `${k.tag}-${fn(k.fn)}`;
case "Param":
return `${k.tag}-${k.idx}`;
case "GetElemPtr":
return `${k.tag}-${i(k.base)}-${k.offset}`;
case "Call":
return `${k.tag}-${i(k.callee)}-${k.args.map(i).join("-")}`;
case "Alloca":
return `${k.tag}`;
case "Load":
return `${k.tag}-${i(k.source)}`;
case "Store":
return `${k.tag}-${i(k.target)}-${i(k.source)}`;
case "ReturnVoid":
return `${k.tag}`;
case "Return":
return `${k.tag}-${i(k.source)}`;
case "Jump":
return `${k.tag}-${bb(k.target)}`;
case "Branch":
return `${k.tag}-${i(k.cond)}-${bb(k.truthy)}-${bb(k.falsy)}`;
case "Select":
return `${k.tag}-${i(k.cond)}-${i(k.truthy)}-${i(k.falsy)}`;
case "Trunc":
return `${k.tag}-${i(k.source)}`;
case "ZeroExt":
return `${k.tag}-${i(k.source)}`;
case "SignExt":
return `${k.tag}-${i(k.source)}`;
case "Not":
case "Neg":
return `${k.tag}-${i(k.source)}-${k.signed}`;
case "Eq":
case "Ne":
case "Lt":
case "Gt":
case "Lte":
case "Gte":
case "Or":
case "Xor":
case "And":
case "Shl":
case "Shr":
case "Add":
case "Sub":
case "Mul":
case "Div":
case "Rem":
return `${k.tag}-${i(k.left)}-${i(k.right)}-${k.signed}`;
}
}
}
export class Builder {
constructor(
private bb: BasicBlock,
private cx: Context,
) {}
createInt(ty: Ty, value: number) {
this.push(ty, { tag: "Int", value });
}
private push(ty: Ty, kind: InstKind) {
this.bb.insts.push(this.cx.createInst(this.bb, ty, kind));
}
}

1
src/middle/mod.ts Normal file
View File

@ -0,0 +1 @@
export * as lir from "./lir.ts";