Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 495 lines 12 kB view raw
1// SPDX-License-Identifier: MIT 2// 3// Copyright 2024 Advanced Micro Devices, Inc. 4 5#include "spl_fixpt31_32.h" 6 7static const struct spl_fixed31_32 spl_fixpt_two_pi = { 26986075409LL }; 8static const struct spl_fixed31_32 spl_fixpt_ln2 = { 2977044471LL }; 9static const struct spl_fixed31_32 spl_fixpt_ln2_div_2 = { 1488522236LL }; 10 11static inline unsigned long long abs_i64( 12 long long arg) 13{ 14 if (arg > 0) 15 return (unsigned long long)arg; 16 else 17 return (unsigned long long)(-arg); 18} 19 20/* 21 * @brief 22 * result = dividend / divisor 23 * *remainder = dividend % divisor 24 */ 25static inline unsigned long long spl_complete_integer_division_u64( 26 unsigned long long dividend, 27 unsigned long long divisor, 28 unsigned long long *remainder) 29{ 30 unsigned long long result; 31 32 result = spl_div64_u64_rem(dividend, divisor, remainder); 33 34 return result; 35} 36 37 38#define FRACTIONAL_PART_MASK \ 39 ((1ULL << FIXED31_32_BITS_PER_FRACTIONAL_PART) - 1) 40 41#define GET_INTEGER_PART(x) \ 42 ((x) >> FIXED31_32_BITS_PER_FRACTIONAL_PART) 43 44#define GET_FRACTIONAL_PART(x) \ 45 (FRACTIONAL_PART_MASK & (x)) 46 47struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_from_fraction( 48 long long numerator, long long denominator)) 49{ 50 struct spl_fixed31_32 res; 51 52 bool arg1_negative = numerator < 0; 53 bool arg2_negative = denominator < 0; 54 55 unsigned long long arg1_value = arg1_negative ? -numerator : numerator; 56 unsigned long long arg2_value = arg2_negative ? -denominator : denominator; 57 58 unsigned long long remainder; 59 60 /* determine integer part */ 61 62 unsigned long long res_value = spl_complete_integer_division_u64( 63 arg1_value, arg2_value, &remainder); 64 65 SPL_ASSERT(res_value <= (unsigned long long)LONG_MAX); 66 67 /* determine fractional part */ 68 { 69 unsigned int i = FIXED31_32_BITS_PER_FRACTIONAL_PART; 70 71 do { 72 remainder <<= 1; 73 74 res_value <<= 1; 75 76 if (remainder >= arg2_value) { 77 res_value |= 1; 78 remainder -= arg2_value; 79 } 80 } while (--i != 0); 81 } 82 83 /* round up LSB */ 84 { 85 unsigned long long summand = (remainder << 1) >= arg2_value; 86 87 SPL_ASSERT(res_value <= (unsigned long long)LLONG_MAX - summand); 88 89 res_value += summand; 90 } 91 92 res.value = (long long)res_value; 93 94 if (arg1_negative ^ arg2_negative) 95 res.value = -res.value; 96 97 return res; 98} 99 100struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_mul( 101 struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)) 102{ 103 struct spl_fixed31_32 res; 104 105 bool arg1_negative = arg1.value < 0; 106 bool arg2_negative = arg2.value < 0; 107 108 unsigned long long arg1_value = arg1_negative ? -arg1.value : arg1.value; 109 unsigned long long arg2_value = arg2_negative ? -arg2.value : arg2.value; 110 111 unsigned long long arg1_int = GET_INTEGER_PART(arg1_value); 112 unsigned long long arg2_int = GET_INTEGER_PART(arg2_value); 113 114 unsigned long long arg1_fra = GET_FRACTIONAL_PART(arg1_value); 115 unsigned long long arg2_fra = GET_FRACTIONAL_PART(arg2_value); 116 117 unsigned long long tmp; 118 119 res.value = arg1_int * arg2_int; 120 121 SPL_ASSERT(res.value <= (long long)LONG_MAX); 122 123 res.value <<= FIXED31_32_BITS_PER_FRACTIONAL_PART; 124 125 tmp = arg1_int * arg2_fra; 126 127 SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); 128 129 res.value += tmp; 130 131 tmp = arg2_int * arg1_fra; 132 133 SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); 134 135 res.value += tmp; 136 137 tmp = arg1_fra * arg2_fra; 138 139 tmp = (tmp >> FIXED31_32_BITS_PER_FRACTIONAL_PART) + 140 (tmp >= (unsigned long long)spl_fixpt_half.value); 141 142 SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); 143 144 res.value += tmp; 145 146 if (arg1_negative ^ arg2_negative) 147 res.value = -res.value; 148 149 return res; 150} 151 152struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_sqr(struct spl_fixed31_32 arg)) 153{ 154 struct spl_fixed31_32 res; 155 156 unsigned long long arg_value = abs_i64(arg.value); 157 158 unsigned long long arg_int = GET_INTEGER_PART(arg_value); 159 160 unsigned long long arg_fra = GET_FRACTIONAL_PART(arg_value); 161 162 unsigned long long tmp; 163 164 res.value = arg_int * arg_int; 165 166 SPL_ASSERT(res.value <= (long long)LONG_MAX); 167 168 res.value <<= FIXED31_32_BITS_PER_FRACTIONAL_PART; 169 170 tmp = arg_int * arg_fra; 171 172 SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); 173 174 res.value += tmp; 175 176 SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); 177 178 res.value += tmp; 179 180 tmp = arg_fra * arg_fra; 181 182 tmp = (tmp >> FIXED31_32_BITS_PER_FRACTIONAL_PART) + 183 (tmp >= (unsigned long long)spl_fixpt_half.value); 184 185 SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value)); 186 187 res.value += tmp; 188 189 return res; 190} 191 192struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_recip(struct spl_fixed31_32 arg)) 193{ 194 /* 195 * @note 196 * Good idea to use Newton's method 197 */ 198 199 return SPL_NAMESPACE(spl_fixpt_from_fraction( 200 spl_fixpt_one.value, 201 arg.value)); 202} 203 204struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_sinc(struct spl_fixed31_32 arg)) 205{ 206 struct spl_fixed31_32 square; 207 208 struct spl_fixed31_32 res = spl_fixpt_one; 209 210 int n = 27; 211 212 struct spl_fixed31_32 arg_norm = arg; 213 214 if (spl_fixpt_le( 215 spl_fixpt_two_pi, 216 spl_fixpt_abs(arg))) { 217 arg_norm = spl_fixpt_sub( 218 arg_norm, 219 spl_fixpt_mul_int( 220 spl_fixpt_two_pi, 221 (int)spl_div64_s64( 222 arg_norm.value, 223 spl_fixpt_two_pi.value))); 224 } 225 226 square = SPL_NAMESPACE(spl_fixpt_sqr(arg_norm)); 227 228 do { 229 res = spl_fixpt_sub( 230 spl_fixpt_one, 231 spl_fixpt_div_int( 232 SPL_NAMESPACE(spl_fixpt_mul( 233 square, 234 res)), 235 n * (n - 1))); 236 237 n -= 2; 238 } while (n > 2); 239 240 if (arg.value != arg_norm.value) 241 res = spl_fixpt_div( 242 SPL_NAMESPACE(spl_fixpt_mul(res, arg_norm)), 243 arg); 244 245 return res; 246} 247 248struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_sin(struct spl_fixed31_32 arg)) 249{ 250 return SPL_NAMESPACE(spl_fixpt_mul( 251 arg, 252 SPL_NAMESPACE(spl_fixpt_sinc(arg)))); 253} 254 255struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_cos(struct spl_fixed31_32 arg)) 256{ 257 /* TODO implement argument normalization */ 258 259 const struct spl_fixed31_32 square = SPL_NAMESPACE(spl_fixpt_sqr(arg)); 260 261 struct spl_fixed31_32 res = spl_fixpt_one; 262 263 int n = 26; 264 265 do { 266 res = spl_fixpt_sub( 267 spl_fixpt_one, 268 spl_fixpt_div_int( 269 SPL_NAMESPACE(spl_fixpt_mul( 270 square, 271 res)), 272 n * (n - 1))); 273 274 n -= 2; 275 } while (n != 0); 276 277 return res; 278} 279 280/* 281 * @brief 282 * result = exp(arg), 283 * where abs(arg) < 1 284 * 285 * Calculated as Taylor series. 286 */ 287static struct spl_fixed31_32 spl_fixed31_32_exp_from_taylor_series(struct spl_fixed31_32 arg) 288{ 289 unsigned int n = 9; 290 291 struct spl_fixed31_32 res = SPL_NAMESPACE(spl_fixpt_from_fraction( 292 n + 2, 293 n + 1)); 294 /* TODO find correct res */ 295 296 SPL_ASSERT(spl_fixpt_lt(arg, spl_fixpt_one)); 297 298 do 299 res = spl_fixpt_add( 300 spl_fixpt_one, 301 spl_fixpt_div_int( 302 SPL_NAMESPACE(spl_fixpt_mul( 303 arg, 304 res)), 305 n)); 306 while (--n != 1); 307 308 return spl_fixpt_add( 309 spl_fixpt_one, 310 SPL_NAMESPACE(spl_fixpt_mul( 311 arg, 312 res))); 313} 314 315struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_exp(struct spl_fixed31_32 arg)) 316{ 317 /* 318 * @brief 319 * Main equation is: 320 * exp(x) = exp(r + m * ln(2)) = (1 << m) * exp(r), 321 * where m = round(x / ln(2)), r = x - m * ln(2) 322 */ 323 324 if (spl_fixpt_le( 325 spl_fixpt_ln2_div_2, 326 spl_fixpt_abs(arg))) { 327 int m = spl_fixpt_round( 328 spl_fixpt_div( 329 arg, 330 spl_fixpt_ln2)); 331 332 struct spl_fixed31_32 r = spl_fixpt_sub( 333 arg, 334 spl_fixpt_mul_int( 335 spl_fixpt_ln2, 336 m)); 337 338 SPL_ASSERT(m != 0); 339 340 SPL_ASSERT(spl_fixpt_lt( 341 spl_fixpt_abs(r), 342 spl_fixpt_one)); 343 344 if (m > 0) 345 return spl_fixpt_shl( 346 spl_fixed31_32_exp_from_taylor_series(r), 347 (unsigned int)m); 348 else 349 return spl_fixpt_div_int( 350 spl_fixed31_32_exp_from_taylor_series(r), 351 1LL << -m); 352 } else if (arg.value != 0) 353 return spl_fixed31_32_exp_from_taylor_series(arg); 354 else 355 return spl_fixpt_one; 356} 357 358struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_log(struct spl_fixed31_32 arg)) 359{ 360 struct spl_fixed31_32 res = spl_fixpt_neg(spl_fixpt_one); 361 /* TODO improve 1st estimation */ 362 363 struct spl_fixed31_32 error; 364 365 SPL_ASSERT(arg.value > 0); 366 /* TODO if arg is negative, return NaN */ 367 /* TODO if arg is zero, return -INF */ 368 369 do { 370 struct spl_fixed31_32 res1 = spl_fixpt_add( 371 spl_fixpt_sub( 372 res, 373 spl_fixpt_one), 374 spl_fixpt_div( 375 arg, 376 SPL_NAMESPACE(spl_fixpt_exp(res)))); 377 378 error = spl_fixpt_sub( 379 res, 380 res1); 381 382 res = res1; 383 /* TODO determine max_allowed_error based on quality of exp() */ 384 } while (abs_i64(error.value) > 100ULL); 385 386 return res; 387} 388 389 390/* this function is a generic helper to translate fixed point value to 391 * specified integer format that will consist of integer_bits integer part and 392 * fractional_bits fractional part. For example it is used in 393 * spl_fixpt_u2d19 to receive 2 bits integer part and 19 bits fractional 394 * part in 32 bits. It is used in hw programming (scaler) 395 */ 396 397static inline unsigned int spl_ux_dy( 398 long long value, 399 unsigned int integer_bits, 400 unsigned int fractional_bits) 401{ 402 /* 1. create mask of integer part */ 403 unsigned int result = (1 << integer_bits) - 1; 404 /* 2. mask out fractional part */ 405 unsigned int fractional_part = FRACTIONAL_PART_MASK & value; 406 /* 3. shrink fixed point integer part to be of integer_bits width*/ 407 result &= GET_INTEGER_PART(value); 408 /* 4. make space for fractional part to be filled in after integer */ 409 result <<= fractional_bits; 410 /* 5. shrink fixed point fractional part to of fractional_bits width*/ 411 fractional_part >>= FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits; 412 /* 6. merge the result */ 413 return result | fractional_part; 414} 415 416static inline unsigned int spl_clamp_ux_dy( 417 long long value, 418 unsigned int integer_bits, 419 unsigned int fractional_bits, 420 unsigned int min_clamp) 421{ 422 unsigned int truncated_val = spl_ux_dy(value, integer_bits, fractional_bits); 423 424 if (value >= (1LL << (integer_bits + FIXED31_32_BITS_PER_FRACTIONAL_PART))) 425 return (1 << (integer_bits + fractional_bits)) - 1; 426 else if (truncated_val > min_clamp) 427 return truncated_val; 428 else 429 return min_clamp; 430} 431 432unsigned int SPL_NAMESPACE(spl_fixpt_u4d19(struct spl_fixed31_32 arg)) 433{ 434 return spl_ux_dy(arg.value, 4, 19); 435} 436 437unsigned int SPL_NAMESPACE(spl_fixpt_u3d19(struct spl_fixed31_32 arg)) 438{ 439 return spl_ux_dy(arg.value, 3, 19); 440} 441 442unsigned int SPL_NAMESPACE(spl_fixpt_u2d19(struct spl_fixed31_32 arg)) 443{ 444 return spl_ux_dy(arg.value, 2, 19); 445} 446 447unsigned int SPL_NAMESPACE(spl_fixpt_u0d19(struct spl_fixed31_32 arg)) 448{ 449 return spl_ux_dy(arg.value, 0, 19); 450} 451 452unsigned int SPL_NAMESPACE(spl_fixpt_clamp_u0d14(struct spl_fixed31_32 arg)) 453{ 454 return spl_clamp_ux_dy(arg.value, 0, 14, 1); 455} 456 457unsigned int SPL_NAMESPACE(spl_fixpt_clamp_u0d10(struct spl_fixed31_32 arg)) 458{ 459 return spl_clamp_ux_dy(arg.value, 0, 10, 1); 460} 461 462int SPL_NAMESPACE(spl_fixpt_s4d19(struct spl_fixed31_32 arg)) 463{ 464 if (arg.value < 0) 465 return -(int)spl_ux_dy(spl_fixpt_abs(arg).value, 4, 19); 466 else 467 return spl_ux_dy(arg.value, 4, 19); 468} 469 470struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_from_ux_dy(unsigned int value, 471 unsigned int integer_bits, 472 unsigned int fractional_bits)) 473{ 474 struct spl_fixed31_32 fixpt_value = spl_fixpt_zero; 475 struct spl_fixed31_32 fixpt_int_value = spl_fixpt_zero; 476 long long frac_mask = ((long long)1 << (long long)integer_bits) - 1; 477 478 fixpt_value.value = (long long)value << (FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits); 479 frac_mask = frac_mask << fractional_bits; 480 fixpt_int_value.value = value & frac_mask; 481 fixpt_int_value.value <<= (FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits); 482 fixpt_value.value |= fixpt_int_value.value; 483 return fixpt_value; 484} 485 486struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_from_int_dy(unsigned int int_value, 487 unsigned int frac_value, 488 unsigned int integer_bits, 489 unsigned int fractional_bits)) 490{ 491 struct spl_fixed31_32 fixpt_value = spl_fixpt_from_int(int_value); 492 493 fixpt_value.value |= (long long)frac_value << (FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits); 494 return fixpt_value; 495}