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 {...@@ -49,7 +49,13 @@ pub fn sinf(x: f32) callconv(.c) f32 {
49 if (ix <= 0x3f490fda) { // |x| ~<= pi/449 if (ix <= 0x3f490fda) { // |x| ~<= pi/4
50 if (ix < 0x39800000) { // |x| < 2**-1250 if (ix < 0x39800000) { // |x| < 2**-12
51 // raise inexact if x!=0 and underflow if subnormal51 // 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 return x;59 return x;
54 }60 }
55 return trig.__sindf(x);61 return trig.__sindf(x);
...@@ -98,7 +104,13 @@ pub fn sin(x: f64) callconv(.c) f64 {...@@ -98,7 +104,13 @@ pub fn sin(x: f64) callconv(.c) f64 {
98 if (ix <= 0x3fe921fb) {104 if (ix <= 0x3fe921fb) {
99 if (ix < 0x3e500000) { // |x| < 2**-26105 if (ix < 0x3e500000) { // |x| < 2**-26
100 // raise inexact if x != 0 and underflow if subnormal106 // 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 return x;114 return x;
103 }115 }
104 return trig.__sin(x, 0.0, 0);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,7 +46,13 @@ pub fn sincosf(x: f32, r_sin: *f32, r_cos: *f32) callconv(.c) void {
46 // |x| < 2**-1246 // |x| < 2**-12
47 if (ix < 0x39800000) {47 if (ix < 0x39800000) {
48 // raise inexact if x!=0 and underflow if subnormal48 // 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 r_sin.* = x;56 r_sin.* = x;
51 r_cos.* = 1.0;57 r_cos.* = 1.0;
52 return;58 return;
...@@ -134,7 +140,13 @@ pub fn sincos(x: f64, r_sin: *f64, r_cos: *f64) callconv(.c) void {...@@ -134,7 +140,13 @@ pub fn sincos(x: f64, r_sin: *f64, r_cos: *f64) callconv(.c) void {
134 // if |x| < 2**-27 * sqrt(2)140 // if |x| < 2**-27 * sqrt(2)
135 if (ix < 0x3e46a09e) {141 if (ix < 0x3e46a09e) {
136 // raise inexact if x != 0 and underflow if subnormal142 // 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 r_sin.* = x;150 r_sin.* = x;
139 r_cos.* = 1.0;151 r_cos.* = 1.0;
140 return;152 return;
lib/compiler_rt/tan.zig+14-2
...@@ -51,7 +51,13 @@ pub fn tanf(x: f32) callconv(.c) f32 {...@@ -51,7 +51,13 @@ pub fn tanf(x: f32) callconv(.c) f32 {
51 if (ix <= 0x3f490fda) { // |x| ~<= pi/451 if (ix <= 0x3f490fda) { // |x| ~<= pi/4
52 if (ix < 0x39800000) { // |x| < 2**-1252 if (ix < 0x39800000) { // |x| < 2**-12
53 // raise inexact if x!=0 and underflow if subnormal53 // 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 return x;61 return x;
56 }62 }
57 return kernel.__tandf(x, false);63 return kernel.__tandf(x, false);
...@@ -89,7 +95,13 @@ pub fn tan(x: f64) callconv(.c) f64 {...@@ -89,7 +95,13 @@ pub fn tan(x: f64) callconv(.c) f64 {
89 if (ix <= 0x3fe921fb) {95 if (ix <= 0x3fe921fb) {
90 if (ix < 0x3e400000) { // |x| < 2**-2796 if (ix < 0x3e400000) { // |x| < 2**-27
91 // raise inexact if x!=0 and underflow if subnormal97 // 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 return x;105 return x;
94 }106 }
95 return kernel.__tan(x, 0.0, false);107 return kernel.__tan(x, 0.0, false);