Skip to content

Commit 92a149d

Browse files
authored
[UnitTests] Tests for __builtin_flt_rounds and __builtin_set_flt_rounds (#48)
These tests check setting and querying rounding mode using builtin functions. Pull request: #48
1 parent 7e54b7b commit 92a149d

File tree

10 files changed

+434
-1
lines changed

10 files changed

+434
-1
lines changed

MultiSource/UnitTests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ add_subdirectory(C++11)
22
if(ARCH STREQUAL "Mips")
33
add_subdirectory(Mips)
44
endif()
5+
add_subdirectory(Float)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Tests in Rounding can run only if the target implements builtin functions for
2+
# manipulation of rounding mode.
3+
set(SUPPORTED_ARCHS x86 AArch64)
4+
if(ARCH IN_LIST SUPPORTED_ARCHS)
5+
add_subdirectory(rounding)
6+
endif()

MultiSource/UnitTests/Float/Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# MultiSource/UnitTests/Float Makefile: Build all subdirectories automatically
2+
3+
LEVEL = ../../..
4+
5+
PARALLEL_DIRS :=
6+
7+
# Tests in 'rounding' can run only if the target implements builtin functions
8+
# for rounding mode manipulation.
9+
ifneq (, $filter($(ARCH), X86_64 AArch64)
10+
PARALLEL_DIRS += rounding
11+
endif
12+
13+
include $(LEVEL)/Makefile.config
14+
include $(LEVEL)/Makefile.programs
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
llvm_multisource(rounding)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
LEVEL = ../../../..
2+
PROG = rounding
3+
LDFLAGS =
4+
include ../../../Makefile.multisrc
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===--- rounding.c --Tests for changing rounding mode ----------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Helper function for rounding mode tests. It is intended for making a dynamic
10+
// rounding mode, unknown at compile time, from a constant values. It is in a
11+
// separate translation unit to prevent constant folding.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "rounding.h"
16+
17+
int get_rounding_mode(int rm) {
18+
return rm;
19+
}
Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
//===--- rounding.c --Tests for changing rounding mode ----------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Checks setting/getting rounding mode using builtin functions
10+
// __builtin_flt_rounds and __builtin_set_flt_rounds.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "rounding.h"
15+
#include <stdio.h>
16+
17+
#ifdef FLOAT_AVAILABLE
18+
// The "base" even values. They can be represented exactly and the lest
19+
// significant bit of the significand is zero.
20+
float PosEvenF = 0x1p+0F;
21+
float NegEvenF = -0x1p+0F;
22+
23+
// The "base" odd values. They can be represented exactly and the lest
24+
// significant bit of the significand is one.
25+
float PosOddF = 0x1.000002p+0F;
26+
float NegOddF = -0x1.000002p+0F;
27+
28+
// The values closest to the base ones with higher magnitude.
29+
float NextToPosEvenF = 0x1.000002p+0F;
30+
float NextToNegEvenF = -0x1.000002p+0F;
31+
float NextToPosOddF = 0x1.000004p+0F;
32+
float NextToNegOddF = -0x1.000004p+0F;
33+
34+
// Value that is half of the lest significant bit of the "base" value.
35+
float PosDeltaF = 0x1.0p-24F;
36+
float NegDeltaF = -0x1.0p-24F;
37+
#endif
38+
39+
#ifdef DOUBLE_AVAILABLE
40+
double PosEvenD = 0x1p+0;
41+
double NegEvenD = -0x1p+0;
42+
43+
double PosOddD = 0x1.0000000000001p+0;
44+
double NegOddD = -0x1.0000000000001p+0;
45+
46+
double NextToPosEvenD = 0x1.0000000000001p+0;
47+
double NextToNegEvenD = -0x1.0000000000001p+0;
48+
double NextToPosOddD = 0x1.0000000000002p+0;
49+
double NextToNegOddD = -0x1.0000000000002p+0;
50+
51+
double PosDeltaD = 0x1.0p-52;
52+
double NegDeltaD = -0x1.0p-52;
53+
#endif
54+
55+
// Check macros. They may be overriden to implement different reaction on
56+
// broken condition, rather that printing a message.
57+
58+
#ifndef REPORT_STAGE
59+
#define REPORT_STAGE(x) printf(x)
60+
#endif
61+
62+
#ifndef CHECK_INT_EQ
63+
#define CHECK_INT_EQ(VExp, VAct) \
64+
if (VExp != VAct) { \
65+
printf("Failure on line %i - expected: %d, actual: %d\n", \
66+
__LINE__, VExp, VAct); \
67+
}
68+
#endif
69+
70+
#ifdef FLOAT_AVAILABLE
71+
#ifndef CHECK_FLT_EQ
72+
#define CHECK_FLT_EQ(VExp, VAct) \
73+
if (VExp != VAct) { \
74+
printf("Failure on line %i - expected: %a, actual: %a\n", \
75+
__LINE__, VExp, VAct); \
76+
}
77+
#endif
78+
#endif
79+
80+
#ifdef DOUBLE_AVAILABLE
81+
#ifndef CHECK_DBL_EQ
82+
#define CHECK_DBL_EQ(VExp, VAct) \
83+
if (VExp != VAct) { \
84+
printf("Failure on line %i - expected: %la, actual: %la\n", \
85+
__LINE__, VExp, VAct); \
86+
}
87+
#endif
88+
#endif
89+
90+
#ifdef FLOAT_AVAILABLE
91+
static void check_float_toward_zero() {
92+
float Res;
93+
94+
Res = PosEvenF + PosDeltaF; // Rounds down
95+
CHECK_FLT_EQ(PosEvenF, Res);
96+
Res = NegEvenF + NegDeltaF; // Rounsd up
97+
CHECK_FLT_EQ(NegEvenF, Res);
98+
99+
Res = PosOddF + PosDeltaF; // Rounsd down
100+
CHECK_FLT_EQ(PosOddF, Res);
101+
Res = NegOddF + NegDeltaF; // Rounsd up
102+
CHECK_FLT_EQ(NegOddF, Res);
103+
}
104+
105+
static void check_float_toward_nearest() {
106+
float Res;
107+
108+
Res = PosEvenF + PosDeltaF; // Rounsd down
109+
CHECK_FLT_EQ(PosEvenF, Res);
110+
Res = NegEvenF + NegDeltaF; // Pounds up
111+
CHECK_FLT_EQ(NegEvenF, Res);
112+
113+
Res = PosOddF + PosDeltaF; // Rounsd up
114+
CHECK_FLT_EQ(NextToPosOddF, Res);
115+
Res = NegOddF + NegDeltaF; // Rounds down
116+
CHECK_FLT_EQ(NextToNegOddF, Res);
117+
}
118+
119+
static void check_float_upward() {
120+
float Res;
121+
122+
Res = PosEvenF + PosDeltaF; // Rounsd up
123+
CHECK_FLT_EQ(NextToPosEvenF, Res);
124+
Res = NegEvenF + NegDeltaF; // Pounds up
125+
CHECK_FLT_EQ(NegEvenF, Res);
126+
127+
Res = PosOddF + PosDeltaF; // Rounsd up
128+
CHECK_FLT_EQ(NextToPosOddF, Res);
129+
Res = NegOddF + NegDeltaF; // Rounds up
130+
CHECK_FLT_EQ(NegOddF, Res);
131+
}
132+
133+
static void check_float_downward() {
134+
float Res;
135+
136+
Res = PosEvenF + PosDeltaF; // Rounsd down
137+
CHECK_FLT_EQ(PosEvenF, Res);
138+
Res = NegEvenF + NegDeltaF; // Pounds down
139+
CHECK_FLT_EQ(NextToNegEvenF, Res);
140+
141+
Res = PosOddF + PosDeltaF; // Rounsd down
142+
CHECK_FLT_EQ(PosOddF, Res);
143+
Res = NegOddF + NegDeltaF; // Rounds down
144+
CHECK_FLT_EQ(NextToNegOddF, Res);
145+
}
146+
147+
static void check_float() {
148+
#pragma STDC FENV_ACCESS ON
149+
150+
REPORT_STAGE("Checking float\n");
151+
float Res;
152+
int RM;
153+
154+
REPORT_STAGE(" towardzero\n");
155+
__builtin_set_flt_rounds(ROUNDING_TOWARDZERO);
156+
RM = __builtin_flt_rounds();
157+
CHECK_INT_EQ(ROUNDING_TOWARDZERO, RM);
158+
check_float_toward_zero();
159+
160+
REPORT_STAGE(" tonearest\n");
161+
__builtin_set_flt_rounds(ROUNDING_TONEAREST);
162+
RM = __builtin_flt_rounds();
163+
CHECK_INT_EQ(ROUNDING_TONEAREST, RM);
164+
check_float_toward_nearest();
165+
166+
REPORT_STAGE(" upward\n");
167+
__builtin_set_flt_rounds(ROUNDING_UPWARD);
168+
RM = __builtin_flt_rounds();
169+
CHECK_INT_EQ(ROUNDING_UPWARD, RM);
170+
check_float_upward();
171+
172+
REPORT_STAGE(" downward\n");
173+
__builtin_set_flt_rounds(ROUNDING_DOWNWARD);
174+
RM = __builtin_flt_rounds();
175+
CHECK_INT_EQ(ROUNDING_DOWNWARD, RM);
176+
check_float_downward();
177+
178+
REPORT_STAGE(" towardzero (dynamic)\n");
179+
RM = get_rounding_mode(ROUNDING_TOWARDZERO);
180+
__builtin_set_flt_rounds(RM);
181+
RM = __builtin_flt_rounds();
182+
CHECK_INT_EQ(ROUNDING_TOWARDZERO, RM);
183+
check_float_toward_zero();
184+
185+
REPORT_STAGE(" tonearest (dynamic)\n");
186+
RM = get_rounding_mode(ROUNDING_TONEAREST);
187+
__builtin_set_flt_rounds(RM);
188+
RM = __builtin_flt_rounds();
189+
CHECK_INT_EQ(ROUNDING_TONEAREST, RM);
190+
check_float_toward_nearest();
191+
192+
REPORT_STAGE(" upward (dynamic)\n");
193+
RM = get_rounding_mode(ROUNDING_UPWARD);
194+
__builtin_set_flt_rounds(RM);
195+
RM = __builtin_flt_rounds();
196+
CHECK_INT_EQ(ROUNDING_UPWARD, RM);
197+
check_float_upward();
198+
199+
REPORT_STAGE(" downward (dynamic)\n");
200+
RM = get_rounding_mode(ROUNDING_DOWNWARD);
201+
__builtin_set_flt_rounds(RM);
202+
RM = __builtin_flt_rounds();
203+
CHECK_INT_EQ(ROUNDING_DOWNWARD, RM);
204+
check_float_downward();
205+
}
206+
#else
207+
static void check_float() {}
208+
#endif
209+
210+
#ifdef DOUBLE_AVAILABLE
211+
static void check_double_toward_zero() {
212+
double Res;
213+
214+
Res = PosEvenF + PosDeltaF; // Rounds down
215+
CHECK_DBL_EQ(PosEvenF, Res);
216+
Res = NegEvenF + NegDeltaF; // Rounsd up
217+
CHECK_DBL_EQ(NegEvenF, Res);
218+
219+
Res = PosOddF + PosDeltaF; // Rounsd down
220+
CHECK_DBL_EQ(PosOddF, Res);
221+
Res = NegOddF + NegDeltaF; // Rounsd up
222+
CHECK_DBL_EQ(NegOddF, Res);
223+
}
224+
225+
static void check_double_toward_nearest() {
226+
double Res;
227+
228+
Res = PosEvenF + PosDeltaF; // Rounsd down
229+
CHECK_DBL_EQ(PosEvenF, Res);
230+
Res = NegEvenF + NegDeltaF; // Pounds up
231+
CHECK_DBL_EQ(NegEvenF, Res);
232+
233+
Res = PosOddF + PosDeltaF; // Rounsd up
234+
CHECK_DBL_EQ(NextToPosOddF, Res);
235+
Res = NegOddF + NegDeltaF; // Rounds down
236+
CHECK_DBL_EQ(NextToNegOddF, Res);
237+
}
238+
239+
static void check_double_upward() {
240+
double Res;
241+
242+
Res = PosEvenF + PosDeltaF; // Rounsd up
243+
CHECK_DBL_EQ(NextToPosEvenF, Res);
244+
Res = NegEvenF + NegDeltaF; // Pounds up
245+
CHECK_DBL_EQ(NegEvenF, Res);
246+
247+
Res = PosOddF + PosDeltaF; // Rounsd up
248+
CHECK_DBL_EQ(NextToPosOddF, Res);
249+
Res = NegOddF + NegDeltaF; // Rounds up
250+
CHECK_DBL_EQ(NegOddF, Res);
251+
}
252+
253+
static void check_double_downward() {
254+
double Res;
255+
256+
Res = PosEvenF + PosDeltaF; // Rounsd down
257+
CHECK_DBL_EQ(PosEvenF, Res);
258+
Res = NegEvenF + NegDeltaF; // Pounds down
259+
CHECK_DBL_EQ(NextToNegEvenF, Res);
260+
261+
Res = PosOddF + PosDeltaF; // Rounsd down
262+
CHECK_DBL_EQ(PosOddF, Res);
263+
Res = NegOddF + NegDeltaF; // Rounds down
264+
CHECK_DBL_EQ(NextToNegOddF, Res);
265+
}
266+
267+
static void check_double() {
268+
#pragma STDC FENV_ACCESS ON
269+
270+
REPORT_STAGE("Checking double\n");
271+
double Res;
272+
int RM;
273+
274+
REPORT_STAGE(" towardzero\n");
275+
__builtin_set_flt_rounds(ROUNDING_TOWARDZERO);
276+
RM = __builtin_flt_rounds();
277+
CHECK_INT_EQ(ROUNDING_TOWARDZERO, RM);
278+
check_double_toward_zero();
279+
280+
REPORT_STAGE(" tonearest\n");
281+
__builtin_set_flt_rounds(ROUNDING_TONEAREST);
282+
RM = __builtin_flt_rounds();
283+
CHECK_INT_EQ(ROUNDING_TONEAREST, RM);
284+
check_double_toward_nearest();
285+
286+
REPORT_STAGE(" upward\n");
287+
__builtin_set_flt_rounds(ROUNDING_UPWARD);
288+
RM = __builtin_flt_rounds();
289+
CHECK_INT_EQ(ROUNDING_UPWARD, RM);
290+
check_double_upward();
291+
292+
REPORT_STAGE(" downward\n");
293+
__builtin_set_flt_rounds(ROUNDING_DOWNWARD);
294+
RM = __builtin_flt_rounds();
295+
CHECK_INT_EQ(ROUNDING_DOWNWARD, RM);
296+
check_double_downward();
297+
298+
REPORT_STAGE(" towardzero (dynamic)\n");
299+
RM = get_rounding_mode(ROUNDING_TOWARDZERO);
300+
__builtin_set_flt_rounds(RM);
301+
RM = __builtin_flt_rounds();
302+
CHECK_INT_EQ(ROUNDING_TOWARDZERO, RM);
303+
check_double_toward_zero();
304+
305+
REPORT_STAGE(" tonearest (dynamic)\n");
306+
RM = get_rounding_mode(ROUNDING_TONEAREST);
307+
__builtin_set_flt_rounds(RM);
308+
RM = __builtin_flt_rounds();
309+
CHECK_INT_EQ(ROUNDING_TONEAREST, RM);
310+
check_double_toward_nearest();
311+
312+
REPORT_STAGE(" upward (dynamic)\n");
313+
RM = get_rounding_mode(ROUNDING_UPWARD);
314+
__builtin_set_flt_rounds(RM);
315+
RM = __builtin_flt_rounds();
316+
CHECK_INT_EQ(ROUNDING_UPWARD, RM);
317+
check_double_upward();
318+
319+
REPORT_STAGE(" downward (dynamic)\n");
320+
RM = get_rounding_mode(ROUNDING_DOWNWARD);
321+
__builtin_set_flt_rounds(RM);
322+
RM = __builtin_flt_rounds();
323+
CHECK_INT_EQ(ROUNDING_DOWNWARD, RM);
324+
check_double_downward();
325+
}
326+
#else
327+
static void check_double() {}
328+
#endif
329+
330+
int main(int argc, char *argv[]) {
331+
REPORT_STAGE("Checking rounding\n");
332+
check_float();
333+
check_double();
334+
}

0 commit comments

Comments
 (0)