Implement aggregate locals

This commit is contained in:
nora 2023-07-30 00:03:18 +02:00
parent 7c88a3513e
commit 1d9ab31baf
2 changed files with 35 additions and 31 deletions

View file

@ -12,10 +12,12 @@ import { exec } from "child_process";
const input = ` const input = `
function main() = uwu(10); function main() = uwu(10);
function ___print() = ; function print_a(
a: String,
): String = a;
function uwu(a: Int) = if a != 0 then ( function uwu(a: Int) = if a != 0 then (
print("uwu\n"); print(print_a("uwu\n"));
uwu(a - 1); uwu(a - 1);
); );
`; `;

View file

@ -52,9 +52,9 @@ export type Context = {
}; };
function escapeIdentName(name: string): string { function escapeIdentName(name: string): string {
// this allows the implementation to use an odd number of leading // This allows the implementation to use 2 leading underscores
// underscores // for any names and it will not conflict.
return name.replace(/_/g, "__"); return name.startsWith("__") ? `_${name}` : name;
} }
function internFuncType(cx: Context, type: wasm.FuncType): wasm.TypeIdx { function internFuncType(cx: Context, type: wasm.FuncType): wasm.TypeIdx {
@ -178,7 +178,7 @@ type ArgRetAbi =
| { kind: "zst" } | { kind: "zst" }
| { kind: "aggregate"; types: wasm.ValType[] }; | { kind: "aggregate"; types: wasm.ValType[] };
type VarLocation = { kind: "local"; idx: number } | { kind: "zst" }; type VarLocation = { localIdx: number; types: wasm.ValType[] };
function lowerFunc(cx: Context, item: Item, func: FunctionDef) { function lowerFunc(cx: Context, item: Item, func: FunctionDef) {
const abi = computeAbi(func.ty!); const abi = computeAbi(func.ty!);
@ -226,19 +226,17 @@ function lowerExpr(fcx: FuncContext, instrs: wasm.Instr[], expr: Expr) {
} }
case "let": { case "let": {
lowerExpr(fcx, instrs, expr.rhs); lowerExpr(fcx, instrs, expr.rhs);
const type = wasmTypeForBody(expr.rhs.ty!); const types = wasmTypeForBody(expr.rhs.ty!);
if (type.length === 0) {
fcx.varLocations.push({ kind: "zst" });
} else if (type.length === 1) {
const local = fcx.wasm.locals.length;
fcx.wasm.locals.push(type[0]);
instrs.push({ kind: "local.set", imm: local }); const local = fcx.wasm.locals.length;
fcx.varLocations.push({ kind: "local", idx: local }); fcx.wasm.locals.push(...types);
} else {
todo("complex locals"); types.forEach((_, i) => {
} instrs.push({ kind: "local.set", imm: local + i });
});
fcx.varLocations.push({ localIdx: local, types });
break; break;
} }
@ -507,17 +505,15 @@ function lowerExprBlockBody(
} }
function loadVariable(instrs: wasm.Instr[], loc: VarLocation) { function loadVariable(instrs: wasm.Instr[], loc: VarLocation) {
switch (loc.kind) { // If the type is a ZST we'll have no types and do the following:
case "local": { // Load the ZST:
instrs.push({ kind: "local.get", imm: loc.idx }); // ...
break; // 🪄 poof, the ZST is on the stack now.
} // --
case "zst": // Otherwise, load each part.
// Load the ZST: loc.types.forEach((_, i) => {
// ... instrs.push({ kind: "local.get", imm: loc.localIdx + i });
// 🪄 poof, the ZST is on the stack now. });
break;
}
} }
function computeAbi(ty: TyFn): FnAbi { function computeAbi(ty: TyFn): FnAbi {
@ -601,14 +597,20 @@ function wasmTypeForAbi(abi: FnAbi): {
abi.params.forEach((arg) => { abi.params.forEach((arg) => {
switch (arg.kind) { switch (arg.kind) {
case "scalar": case "scalar":
paramLocations.push({ kind: "local", idx: params.length }); paramLocations.push({
localIdx: params.length,
types: [arg.type],
});
params.push(arg.type); params.push(arg.type);
break; break;
case "zst": case "zst":
paramLocations.push({ kind: "zst" }); paramLocations.push({ localIdx: /* dummy */ 0, types: [] });
break; break;
case "aggregate": case "aggregate":
paramLocations.push({ kind: "local", idx: params.length }); paramLocations.push({
localIdx: params.length,
types: arg.types,
});
params.push(...arg.types); params.push(...arg.types);
break; break;
} }