| author | |
| committer | |
| log | 878b7b80c15d4b9a894f6ab1d4e8753de77568ad |
| tree | db26c68ae9e0da28fefba8c0b2b2f917655bbbdb |
| parent | 3ce8d19f76690afe21b77651cffef9a9866cbf30 |
If you write an if expression in mem.doNotOptimizeAway like
doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120);,
FCSEL instruction is used on AArch64.
FCSEL instruction selects one of the two registers according to
the condition and copies its value.
In this example, `x / 0x1p120` and `x + 0x1p120` are expressions
that raise different floating-point exceptions.
However, since both are actually evaluated before the FCSEL
instruction, the exception not intended by the programmer may
also be raised.
To prevent FCSEL instruction from being used here, this commit
splits doNotOptimizeAway in two.3 files changed, 42 insertions(+), 6 deletions(-)
lib/compiler_rt/sin.zig+14-2| ... | ... | @@ -49,7 +49,13 @@ pub fn sinf(x: f32) callconv(.c) f32 { |
| 49 | 49 | if (ix <= 0x3f490fda) { // |x| ~<= pi/4 |
| 50 | 50 | if (ix < 0x39800000) { // |x| < 2**-12 |
| 51 | 51 | // raise inexact if x!=0 and underflow if subnormal |
| 52 | if (common.want_float_exceptions) mem.doNotOptimizeAway(if (ix < 0x00800000) x / 0x1p120 else x + 0x1p120); | |
| 52 | if (common.want_float_exceptions) { | |
| 53 | if (ix < 0x00800000) { | |
| 54 | mem.doNotOptimizeAway(x / 0x1p120); | |
| 55 | } else { | |
| 56 | mem.doNotOptimizeAway(x + 0x1p120); | |
| 57 | } | |
| 58 | } | |
| 53 | 59 | return x; |
| 54 | 60 | } |
| 55 | 61 | return trig.__sindf(x); |
| ... | ... | @@ -98,7 +104,13 @@ pub fn sin(x: f64) callconv(.c) f64 { |
| 98 | 104 | if (ix <= 0x3fe921fb) { |
| 99 | 105 | if (ix < 0x3e500000) { // |x| < 2**-26 |
| 100 | 106 | // raise inexact if x != 0 and underflow if subnormal |
| 101 | if (common.want_float_exceptions) mem.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120); | |
| 107 | if (common.want_float_exceptions) { | |
| 108 | if (ix < 0x00100000) { | |
| 109 | mem.doNotOptimizeAway(x / 0x1p120); | |
| 110 | } else { | |
| 111 | mem.doNotOptimizeAway(x + 0x1p120); | |
| 112 | } | |
| 113 | } | |
| 102 | 114 | return x; |
| 103 | 115 | } |
| 104 | 116 | return trig.__sin(x, 0.0, 0); |
lib/compiler_rt/sincos.zig+14-2| ... | ... | @@ -46,7 +46,13 @@ pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void { |
| 46 | 46 | // |x| < 2**-12 |
| 47 | 47 | if (ix < 0x39800000) { |
| 48 | 48 | // raise inexact if x!=0 and underflow if subnormal |
| 49 | if (common.want_float_exceptions) mem.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120); | |
| 49 | if (common.want_float_exceptions) { | |
| 50 | if (ix < 0x00100000) { | |
| 51 | mem.doNotOptimizeAway(x / 0x1p120); | |
| 52 | } else { | |
| 53 | mem.doNotOptimizeAway(x + 0x1p120); | |
| 54 | } | |
| 55 | } | |
| 50 | 56 | r_sin.* = x; |
| 51 | 57 | r_cos.* = 1.0; |
| 52 | 58 | return; |
| ... | ... | @@ -134,7 +140,13 @@ pub fn sincos(x: f64, r_sin: *f64, r_cos: *f64) callconv(.c) void { |
| 134 | 140 | // if |x| < 2**-27 * sqrt(2) |
| 135 | 141 | if (ix < 0x3e46a09e) { |
| 136 | 142 | // raise inexact if x != 0 and underflow if subnormal |
| 137 | if (common.want_float_exceptions) mem.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120); | |
| 143 | if (common.want_float_exceptions) { | |
| 144 | if (ix < 0x00100000) { | |
| 145 | mem.doNotOptimizeAway(x / 0x1p120); | |
| 146 | } else { | |
| 147 | mem.doNotOptimizeAway(x + 0x1p120); | |
| 148 | } | |
| 149 | } | |
| 138 | 150 | r_sin.* = x; |
| 139 | 151 | r_cos.* = 1.0; |
| 140 | 152 | return; |
lib/compiler_rt/tan.zig+14-2| ... | ... | @@ -51,7 +51,13 @@ pub fn tanf(x: f32) callconv(.c) f32 { |
| 51 | 51 | if (ix <= 0x3f490fda) { // |x| ~<= pi/4 |
| 52 | 52 | if (ix < 0x39800000) { // |x| < 2**-12 |
| 53 | 53 | // raise inexact if x!=0 and underflow if subnormal |
| 54 | if (common.want_float_exceptions) mem.doNotOptimizeAway(if (ix < 0x00800000) x / 0x1p120 else x + 0x1p120); | |
| 54 | if (common.want_float_exceptions) { | |
| 55 | if (ix < 0x00800000) { | |
| 56 | mem.doNotOptimizeAway(x / 0x1p120); | |
| 57 | } else { | |
| 58 | mem.doNotOptimizeAway(x + 0x1p120); | |
| 59 | } | |
| 60 | } | |
| 55 | 61 | return x; |
| 56 | 62 | } |
| 57 | 63 | return kernel.__tandf(x, false); |
| ... | ... | @@ -89,7 +95,13 @@ pub fn tan(x: f64) callconv(.c) f64 { |
| 89 | 95 | if (ix <= 0x3fe921fb) { |
| 90 | 96 | if (ix < 0x3e400000) { // |x| < 2**-27 |
| 91 | 97 | // raise inexact if x!=0 and underflow if subnormal |
| 92 | if (common.want_float_exceptions) mem.doNotOptimizeAway(if (ix < 0x00100000) x / 0x1p120 else x + 0x1p120); | |
| 98 | if (common.want_float_exceptions) { | |
| 99 | if (ix < 0x00100000) { | |
| 100 | mem.doNotOptimizeAway(x / 0x1p120); | |
| 101 | } else { | |
| 102 | mem.doNotOptimizeAway(x + 0x1p120); | |
| 103 | } | |
| 104 | } | |
| 93 | 105 | return x; |
| 94 | 106 | } |
| 95 | 107 | return kernel.__tan(x, 0.0, false); |