mirror of
https://github.com/elwrcl/intel-hard-graphics.git
synced 2026-11-01 19:28:02 +03:00
72 lines
2.1 KiB
C
72 lines
2.1 KiB
C
/*
|
|
* Copyright 2024 Alyssa Rosenzweig
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "agx_builder.h"
|
|
#include "agx_compiler.h"
|
|
#include "agx_opcodes.h"
|
|
|
|
static bool
|
|
is_shuffle(enum agx_opcode op)
|
|
{
|
|
switch (op) {
|
|
case AGX_OPCODE_SHUFFLE:
|
|
case AGX_OPCODE_SHUFFLE_UP:
|
|
case AGX_OPCODE_SHUFFLE_DOWN:
|
|
case AGX_OPCODE_SHUFFLE_XOR:
|
|
case AGX_OPCODE_QUAD_SHUFFLE:
|
|
case AGX_OPCODE_QUAD_SHUFFLE_UP:
|
|
case AGX_OPCODE_QUAD_SHUFFLE_DOWN:
|
|
case AGX_OPCODE_QUAD_SHUFFLE_XOR:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* AGX shuffle instructions read indices to shuffle with from the entire quad
|
|
* and accumulate them. That means that an inactive thread anywhere in the quad
|
|
* can make the whole shuffle undefined! To workaround, we reserve a scratch
|
|
* register (r0h) which we keep zero throughout the program... except for when
|
|
* actually shuffling, when we copy the shuffle index into r0h for the
|
|
* operation. This ensures that inactive threads read 0 for their index and
|
|
* hence do not contribute to the accumulated index.
|
|
*/
|
|
void
|
|
agx_lower_divergent_shuffle(agx_context *ctx)
|
|
{
|
|
agx_builder b = agx_init_builder(ctx, agx_before_function(ctx));
|
|
agx_index scratch = agx_register(1, AGX_SIZE_16);
|
|
|
|
assert(ctx->any_quad_divergent_shuffle);
|
|
agx_mov_imm_to(&b, scratch, 0);
|
|
|
|
agx_foreach_block(ctx, block) {
|
|
bool needs_zero = false;
|
|
|
|
agx_foreach_instr_in_block_safe(block, I) {
|
|
if (is_shuffle(I->op) && I->src[1].type == AGX_INDEX_REGISTER) {
|
|
assert(I->dest[0].value != scratch.value);
|
|
assert(I->src[0].value != scratch.value);
|
|
assert(I->src[1].value != scratch.value);
|
|
|
|
/* Use scratch register for our input, then zero it at the end of
|
|
* the block so all inactive threads read zero.
|
|
*/
|
|
b.cursor = agx_before_instr(I);
|
|
agx_mov_to(&b, scratch, I->src[1]);
|
|
needs_zero = true;
|
|
|
|
I->src[1] = scratch;
|
|
}
|
|
}
|
|
|
|
if (needs_zero) {
|
|
b.cursor = agx_after_block_logical(block);
|
|
agx_mov_imm_to(&b, scratch, 0);
|
|
}
|
|
}
|
|
}
|