Skip to content

return early #1044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mnater opened this issue Jan 3, 2020 · 6 comments
Closed

return early #1044

mnater opened this issue Jan 3, 2020 · 6 comments
Labels

Comments

@mnater
Copy link

mnater commented Jan 3, 2020

Hi

With the following .ts-code (simplified example)

export function check(): i32 {
  let i: i32 = 0;
  while (i < 32) {
    if (load<i16>(16 + i) == 255) {
      return 0;
    }
    i++;
  }
  return 1;
}

I get

  (func $check (export "check") (type $t0) (result i32)
    (local $l0 i32)
    loop $L0
      get_local $l0
      i32.const 32
      i32.lt_s
      if $I1
        get_local $l0
        i32.const 16
        i32.add
        i32.load16_s
        i32.const 255
        i32.eq
        if $I2
          i32.const 0
          return
        else
          get_local $l0
          i32.const 1
          i32.add
          set_local $l0
          br $L0
        end
        unreachable
      end
    end
    i32.const 1)

but expected something like

  (func $check (export "check") (type $t0) (result i32)
    (local $l0 i32)
    loop $L0
      get_local $l0
      i32.const 32
      i32.lt_s
      if $I1
        get_local $l0
        i32.const 16
        i32.add
        i32.load16_s
        i32.const 255
        i32.eq
        if $I2
          i32.const 0
          return
        end
        get_local $l0
        i32.const 1
        i32.add
        set_local $l0
        br $L0
      end
    end
    i32.const 1)

How can I optimise this?

@MaxGraey
Copy link
Member

MaxGraey commented Jan 3, 2020

Are you worried about else and unreachable? It seems this inserted only in wat text format. See more about it here: WebAssembly/binaryen#1541 (comment)

@MaxGraey
Copy link
Member

MaxGraey commented Jan 3, 2020

and both versions produces the same native code:

actual example:

wasm-function[0]:
 0x000000:                              ; 0x000000 from: [0x000009, 0x00001f, 0x00002c]
  sub rsp, 8                            ; 0x000000 48 83 ec 08
  xor eax, eax                          ; 0x000004 33 c0
 0x000006:                              ; 0x000006 from: [0x000028]
  cmp eax, 0x20                         ; 0x000006 83 f8 20
  jge 0x31                              ; 0x000009 0f 8d 22 00 00 00
 0x00000f:                              
  mov ecx, eax                          ; 0x00000f 8b c8
  add ecx, 0x10                         ; 0x000011 83 c1 10
  movsx ecx, word ptr [r15 + rcx]       ; 0x000014 41 0f bf 0c 0f
  cmp ecx, 0xff                         ; 0x000019 81 f9 ff 00 00 00
  je 0x2a                               ; 0x00001f 0f 84 05 00 00 00
 0x000025:                              
  add eax, 1                            ; 0x000025 83 c0 01
  jmp 6                                 ; 0x000028 eb dc
 0x00002a:                              
  xor eax, eax                          ; 0x00002a 33 c0
  jmp 0x36                              ; 0x00002c e9 05 00 00 00
 0x000031:                              
  mov eax, 1                            ; 0x000031 b8 01 00 00 00
  nop                                   ; 0x000036 66 90
  add rsp, 8                            ; 0x000038 48 83 c4 08
  ret                                   ; 0x00003c c3

expected example:

wasm-function[0]:
 0x000000:                              ; 0x000000 from: [0x000009, 0x00001f, 0x00002c]
  sub rsp, 8                            ; 0x000000 48 83 ec 08
  xor eax, eax                          ; 0x000004 33 c0
 0x000006:                              ; 0x000006 from: [0x000028]
  cmp eax, 0x20                         ; 0x000006 83 f8 20
  jge 0x31                              ; 0x000009 0f 8d 22 00 00 00
 0x00000f:                              
  mov ecx, eax                          ; 0x00000f 8b c8
  add ecx, 0x10                         ; 0x000011 83 c1 10
  movsx ecx, word ptr [r15 + rcx]       ; 0x000014 41 0f bf 0c 0f
  cmp ecx, 0xff                         ; 0x000019 81 f9 ff 00 00 00
  je 0x2a                               ; 0x00001f 0f 84 05 00 00 00
 0x000025:                              
  add eax, 1                            ; 0x000025 83 c0 01
  jmp 6                                 ; 0x000028 eb dc
 0x00002a:                              
  xor eax, eax                          ; 0x00002a 33 c0
  jmp 0x36                              ; 0x00002c e9 05 00 00 00
 0x000031:                              
  mov eax, 1                            ; 0x000031 b8 01 00 00 00
  nop                                   ; 0x000036 66 90
  add rsp, 8                            ; 0x000038 48 83 c4 08
  ret                                   ; 0x00003c c3

So it should have same performance

@mnater
Copy link
Author

mnater commented Jan 4, 2020

Hi

Thanks for your response.

Are you worried about else and unreachable?

Yes. It looks like something that could be optimized away for sake of code size.

It seems this inserted only in wat text format.

After my explorations it is in the binary, too:

0B 00 0B 0B

A little bit of background:
I'm currently creating my .wasm from a .asm.js file using asm2wasm, but this limits me to the MVP and I'm looking for a more future-proof toolchain.
While porting to AssemblyScript I diffed the outputs and stumbled over this.

.asm.js -> asm2wasm -> wasm-opt -Oz emits code in text format and binary as expected above.

@MaxGraey
Copy link
Member

MaxGraey commented Jan 4, 2020

if you turn-off optimizations: https://webassembly.studio/?f=uwezhpittw you could see as CFG of loop's body has structure (monoblock without else) as you desire. But after binaryen's optimizations it separate to if-else blocks which produce 2 extra bytes compare to optimal case.

I don't think it's such a big deal, but if you really need smallest possible output and you're not happy with current opt stage, you can open issue at the binaryen repo.

@MaxGraey
Copy link
Member

MaxGraey commented Jan 4, 2020

btw #1046 could potentially fix this problem as a side effect

@mnater
Copy link
Author

mnater commented Jan 28, 2020

Thank you for the detailed answer. It is now optimized away by -O3.

@mnater mnater closed this as completed Jan 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants