3#include "native/attributes.h"
7#ifndef FTZ_SHADER_INT64
8#define FTZ_SHADER_INT64 0
10#if FTZ_SHADER_INT64 != 0 && FTZ_SHADER_INT64 != 1
11#error "FTZ_SHADER_INT64 must be 0 or 1"
13#if !defined(__cplusplus) && !FTZ_SHADER_INT64
21namespace ftz {
namespace detail {
namespace math {
26 struct unsigned_word_product {
unsigned int low, high; };
27 native_constexpr
inline unsigned_word_product word_pair(
unsigned int low,
unsigned int high) {
28 unsigned_word_product r; r.low = low; r.high = high;
return r;
30 native_constexpr
inline unsigned_word_product word_pair(uint64_t value) {
31 return word_pair((
unsigned int)value, (
unsigned int)(value >> 32));
33 native_constexpr
inline uint64_t word_value(unsigned_word_product value) {
34 return (uint64_t(value.high) << 32) | uint64_t(value.low);
36 native_constexpr
inline unsigned_word_product unsigned_multiply_words(
unsigned int a,
unsigned int b) {
37 return word_pair(uint64_t(a) * uint64_t(b));
39 native_constexpr
inline unsigned_word_product word_pair_left(unsigned_word_product value,
unsigned int shift) {
40 return word_pair(shift < 64u ? word_value(value) << shift : uint64_t(0));
42 native_constexpr
inline unsigned int word_leading_zeros(
unsigned int value) {
44 return (
unsigned int)std::countl_zero(value);
46 return value == 0u ? 32u : 31u - (
unsigned int)firstbithigh(value);
49 native_constexpr
inline unsigned int word_top(uint64_t value) {
51 return 63u - (
unsigned int)std::countl_zero(value);
54 unsigned int high = (
unsigned int)(value >> 32);
55 return high != 0u ? 63u - word_leading_zeros(high)
56 : 31u - word_leading_zeros((unsigned int)value);
60 native_constexpr
inline uint64_t word_right_jam(uint64_t value,
unsigned int shift) {
61 if (shift == 0u)
return value;
62 if (shift >= 64u)
return uint64_t(value != 0);
63 return (value >> shift) | uint64_t((value << (64u - shift)) != 0);
65 struct fp32_result {
unsigned int bits, valid; };
66 native_constexpr
inline fp32_result fp32_result_of(
unsigned int bits,
unsigned int valid) {
67 fp32_result r; r.bits = bits; r.valid = valid;
return r;
69 native_constexpr
inline unsigned int fp32_flush_word(
unsigned int bits) {
70 return (bits & 0x7fffffffu) < 0x00800000u ? bits & 0x80000000u : bits;
72 native_constexpr
inline bool fp32_finite(
unsigned int bits) {
73 return (bits & 0x7f800000u) != 0x7f800000u;
78 native_constexpr
inline fp32_result fp32_pack(uint64_t magnitude,
int exponent,
unsigned int sign) {
79 if (magnitude == 0)
return fp32_result_of(sign, 1u);
80 int top = (int)word_top(magnitude);
81 int biased = exponent - 61 + top + 127;
82 if (biased >= 255)
return fp32_result_of(0u, 0u);
84 int denormal_shift = -88 - exponent;
85 if (shift < denormal_shift) shift = denormal_shift;
86 unsigned int quotient;
88 quotient = (
unsigned int)(magnitude << (
unsigned int)(-shift));
89 }
else if (shift == 1) {
90 quotient = (
unsigned int)(magnitude >> 1);
91 quotient += ((
unsigned int)magnitude & quotient & 1u);
93 unsigned int window = (
unsigned int)word_right_jam(magnitude, (
unsigned int)(shift - 2));
94 quotient = window >> 2;
95 quotient += ((window & 2u) != 0u && ((window & 1u) != 0u || (quotient & 1u) != 0u)) ? 1u : 0u;
98 return fp32_result_of(sign | (quotient >= 0x00800000u ? 0x00800000u : 0u), 1u);
99 if (quotient == 0x01000000u) { quotient >>= 1; ++biased; }
100 if (biased >= 255)
return fp32_result_of(0u, 0u);
101 return fp32_result_of(sign | ((
unsigned int)biased << 23) | (quotient & 0x007fffffu), 1u);
103 native_constexpr
inline fp32_result fp32_pack(unsigned_word_product magnitude,
int exponent,
unsigned int sign) {
104 return fp32_pack(word_value(magnitude), exponent, sign);
106 native_constexpr
inline fp32_result fp32_fma_words(
unsigned int a,
unsigned int b,
unsigned int c) {
107 if (!fp32_finite(a) || !fp32_finite(b) || !fp32_finite(c))
108 return fp32_result_of(0u, 0u);
109 a = fp32_flush_word(a); b = fp32_flush_word(b); c = fp32_flush_word(c);
110 unsigned int sign = (a ^ b) & 0x80000000u;
111 unsigned int csign = c & 0x80000000u;
112 unsigned int ea = (a >> 23) & 255u, eb = (b >> 23) & 255u, ec = (c >> 23) & 255u;
113 if (ea == 0u || eb == 0u)
114 return fp32_result_of(ec == 0u ? sign & csign : c, 1u);
115 unsigned int ma = (a & 0x7fffffu) | 0x800000u, mb = (b & 0x7fffffu) | 0x800000u;
116 uint64_t product = uint64_t(ma) * uint64_t(mb);
117 unsigned int top = word_top(product);
118 int exponent = (int)ea + (
int)eb - 300 + (int)top;
119 product <<= 61u - top;
120 if (ec == 0u)
return fp32_pack(product, exponent, sign);
121 uint64_t addend = uint64_t((c & 0x7fffffu) | 0x800000u) << 38;
122 int ce = (int)ec - 127;
124 product = word_right_jam(product, (
unsigned int)(ce - exponent));
127 addend = word_right_jam(addend, (
unsigned int)(exponent - ce));
131 magnitude = product + addend;
132 }
else if (product < addend) {
133 magnitude = addend - product; sign = csign;
135 magnitude = product - addend;
136 if (magnitude == 0) sign = 0u;
138 return fp32_pack(magnitude, exponent, sign);
Word-pair arithmetic and exact binary32 packing, multiplication, and FMA repair.