Skip to content

Distribute an effect-run application into IfThenElse branches #266

Description

@Unisay

Problem

magicDo wraps a do-block's final action in a run application: App finalAction EffectRunArg. When the final action is a conditional, which is the standard shape of a tail-recursive effect loop (do logShow n; if n <= 1 then log "done" else loop (n - 1)), the marker applies to the whole IfThenElse. Codegen then emits an IIFE that returns the selected action plus a second call that forces it: (function() if ... then return A else return B end end)()(). Two costs follow. Each executed conditional tail pays an extra closure and two extra calls, and the branch call loop (n - 1) stays partial because the run sits outside the if, so the self-call never becomes a saturated worker call: loopification (#181) sees no tail self-call and cannot rewrite the recursion into while true.

Approach

Rewrite App (IfThenElse c t e) EffectRunArg to IfThenElse c (App t EffectRunArg) (App e EffectRunArg). Selecting the action first and running it second is the same evaluation order, so the rewrite preserves semantics; it consumes the outer application while adding one marker node per branch, so it terminates and cannot re-fire on its own output. Placed before the late uncurry run (#200), the pushed-in runs saturate the branch spines: loop(n-1)(run) becomes loop$w(n-1, run), which the Lua backend emits as the tail call return M.loop_S_w(n - 1), and loopification turns the recursion into a loop.

Prerequisites / Relations

Unlocks the #181 synergy sketched in #200 for if-terminated effect loops; the Golden/UncurryEffect countdown documents today's wrapper round-trip. Nested conditionals distribute recursively.

Open questions

  • Where the rewrite lives: magicDo's buildThunk could emit per-branch runs directly, while an optimizer rule would also catch run-of-if shapes from other producers such as ForeignLift.
  • Interaction with the if-folding rules (removeIfWithEqualBranches, the boolean folds): distribution strictly consumes the outer run, so fixpoint convergence should hold, but the rule ordering deserves a test.

Metadata

Metadata

Assignees

No one assigned

    Labels

    OptimisationA Compiler Optimisationarea: irIR / optimizer / DCE / inlinerenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions