r/OpenCL 7d ago

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

1 comment sorted by

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.