Skip to content

improve(math): Add fast path for x % 1.0 and x % -1.0 #1447

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

Merged
merged 2 commits into from
Sep 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions std/assembly/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1567,6 +1567,12 @@ export namespace NativeMath {
}

export function mod(x: f64, y: f64): f64 { // see: musl/src/math/fmod.c
if (builtin_abs<f64>(y) == 1.0) {
// x % 1, x % -1 ==> sign(x) * abs(x - 1.0 * trunc(x / 1.0))
// TODO: move this rule to compiler's optimization pass.
// It could be apply for any x % C_pot, where "C_pot" is pow of two const.
return builtin_copysign<f64>(x - builtin_trunc<f64>(x), x);
Copy link
Member Author

@MaxGraey MaxGraey Aug 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copysign necessary for handling -0.0 % 1.0 -> -0.0 edge case

}
var ux = reinterpret<u64>(x);
var uy = reinterpret<u64>(y);
var ex = <i64>(ux >> 52 & 0x7FF);
Expand Down Expand Up @@ -2871,6 +2877,12 @@ export namespace NativeMathf {
}

export function mod(x: f32, y: f32): f32 { // see: musl/src/math/fmodf.c
if (builtin_abs<f32>(y) == 1.0) {
// x % 1, x % -1 ==> sign(x) * abs(x - 1.0 * trunc(x / 1.0))
// TODO: move this rule to compiler's optimization pass.
// It could be apply for any x % C_pot, where "C_pot" is pow of two const.
return builtin_copysign<f32>(x - builtin_trunc<f32>(x), x);
}
var ux = reinterpret<u32>(x);
var uy = reinterpret<u32>(y);
var ex = <i32>(ux >> 23 & 0xFF);
Expand Down
289 changes: 8 additions & 281 deletions tests/compiler/binary.optimized.wat
Original file line number Diff line number Diff line change
Expand Up @@ -43,293 +43,20 @@
local.get $2
)
(func $~lib/math/NativeMathf.mod (param $0 f32) (result f32)
(local $1 i32)
(local $2 i32)
(local $3 i32)
(local $4 i32)
local.get $0
i32.reinterpret_f32
local.tee $1
i32.const -2147483648
i32.and
local.set $4
local.get $1
i32.const 23
i32.shr_u
i32.const 255
i32.and
local.tee $2
i32.const 255
i32.eq
if
local.get $0
local.get $0
f32.div
return
end
block $folding-inner0
local.get $1
i32.const 1
i32.shl
local.tee $3
i32.const 2130706432
i32.le_u
if
local.get $3
i32.const 2130706432
i32.eq
br_if $folding-inner0
local.get $0
return
end
local.get $2
if (result i32)
local.get $1
i32.const 8388607
i32.and
i32.const 8388608
i32.or
else
local.get $1
i32.const 1
local.get $2
local.get $1
i32.const 9
i32.shl
i32.clz
i32.sub
local.tee $2
i32.sub
i32.shl
end
local.set $1
loop $while-continue|0
local.get $2
i32.const 127
i32.gt_s
if
local.get $1
i32.const 8388608
i32.ge_u
if (result i32)
local.get $1
i32.const 8388608
i32.eq
br_if $folding-inner0
local.get $1
i32.const 8388608
i32.sub
else
local.get $1
end
i32.const 1
i32.shl
local.set $1
local.get $2
i32.const 1
i32.sub
local.set $2
br $while-continue|0
end
end
local.get $1
i32.const 8388608
i32.ge_u
if
local.get $1
i32.const 8388608
i32.eq
br_if $folding-inner0
local.get $1
i32.const 8388608
i32.sub
local.set $1
end
local.get $1
local.get $1
i32.const 8
i32.shl
i32.clz
local.tee $3
i32.shl
local.set $1
local.get $2
local.get $3
i32.sub
local.tee $2
i32.const 0
i32.gt_s
if (result i32)
local.get $1
i32.const 8388608
i32.sub
local.get $2
i32.const 23
i32.shl
i32.or
else
local.get $1
i32.const 1
local.get $2
i32.sub
i32.shr_u
end
local.get $4
i32.or
f32.reinterpret_i32
return
end
f32.const 0
local.get $0
f32.mul
f32.trunc
f32.sub
local.get $0
f32.copysign
)
(func $~lib/math/NativeMath.mod (param $0 f64) (result f64)
(local $1 i64)
(local $2 i64)
(local $3 i64)
(local $4 i64)
local.get $0
i64.reinterpret_f64
local.tee $1
i64.const 63
i64.shr_u
local.set $4
local.get $1
i64.const 52
i64.shr_u
i64.const 2047
i64.and
local.tee $2
i64.const 2047
i64.eq
if
local.get $0
local.get $0
f64.div
return
end
block $folding-inner0
local.get $1
i64.const 1
i64.shl
local.tee $3
i64.const 9214364837600034816
i64.le_u
if
local.get $3
i64.const 9214364837600034816
i64.eq
br_if $folding-inner0
local.get $0
return
end
local.get $2
i64.eqz
if (result i64)
local.get $1
i64.const 0
local.get $2
local.get $1
i64.const 12
i64.shl
i64.clz
i64.sub
local.tee $2
i64.sub
i64.const 1
i64.add
i64.shl
else
local.get $1
i64.const 4503599627370495
i64.and
i64.const 4503599627370496
i64.or
end
local.set $1
loop $while-continue|0
local.get $2
i64.const 1023
i64.gt_s
if
local.get $1
i64.const 4503599627370496
i64.ge_u
if (result i64)
local.get $1
i64.const 4503599627370496
i64.eq
br_if $folding-inner0
local.get $1
i64.const 4503599627370496
i64.sub
else
local.get $1
end
i64.const 1
i64.shl
local.set $1
local.get $2
i64.const 1
i64.sub
local.set $2
br $while-continue|0
end
end
local.get $1
i64.const 4503599627370496
i64.ge_u
if
local.get $1
i64.const 4503599627370496
i64.eq
br_if $folding-inner0
local.get $1
i64.const 4503599627370496
i64.sub
local.set $1
end
local.get $1
local.get $1
i64.const 11
i64.shl
i64.clz
local.tee $3
i64.shl
local.set $1
local.get $2
local.get $3
i64.sub
local.tee $2
i64.const 0
i64.gt_s
if (result i64)
local.get $1
i64.const 4503599627370496
i64.sub
local.get $2
i64.const 52
i64.shl
i64.or
else
local.get $1
i64.const 0
local.get $2
i64.sub
i64.const 1
i64.add
i64.shr_u
end
local.get $4
i64.const 63
i64.shl
i64.or
f64.reinterpret_i64
return
end
f64.const 0
local.get $0
f64.mul
f64.trunc
f64.sub
local.get $0
f64.copysign
)
(func $start:binary
global.get $binary/i
Expand Down
26 changes: 26 additions & 0 deletions tests/compiler/binary.untouched.wat
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,19 @@
(local $9 i32)
(local $10 i32)
(local $11 i32)
local.get $1
f32.abs
f32.const 1
f32.eq
if
local.get $0
local.get $0
f32.trunc
f32.sub
local.get $0
f32.copysign
return
end
local.get $0
i32.reinterpret_f32
local.set $2
Expand Down Expand Up @@ -2076,6 +2089,19 @@
(local $9 i64)
(local $10 i32)
(local $11 i64)
local.get $1
f64.abs
f64.const 1
f64.eq
if
local.get $0
local.get $0
f64.trunc
f64.sub
local.get $0
f64.copysign
return
end
local.get $0
i64.reinterpret_f64
local.set $2
Expand Down
Loading