agx: fix incorrect 16-bit promotions with comparisons

hardware seems to sign extend with a signed comparison, which I guess is
reasonable! so our logic was busted if we had a zero-extend source with a signed
comparison. this broke someone's OpenCL app, and could probably be hit from
GLES/Vulkan too...

on fossil-db, only parallel-rdp affected:

Totals from 312 (0.58% of 53701) affected shaders:
Instrs: 404772 -> 405697 (+0.23%); split: -0.01%, +0.24%
CodeSize: 2863314 -> 2868998 (+0.20%); split: -0.01%, +0.21%
Spills: 40239 -> 40286 (+0.12%); split: -0.02%, +0.14%
Fills: 33763 -> 33810 (+0.14%); split: -0.03%, +0.17%
ALU: 290757 -> 291071 (+0.11%); split: -0.02%, +0.13%
FSCIB: 261844 -> 262652 (+0.31%); split: -0.02%, +0.33%
IC: 230312 -> 230336 (+0.01%); split: -0.01%, +0.02%
GPRs: 24656 -> 24648 (-0.03%); split: -0.05%, +0.02%

Reported-by: RowanG
Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35949>
This commit is contained in:
Alyssa Rosenzweig
2025-07-03 11:56:28 -04:00
parent b5f56fb47b
commit 0bd1cd3230
+26 -3
View File
@@ -247,13 +247,30 @@ agx_optimizer_fmov_rev(agx_instr *I, agx_instr *use)
return true;
}
static bool
agx_icond_is_unsigned(enum agx_icond cond)
{
switch (cond) {
case AGX_ICOND_UEQ:
case AGX_ICOND_ULT:
case AGX_ICOND_UGT:
return true;
case AGX_ICOND_SEQ:
case AGX_ICOND_SLT:
case AGX_ICOND_SGT:
return false;
}
unreachable("invalid condition");
}
static bool
agx_supports_zext(agx_instr *I, unsigned s)
{
switch (I->op) {
case AGX_OPCODE_IADD:
case AGX_OPCODE_IMAD:
case AGX_OPCODE_ICMP:
case AGX_OPCODE_INTL:
case AGX_OPCODE_FFS:
case AGX_OPCODE_BITREV:
@@ -268,9 +285,15 @@ agx_supports_zext(agx_instr *I, unsigned s)
case AGX_OPCODE_ICMP_BALLOT:
case AGX_OPCODE_ICMP_QUAD_BALLOT:
return true;
case AGX_OPCODE_ICMP:
case AGX_OPCODE_ICMPSEL:
/* Only the comparisons can be extended, not the selection */
return s < 2;
/* Only the comparisons can be extended, not the selection. And we can
* only zero-extend with unsigned comparison. Presumably the hardware
* sign-extends with signed comparisons but we don't handle that yet.
*/
return (s < 2) && agx_icond_is_unsigned(I->icond);
default:
return false;
}