https://github.com/akkartik/mu/blob/main/302stack_allocate.subx

     1 # A function which pushes n zeros on the stack.
     2 # Really only intended to be called from code generated by mu.subx (for array
     3 # vars on the stack).
     4
     5 == code
     6
     7 #? Entry:
     8 #?     # . prologue
     9 #?     89/<- %ebp 4/r32/esp
    10 #?     #
    11 #?     68/push 0xfcfdfeff/imm32
    12 #?     b8/copy-to-eax 0x34353637/imm32
    13 #? $dump-stack0:
    14 #?     (push-n-zero-bytes 4)
    15 #?     68/push 0x20/imm32
    16 #? $dump-stack9:
    17 #?     b8/copy-to-eax 1/imm32/exit
    18 #?     cd/syscall 0x80/imm8
    19
    20 # This is not a regular function, so it won't be idiomatic.
    21 # Registers must be properly restored.
    22 # Registers can be spilled, but that modifies the stack and needs to be
    23 # cleaned up.
    24
    25 # Overhead:
    26 #   62 + n*6 instructions to push n bytes.
    27 # If we just emitted code to push n zeroes, it would be:
    28 #   5 bytes for 4 zero bytes, so 1.25 bytes per zero. And that's not even
    29 #   instructions.
    30 # But on the other hand it would destroy the instruction cache, where this
    31 # approach requires 15 instructions, fixed.
    32
    33 # n must be positive
    34 push-n-zero-bytes:  # n: int
    35 $push-n-zero-bytes:prologue:
    36     89/<- *Push-n-zero-bytes-ebp 5/r32/ebp  # spill ebp without affecting stack
    37     89/<- %ebp 4/r32/esp
    38 $push-n-zero-bytes:copy-ra:
    39     # -- esp = ebp
    40     89/<- *Push-n-zero-bytes-eax 0/r32/eax
    41     8b/-> *esp 0/r32/eax
    42     2b/subtract *(ebp+4) 4/r32/esp
    43     # -- esp+n = ebp
    44     89/<- *esp 0/r32/eax
    45     8b/-> *Push-n-zero-bytes-eax 0/r32/eax
    46 $push-n-zero-bytes:bulk-cleaning:
    47     89/<- *Push-n-zero-bytes-esp 4/r32/esp
    48     81 0/subop/add *Push-n-zero-bytes-esp 4/imm32
    49     81 0/subop/add *(ebp+4) 4/imm32
    50     (zero-out *Push-n-zero-bytes-esp *(ebp+4))  # n+4
    51 $push-n-zero-bytes:epilogue:
    52     8b/-> *Push-n-zero-bytes-ebp 5/r32/ebp  # restore spill
    53     c3/return
    54
    55 == data
    56 Push-n-zero-bytes-ebp:  # (addr int)
    57   0/imm32
    58 Push-n-zero-bytes-esp:  # (addr int)
    59   0/imm32
    60 Push-n-zero-bytes-eax:
    61   0/imm32