43 lines · c
1//===-- fnan2.c - Handle single-precision NaN inputs to binary operation --===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This helper function is available for use by single-precision float10// arithmetic implementations to handle propagating NaNs from the input11// operands to the output, in a way that matches Arm hardware FP.12//13// On input, a and b are floating-point numbers in IEEE 754 encoding, and at14// least one of them must be a NaN. The return value is the correct output NaN.15//16// A signalling NaN in the input (with bit 22 clear) takes priority over any17// quiet NaN, and is adjusted on return by setting bit 22 to make it quiet. If18// both inputs are the same type of NaN then the first input takes priority:19// the input a is used instead of b.20//21//===----------------------------------------------------------------------===//22 23#include <stdint.h>24 25uint32_t __compiler_rt_fnan2(uint32_t a, uint32_t b) {26 // Make shifted-left copies of a and b to discard the sign bit. Then add 1 at27 // the bit position where the quiet vs signalling bit ended up. This squashes28 // all the signalling NaNs to the top of the range of 32-bit values, from29 // 0xff800001 to 0xffffffff inclusive; meanwhile, all the quiet NaN values30 // wrap round to the bottom, from 0 to 0x007fffff inclusive. So we can detect31 // a signalling NaN by asking if it's greater than 0xff800000, and a quiet32 // one by asking if it's less than 0x00800000.33 uint32_t aadj = (a << 1) + 0x00800000;34 uint32_t badj = (b << 1) + 0x00800000;35 if (aadj > 0xff800000) // a is a signalling NaN?36 return a | 0x00400000; // if so, return it with the quiet bit set37 if (badj > 0xff800000) // b is a signalling NaN?38 return b | 0x00400000; // if so, return it with the quiet bit set39 if (aadj < 0x00800000) // a is a quiet NaN?40 return a; // if so, return it41 return b; // otherwise we expect b must be a quiet NaN42}43