Skip to content

Commit a28dca5

Browse files
authored
[libclc] Avoid out-of-range float-to-int. (#19144)
For a kernel such as kernel void foo(__global double3 *z) { double3 x = {0.6631661088,0.6612268107,0.1513627528}; int3 y = {-1980459213,-660855407,615708204}; *z = pown(x, y); } we were not storing anything to z, because the implementation of pown relied on an floating-point-to-integer conversion where the floating-point value was outside of the integer's range. Although in LLVM IR we permit that operation so long as we end up ignoring its result -- that is the general rule for poison -- one thing we are not permitted to do is have conditional branches that depend on it, and through the call to __clc_ldexp, we did have that. To fix this, rather than changing expv at the end to INFINITY/0, we can change v at the start to values that we know will produce INFINITY/0 without performing such out-of-range conversions. Tested with clang --target=nvptx64 -S -O3 -o - test.cl \ -Xclang -mlink-builtin-bitcode \ -Xclang runtimes/runtimes-bins/libclc/nvptx64--.bc A grep showed that this exact same code existed in three more places, so I changed it there too, though I did not do a broader search for other similar code that potentially has the same problem. (cherry picked from commit 46ee7f1, with a minor downstream-only follow-up in `libclc/libspirv/lib/generic/math/clc_rootn.cl`)
1 parent e7c4bf6 commit a28dca5

File tree

5 files changed

+45
-19
lines changed

5 files changed

+45
-19
lines changed

libclc/clc/lib/generic/math/clc_pow.inc

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,15 @@ _CLC_DEF _CLC_OVERLOAD __CLC_GENTYPE __clc_pow(__CLC_GENTYPE x,
330330
const __CLC_GENTYPE lnof2_by_64_head = 0.010830424260348081;
331331
const __CLC_GENTYPE lnof2_by_64_tail = -4.359010638708991e-10;
332332

333+
// If v is so large that we need to return INFINITY, or so small that we
334+
// need to return 0, set v to known values that will produce that result. Do
335+
// not try to continue the computation with the original v and patch it up
336+
// afterwards because v may be so large that temp is out of range of int, in
337+
// which case that conversion, and a value based on that conversion being
338+
// passed to __clc_ldexp, results in undefined behavior.
339+
v = v > max_exp_arg ? 1000.0 : v;
340+
v = v < min_exp_arg ? -1000.0 : v;
341+
333342
__CLC_GENTYPE temp = v * sixtyfour_by_lnof2;
334343
__CLC_INTN n = __CLC_CONVERT_INTN(temp);
335344
__CLC_GENTYPE dn = __CLC_CONVERT_GENTYPE(n);
@@ -357,10 +366,6 @@ _CLC_DEF _CLC_OVERLOAD __CLC_GENTYPE __clc_pow(__CLC_GENTYPE x,
357366

358367
expv = __clc_fma(f, q, f2) + f1;
359368
expv = __clc_ldexp(expv, m);
360-
361-
expv = v > max_exp_arg ? __CLC_AS_GENTYPE((__CLC_ULONGN)0x7FF0000000000000L)
362-
: expv;
363-
expv = v < min_exp_arg ? 0.0 : expv;
364369
}
365370

366371
// See whether y is an integer.

libclc/clc/lib/generic/math/clc_pown.inc

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,15 @@ _CLC_DEF _CLC_OVERLOAD __CLC_GENTYPE __clc_pown(__CLC_GENTYPE x,
317317
const __CLC_GENTYPE lnof2_by_64_head = 0.010830424260348081;
318318
const __CLC_GENTYPE lnof2_by_64_tail = -4.359010638708991e-10;
319319

320+
// If v is so large that we need to return INFINITY, or so small that we
321+
// need to return 0, set v to known values that will produce that result. Do
322+
// not try to continue the computation with the original v and patch it up
323+
// afterwards because v may be so large that temp is out of range of int, in
324+
// which case that conversion, and a value based on that conversion being
325+
// passed to __clc_ldexp, results in undefined behavior.
326+
v = v > max_exp_arg ? 1000.0 : v;
327+
v = v < min_exp_arg ? -1000.0 : v;
328+
320329
__CLC_GENTYPE temp = v * sixtyfour_by_lnof2;
321330
__CLC_INTN n = __CLC_CONVERT_INTN(temp);
322331
__CLC_GENTYPE dn = __CLC_CONVERT_GENTYPE(n);
@@ -344,10 +353,6 @@ _CLC_DEF _CLC_OVERLOAD __CLC_GENTYPE __clc_pown(__CLC_GENTYPE x,
344353

345354
expv = __clc_fma(f, q, f2) + f1;
346355
expv = __clc_ldexp(expv, m);
347-
348-
expv = v > max_exp_arg ? __CLC_AS_GENTYPE((__CLC_ULONGN)0x7FF0000000000000L)
349-
: expv;
350-
expv = v < min_exp_arg ? 0.0 : expv;
351356
}
352357

353358
// See whether y is an integer.

libclc/clc/lib/generic/math/clc_powr.inc

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,15 @@ _CLC_DEF _CLC_OVERLOAD __CLC_GENTYPE __clc_powr(__CLC_GENTYPE x,
316316
const __CLC_GENTYPE lnof2_by_64_head = 0.010830424260348081;
317317
const __CLC_GENTYPE lnof2_by_64_tail = -4.359010638708991e-10;
318318

319+
// If v is so large that we need to return INFINITY, or so small that we
320+
// need to return 0, set v to known values that will produce that result. Do
321+
// not try to continue the computation with the original v and patch it up
322+
// afterwards because v may be so large that temp is out of range of int, in
323+
// which case that conversion, and a value based on that conversion being
324+
// passed to __clc_ldexp, results in undefined behavior.
325+
v = v > max_exp_arg ? 1000.0 : v;
326+
v = v < min_exp_arg ? -1000.0 : v;
327+
319328
__CLC_GENTYPE temp = v * sixtyfour_by_lnof2;
320329
__CLC_INTN n = __CLC_CONVERT_INTN(temp);
321330
__CLC_GENTYPE dn = __CLC_CONVERT_GENTYPE(n);
@@ -343,10 +352,6 @@ _CLC_DEF _CLC_OVERLOAD __CLC_GENTYPE __clc_powr(__CLC_GENTYPE x,
343352

344353
expv = __clc_fma(f, q, f2) + f1;
345354
expv = __clc_ldexp(expv, m);
346-
347-
expv = v > max_exp_arg ? __CLC_AS_GENTYPE((__CLC_ULONGN)0x7FF0000000000000L)
348-
: expv;
349-
expv = v < min_exp_arg ? 0.0 : expv;
350355
}
351356

352357
// See whether y is an integer.

libclc/clc/lib/generic/math/clc_rootn.inc

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,15 @@ _CLC_DEF _CLC_OVERLOAD __CLC_GENTYPE __clc_rootn(__CLC_GENTYPE x,
323323
const __CLC_GENTYPE lnof2_by_64_head = 0.010830424260348081;
324324
const __CLC_GENTYPE lnof2_by_64_tail = -4.359010638708991e-10;
325325

326+
// If v is so large that we need to return INFINITY, or so small that we
327+
// need to return 0, set v to known values that will produce that result. Do
328+
// not try to continue the computation with the original v and patch it up
329+
// afterwards because v may be so large that temp is out of range of int, in
330+
// which case that conversion, and a value based on that conversion being
331+
// passed to __clc_ldexp, results in undefined behavior.
332+
v = v > max_exp_arg ? 1000.0 : v;
333+
v = v < min_exp_arg ? -1000.0 : v;
334+
326335
__CLC_GENTYPE temp = v * sixtyfour_by_lnof2;
327336
__CLC_INTN n = __CLC_CONVERT_INTN(temp);
328337
__CLC_GENTYPE dn = __CLC_CONVERT_GENTYPE(n);
@@ -350,10 +359,6 @@ _CLC_DEF _CLC_OVERLOAD __CLC_GENTYPE __clc_rootn(__CLC_GENTYPE x,
350359

351360
expv = __clc_fma(f, q, f2) + f1;
352361
expv = __clc_ldexp(expv, m);
353-
354-
expv = v > max_exp_arg ? __CLC_AS_GENTYPE((__CLC_ULONGN)0x7FF0000000000000L)
355-
: expv;
356-
expv = v < min_exp_arg ? 0.0 : expv;
357362
}
358363

359364
// See whether y is an integer.

libclc/libspirv/lib/generic/math/clc_rootn.cl

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,15 @@ _CLC_DEF _CLC_OVERLOAD double __clc_rootn(double x, int ny) {
323323
const double lnof2_by_64_head = 0.010830424260348081;
324324
const double lnof2_by_64_tail = -4.359010638708991e-10;
325325

326+
// If v is so large that we need to return INFINITY, or so small that we
327+
// need to return 0, set v to known values that will produce that result. Do
328+
// not try to continue the computation with the original v and patch it up
329+
// afterwards because v may be so large that temp is out of range of int, in
330+
// which case that conversion, and a value based on that conversion being
331+
// passed to __spirv_ocl_ldexp, results in undefined behavior.
332+
v = v > max_exp_arg ? 1000.0 : v;
333+
v = v < min_exp_arg ? -1000.0 : v;
334+
326335
double temp = v * sixtyfour_by_lnof2;
327336
int n = (int)(long)temp;
328337
double dn = (double)n;
@@ -354,9 +363,6 @@ _CLC_DEF _CLC_OVERLOAD double __clc_rootn(double x, int ny) {
354363

355364
expv = __spirv_ocl_fma(f, q, f2) + f1;
356365
expv = __spirv_ocl_ldexp(expv, m);
357-
358-
expv = v > max_exp_arg ? __clc_as_double(0x7FF0000000000000L) : expv;
359-
expv = v < min_exp_arg ? 0.0 : expv;
360366
}
361367

362368
// See whether y is an integer.

0 commit comments

Comments
 (0)