You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bugc: Block.predecessors includes call edges only after inlining #394
Block.predecessors means two different things depending on whether inlining touched a function.
irgen leaves a call's edge to its continuation out on purpose (packages/bugc/src/irgen/generate/function.ts:138-143: block merging, jump optimization, return merging and tail calls read predecessors without call edges).
InliningStep recomputes the caller's predecessors with call edges (recomputePredecessors in packages/bugc/src/optimizer/steps/inlining.ts:714-719, via successors, which includes call → continuation). irgen/generate/process.ts:82 also adds them, before function.ts recomputes.
Example at -O2 (f is recursive, so not inlined; g is inlined):
name Preds;
define {
function g(n: uint256) -> uint256 { return n + 1; };
function f(n: uint256) -> uint256 {
if (n == 0) { return 0; }
r = r + 1;
return f(n - 1);
};
}
storage { [0] r: uint256; }
create {}
code {
r = g(msg.value); // remove this line for the other case
f(msg.data.length);
r = r + 5;
}
With the g line, main's call_cont_2 has predecessors ["call_cont_1"] (the calling block). Without it, call_cont_1 has []. The passes that count predecessors (block merging's size === 1 checks, tail calls' "other predecessors" of a continuation) can therefore decide differently for the same shape of CFG. No miscompile found yet; this is about picking one meaning and making both producers agree.
Activity