180d59932Sopenharmony_ci//
280d59932Sopenharmony_ci// Copyright (c) 2020 The Khronos Group Inc.
380d59932Sopenharmony_ci//
480d59932Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
580d59932Sopenharmony_ci// you may not use this file except in compliance with the License.
680d59932Sopenharmony_ci// You may obtain a copy of the License at
780d59932Sopenharmony_ci//
880d59932Sopenharmony_ci//    http://www.apache.org/licenses/LICENSE-2.0
980d59932Sopenharmony_ci//
1080d59932Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
1180d59932Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
1280d59932Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1380d59932Sopenharmony_ci// See the License for the specific language governing permissions and
1480d59932Sopenharmony_ci// limitations under the License.
1580d59932Sopenharmony_ci//
1680d59932Sopenharmony_ci
1780d59932Sopenharmony_ci#include <math.h>
1880d59932Sopenharmony_ci#include <stdio.h>
1980d59932Sopenharmony_ci
2080d59932Sopenharmony_ci#include "CL/cl_half.h"
2180d59932Sopenharmony_ci
2280d59932Sopenharmony_ciunion FI {
2380d59932Sopenharmony_ci  float f;
2480d59932Sopenharmony_ci  uint32_t i;
2580d59932Sopenharmony_ci};
2680d59932Sopenharmony_ci
2780d59932Sopenharmony_ciint test_half_to_float(cl_half h, cl_float ref)
2880d59932Sopenharmony_ci{
2980d59932Sopenharmony_ci  cl_float f = cl_half_to_float(h);
3080d59932Sopenharmony_ci  if (f != ref) {
3180d59932Sopenharmony_ci    union FI f_i, ref_i;
3280d59932Sopenharmony_ci    f_i.f = f;
3380d59932Sopenharmony_ci    ref_i.f = ref;
3480d59932Sopenharmony_ci    printf("\nERROR: converting 0x%04x to float: expected 0x%08x, got 0x%08x\n",
3580d59932Sopenharmony_ci           h, ref_i.i, f_i.i);
3680d59932Sopenharmony_ci    return 0;
3780d59932Sopenharmony_ci  }
3880d59932Sopenharmony_ci  return 1;
3980d59932Sopenharmony_ci}
4080d59932Sopenharmony_ci
4180d59932Sopenharmony_ciint test_half_from_float(cl_float f, cl_half ref,
4280d59932Sopenharmony_ci                         cl_half_rounding_mode mode, const char *mode_str)
4380d59932Sopenharmony_ci{
4480d59932Sopenharmony_ci  cl_half h = cl_half_from_float(f, mode);
4580d59932Sopenharmony_ci  if (h != ref) {
4680d59932Sopenharmony_ci    union FI f_i;
4780d59932Sopenharmony_ci    f_i.f = f;
4880d59932Sopenharmony_ci    printf(
4980d59932Sopenharmony_ci      "\nERROR: converting 0x%08x to half (%s): expected 0x%04x, got 0x%04x\n",
5080d59932Sopenharmony_ci      f_i.i, mode_str, ref, h);
5180d59932Sopenharmony_ci    return 0;
5280d59932Sopenharmony_ci  }
5380d59932Sopenharmony_ci  return 1;
5480d59932Sopenharmony_ci}
5580d59932Sopenharmony_ci
5680d59932Sopenharmony_ciint main(void)
5780d59932Sopenharmony_ci{
5880d59932Sopenharmony_ci  printf("\nChecking conversion routines in cl_half.h\n");
5980d59932Sopenharmony_ci
6080d59932Sopenharmony_ci#define CHECK_TO_FLOAT(h, ref)                     \
6180d59932Sopenharmony_ci  if (!test_half_to_float(h, ref)) {               \
6280d59932Sopenharmony_ci    printf("Test failed on line %d.\n", __LINE__); \
6380d59932Sopenharmony_ci    return 1;                                      \
6480d59932Sopenharmony_ci  }
6580d59932Sopenharmony_ci
6680d59932Sopenharmony_ci  // Check a handful of values
6780d59932Sopenharmony_ci  CHECK_TO_FLOAT(0x0000, 0.f);
6880d59932Sopenharmony_ci  CHECK_TO_FLOAT(0x3c00, 1.f);
6980d59932Sopenharmony_ci  CHECK_TO_FLOAT(0xbc00, -1.f);
7080d59932Sopenharmony_ci  CHECK_TO_FLOAT(0x7c00, INFINITY);
7180d59932Sopenharmony_ci  CHECK_TO_FLOAT(0xfc00, -INFINITY);
7280d59932Sopenharmony_ci
7380d59932Sopenharmony_ci
7480d59932Sopenharmony_ci#define CHECK_FROM_FLOAT(f, ref, mode)                         \
7580d59932Sopenharmony_ci  if (!test_half_from_float(f, ref, CL_HALF_##mode, #mode)) {  \
7680d59932Sopenharmony_ci    printf("Test failed on line %d.\n", __LINE__);             \
7780d59932Sopenharmony_ci    return 1;                                                  \
7880d59932Sopenharmony_ci  }
7980d59932Sopenharmony_ci
8080d59932Sopenharmony_ci  // Check a handful of normal values
8180d59932Sopenharmony_ci  CHECK_FROM_FLOAT(0.f, 0x0000, RTE);
8280d59932Sopenharmony_ci  CHECK_FROM_FLOAT(1.f, 0x3c00, RTE);
8380d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-1.f, 0xbc00, RTE);
8480d59932Sopenharmony_ci  CHECK_FROM_FLOAT(CL_HALF_MAX, 0x7bff, RTE);
8580d59932Sopenharmony_ci  CHECK_FROM_FLOAT(CL_HALF_MIN, 0x0400, RTE);
8680d59932Sopenharmony_ci
8780d59932Sopenharmony_ci  // Check huge positive (non-inf) values round properly
8880d59932Sopenharmony_ci  CHECK_FROM_FLOAT(CL_HALF_MAX + 1000.f, 0x7c00, RTE);
8980d59932Sopenharmony_ci  CHECK_FROM_FLOAT(CL_HALF_MAX + 1000.f, 0x7c00, RTP);
9080d59932Sopenharmony_ci  CHECK_FROM_FLOAT(CL_HALF_MAX + 1000.f, 0x7bff, RTN);
9180d59932Sopenharmony_ci  CHECK_FROM_FLOAT(CL_HALF_MAX + 1000.f, 0x7bff, RTZ);
9280d59932Sopenharmony_ci
9380d59932Sopenharmony_ci  // Check huge negative (non-inf) values round properly
9480d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-(CL_HALF_MAX + 1000.f), 0xfc00, RTE);
9580d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-(CL_HALF_MAX + 1000.f), 0xfbff, RTP);
9680d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-(CL_HALF_MAX + 1000.f), 0xfc00, RTN);
9780d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-(CL_HALF_MAX + 1000.f), 0xfbff, RTZ);
9880d59932Sopenharmony_ci#if 0 // Hexadecimal float constant is C++17
9980d59932Sopenharmony_ci  // Check tiny positive values round properly
10080d59932Sopenharmony_ci  CHECK_FROM_FLOAT(0x1.000000p-25, 0x0000, RTE);
10180d59932Sopenharmony_ci  CHECK_FROM_FLOAT(0x1.000000p-25, 0x0001, RTP);
10280d59932Sopenharmony_ci  CHECK_FROM_FLOAT(0x1.000000p-25, 0x0000, RTN);
10380d59932Sopenharmony_ci  CHECK_FROM_FLOAT(0x1.000000p-25, 0x0000, RTZ);
10480d59932Sopenharmony_ci
10580d59932Sopenharmony_ci  // Check tiny negative values round properly
10680d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-0x1.000000p-25, 0x8000, RTE);
10780d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-0x1.000000p-25, 0x8000, RTP);
10880d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-0x1.000000p-25, 0x8001, RTN);
10980d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-0x1.000000p-25, 0x8000, RTZ);
11080d59932Sopenharmony_ci#else
11180d59932Sopenharmony_ci  // Check tiny positive values round properly
11280d59932Sopenharmony_ci  CHECK_FROM_FLOAT(2.98023223876953125e-08, 0x0000, RTE);
11380d59932Sopenharmony_ci  CHECK_FROM_FLOAT(2.98023223876953125e-08, 0x0001, RTP);
11480d59932Sopenharmony_ci  CHECK_FROM_FLOAT(2.98023223876953125e-08, 0x0000, RTN);
11580d59932Sopenharmony_ci  CHECK_FROM_FLOAT(2.98023223876953125e-08, 0x0000, RTZ);
11680d59932Sopenharmony_ci
11780d59932Sopenharmony_ci  // Check tiny negative values round properly
11880d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-2.98023223876953125e-08, 0x8000, RTE);
11980d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-2.98023223876953125e-08, 0x8000, RTP);
12080d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-2.98023223876953125e-08, 0x8001, RTN);
12180d59932Sopenharmony_ci  CHECK_FROM_FLOAT(-2.98023223876953125e-08, 0x8000, RTZ);
12280d59932Sopenharmony_ci#endif
12380d59932Sopenharmony_ci  printf("\nAll tests passed!\n");
12480d59932Sopenharmony_ci
12580d59932Sopenharmony_ci  return 0;
12680d59932Sopenharmony_ci}
127