captbaritone / eel-wasm

Compile Nullsoft's EEL code to Web Assembly
https://eel.capt.dev
48 stars 4 forks source link

Is our handling of % correct? #32

Open captbaritone opened 4 years ago

captbaritone commented 4 years ago

Trying compile C's fmod to wasm results in dramatically more code:

Try the following in https://webassembly.studio/

#define WASM_EXPORT __attribute__((visibility("default")))
#include <math.h>

WASM_EXPORT
double mod(double a, double b)
{
    return fmod(a, b);
}

WASM_EXPORT
int main()
{
    return 42;
}

And you will get the following wat:

(module
  (type $t0 (func))
  (type $t1 (func (param f64 f64) (result f64)))
  (type $t2 (func (result i32)))
  (func $__wasm_call_ctors (type $t0))
  (func $mod (export "mod") (type $t1) (param $p0 f64) (param $p1 f64) (result f64)
    get_local $p0
    get_local $p1
    call $fmod)
  (func $main (export "main") (type $t2) (result i32)
    i32.const 42)
  (func $fmod (type $t1) (param $p0 f64) (param $p1 f64) (result f64)
    (local $l0 i64) (local $l1 i64) (local $l2 i64) (local $l3 i32) (local $l4 i64) (local $l5 i32) (local $l6 i32)
    block $B0
      block $B1
        block $B2
          block $B3
            block $B4
              block $B5
                get_local $p1
                i64.reinterpret/f64
                tee_local $l0
                i64.const 1
                i64.shl
                tee_local $l1
                i64.eqz
                br_if $B5
                get_local $l0
                i64.const 9223372036854775807
                i64.and
                i64.const 9218868437227405312
                i64.gt_u
                br_if $B5
                get_local $p0
                i64.reinterpret/f64
                tee_local $l2
                i64.const 52
                i64.shr_u
                i32.wrap/i64
                i32.const 2047
                i32.and
                tee_local $l3
                i32.const 2047
                i32.eq
                br_if $B5
                get_local $l2
                i64.const 1
                i64.shl
                tee_local $l4
                get_local $l1
                i64.le_u
                br_if $B4
                get_local $l0
                i64.const 52
                i64.shr_u
                i32.wrap/i64
                i32.const 2047
                i32.and
                set_local $l5
                get_local $l3
                i32.eqz
                br_if $B3
                get_local $l2
                i64.const 4503599627370495
                i64.and
                i64.const 4503599627370496
                i64.or
                set_local $l1
                get_local $l5
                i32.eqz
                br_if $B2
                br $B1
              end
              get_local $p0
              get_local $p1
              f64.mul
              tee_local $p1
              get_local $p1
              f64.div
              return
            end
            get_local $p0
            f64.const 0x0p+0 (;=0;)
            f64.mul
            get_local $p0
            get_local $l4
            get_local $l1
            i64.eq
            select
            return
          end
          i32.const 0
          set_local $l3
          block $B6
            get_local $l2
            i64.const 12
            i64.shl
            tee_local $l1
            i64.const 0
            i64.lt_s
            br_if $B6
            loop $L7
              get_local $l3
              i32.const -1
              i32.add
              set_local $l3
              get_local $l1
              i64.const 1
              i64.shl
              tee_local $l1
              i64.const -1
              i64.gt_s
              br_if $L7
            end
          end
          get_local $l2
          i32.const 1
          get_local $l3
          i32.sub
          i64.extend_u/i32
          i64.shl
          set_local $l1
          get_local $l5
          br_if $B1
        end
        i32.const 0
        set_local $l5
        block $B8
          get_local $l0
          i64.const 12
          i64.shl
          tee_local $l4
          i64.const 0
          i64.lt_s
          br_if $B8
          loop $L9
            get_local $l5
            i32.const -1
            i32.add
            set_local $l5
            get_local $l4
            i64.const 1
            i64.shl
            tee_local $l4
            i64.const -1
            i64.gt_s
            br_if $L9
          end
        end
        get_local $l0
        i32.const 1
        get_local $l5
        i32.sub
        i64.extend_u/i32
        i64.shl
        set_local $l0
        br $B0
      end
      get_local $l0
      i64.const 4503599627370495
      i64.and
      i64.const 4503599627370496
      i64.or
      set_local $l0
    end
    get_local $l1
    get_local $l0
    i64.sub
    tee_local $l4
    i64.const -1
    i64.gt_s
    set_local $l6
    block $B10
      block $B11
        block $B12
          get_local $l3
          get_local $l5
          i32.le_s
          br_if $B12
          loop $L13
            block $B14
              get_local $l6
              i32.const 1
              i32.and
              i32.eqz
              br_if $B14
              get_local $l4
              set_local $l1
              get_local $l4
              i64.const 0
              i64.eq
              br_if $B11
            end
            get_local $l1
            i64.const 1
            i64.shl
            tee_local $l1
            get_local $l0
            i64.sub
            tee_local $l4
            i64.const -1
            i64.gt_s
            set_local $l6
            get_local $l3
            i32.const -1
            i32.add
            tee_local $l3
            get_local $l5
            i32.gt_s
            br_if $L13
          end
        end
        block $B15
          get_local $l6
          i32.eqz
          br_if $B15
          get_local $l4
          set_local $l1
          get_local $l4
          i64.const 0
          i64.eq
          br_if $B10
        end
        block $B16
          get_local $l1
          i64.const 4503599627370495
          i64.gt_u
          br_if $B16
          loop $L17
            get_local $l3
            i32.const -1
            i32.add
            set_local $l3
            get_local $l1
            i64.const 1
            i64.shl
            tee_local $l1
            i64.const 4503599627370496
            i64.lt_u
            br_if $L17
          end
        end
        get_local $l2
        i64.const -9223372036854775808
        i64.and
        set_local $l4
        block $B18
          get_local $l3
          i32.const 1
          i32.lt_s
          br_if $B18
          get_local $l1
          i64.const -4503599627370496
          i64.add
          get_local $l3
          i64.extend_u/i32
          i64.const 52
          i64.shl
          i64.or
          get_local $l4
          i64.or
          f64.reinterpret/i64
          return
        end
        get_local $l1
        i32.const 1
        get_local $l3
        i32.sub
        i64.extend_u/i32
        i64.shr_u
        get_local $l4
        i64.or
        f64.reinterpret/i64
        return
      end
      get_local $p0
      f64.const 0x0p+0 (;=0;)
      f64.mul
      return
    end
    get_local $p0
    f64.const 0x0p+0 (;=0;)
    f64.mul)
  (table $T0 1 1 anyfunc)
  (memory $memory (export "memory") 2)
  (global $g0 (mut i32) (i32.const 66560))
  (global $__heap_base (export "__heap_base") i32 (i32.const 66560))
  (global $__data_end (export "__data_end") i32 (i32.const 1024)))
captbaritone commented 4 years ago

Here's the assembly used in the actual implementation: https://github.com/WACUP/vis_milk2/blob/de9625a89e724afe23ed273b96b8e48496095b6c/ns-eel2/asm-nseel-x86-gcc.c#L507-L531

captbaritone commented 4 years ago
void nseel_asm_mod(void)
{
  __asm__(
    "fld" EEL_F_SUFFIX " (%edi)\n"
    "fld" EEL_F_SUFFIX " (%eax)\n"
    "fabs\n"
    "fistpl (%esi)\n"
    "fabs\n"
    "fistpl 4(%esi)\n"
    "xorl %edx, %edx\n"
#ifdef TARGET_X64
    "subl %eax, %eax\n"
#endif
    "cmpl $0, (%esi)\n"
    "je 0f\n" // skip devide, set return to 0
    "movl 4(%esi), %eax\n"
    "divl (%esi)\n"
    "0:\n"
    "movl %edx, (%esi)\n"
    "fildl (%esi)\n"
    "movl %esi, %eax\n"
    "fstp" EEL_F_SUFFIX " (%esi)\n"
    "addl $" EEL_F_SSTR ", %esi\n"
  );
}
captbaritone commented 3 years ago

Auto-close was due to a typo in commit message