From 349ba2f4f669923a888698836f44fe442bd25088 Mon Sep 17 00:00:00 2001 From: Tyler Hou Date: Thu, 17 Oct 2024 13:38:05 -0700 Subject: [PATCH] Modify brili to properly execute phi instructions This fixes issue 330: https://github.com/sampsyo/bril/issues/330 The approach (copy the environment at the end of the last basic block) was inspired/copied from the comment on the Bril issue: https://github.com/sampsyo/bril/issues/330#issuecomment-2380389110 --- brili.ts | 31 +++++++++++++++++++++---------- test/interp/ssa/ssa-swap.bril | 21 +++++++++++++++++++++ test/interp/ssa/ssa-swap.out | 6 ++++++ 3 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 test/interp/ssa/ssa-swap.bril create mode 100644 test/interp/ssa/ssa-swap.out diff --git a/brili.ts b/brili.ts index ff6e2a8b3..8df683114 100644 --- a/brili.ts +++ b/brili.ts @@ -316,9 +316,15 @@ type State = { // For profiling: a total count of the number of instructions executed. icount: bigint, - // For SSA (phi-node) execution: keep track of recently-seen labels.j + // For SSA (phi-node) execution: keep track of recently-seen labels. curlabel: string | null, - lastlabel: string | null, + lastblock: null | { + label: string, + // The environment at the end of the last basic block. To evaluate the RHS + // of phi nodes, we lookup values in this map to avoid the "swap problem" + // (https://github.com/sampsyo/bril/issues/330) + endenv: Env, + }, // For speculation: the state at the point where speculation began. specparent: State | null, @@ -363,7 +369,7 @@ function evalCall(instr: bril.Operation, state: State): Action { heap: state.heap, funcs: state.funcs, icount: state.icount, - lastlabel: null, + lastblock: null, curlabel: null, specparent: null, // Speculation not allowed. } @@ -681,10 +687,10 @@ function evalInstr(instr: bril.Instruction, state: State): Action { if (labels.length != args.length) { throw error(`phi node has unequal numbers of labels and args`); } - if (!state.lastlabel) { + if (state.lastblock === null) { throw error(`phi node executed with no last label`); } - let idx = labels.indexOf(state.lastlabel); + let idx = labels.indexOf(state.lastblock.label); if (idx === -1) { // Last label not handled. Leave uninitialized. state.env.delete(instr.dest); @@ -694,7 +700,7 @@ function evalInstr(instr: bril.Instruction, state: State): Action { throw error(`phi node needed at least ${idx+1} arguments`); } let src = instr.args[idx]; - let val = state.env.get(src); + let val = state.lastblock.endenv.get(src); if (val === undefined) { state.env.delete(instr.dest); } else { @@ -811,7 +817,7 @@ function evalFunc(func: bril.Function, state: State): Value | null { // count "aborted" instructions. Object.assign(state, { env: state.specparent.env, - lastlabel: state.specparent.lastlabel, + lastblock: state.specparent.lastblock, curlabel: state.specparent.curlabel, specparent: state.specparent.specparent, }); @@ -839,8 +845,13 @@ function evalFunc(func: bril.Function, state: State): Value | null { } } } else if ('label' in line) { - // Update CFG tracking for SSA phi nodes. - state.lastlabel = state.curlabel; + if (state.curlabel !== null) { + // Update CFG tracking for SSA phi nodes. + state.lastblock = { + label: state.curlabel, + endenv: new Map(state.env), + }; + } state.curlabel = line.label; } } @@ -943,7 +954,7 @@ function evalProg(prog: bril.Program) { heap, env: newEnv, icount: BigInt(0), - lastlabel: null, + lastblock: null, curlabel: null, specparent: null, } diff --git a/test/interp/ssa/ssa-swap.bril b/test/interp/ssa/ssa-swap.bril new file mode 100644 index 000000000..2c37299c5 --- /dev/null +++ b/test/interp/ssa/ssa-swap.bril @@ -0,0 +1,21 @@ +@main { + i: int = const 5; + one: int = const 1; + zero: int = const 0; + +.l0: + x0: int = const 0; + y0: int = const 1; + jmp .l1; + +.l1: + x1: int = phi .l0 x0 .l1 y1; + y1: int = phi .l0 y0 .l1 x1; + print x1 y1; + + cond: bool = gt i zero; + i: int = sub i one; + br cond .l1 .end; + +.end: +} diff --git a/test/interp/ssa/ssa-swap.out b/test/interp/ssa/ssa-swap.out new file mode 100644 index 000000000..8c3dac765 --- /dev/null +++ b/test/interp/ssa/ssa-swap.out @@ -0,0 +1,6 @@ +0 1 +1 0 +0 1 +1 0 +0 1 +1 0