1//
2// Copyright (c) 2020 The Khronos Group Inc.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//    http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include <math.h>
18#include <stdio.h>
19
20#include "CL/cl_half.h"
21
22union FI {
23  float f;
24  uint32_t i;
25};
26
27int test_half_to_float(cl_half h, cl_float ref)
28{
29  cl_float f = cl_half_to_float(h);
30  if (f != ref) {
31    union FI f_i, ref_i;
32    f_i.f = f;
33    ref_i.f = ref;
34    printf("\nERROR: converting 0x%04x to float: expected 0x%08x, got 0x%08x\n",
35           h, ref_i.i, f_i.i);
36    return 0;
37  }
38  return 1;
39}
40
41int test_half_from_float(cl_float f, cl_half ref,
42                         cl_half_rounding_mode mode, const char *mode_str)
43{
44  cl_half h = cl_half_from_float(f, mode);
45  if (h != ref) {
46    union FI f_i;
47    f_i.f = f;
48    printf(
49      "\nERROR: converting 0x%08x to half (%s): expected 0x%04x, got 0x%04x\n",
50      f_i.i, mode_str, ref, h);
51    return 0;
52  }
53  return 1;
54}
55
56int main(void)
57{
58  printf("\nChecking conversion routines in cl_half.h\n");
59
60#define CHECK_TO_FLOAT(h, ref)                     \
61  if (!test_half_to_float(h, ref)) {               \
62    printf("Test failed on line %d.\n", __LINE__); \
63    return 1;                                      \
64  }
65
66  // Check a handful of values
67  CHECK_TO_FLOAT(0x0000, 0.f);
68  CHECK_TO_FLOAT(0x3c00, 1.f);
69  CHECK_TO_FLOAT(0xbc00, -1.f);
70  CHECK_TO_FLOAT(0x7c00, INFINITY);
71  CHECK_TO_FLOAT(0xfc00, -INFINITY);
72
73
74#define CHECK_FROM_FLOAT(f, ref, mode)                         \
75  if (!test_half_from_float(f, ref, CL_HALF_##mode, #mode)) {  \
76    printf("Test failed on line %d.\n", __LINE__);             \
77    return 1;                                                  \
78  }
79
80  // Check a handful of normal values
81  CHECK_FROM_FLOAT(0.f, 0x0000, RTE);
82  CHECK_FROM_FLOAT(1.f, 0x3c00, RTE);
83  CHECK_FROM_FLOAT(-1.f, 0xbc00, RTE);
84  CHECK_FROM_FLOAT(CL_HALF_MAX, 0x7bff, RTE);
85  CHECK_FROM_FLOAT(CL_HALF_MIN, 0x0400, RTE);
86
87  // Check huge positive (non-inf) values round properly
88  CHECK_FROM_FLOAT(CL_HALF_MAX + 1000.f, 0x7c00, RTE);
89  CHECK_FROM_FLOAT(CL_HALF_MAX + 1000.f, 0x7c00, RTP);
90  CHECK_FROM_FLOAT(CL_HALF_MAX + 1000.f, 0x7bff, RTN);
91  CHECK_FROM_FLOAT(CL_HALF_MAX + 1000.f, 0x7bff, RTZ);
92
93  // Check huge negative (non-inf) values round properly
94  CHECK_FROM_FLOAT(-(CL_HALF_MAX + 1000.f), 0xfc00, RTE);
95  CHECK_FROM_FLOAT(-(CL_HALF_MAX + 1000.f), 0xfbff, RTP);
96  CHECK_FROM_FLOAT(-(CL_HALF_MAX + 1000.f), 0xfc00, RTN);
97  CHECK_FROM_FLOAT(-(CL_HALF_MAX + 1000.f), 0xfbff, RTZ);
98#if 0 // Hexadecimal float constant is C++17
99  // Check tiny positive values round properly
100  CHECK_FROM_FLOAT(0x1.000000p-25, 0x0000, RTE);
101  CHECK_FROM_FLOAT(0x1.000000p-25, 0x0001, RTP);
102  CHECK_FROM_FLOAT(0x1.000000p-25, 0x0000, RTN);
103  CHECK_FROM_FLOAT(0x1.000000p-25, 0x0000, RTZ);
104
105  // Check tiny negative values round properly
106  CHECK_FROM_FLOAT(-0x1.000000p-25, 0x8000, RTE);
107  CHECK_FROM_FLOAT(-0x1.000000p-25, 0x8000, RTP);
108  CHECK_FROM_FLOAT(-0x1.000000p-25, 0x8001, RTN);
109  CHECK_FROM_FLOAT(-0x1.000000p-25, 0x8000, RTZ);
110#else
111  // Check tiny positive values round properly
112  CHECK_FROM_FLOAT(2.98023223876953125e-08, 0x0000, RTE);
113  CHECK_FROM_FLOAT(2.98023223876953125e-08, 0x0001, RTP);
114  CHECK_FROM_FLOAT(2.98023223876953125e-08, 0x0000, RTN);
115  CHECK_FROM_FLOAT(2.98023223876953125e-08, 0x0000, RTZ);
116
117  // Check tiny negative values round properly
118  CHECK_FROM_FLOAT(-2.98023223876953125e-08, 0x8000, RTE);
119  CHECK_FROM_FLOAT(-2.98023223876953125e-08, 0x8000, RTP);
120  CHECK_FROM_FLOAT(-2.98023223876953125e-08, 0x8001, RTN);
121  CHECK_FROM_FLOAT(-2.98023223876953125e-08, 0x8000, RTZ);
122#endif
123  printf("\nAll tests passed!\n");
124
125  return 0;
126}
127