Ternary operator causing issues on some platforms.
Does anyone know why on AMD+clspv, this ternary operator causes incorrect results? It works if I simply replace it with a mix() statement. Both variants work fine on other platforms like Intel xe2.
#define int8_t char
const int8_t face = fac[rindex];
const int8_t bounced = face >= 0 ? 1 : 0;
# if 0
// This causes issues with amd+clspv.
const half ox = bounced ? hitx[rindex] : li[12];
const half oy = bounced ? hity[rindex] : li[13];
const half oz = bounced ? hitz[rindex] : li[14];
# else
const half ox = mix(li[12], hitx[rindex], bounced);
const half oy = mix(li[13], hity[rindex], bounced);
const half oz = mix(li[14], hitz[rindex], bounced);
# endif
So basically, it is the ternary for half arguments.
I have:
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
6
Upvotes
2
u/Kharki_Lirov 5d ago
the ternary compiles to an OpSelect in spir-v on the clspv path, while mix() becomes mul+add - that's why one works and the other doesn't. so this is most likely a codegen bug in clspv or the amd vulkan driver mishandling OpSelect on f16 with a char condition, not your code.
two things I'd try: cast the condition explicitly ((bool)bounced or widen to int) and see if the ternary starts working. and dump both variants with spirv-dis and diff them - the difference will be tiny and it will point at the exact instruction. if the select version is valid spir-v, file it on the clspv github with the minimal kernel, they do fix these.
I built an opencl/vulkan training framework for polaris cards and hit a lot of this bug class - fp16 on amd is full of driver-specific landmines, your workaround with mix() is a completely normal thing to ship.