3 ms·
This example seems a bit pessimised: head_of_loop: load_var x push_int 1000 less_than jump_if_false :end_of_loop load_var x increment
by mst 5y ago
This example seems a bit pessimised:
head_of_loop:
load_var x
push_int 1000
less_than
jump_if_false :end_of_loop
load_var x
increment
store_var x
end_of_loop:
I'd more expect a stack engine to be something like something like -
load_var x
head_of_loop:
jump_lt_keep 1000 :end_of_loop
increment
end_of_loop:
store_var x
in the sense that anything that can figure out how to populate and use r0 would likely also be able to figure out it can wrap the load/store calls around the outside of the loop.
(I'm far from an expert on stack versus register VMs though so I may be missing several somethings here)
- tln 5y agoThat would be a nice optimization. Here's what Python does 0 LOAD_FAST 0 (x) 2 LOAD_CONST 1 (1000) 4 COMPARE_OP 0 (<) 6 POP_JUMP_IF_FALSE 18 8 LOAD_FAST 0 (x) 10 LOAD_CONST 2 (1) 12 BINARY_ADD 14 STORE_FAST 0 (x) 16 JUMP_ABSOLUTE 0 18 LOAD_CONST 0 (None) Python's VM is very slow, but note only one arg per op and the compare + jump are not fused. BTW, if we're considering "advanced" optimization might as well elide the whole loop :) EG https://godbolt.org/z/n3GznqKsM https://godbolt.org/z/n3GznqKsM test(int): push rbp mov rbp, rsp mov DWORD PTR [rbp-4], edi jmp .L2 .L3: add DWORD PTR [rbp-4], 1 .L2: cmp DWORD PTR [rbp-4], 999 jle .L3 nop pop rbp ret
- mst 5y agoWell, sure, but I was thinking along the lines of "reserving a spot on the stack and reserving a register seem like about the same level of clever", especially thinking about how mixed register/stack argument passing works in even relatively stupid C compilers. Eliding the entire loop seems relatively similarly clever for either architecture, but would've counted as cheating in the frame I was pondering from. Still neat to see even if x86 asm continues to make my eyes cross ;)
- exikyut 5y ago(Why is there a "nop" near the end? What does it do?)