Skip to content

cc: elide push/pop in kernel_outb/outw when port is a literal#447

Merged
bboe merged 1 commit into
mainfrom
bboe/cc-kernel-outb-skip-push
May 20, 2026
Merged

cc: elide push/pop in kernel_outb/outw when port is a literal#447
bboe merged 1 commit into
mainfrom
bboe/cc-kernel-outb-skip-push

Conversation

@bboe
Copy link
Copy Markdown
Owner

@bboe bboe commented May 20, 2026

Summary

The general non-const-value path in builtin_kernel_outb / builtin_kernel_outw was emitting an unconditional save-around-eval guard:

eval value → AX
push AX
eval port → DX        ; might clobber AX in the general case
pop AX
out dx, al

But when port is an Int literal, the port lowering is a single mov dx, <imm> that doesn't touch AX — so the save is dead. Adding an isinstance(port_arg, Int) branch elides the push/pop in that case.

Almost every kernel kernel_outb / kernel_outw call site uses a hex-literal port (0x21, 0x3F6, 0x300, ...), so this fires kernel-wide.

Impact

Kernel kasm: -1,980 bytes (on top of the -217 from PR #446). Folds fire in ata, fdc, ne2k, ps2, sb16, opl3, console, vga, serial, rtc.

Test plan

  • Two new unit tests: test_kernel_outb_constant_port_runtime_value_no_push_pop, test_kernel_outw_constant_port_runtime_value_no_push_pop
  • Pre-existing test_kernel_outb_variable_value_uses_push_pop (with a non-Int port) still exercises the general save-around-eval path
  • Full unit suite: 458 passed
  • Full matrix: test_asm (42), test_programs bbfs (89), test_programs ext2 (119), test_bboefs (6), test_cc_bits (110), test_cc_bitfields (12), test_cc_casts (6), test_cc_local_structs (10), test_cc_compatibility (57), test_kernel_archive (12), test_archive (12), test_pipeline_basic, test_floppy_boot, test_draw

🤖 Generated with Claude Code

The general non-const-value path in ``builtin_kernel_outb`` /
``builtin_kernel_outw`` was emitting an unconditional save-around-eval
guard:

    eval value → AX
    push AX
    eval port → DX     ; might clobber AX in the general case
    pop AX
    out dx, al

But when ``port`` is an ``Int`` literal, the port lowering is a single
``mov dx, <imm>`` that doesn't touch AX — so the save is dead.  Add an
``isinstance(port_arg, Int)`` branch that evaluates value into AX,
then loads the literal port into DX with a bare ``mov``, and skips
the push/pop entirely.

Almost every kernel ``kernel_outb`` / ``kernel_outw`` call site uses a
hex-literal port (``0x21``, ``0x3F6``, ``0x300``, ...), so this fires
kernel-wide.

Real-kernel impact: 1,980 bytes of kasm reduction across the kernel
C build (folds in ata, fdc, ne2k, ps2, sb16, opl3, console, vga,
serial, rtc).

Covered by two new unit tests:
- ``test_kernel_outb_constant_port_runtime_value_no_push_pop``
- ``test_kernel_outw_constant_port_runtime_value_no_push_pop``

The pre-existing ``test_kernel_outb_variable_value_uses_push_pop``
test uses a non-Int port (a function parameter) so it still
exercises the general save-around-eval path and stays green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bboe bboe merged commit dabbce7 into main May 20, 2026
27 checks passed
@bboe bboe deleted the bboe/cc-kernel-outb-skip-push branch May 20, 2026 13:03
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.

1 participant