eel-wasm
eel-wasm copied to clipboard
Is our handling of % correct?
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)))
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
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"
);
}
Auto-close was due to a typo in commit message