mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-25 06:30:10 +01:00
nir: remove nir_intrinsic_discard
The semantics of discard differ between GLSL and HLSL and
their various implementations. Subsequently, numerous application
bugs occurred and SPV_EXT_demote_to_helper_invocation was written
in order to clarify the behavior. In NIR, we now have 3 different
intrinsics for 2 things, and while demote and terminate have clear
semantics, discard still doesn't and can mean either of the two.
This patch entirely removes nir_intrinsic_discard and
nir_intrinsic_discard_if and replaces all occurences either with
nir_intrinsic_terminate{_if} or nir_intrinsic_demote{_if} in the
case that the NIR option 'discard_is_demote' is being set.
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Reviewed-by: Faith Ekstrand <faith.ekstrand@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27617>
This commit is contained in:
parent
4a84725ebb
commit
9b1a748b5e
42 changed files with 77 additions and 316 deletions
|
|
@ -8850,12 +8850,9 @@ visit_intrinsic(isel_context* ctx, nir_intrinsic_instr* instr)
|
|||
break;
|
||||
}
|
||||
case nir_intrinsic_demote:
|
||||
case nir_intrinsic_demote_if:
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_discard_if: {
|
||||
case nir_intrinsic_demote_if: {
|
||||
Operand cond = Operand::c32(-1u);
|
||||
if (instr->intrinsic == nir_intrinsic_discard_if ||
|
||||
instr->intrinsic == nir_intrinsic_demote_if) {
|
||||
if (instr->intrinsic == nir_intrinsic_demote_if) {
|
||||
Temp src = get_ssa_temp(ctx, instr->src[0].ssa);
|
||||
assert(src.regClass() == bld.lm);
|
||||
cond =
|
||||
|
|
|
|||
|
|
@ -2501,12 +2501,10 @@ static void emit_demote(struct ac_nir_context *ctx, const nir_intrinsic_instr *i
|
|||
{
|
||||
LLVMValueRef cond;
|
||||
|
||||
if (instr->intrinsic == nir_intrinsic_discard_if ||
|
||||
instr->intrinsic == nir_intrinsic_demote_if) {
|
||||
if (instr->intrinsic == nir_intrinsic_demote_if) {
|
||||
cond = LLVMBuildNot(ctx->ac.builder, get_src(ctx, instr->src[0]), "");
|
||||
} else {
|
||||
assert(instr->intrinsic == nir_intrinsic_discard ||
|
||||
instr->intrinsic == nir_intrinsic_demote);
|
||||
assert(instr->intrinsic == nir_intrinsic_demote);
|
||||
cond = ctx->ac.i1false;
|
||||
}
|
||||
|
||||
|
|
@ -3144,8 +3142,6 @@ static bool visit_intrinsic(struct ac_nir_context *ctx, nir_intrinsic_instr *ins
|
|||
case nir_intrinsic_terminate_if:
|
||||
emit_discard(ctx, instr);
|
||||
break;
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_demote:
|
||||
case nir_intrinsic_demote_if:
|
||||
emit_demote(ctx, instr);
|
||||
|
|
|
|||
|
|
@ -83,8 +83,8 @@ lower_zs_emit(nir_block *block, bool force_early_z)
|
|||
static bool
|
||||
lower_discard(nir_builder *b, nir_intrinsic_instr *intr, UNUSED void *data)
|
||||
{
|
||||
if (intr->intrinsic != nir_intrinsic_discard &&
|
||||
intr->intrinsic != nir_intrinsic_discard_if &&
|
||||
if (intr->intrinsic != nir_intrinsic_terminate &&
|
||||
intr->intrinsic != nir_intrinsic_terminate_if &&
|
||||
intr->intrinsic != nir_intrinsic_demote &&
|
||||
intr->intrinsic != nir_intrinsic_demote_if)
|
||||
return false;
|
||||
|
|
@ -95,7 +95,7 @@ lower_discard(nir_builder *b, nir_intrinsic_instr *intr, UNUSED void *data)
|
|||
nir_def *no_samples = nir_imm_intN_t(b, 0, 16);
|
||||
nir_def *killed_samples = all_samples;
|
||||
|
||||
if (intr->intrinsic == nir_intrinsic_discard_if ||
|
||||
if (intr->intrinsic == nir_intrinsic_terminate_if ||
|
||||
intr->intrinsic == nir_intrinsic_demote_if)
|
||||
killed_samples = nir_bcsel(b, intr->src[0].ssa, all_samples, no_samples);
|
||||
|
||||
|
|
|
|||
|
|
@ -3573,7 +3573,6 @@ ntq_emit_intrinsic(struct v3d_compile *c, nir_intrinsic_instr *instr)
|
|||
* early termination by emitting a (maybe conditional) jump to the
|
||||
* end section of the fragment shader for affected invocations.
|
||||
*/
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
c->emitted_discard = true;
|
||||
FALLTHROUGH;
|
||||
|
|
@ -3592,7 +3591,6 @@ ntq_emit_intrinsic(struct v3d_compile *c, nir_intrinsic_instr *instr)
|
|||
}
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate_if:
|
||||
c->emitted_discard = true;
|
||||
FALLTHROUGH;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ set_discard_global(nir_builder *b, nir_variable *discarded,
|
|||
{
|
||||
nir_deref_instr *lhs = nir_build_deref_var(b, discarded);
|
||||
nir_def *rhs;
|
||||
if (intrin->intrinsic == nir_intrinsic_discard_if) {
|
||||
if (intrin->intrinsic == nir_intrinsic_terminate_if ||
|
||||
intrin->intrinsic == nir_intrinsic_demote_if) {
|
||||
/* discarded <- condition, use discarded as the condition */
|
||||
rhs = intrin->src[0].ssa;
|
||||
nir_src_rewrite(&intrin->src[0], &lhs->def);
|
||||
|
|
@ -91,8 +92,10 @@ lower_discard_flow(nir_builder *b, nir_cf_node *cf_node,
|
|||
}
|
||||
} else if (instr->type == nir_instr_type_intrinsic) {
|
||||
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
|
||||
if (intrin->intrinsic == nir_intrinsic_discard_if ||
|
||||
intrin->intrinsic == nir_intrinsic_discard) {
|
||||
if (intrin->intrinsic == nir_intrinsic_terminate_if ||
|
||||
intrin->intrinsic == nir_intrinsic_terminate ||
|
||||
intrin->intrinsic == nir_intrinsic_demote_if ||
|
||||
intrin->intrinsic == nir_intrinsic_demote) {
|
||||
b->cursor = nir_before_instr(instr);
|
||||
set_discard_global(b, discarded, intrin);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,7 +150,6 @@ files_libnir = files(
|
|||
'nir_lower_convert_alu_types.c',
|
||||
'nir_lower_variable_initializers.c',
|
||||
'nir_lower_discard_if.c',
|
||||
'nir_lower_discard_or_demote.c',
|
||||
'nir_lower_double_ops.c',
|
||||
'nir_lower_drawpixels.c',
|
||||
'nir_lower_fb_read.c',
|
||||
|
|
|
|||
|
|
@ -6400,9 +6400,6 @@ typedef enum {
|
|||
|
||||
bool nir_lower_discard_if(nir_shader *shader, nir_lower_discard_if_options options);
|
||||
|
||||
bool nir_lower_discard_or_demote(nir_shader *shader,
|
||||
bool force_correct_quad_ops_after_discard);
|
||||
|
||||
bool nir_lower_terminate_to_demote(nir_shader *nir);
|
||||
|
||||
bool nir_lower_memory_model(nir_shader *shader);
|
||||
|
|
|
|||
|
|
@ -2137,6 +2137,24 @@ nir_build_call(nir_builder *build, nir_function *func, size_t count,
|
|||
nir_builder_instr_insert(build, &call->instr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
nir_discard(nir_builder *build)
|
||||
{
|
||||
if (build->shader->options->discard_is_demote)
|
||||
nir_demote(build);
|
||||
else
|
||||
nir_terminate(build);
|
||||
}
|
||||
|
||||
static inline void
|
||||
nir_discard_if(nir_builder *build, nir_def *src)
|
||||
{
|
||||
if (build->shader->options->discard_is_demote)
|
||||
nir_demote_if(build, src);
|
||||
else
|
||||
nir_terminate_if(build, src);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call a given nir_function * with a variadic number of nir_def * arguments.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -469,8 +469,6 @@ gather_intrinsic_info(nir_intrinsic_instr *instr, nir_shader *shader,
|
|||
case nir_intrinsic_demote_if:
|
||||
shader->info.fs.uses_demote = true;
|
||||
FALLTHROUGH; /* quads with helper lanes only might be discarded entirely */
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate:
|
||||
case nir_intrinsic_terminate_if:
|
||||
/* Freedreno uses discard_if() to end GS invocations that don't produce
|
||||
|
|
|
|||
|
|
@ -306,9 +306,7 @@ is_barrier(nir_instr *instr)
|
|||
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
|
||||
const char *name = nir_intrinsic_infos[intr->intrinsic].name;
|
||||
|
||||
if (intr->intrinsic == nir_intrinsic_discard ||
|
||||
intr->intrinsic == nir_intrinsic_discard_if ||
|
||||
intr->intrinsic == nir_intrinsic_terminate ||
|
||||
if (intr->intrinsic == nir_intrinsic_terminate ||
|
||||
intr->intrinsic == nir_intrinsic_terminate_if ||
|
||||
/* TODO: nir_intrinsics.py could do this */
|
||||
strstr(name, "barrier"))
|
||||
|
|
|
|||
|
|
@ -414,8 +414,6 @@ intrinsic("is_sparse_resident_zink", dest_comp=1, src_comp=[0], bit_sizes=[1],
|
|||
def barrier(name):
|
||||
intrinsic(name)
|
||||
|
||||
barrier("discard")
|
||||
|
||||
# Demote fragment shader invocation to a helper invocation. Any stores to
|
||||
# memory after this instruction are suppressed and the fragment does not write
|
||||
# outputs to the framebuffer. Unlike discard, demote needs to ensure that
|
||||
|
|
@ -480,8 +478,7 @@ intrinsic("inverse_ballot", src_comp=[0], dest_comp=1, flags=[CAN_ELIMINATE])
|
|||
barrier("begin_invocation_interlock")
|
||||
barrier("end_invocation_interlock")
|
||||
|
||||
# A conditional discard/demote/terminate, with a single boolean source.
|
||||
intrinsic("discard_if", src_comp=[1])
|
||||
# A conditional demote/terminate, with a single boolean source.
|
||||
intrinsic("demote_if", src_comp=[1])
|
||||
intrinsic("terminate_if", src_comp=[1])
|
||||
|
||||
|
|
|
|||
|
|
@ -30,10 +30,6 @@ lower_discard_if(nir_builder *b, nir_intrinsic_instr *instr, void *cb_data)
|
|||
nir_lower_discard_if_options options = *(nir_lower_discard_if_options *)cb_data;
|
||||
|
||||
switch (instr->intrinsic) {
|
||||
case nir_intrinsic_discard_if:
|
||||
if (!(options & nir_lower_discard_if_to_cf))
|
||||
return false;
|
||||
break;
|
||||
case nir_intrinsic_demote_if:
|
||||
if (!(options & nir_lower_demote_if_to_cf))
|
||||
return false;
|
||||
|
|
@ -50,9 +46,6 @@ lower_discard_if(nir_builder *b, nir_intrinsic_instr *instr, void *cb_data)
|
|||
|
||||
nir_if *if_stmt = nir_push_if(b, instr->src[0].ssa);
|
||||
switch (instr->intrinsic) {
|
||||
case nir_intrinsic_discard_if:
|
||||
nir_discard(b);
|
||||
break;
|
||||
case nir_intrinsic_demote_if:
|
||||
nir_demote(b);
|
||||
break;
|
||||
|
|
@ -94,7 +87,7 @@ lower_discard_if(nir_builder *b, nir_intrinsic_instr *instr, void *cb_data)
|
|||
} else {
|
||||
block block_6:
|
||||
/ preds: block_4 /
|
||||
intrinsic discard () () <-- not last instruction
|
||||
intrinsic terminate () () <-- not last instruction
|
||||
vec1 32 ssa_23 = iadd ssa_50, ssa_31 <-- dead code loop itr increment
|
||||
/ succs: block_7 /
|
||||
}
|
||||
|
|
@ -103,7 +96,7 @@ lower_discard_if(nir_builder *b, nir_intrinsic_instr *instr, void *cb_data)
|
|||
|
||||
which means that we can't assert like this:
|
||||
|
||||
assert(instr->intrinsic != nir_intrinsic_discard ||
|
||||
assert(instr->intrinsic != nir_intrinsic_terminate ||
|
||||
nir_block_last_instr(instr->instr.block) == &instr->instr);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,187 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2020 Valve Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nir.h"
|
||||
#include "nir_builder.h"
|
||||
|
||||
static bool
|
||||
lower_discard_to_demote(nir_builder *b, nir_intrinsic_instr *intrin, void *data)
|
||||
{
|
||||
switch (intrin->intrinsic) {
|
||||
case nir_intrinsic_discard:
|
||||
intrin->intrinsic = nir_intrinsic_demote;
|
||||
return true;
|
||||
case nir_intrinsic_discard_if:
|
||||
intrin->intrinsic = nir_intrinsic_demote_if;
|
||||
return true;
|
||||
case nir_intrinsic_load_helper_invocation:
|
||||
intrin->intrinsic = nir_intrinsic_is_helper_invocation;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
lower_demote_to_discard(nir_builder *b, nir_intrinsic_instr *intrin, void *data)
|
||||
{
|
||||
switch (intrin->intrinsic) {
|
||||
case nir_intrinsic_demote:
|
||||
intrin->intrinsic = nir_intrinsic_discard;
|
||||
return true;
|
||||
case nir_intrinsic_demote_if:
|
||||
intrin->intrinsic = nir_intrinsic_discard_if;
|
||||
return true;
|
||||
case nir_intrinsic_is_helper_invocation:
|
||||
case nir_intrinsic_load_helper_invocation: {
|
||||
/* If the shader doesn't need helper invocations,
|
||||
* we can assume there are none */
|
||||
b->cursor = nir_before_instr(&intrin->instr);
|
||||
nir_def *zero = nir_imm_false(b);
|
||||
nir_def_rewrite_uses(&intrin->def, zero);
|
||||
nir_instr_remove(&intrin->instr);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static nir_def *
|
||||
insert_is_helper(nir_builder *b, nir_instr *instr)
|
||||
{
|
||||
/* find best place to insert is_helper */
|
||||
nir_cf_node *node = &instr->block->cf_node;
|
||||
while (node->parent->type != nir_cf_node_function)
|
||||
node = nir_cf_node_prev(node->parent);
|
||||
nir_block *block = nir_cf_node_as_block(node);
|
||||
if (block == instr->block) {
|
||||
b->cursor = nir_before_instr(instr);
|
||||
} else {
|
||||
b->cursor = nir_after_block_before_jump(block);
|
||||
}
|
||||
return nir_is_helper_invocation(b, 1);
|
||||
}
|
||||
|
||||
static bool
|
||||
lower_load_helper_to_is_helper(nir_builder *b,
|
||||
nir_intrinsic_instr *intrin, void *data)
|
||||
{
|
||||
nir_def *is_helper = *(nir_def **)data;
|
||||
switch (intrin->intrinsic) {
|
||||
case nir_intrinsic_demote:
|
||||
case nir_intrinsic_demote_if:
|
||||
/* insert is_helper at last top level occasion */
|
||||
if (is_helper == NULL) {
|
||||
is_helper = insert_is_helper(b, &intrin->instr);
|
||||
*(nir_def **)data = is_helper;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case nir_intrinsic_load_helper_invocation:
|
||||
/* Don't update data: as long as we didn't encounter any demote(),
|
||||
* we can insert new is_helper() intrinsics. These are placed at
|
||||
* top-level blocks to ensure correct behavior w.r.t. loops */
|
||||
if (is_helper == NULL)
|
||||
is_helper = insert_is_helper(b, &intrin->instr);
|
||||
nir_def_rewrite_uses(&intrin->def, is_helper);
|
||||
nir_instr_remove(&intrin->instr);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize discard and demote opcodes.
|
||||
*
|
||||
* If force_correct_quad_ops_after_discard is true and quad operations are
|
||||
* used, discard() will be converted to demote() and gl_HelperInvocation will
|
||||
* be lowered to helperInvocationEXT(). This is intended as workaround for
|
||||
* game bugs to force correct derivatives after kill. This lowering is not
|
||||
* valid in the general case as it might change the result of subgroup
|
||||
* operations and loop behavior.
|
||||
*
|
||||
* Otherwise, if demote is used and no ops need helper invocations, demote()
|
||||
* will be converted to discard() as an optimization.
|
||||
*/
|
||||
bool
|
||||
nir_lower_discard_or_demote(nir_shader *shader,
|
||||
bool force_correct_quad_ops_after_discard)
|
||||
{
|
||||
if (shader->info.stage != MESA_SHADER_FRAGMENT)
|
||||
return false;
|
||||
|
||||
/* We need uses_discard/demote and needs_*_helper_invocations. */
|
||||
nir_shader_gather_info(shader, nir_shader_get_entrypoint(shader));
|
||||
/* Validate that if uses_demote is set, uses_discard is also be set. */
|
||||
assert(!shader->info.fs.uses_demote || shader->info.fs.uses_discard);
|
||||
|
||||
/* Quick skip. */
|
||||
if (!shader->info.fs.uses_discard)
|
||||
return false;
|
||||
|
||||
bool progress = false;
|
||||
|
||||
if (force_correct_quad_ops_after_discard &&
|
||||
shader->info.fs.needs_quad_helper_invocations) {
|
||||
/* If we need correct derivatives, convert discard to demote only when
|
||||
* derivatives are actually used.
|
||||
*/
|
||||
progress = nir_shader_intrinsics_pass(shader, lower_discard_to_demote,
|
||||
nir_metadata_block_index |
|
||||
nir_metadata_dominance |
|
||||
nir_metadata_live_defs |
|
||||
nir_metadata_instr_index,
|
||||
NULL);
|
||||
shader->info.fs.uses_demote = true;
|
||||
} else if (!shader->info.fs.needs_quad_helper_invocations &&
|
||||
!shader->info.uses_wide_subgroup_intrinsics &&
|
||||
shader->info.fs.uses_demote) {
|
||||
/* If we don't need any helper invocations, convert demote to discard. */
|
||||
progress = nir_shader_intrinsics_pass(shader, lower_demote_to_discard,
|
||||
nir_metadata_block_index |
|
||||
nir_metadata_dominance,
|
||||
NULL);
|
||||
shader->info.fs.uses_demote = false;
|
||||
} else if (shader->info.fs.uses_demote &&
|
||||
BITSET_TEST(shader->info.system_values_read,
|
||||
nir_system_value_from_intrinsic(nir_intrinsic_load_helper_invocation))) {
|
||||
/* load_helper needs to preserve the value (whether an invocation is
|
||||
* a helper lane) from the beginning of the shader. */
|
||||
nir_def *is_helper = NULL;
|
||||
progress = nir_shader_intrinsics_pass(shader,
|
||||
lower_load_helper_to_is_helper,
|
||||
nir_metadata_block_index |
|
||||
nir_metadata_dominance,
|
||||
&is_helper);
|
||||
BITSET_CLEAR(shader->info.system_values_read,
|
||||
nir_system_value_from_intrinsic(nir_intrinsic_load_helper_invocation));
|
||||
}
|
||||
|
||||
/* Validate again that if uses_demote is set, uses_discard is also be set. */
|
||||
assert(!shader->info.fs.uses_demote || shader->info.fs.uses_discard);
|
||||
return progress;
|
||||
}
|
||||
|
|
@ -84,16 +84,12 @@ nir_opt_conditional_discard_block(nir_builder *b, nir_block *block)
|
|||
b->cursor = nir_before_cf_node(prev_node);
|
||||
|
||||
switch (intrin->intrinsic) {
|
||||
case nir_intrinsic_discard:
|
||||
op = nir_intrinsic_discard_if;
|
||||
break;
|
||||
case nir_intrinsic_demote:
|
||||
op = nir_intrinsic_demote_if;
|
||||
break;
|
||||
case nir_intrinsic_terminate:
|
||||
op = nir_intrinsic_terminate_if;
|
||||
break;
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_demote_if:
|
||||
case nir_intrinsic_terminate_if:
|
||||
cond = nir_iand(b, cond, intrin->src[0].ssa);
|
||||
|
|
|
|||
|
|
@ -175,16 +175,12 @@ try_fold_intrinsic(nir_builder *b, nir_intrinsic_instr *intrin,
|
|||
{
|
||||
switch (intrin->intrinsic) {
|
||||
case nir_intrinsic_demote_if:
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate_if:
|
||||
if (nir_src_is_const(intrin->src[0])) {
|
||||
if (nir_src_as_bool(intrin->src[0])) {
|
||||
b->cursor = nir_before_instr(&intrin->instr);
|
||||
nir_intrinsic_op op;
|
||||
switch (intrin->intrinsic) {
|
||||
case nir_intrinsic_discard_if:
|
||||
op = nir_intrinsic_discard;
|
||||
break;
|
||||
case nir_intrinsic_demote_if:
|
||||
op = nir_intrinsic_demote;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -375,9 +375,7 @@ opt_intrinsics_impl(nir_function_impl *impl,
|
|||
|
||||
case nir_instr_type_intrinsic: {
|
||||
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
|
||||
if (intrin->intrinsic == nir_intrinsic_discard ||
|
||||
intrin->intrinsic == nir_intrinsic_discard_if ||
|
||||
intrin->intrinsic == nir_intrinsic_demote ||
|
||||
if (intrin->intrinsic == nir_intrinsic_demote ||
|
||||
intrin->intrinsic == nir_intrinsic_demote_if ||
|
||||
intrin->intrinsic == nir_intrinsic_terminate ||
|
||||
intrin->intrinsic == nir_intrinsic_terminate_if)
|
||||
|
|
|
|||
|
|
@ -1310,8 +1310,6 @@ handle_barrier(struct vectorize_ctx *ctx, bool *progress, nir_function_impl *imp
|
|||
nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
|
||||
switch (intrin->intrinsic) {
|
||||
/* prevent speculative loads/stores */
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate_if:
|
||||
case nir_intrinsic_terminate:
|
||||
case nir_intrinsic_launch_mesh_workgroups:
|
||||
|
|
|
|||
|
|
@ -195,9 +195,9 @@ opt_move_discards_to_top_impl(nir_function_impl *impl)
|
|||
case nir_intrinsic_masked_swizzle_amd:
|
||||
instr->pass_flags = STOP_PROCESSING_INSTR_FLAG;
|
||||
goto break_all;
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate_if:
|
||||
if (!consider_discards) {
|
||||
/* assume that a shader either uses discard or demote, but not both */
|
||||
/* assume that a shader either uses terminate or demote, but not both */
|
||||
instr->pass_flags = STOP_PROCESSING_INSTR_FLAG;
|
||||
goto break_all;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,8 +80,6 @@ block_check_for_allowed_instrs(nir_block *block, unsigned *count,
|
|||
switch (intr->intrinsic) {
|
||||
case nir_intrinsic_terminate:
|
||||
case nir_intrinsic_terminate_if:
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_discard_if:
|
||||
/* For non-CF hardware, we need to be able to move discards up
|
||||
* and flatten, so let them pass.
|
||||
*/
|
||||
|
|
@ -394,8 +392,7 @@ rewrite_discard_conds(nir_instr *instr, nir_def *if_cond, bool is_else)
|
|||
return;
|
||||
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
|
||||
|
||||
if (intr->intrinsic != nir_intrinsic_discard_if && intr->intrinsic != nir_intrinsic_discard &&
|
||||
intr->intrinsic != nir_intrinsic_terminate_if && intr->intrinsic != nir_intrinsic_terminate)
|
||||
if (intr->intrinsic != nir_intrinsic_terminate_if && intr->intrinsic != nir_intrinsic_terminate)
|
||||
return;
|
||||
|
||||
nir_builder b = nir_builder_at(nir_before_instr(instr));
|
||||
|
|
@ -403,8 +400,7 @@ rewrite_discard_conds(nir_instr *instr, nir_def *if_cond, bool is_else)
|
|||
if (is_else)
|
||||
if_cond = nir_inot(&b, if_cond);
|
||||
|
||||
if (intr->intrinsic == nir_intrinsic_discard_if ||
|
||||
intr->intrinsic == nir_intrinsic_terminate_if) {
|
||||
if (intr->intrinsic == nir_intrinsic_terminate_if) {
|
||||
nir_src_rewrite(&intr->src[0], nir_iand(&b, intr->src[0].ssa, if_cond));
|
||||
} else {
|
||||
nir_discard_if(&b, if_cond);
|
||||
|
|
|
|||
|
|
@ -349,8 +349,6 @@ nir_schedule_intrinsic_deps(nir_deps_state *state,
|
|||
case nir_intrinsic_load_front_face:
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_demote:
|
||||
case nir_intrinsic_demote_if:
|
||||
case nir_intrinsic_terminate:
|
||||
|
|
|
|||
|
|
@ -2637,16 +2637,13 @@ emit_intrinsic(struct ir3_context *ctx, nir_intrinsic_instr *intr)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_demote:
|
||||
case nir_intrinsic_demote_if:
|
||||
case nir_intrinsic_terminate:
|
||||
case nir_intrinsic_terminate_if: {
|
||||
struct ir3_instruction *cond, *kill;
|
||||
|
||||
if (intr->intrinsic == nir_intrinsic_discard_if ||
|
||||
intr->intrinsic == nir_intrinsic_demote_if ||
|
||||
if (intr->intrinsic == nir_intrinsic_demote_if ||
|
||||
intr->intrinsic == nir_intrinsic_terminate_if) {
|
||||
/* conditional discard: */
|
||||
src = ir3_get_src(ctx, &intr->src[0]);
|
||||
|
|
@ -3969,8 +3966,6 @@ instr_can_be_predicated(nir_instr *instr)
|
|||
case nir_intrinsic_ballot:
|
||||
case nir_intrinsic_elect:
|
||||
case nir_intrinsic_read_invocation_cond_ir3:
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_demote:
|
||||
case nir_intrinsic_demote_if:
|
||||
case nir_intrinsic_terminate:
|
||||
|
|
|
|||
|
|
@ -1901,7 +1901,7 @@ visit_discard(struct lp_build_nir_context *bld_base,
|
|||
nir_intrinsic_instr *instr)
|
||||
{
|
||||
LLVMValueRef cond = NULL;
|
||||
if (instr->intrinsic == nir_intrinsic_discard_if) {
|
||||
if (instr->intrinsic == nir_intrinsic_terminate_if) {
|
||||
cond = get_src(bld_base, instr->src[0]);
|
||||
cond = cast_type(bld_base, cond, nir_type_int, 32);
|
||||
}
|
||||
|
|
@ -2175,8 +2175,8 @@ visit_intrinsic(struct lp_build_nir_context *bld_base,
|
|||
case nir_intrinsic_load_helper_invocation:
|
||||
bld_base->helper_invocation(bld_base, &result[0]);
|
||||
break;
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate_if:
|
||||
case nir_intrinsic_terminate:
|
||||
visit_discard(bld_base, instr);
|
||||
break;
|
||||
case nir_intrinsic_emit_vertex:
|
||||
|
|
|
|||
|
|
@ -2558,11 +2558,11 @@ ntt_emit_intrinsic(struct ntt_compile *c, nir_intrinsic_instr *instr)
|
|||
ntt_DEMOTE(c);
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
ntt_KILL(c);
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard_if: {
|
||||
case nir_intrinsic_terminate_if: {
|
||||
struct ureg_src cond = ureg_scalar(ntt_get_src(c, instr->src[0]), 0);
|
||||
|
||||
if (c->native_integers) {
|
||||
|
|
|
|||
|
|
@ -561,10 +561,10 @@ emit_intrinsic(struct etna_compile *c, nir_intrinsic_instr * intr)
|
|||
case nir_intrinsic_store_deref:
|
||||
etna_emit_output(c, nir_src_as_deref(intr->src[0])->var, get_src(c, &intr->src[1]));
|
||||
break;
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate_if:
|
||||
etna_emit_discard(c, get_src(c, &intr->src[0]));
|
||||
break;
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
etna_emit_discard(c, SRC_DISABLE);
|
||||
break;
|
||||
case nir_intrinsic_load_uniform: {
|
||||
|
|
|
|||
|
|
@ -644,11 +644,11 @@ emit_intrinsic(struct ir2_context *ctx, nir_intrinsic_instr *intr)
|
|||
instr = instr_create_alu_dest(ctx, nir_op_mov, &intr->def);
|
||||
instr->src[0] = ir2_src(idx, 0, IR2_SRC_CONST);
|
||||
break;
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate:
|
||||
case nir_intrinsic_terminate_if:
|
||||
instr = ir2_instr_create(ctx, IR2_ALU);
|
||||
instr->alu.vector_opc = VECTOR_NONE;
|
||||
if (intr->intrinsic == nir_intrinsic_discard_if) {
|
||||
if (intr->intrinsic == nir_intrinsic_terminate_if) {
|
||||
instr->alu.scalar_opc = KILLNEs;
|
||||
instr->src[0] = make_src(ctx, intr->src[0]);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -437,12 +437,12 @@ static bool ppir_emit_intrinsic(ppir_block *block, nir_instr *ni)
|
|||
return true;
|
||||
}
|
||||
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
node = ppir_emit_discard(block, ni);
|
||||
list_addtail(&node->list, &block->node_list);
|
||||
return true;
|
||||
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate_if:
|
||||
node = ppir_emit_discard_if(block, ni);
|
||||
list_addtail(&node->list, &block->node_list);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1621,11 +1621,11 @@ ntr_emit_intrinsic(struct ntr_compile *c, nir_intrinsic_instr *instr)
|
|||
ntr_emit_load_output(c, instr);
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
ntr_KILL(c);
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard_if: {
|
||||
case nir_intrinsic_terminate_if: {
|
||||
struct ureg_src cond = ureg_scalar(ntr_get_src(c, instr->src[0]), 0);
|
||||
/* For !native_integers, the bool got lowered to 1.0 or 0.0. */
|
||||
ntr_KILL_IF(c, ureg_negate(cond));
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ FragmentShader::process_stage_intrinsic(nir_intrinsic_instr *intr)
|
|||
return load_input(intr);
|
||||
case nir_intrinsic_load_interpolated_input:
|
||||
return load_interpolated_input(intr);
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate_if:
|
||||
m_uses_discard = true;
|
||||
emit_instruction(new AluInstr(op2_killne_int,
|
||||
nullptr,
|
||||
|
|
@ -146,7 +146,7 @@ FragmentShader::process_stage_intrinsic(nir_intrinsic_instr *intr)
|
|||
{AluInstr::last}));
|
||||
|
||||
return true;
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
m_uses_discard = true;
|
||||
emit_instruction(new AluInstr(op2_kille_int,
|
||||
nullptr,
|
||||
|
|
|
|||
|
|
@ -303,8 +303,6 @@ static void si_lower_nir(struct si_screen *sscreen, struct nir_shader *nir)
|
|||
|
||||
NIR_PASS_V(nir, nir_lower_subgroups, sscreen->nir_lower_subgroups_options);
|
||||
|
||||
NIR_PASS_V(nir, nir_lower_discard_or_demote, true);
|
||||
|
||||
/* Lower load constants to scalar and then clean up the mess */
|
||||
NIR_PASS_V(nir, nir_lower_load_const_to_scalar);
|
||||
NIR_PASS_V(nir, nir_lower_var_copies);
|
||||
|
|
|
|||
|
|
@ -1815,7 +1815,7 @@ ntq_emit_intrinsic(struct vc4_compile *c, nir_intrinsic_instr *instr)
|
|||
}
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
if (c->execute.file != QFILE_NULL) {
|
||||
qir_SF(c, c->execute);
|
||||
qir_MOV_cond(c, QPU_COND_ZS, c->discard,
|
||||
|
|
@ -1825,7 +1825,7 @@ ntq_emit_intrinsic(struct vc4_compile *c, nir_intrinsic_instr *instr)
|
|||
}
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard_if: {
|
||||
case nir_intrinsic_terminate_if: {
|
||||
/* true (~0) if we're discarding */
|
||||
struct qreg cond = ntq_get_src(c, instr->src[0], 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -3228,7 +3228,7 @@ emit_intrinsic(struct ntv_context *ctx, nir_intrinsic_instr *intr)
|
|||
emit_store_reg(ctx, intr);
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
emit_discard(ctx, intr);
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -6228,10 +6228,6 @@ zink_shader_init(struct zink_screen *screen, struct zink_shader *zs)
|
|||
NIR_PASS_V(nir, strip_tex_ms);
|
||||
NIR_PASS_V(nir, nir_lower_frexp); /* TODO: Use the spirv instructions for this. */
|
||||
|
||||
if (screen->info.have_EXT_shader_demote_to_helper_invocation) {
|
||||
NIR_PASS_V(nir, nir_lower_discard_or_demote, true);
|
||||
}
|
||||
|
||||
if (screen->need_2D_zs)
|
||||
NIR_PASS_V(nir, lower_1d_shadow, screen);
|
||||
|
||||
|
|
|
|||
|
|
@ -169,12 +169,12 @@ remove_barriers(nir_shader *nir, bool is_compute)
|
|||
static bool
|
||||
lower_demote_impl(nir_builder *b, nir_intrinsic_instr *intr, void *data)
|
||||
{
|
||||
if (intr->intrinsic == nir_intrinsic_demote || intr->intrinsic == nir_intrinsic_terminate) {
|
||||
intr->intrinsic = nir_intrinsic_discard;
|
||||
if (intr->intrinsic == nir_intrinsic_demote) {
|
||||
intr->intrinsic = nir_intrinsic_terminate;
|
||||
return true;
|
||||
}
|
||||
if (intr->intrinsic == nir_intrinsic_demote_if || intr->intrinsic == nir_intrinsic_terminate_if) {
|
||||
intr->intrinsic = nir_intrinsic_discard_if;
|
||||
if (intr->intrinsic == nir_intrinsic_demote_if) {
|
||||
intr->intrinsic = nir_intrinsic_terminate_if;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -3904,10 +3904,8 @@ fs_nir_emit_fs_intrinsic(nir_to_brw_state &ntb,
|
|||
}
|
||||
|
||||
case nir_intrinsic_demote:
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
case nir_intrinsic_demote_if:
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate_if: {
|
||||
/* We track our discarded pixels in f0.1/f1.0. By predicating on it, we
|
||||
* can update just the flag bits that aren't yet discarded. If there's
|
||||
|
|
@ -3916,7 +3914,6 @@ fs_nir_emit_fs_intrinsic(nir_to_brw_state &ntb,
|
|||
*/
|
||||
fs_inst *cmp = NULL;
|
||||
if (instr->intrinsic == nir_intrinsic_demote_if ||
|
||||
instr->intrinsic == nir_intrinsic_discard_if ||
|
||||
instr->intrinsic == nir_intrinsic_terminate_if) {
|
||||
nir_alu_instr *alu = nir_src_as_alu_instr(instr->src[0]);
|
||||
|
||||
|
|
|
|||
|
|
@ -3748,10 +3748,8 @@ fs_nir_emit_fs_intrinsic(nir_to_elk_state &ntb,
|
|||
}
|
||||
|
||||
case nir_intrinsic_demote:
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
case nir_intrinsic_demote_if:
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate_if: {
|
||||
/* We track our discarded pixels in f0.1/f1.0. By predicating on it, we
|
||||
* can update just the flag bits that aren't yet discarded. If there's
|
||||
|
|
@ -3760,7 +3758,6 @@ fs_nir_emit_fs_intrinsic(nir_to_elk_state &ntb,
|
|||
*/
|
||||
elk_fs_inst *cmp = NULL;
|
||||
if (instr->intrinsic == nir_intrinsic_demote_if ||
|
||||
instr->intrinsic == nir_intrinsic_discard_if ||
|
||||
instr->intrinsic == nir_intrinsic_terminate_if) {
|
||||
nir_alu_instr *alu = nir_src_as_alu_instr(instr->src[0]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1826,17 +1826,14 @@ static bool
|
|||
lower_kill(struct nir_builder *builder, nir_intrinsic_instr *intr,
|
||||
void *_cb_data)
|
||||
{
|
||||
if (intr->intrinsic != nir_intrinsic_discard &&
|
||||
intr->intrinsic != nir_intrinsic_terminate &&
|
||||
intr->intrinsic != nir_intrinsic_discard_if &&
|
||||
if (intr->intrinsic != nir_intrinsic_terminate &&
|
||||
intr->intrinsic != nir_intrinsic_terminate_if)
|
||||
return false;
|
||||
|
||||
builder->cursor = nir_instr_remove(&intr->instr);
|
||||
nir_def *condition;
|
||||
|
||||
if (intr->intrinsic == nir_intrinsic_discard ||
|
||||
intr->intrinsic == nir_intrinsic_terminate) {
|
||||
if (intr->intrinsic == nir_intrinsic_terminate) {
|
||||
nir_demote(builder);
|
||||
condition = nir_imm_true(builder);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4833,10 +4833,10 @@ emit_intrinsic(struct ntd_context *ctx, nir_intrinsic_instr *intr)
|
|||
return emit_load_sample_mask_in(ctx, intr);
|
||||
case nir_intrinsic_load_tess_coord:
|
||||
return emit_load_tess_coord(ctx, intr);
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate_if:
|
||||
case nir_intrinsic_demote_if:
|
||||
return emit_discard_if(ctx, intr);
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
case nir_intrinsic_demote:
|
||||
return emit_discard(ctx);
|
||||
case nir_intrinsic_emit_vertex:
|
||||
|
|
|
|||
|
|
@ -972,12 +972,6 @@ dxil_spirv_nir_passes(nir_shader *nir,
|
|||
.use_view_id_for_layer = !conf->lower_view_index,
|
||||
});
|
||||
|
||||
/* This will lower load_helper to a memoized is_helper if needed; otherwise, load_helper
|
||||
* will stay, but trivially translatable to IsHelperLane(), which will be known to be
|
||||
* constant across the invocation since no demotion would have been used.
|
||||
*/
|
||||
NIR_PASS_V(nir, nir_lower_discard_or_demote, nir->info.use_legacy_math_rules);
|
||||
|
||||
NIR_PASS_V(nir, dxil_nir_lower_discard_and_terminate);
|
||||
NIR_PASS_V(nir, nir_lower_returns);
|
||||
NIR_PASS_V(nir, dxil_nir_lower_sample_pos);
|
||||
|
|
|
|||
|
|
@ -1860,14 +1860,12 @@ Converter::visit(nir_intrinsic_instr *insn)
|
|||
break;
|
||||
}
|
||||
case nir_intrinsic_demote:
|
||||
case nir_intrinsic_discard:
|
||||
mkOp(OP_DISCARD, TYPE_NONE, NULL);
|
||||
break;
|
||||
case nir_intrinsic_demote_if:
|
||||
case nir_intrinsic_discard_if: {
|
||||
case nir_intrinsic_demote_if: {
|
||||
Value *pred = getSSA(1, FILE_PREDICATE);
|
||||
if (insn->num_components > 1) {
|
||||
ERROR("nir_intrinsic_discard_if only with 1 component supported!\n");
|
||||
ERROR("nir_intrinsic_demote_if only with 1 component supported!\n");
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2311,7 +2311,7 @@ impl<'a> ShaderFromNir<'a> {
|
|||
|
||||
b.push_op(OpFSOut { srcs: srcs });
|
||||
}
|
||||
nir_intrinsic_demote | nir_intrinsic_discard => {
|
||||
nir_intrinsic_demote => {
|
||||
if let ShaderIoInfo::Fragment(info) = &mut self.info.io {
|
||||
info.uses_kill = true;
|
||||
} else {
|
||||
|
|
@ -2319,7 +2319,7 @@ impl<'a> ShaderFromNir<'a> {
|
|||
}
|
||||
b.push_op(OpKill {});
|
||||
}
|
||||
nir_intrinsic_demote_if | nir_intrinsic_discard_if => {
|
||||
nir_intrinsic_demote_if => {
|
||||
if let ShaderIoInfo::Fragment(info) = &mut self.info.io {
|
||||
info.uses_kill = true;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1743,11 +1743,11 @@ bi_emit_intrinsic(bi_builder *b, nir_intrinsic_instr *instr)
|
|||
bi_emit_ld_tile(b, instr);
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_terminate_if:
|
||||
bi_discard_b32(b, bi_src_index(&instr->src[0]));
|
||||
break;
|
||||
|
||||
case nir_intrinsic_discard:
|
||||
case nir_intrinsic_terminate:
|
||||
bi_discard_f32(b, bi_zero(), bi_zero(), BI_CMPF_EQ);
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -1570,9 +1570,9 @@ emit_intrinsic(compiler_context *ctx, nir_intrinsic_instr *instr)
|
|||
break;
|
||||
}
|
||||
|
||||
case nir_intrinsic_discard_if:
|
||||
case nir_intrinsic_discard: {
|
||||
bool conditional = instr->intrinsic == nir_intrinsic_discard_if;
|
||||
case nir_intrinsic_terminate_if:
|
||||
case nir_intrinsic_terminate: {
|
||||
bool conditional = instr->intrinsic == nir_intrinsic_terminate_if;
|
||||
struct midgard_instruction discard = v_branch(conditional, false);
|
||||
discard.branch.target_type = TARGET_DISCARD;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue