nir: fix nir_round_int_to_float for fp16

fp16 has quite the limited value range and with bigger integers
nir_round_int_to_float might return Inf where it shouldn't depending on
the rounding mode.

Fixes conversions half_rt[npz]_(u)?(int|long) CL CTS tests.

Cc: mesa-stable
Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Reviewed-by: Rob Clark <rob.clark@oss.qualcomm.com>
(cherry picked from commit e1ed7de274)

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40359>
This commit is contained in:
Karol Herbst 2026-03-01 21:41:25 +01:00 committed by Eric Engestrom
parent 3d8ff40d58
commit d29063d4f2
3 changed files with 26 additions and 1 deletions

View file

@ -3444,7 +3444,7 @@
"description": "nir: fix nir_round_int_to_float for fp16",
"nominated": true,
"nomination_type": 1,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": null,
"notes": null

View file

@ -24,6 +24,7 @@
#ifndef NIR_CONVERSION_BUILDER_H
#define NIR_CONVERSION_BUILDER_H
#include "util/half_float.h"
#include "util/u_math.h"
#include "nir_builder.h"
#include "nir_builtin_builder.h"
@ -162,6 +163,29 @@ nir_round_int_to_float(nir_builder *b, nir_def *src,
}
UNREACHABLE("unexpected rounding mode");
} else {
/* For conversions to FP16 we need to clamp the input against the fp16
* max value when rounding towards zero or down. The reason for that is
* that for integer values outside of FP16 finite value range we could
* get Infinity, which would be incorrect rounding in those cases.
*
* Furthermore, we only need to do the clamping for integers bigger than
* 32 bits, because the lowering below will already clamp 16 bit integers
* correctly.
*
* This isn't a problem for FP32 or FP64 floats as integers can't exceed
* the finite value ranges.
*/
if (dest_bit_size == 16 && src->bit_size >= 32) {
switch (round) {
case nir_rounding_mode_rtz:
case nir_rounding_mode_rd:
src = nir_umin_imm(b, src, FP16_MAX_F);
break;
default:
break;
}
}
nir_def *mantissa_bit_size = nir_imm_int(b, mantissa_bits);
nir_def *msb = nir_imax(b, nir_ufind_msb(b, src), mantissa_bit_size);
nir_def *bits_to_lose = nir_isub(b, msb, mantissa_bit_size);

View file

@ -43,6 +43,7 @@ extern "C" {
#define FP16_ONE ((uint16_t) 0x3c00)
#define FP16_ZERO ((uint16_t) 0)
#define FP16_MAX_F 65504.0
uint16_t _mesa_float_to_half_slow(float val);
float _mesa_half_to_float_slow(uint16_t val);