authorgravatar for jeamsblue@gmail.comKoki Ueha <jeamsblue@gmail.com> 2025-06-15 01:05:58+00:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-06-15 04:01:43-04:00
log878b7b80c15d4b9a894f6ab1d4e8753de77568ad
treedb26c68ae9e0da28fefba8c0b2b2f917655bbbdb
parent3ce8d19f76690afe21b77651cffef9a9866cbf30

libc: Prevent FCSEL instruction from being used to avoid raising an unintended exception

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 {
4949 if (ix <= 0x3f490fda) { // |x| ~<= pi/4
5050 if (ix < 0x39800000) { // |x| < 2**-12
5151 // 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 }
5359 return x;
5460 }
5561 return trig.__sindf(x);
......@@ -98,7 +104,13 @@ pub fn sin(x: f64) callconv(.c) f64 {
98104 if (ix <= 0x3fe921fb) {
99105 if (ix < 0x3e500000) { // |x| < 2**-26
100106 // 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 }
102114 return x;
103115 }
104116 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 {
4646 // |x| < 2**-12
4747 if (ix < 0x39800000) {
4848 // 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 }
5056 r_sin.* = x;
5157 r_cos.* = 1.0;
5258 return;
......@@ -134,7 +140,13 @@ pub fn sincos(x: f64, r_sin: *f64, r_cos: *f64) callconv(.c) void {
134140 // if |x| < 2**-27 * sqrt(2)
135141 if (ix < 0x3e46a09e) {
136142 // 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 }
138150 r_sin.* = x;
139151 r_cos.* = 1.0;
140152 return;
lib/compiler_rt/tan.zig+14-2
......@@ -51,7 +51,13 @@ pub fn tanf(x: f32) callconv(.c) f32 {
5151 if (ix <= 0x3f490fda) { // |x| ~<= pi/4
5252 if (ix < 0x39800000) { // |x| < 2**-12
5353 // 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 }
5561 return x;
5662 }
5763 return kernel.__tandf(x, false);
......@@ -89,7 +95,13 @@ pub fn tan(x: f64) callconv(.c) f64 {
8995 if (ix <= 0x3fe921fb) {
9096 if (ix < 0x3e400000) { // |x| < 2**-27
9197 // 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 }
93105 return x;
94106 }
95107 return kernel.__tan(x, 0.0, false);