leaningtech / cheerp-meta

Cheerp - a C/C++ compiler for Web applications - compiles to WebAssembly and JavaScript
https://labs.leaningtech.com/cheerp
Other
1.02k stars 50 forks source link

Casting error? #126

Closed zyz9740 closed 1 year ago

zyz9740 commented 1 year ago

bug.zip

Can you reproduce this ? I can't locate which statement cause this issue.

carlopi commented 1 year ago

I reproduce, and I think I also have a fix for the problem, thanks a lot for signaling this.

Historically -O0 has been not supported, and less testing is done in this configuration, so we recommend compiling with at least -O1 enabled, since there might be stubble bugs introduced by some optimization passes being tagged as optional while they are actually not.

In this case the problem was not pass ordering/selection, but an actual bug in the Wasm writer while handling Constant non representable as int32_t.

Thanks again for the test-case, should be merged in master in the next batch.

zyz9740 commented 1 year ago

Trigger is as follows:

#include "cd.h"
long long a = 0;
long b = 0;

int main() {
  b = a ^= b;
  long long c = (int)a;
  if (c <= 0)
    transparent_crc(c, "c", 1);
  return 0;
}

When executing the wasm generated by cheerp, this program print nothing. But of course it should output something in "transparent_crc" function because variable "a" is always equal to zero.

We found the cause of this case when debugging wasm.

This is the main function in wasm:

(func (;100;) (type 3)
    (local i64)
    global.get 6
    global.get 12
    i64.extend_i32_s
    i64.xor
    local.tee 0
    global.set 6
    local.get 0
    i32.wrap_i64
    global.set 12
    local.get 0
    i64.const 32
    i64.shl
    local.tee 0
    i64.const 0
    i64.lt_s                           // There should be le_s instead of lt_s, which causes this issue
    if  ;; label = @1
      local.get 0
      i64.const 32
      i64.shr_s
      call 63
    end
    global.get 6
    i64.const 12134
    i64.add
    global.set 6)

What confuses me is that I don't know why this happens and if change anything in the C program, it print correctly. Which transformation compile operator "<=" to lt instead of le ?

carlopi commented 1 year ago

Thanks again for getting in depth! The problem was:

  (func $main (type 3)
    (local i64)
    global.get 11
    global.get 12
    i64.extend_i32_s
    i64.xor
    local.tee 0
    global.set 11
    local.get 0
    i32.wrap_i64
    global.set 12
    local.get 0
    i64.const 32
    i64.shl
    local.tee 0
    i64.const 0                                 // 2^32 -> Overflow !!!
    i64.lt_s
    if  ;; label = @1
      local.get 0
      i64.const 32
      i64.shr_s
      call $transparent_crc
    end)

instead of

  (func $main (type 3)
    (local i64)
    global.get 11
    global.get 12
    i64.extend_i32_s
    i64.xor
    local.tee 0
    global.set 11
    local.get 0
    i32.wrap_i64
    global.set 12
    local.get 0
    i64.const 32
    i64.shl
    local.tee 0
    i64.const 4294967296                       // 2^32
    i64.lt_s
    if  ;; label = @1
      local.get 0
      i64.const 32
      i64.shr_s
      call $transparent_crc
    end)
zyz9740 commented 1 year ago

OK, thanks for your fast response again! We found the cause in the same time Hhhhhh. What a coincidence ; )

zyz9740 commented 1 year ago

I still have a question. To compile C code if (c <= 0) , cheerp printf i64.const 4294967296 // 2^32 .Why wasm compares (0 << 32) with a such huge number instead of 0 ? From my perspective, wasm should compare (0<<32) with "0" and the comparison operators should be le_s instead of lt_s.

Your explaination will help to understand the root cause deeper. I'm looking forward to your reply !