matter-labs / era-compiler-llvm

ZKsync fork of the LLVM framework.
Other
31 stars 16 forks source link

[EVM] Stackification cleans up stack too eagerly #728

Open akiramenai opened 17 hours ago

akiramenai commented 17 hours ago

It looks like stackification attempts to clean up the stack before doing computations. Consider the following example:

define i256 @no_manipulations_needed_no_junk(i256 %a1, i256 %a2, i256 %a3) nounwind {
; CHECK-LABEL: no_manipulations_needed_no_junk:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    JUMPDEST
; CHECK-NEXT:    SWAP1
; CHECK-NEXT:    SWAP2
; CHECK-NEXT:    POP
; CHECK-NEXT:    SUB
; CHECK-NEXT:    SWAP1
; CHECK-NEXT:    JUMP
  %x1 = sub i256 %a1, %a2
  ret i256 %x1
}

Instead of moving %a3 on top of the stack, popping it, and then subtracting, subtracting and then cleaning up would result in better assembly:

JUMPDEST
SUB
SWAP1
POP
SWAP1
JUMP

Other examples showing the same pattern can be found in test/CodeGen/EVM/stack-ops.ll and test/CodeGen/EVM/stack-ops-commutable.ll (e.g. same_arg_alive_with_junk).

akiramenai commented 17 hours ago

Note that sometimes, eager cleanup is preferable:

define i256 @swap_first_no_junk(i256 %a1, i256 %a2, i256 %a3, i256 %a4) nounwind {
; CHECK-LABEL: swap_first_no_junk:
; CHECK:       ; %bb.0:
; CHECK-NEXT:    JUMPDEST
; CHECK-NEXT:    SWAP2
; CHECK-NEXT:    POP
; CHECK-NEXT:    POP
; CHECK-NEXT:    SUB
; CHECK-NEXT:    SWAP1
; CHECK-NEXT:    JUMP
  %x1 = sub i256 %a1, %a4
  ret i256 %x1
}

Here it's better to cleanup first and then subtract.