nir/lower_idiv: Convert to lower_instructions

Helps deduplicate some code between the two lowering paths. In
particular, it ports the missing 32-bit? check to the precise pass. This
does not change anything immediately: drivers depending on this to lower
16-bit did not work before due to type mismatches and will not work now
since it'll refuse to lower. But that means sub-32-bit idiv can be
lowered more efficiently in an algebraic pass.

Signed-off-by: Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8339>
This commit is contained in:
Alyssa Rosenzweig
2021-01-05 11:22:19 -05:00
committed by Marge Bot
parent e4da24bd24
commit 7b0eb4aa00

View File

@@ -40,26 +40,17 @@
* AMDGPU target. It should handle 32-bit idiv/irem/imod/udiv/umod exactly.
*/
static bool
static nir_ssa_def *
convert_instr(nir_builder *bld, nir_alu_instr *alu)
{
nir_ssa_def *numer, *denom, *af, *bf, *a, *b, *q, *r, *rt;
nir_op op = alu->op;
bool is_signed;
if ((op != nir_op_idiv) &&
(op != nir_op_udiv) &&
(op != nir_op_imod) &&
(op != nir_op_umod) &&
(op != nir_op_irem))
return false;
is_signed = (op == nir_op_idiv ||
op == nir_op_imod ||
op == nir_op_irem);
bld->cursor = nir_before_instr(&alu->instr);
numer = nir_ssa_for_alu_src(bld, alu, 0);
denom = nir_ssa_for_alu_src(bld, alu, 1);
@@ -128,10 +119,7 @@ convert_instr(nir_builder *bld, nir_alu_instr *alu)
}
}
assert(alu->dest.dest.is_ssa);
nir_ssa_def_rewrite_uses(&alu->dest.dest.ssa, q);
return true;
return q;
}
/* ported from LLVM's AMDGPUTargetLowering::LowerUDIVREM */
@@ -203,70 +191,58 @@ emit_idiv(nir_builder *bld, nir_ssa_def *numer, nir_ssa_def *denom, nir_op op)
}
}
static bool
static nir_ssa_def *
convert_instr_precise(nir_builder *bld, nir_alu_instr *alu)
{
nir_op op = alu->op;
nir_ssa_def *numer = nir_ssa_for_alu_src(bld, alu, 0);
nir_ssa_def *denom = nir_ssa_for_alu_src(bld, alu, 1);
if ((op != nir_op_idiv) &&
(op != nir_op_imod) &&
(op != nir_op_irem) &&
(op != nir_op_udiv) &&
(op != nir_op_umod))
if (op == nir_op_udiv || op == nir_op_umod)
return emit_udiv(bld, numer, denom, op == nir_op_umod);
else
return emit_idiv(bld, numer, denom, op);
}
static nir_ssa_def *
lower_idiv(nir_builder *b, nir_instr *instr, void *_data)
{
enum nir_lower_idiv_path *path = _data;
if (*path == nir_lower_idiv_precise)
return convert_instr_precise(b, nir_instr_as_alu(instr));
else
return convert_instr(b, nir_instr_as_alu(instr));
}
static bool
inst_is_idiv(const nir_instr *instr, UNUSED const void *_state)
{
if (instr->type != nir_instr_type_alu)
return false;
nir_alu_instr *alu = nir_instr_as_alu(instr);
if (alu->dest.dest.ssa.bit_size != 32)
return false;
bld->cursor = nir_before_instr(&alu->instr);
nir_ssa_def *numer = nir_ssa_for_alu_src(bld, alu, 0);
nir_ssa_def *denom = nir_ssa_for_alu_src(bld, alu, 1);
nir_ssa_def *res = NULL;
if (op == nir_op_udiv || op == nir_op_umod)
res = emit_udiv(bld, numer, denom, op == nir_op_umod);
else
res = emit_idiv(bld, numer, denom, op);
assert(alu->dest.dest.is_ssa);
nir_ssa_def_rewrite_uses(&alu->dest.dest.ssa, res);
switch (alu->op) {
case nir_op_idiv:
case nir_op_udiv:
case nir_op_imod:
case nir_op_umod:
case nir_op_irem:
return true;
}
static bool
convert_impl(nir_function_impl *impl, enum nir_lower_idiv_path path)
{
nir_builder b;
nir_builder_init(&b, impl);
bool progress = false;
nir_foreach_block(block, impl) {
nir_foreach_instr_safe(instr, block) {
if (instr->type == nir_instr_type_alu && path == nir_lower_idiv_precise)
progress |= convert_instr_precise(&b, nir_instr_as_alu(instr));
else if (instr->type == nir_instr_type_alu)
progress |= convert_instr(&b, nir_instr_as_alu(instr));
default:
return false;
}
}
nir_metadata_preserve(impl, nir_metadata_block_index |
nir_metadata_dominance);
return progress;
}
bool
nir_lower_idiv(nir_shader *shader, enum nir_lower_idiv_path path)
{
bool progress = false;
nir_foreach_function(function, shader) {
if (function->impl)
progress |= convert_impl(function->impl, path);
}
return progress;
return nir_shader_lower_instructions(shader,
inst_is_idiv,
lower_idiv,
&path);
}