Skip to content

Stop literal folds from consuming jump targets - #579

Merged
bertysentry merged 2 commits into
mainfrom
578-optimizer-fold-across-jump-targets
Aug 18, 2026
Merged

Stop literal folds from consuming jump targets#579
bertysentry merged 2 commits into
mainfrom
578-optimizer-fold-across-jump-targets

Conversation

@bertysentry

Copy link
Copy Markdown
Contributor

Fixes #578

What

With the default tuple optimization, jawk 'BEGIN { v = 60; print "size:", (v ? v : 24) * 2 }' printed 60 48 — the false branch's folded result, with the true-branch value leaking onto the operand stack and displacing the "size:" operand. It now prints size: 120, like gawk and like -s runs.

How

(v ? v : 24) * 2 compiles so that the false branch's PUSH 24 falls through to the join point (PUSH 2, MULTIPLY) that the true branch jumps to. The binary literal fold merged all three tuples into PUSH 48, and remapAddresses then landed the true branch's GOTO on that folded literal, skipping the multiplication entirely.

The three peephole literal folds — the binary fold, the unary fold, and the literal + GET_INPUT_FIELD fusion — now require that no consumed tuple other than the first be an address target, exactly the guard that the concat-run collapse and the ASSIGN+POP fusion already apply. A jump to the first tuple of a folded range remains safe, because it lands on the replacement, which computes the same value.

Why it matters

Any conditional expression whose result feeds a further operation on a literal was affected: (cond ? a : b) * 2, -(cond ? a : b), $(cond ? 1 : 2). patsie75/awk-demo sizes its framebuffer with terminal["height"] = ($1 ? $1 : 24) * 2, which always produced 48 and made the demo abort with Terminal size (80x48) is smaller than program size (80x50) regardless of the real terminal size.

Tests

AwkTupleOptimizationTest gains five cases: the binary, unary, and field-index join-point shapes (asserting both the runtime result and that the operator tuple survives folding), the assignment form, and the false-branch path of the guarded ternary.

mvn verify passes: all unit and compatibility tests, checkstyle, PMD, and SpotBugs clean. Behavior change documented under Unreleased in behavior-changes.md.

🤖 Generated with Claude Code

The peephole literal folds (binary fold, unary fold, and the literal
field-index fusion) merged a literal push with following operator
tuples without checking whether those tuples are branch targets. A
jump into the middle of the folded range — the join point of a
ternary, for example — was remapped onto the folded replacement, so
one branch of the conditional skipped the operation, produced the
other branch's folded result, and leaked a value onto the operand
stack: (v ? v : 24) * 2 with v = 60 yielded 48 and displaced later
print operands.

Each fold now requires that no consumed tuple other than the first be
an address target, matching the guards the concat-run collapse and the
ASSIGN+POP fusion already apply. A jump to the first tuple of the
range stays safe: it lands on the replacement, which computes the same
value.

Fixes #578

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bertysentry

Copy link
Copy Markdown
Contributor Author

@codex please review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: fcd4d64f36

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@bertysentry

Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

Co-authored-by: bertysentry <32521698+bertysentry@users.noreply.github.com>

Copilot AI commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. The only conflict was in src/site/markdown/behavior-changes.md — both the #578 (literal fold) and #574 (attached CLI options) bullets are now present under Unreleased (commit a686f46).

@bertysentry
bertysentry merged commit 20cf98e into main Aug 18, 2026
@bertysentry
bertysentry deleted the 578-optimizer-fold-across-jump-targets branch August 18, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tuple optimizer folds literals across jump targets, corrupting ternary results and print operands

2 participants