1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
From: Simon McVittie <smcv@debian.org>
Date: Sat, 31 Aug 2024 10:13:48 +0100
Subject: gtkcssnumbervalue: Don't use fesetround() on softfloat
Older ARM CPUs have to emulate floating-point in software, and do not
implement rounding modes other than the default, FE_TONEAREST.
Implement nearbyint() the hard way when targeting an affected platform.
Bug-Debian: https://bugs.debian.org/1079545
Signed-off-by: Simon McVittie <smcv@debian.org>
[daniel@makrotopia.org: also handle MIPS and PowerPC soft-float]
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
gtk/gtkcssnumbervalue.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
--- a/gtk/gtkcssnumbervalue.c
+++ b/gtk/gtkcssnumbervalue.c
@@ -1846,11 +1846,21 @@ gtk_css_dimension_value_is_zero (const G
return value->dimension.value == 0;
}
+#if (defined(__arm__) && !defined(__ARM_PCS_VFP)) || defined(__mips_soft_float) || defined(_SOFT_FLOAT)
+/* Floating-point emulated in software. Setting the rounding mode to
+ * anything other than FE_TONEAREST doesn't work */
+#undef HAVE_WORKING_FESETROUND
+#else
+#define HAVE_WORKING_FESETROUND
+#endif
+
static double
_round (guint mode, double a, double b)
{
+#ifdef HAVE_WORKING_FESETROUND
int old_mode;
int modes[] = { FE_TONEAREST, FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO };
+#endif
double result;
if (b == 0)
@@ -1880,12 +1890,36 @@ _round (guint mode, double a, double b)
}
}
+#ifdef HAVE_WORKING_FESETROUND
old_mode = fegetround ();
fesetround (modes[mode]);
result = nearbyint (a/b) * b;
fesetround (old_mode);
+#else
+ result = a / b;
+
+ switch (mode)
+ {
+ case ROUND_NEAREST:
+ result = round (result);
+ break;
+ case ROUND_TO_ZERO:
+ result = (result >= 0 ? floor (result) : ceil (result));
+ break;
+ case ROUND_UP:
+ result = ceil (result);
+ break;
+ case ROUND_DOWN:
+ result = floor (result);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ result *= b;
+#endif
return result;
}
|