Support bare HIP convergent warp and lane intrinsics - #137
Conversation
|
Hiya! Welcome to Booth, and cheers for jumping in! Thanks for finding that latent bug, and I verified it's fixed myself! Thank you so much. A few things before it lands:
Minor one, now the lowerer always inserts the mask, those num_operands ternaries always take the same branch. Hardcoding index 1 like the AMD shuffle path does would read a bit clearer. Not blocking. Kind regards, |
This change introduces support for convergent __shfl, __shfl_up, __shfl_down, __shfl_xor, __ballot, __any, and __all without the mask argument. - Register bare names in sema.c builtins table. - Prepend default mask (0xFFFFFFFFu) during BIR lowering in bir_lower.c. - Fix backends (NVIDIA, AMDGPU, CPU) to dynamically resolve the value/predicate operand depending on whether a mask is present. - Add integration test in test_shfl.cu and register it in tcomp.c.
337760c to
e2ad80f
Compare
|
Thanks for your contribution! Merging it now. |
ISSUE HIP: bare warp intrinsics without _sync suffix
How the Issue is Fixed
Issue: HIP allows convergent warp/lane intrinsics (
__shfl,__shfl_up,__shfl_down,__shfl_xor,__ballot,__any,__all) to be called without a mask argument (since the mask is implicit in convergent AMD wavefronts). Previously, only the_syncvariants (which require a mask as their first argument) were recognized. Using the bare forms caused unknown-identifier errors.Fix:
_synccounterparts.0xFFFFFFFFu, representing all active lanes). This allows the rest of the compilation pipeline to handle them uniformly as masked operations.num_operandsto determine if a mask is present (operand index1if a mask is present, or index0if not). Note: Previously, the backends had a bug where they incorrectly assumed that the value or predicate was always at operand0(which is the mask).File-by-File Breakdown of Changes
1. src/fe/sema.c
__ballot,__any,__all,__shfl,__shfl_up,__shfl_down,__shfl_xor) to the staticcuda_builtinslist.check_exprto recognize bare versions (__ballot,__any,__all) when resolving the return types (rt), matching them alongside their_syncequivalents.2. src/ir/bir_lower.c
stab(warp shuffle lookup table) andvtab(warp vote lookup table) to include bare functions with asyncflag (0 for bare, 1 for_sync).!sync), a constant0xFFFFFFFFumask is synthetically generated and prepended as the first operand. The remaining function arguments (value, lane, etc.) are then appended normally.3. src/nvidia/isel.c
is_shfl, it now queriesI->num_operands >= 3to determine if a mask is present. If so, it reads the value and lane from indices1and2respectively, instead of assuming they are always at indices0and1.is_vote, it queriesI->num_operands > 1to find the predicate at index1instead of index0.4. src/amdgpu/isel.c
BIR_BALLOT,BIR_VOTE_ANY, andBIR_VOTE_ALLto fetch the predicate fromI->operands[I->num_operands > 1 ? 1 : 0], ensuring the correct predicate is resolved instead of the mask.5. src/cpu/cpu_emit.c
BIR_SHFL/BIR_SHFL_UP/BIR_SHFL_DOWN/BIR_SHFL_XORandBIR_VOTE_ANY/BIR_VOTE_ALLto load from operand1ifnum_operands > 1(since the mask is prepended at index0).6. tests/tcomp.c & tests/test_shfl.cu
cmp_shflin the compiler test runner list (tcomp.c).__shfl,__shfl_up,__shfl_down,__shfl_xor,__ballot,__any, and__allintest_shfl.cu.