* branch out to a pre-optimized shader library routine..
*/
-static void
+static bool
convert_instr(nir_builder *bld, nir_alu_instr *alu)
{
nir_ssa_def *numer, *denom, *af, *bf, *a, *b, *q, *r;
if ((op != nir_op_idiv) &&
(op != nir_op_udiv) &&
(op != nir_op_umod))
- return;
+ return false;
is_signed = (op == nir_op_idiv);
denom = nir_ssa_for_alu_src(bld, alu, 1);
if (is_signed) {
- af = nir_i2f(bld, numer);
- bf = nir_i2f(bld, denom);
+ af = nir_i2f32(bld, numer);
+ bf = nir_i2f32(bld, denom);
af = nir_fabs(bld, af);
bf = nir_fabs(bld, bf);
a = nir_iabs(bld, numer);
b = nir_iabs(bld, denom);
} else {
- af = nir_u2f(bld, numer);
- bf = nir_u2f(bld, denom);
+ af = nir_u2f32(bld, numer);
+ bf = nir_u2f32(bld, denom);
a = numer;
b = denom;
}
q = nir_fmul(bld, af, bf);
if (is_signed) {
- q = nir_f2i(bld, q);
+ q = nir_f2i32(bld, q);
} else {
- q = nir_f2u(bld, q);
+ q = nir_f2u32(bld, q);
}
/* get error of first result: */
r = nir_imul(bld, q, b);
r = nir_isub(bld, a, r);
- r = nir_u2f(bld, r);
+ r = nir_u2f32(bld, r);
r = nir_fmul(bld, r, bf);
- r = nir_f2u(bld, r);
+ r = nir_f2u32(bld, r);
/* add quotients: */
q = nir_iadd(bld, q, r);
if (is_signed) {
/* fix the sign: */
r = nir_ixor(bld, numer, denom);
- r = nir_ushr(bld, r, nir_imm_int(bld, 31));
- r = nir_i2b(bld, r);
+ r = nir_ishr(bld, r, nir_imm_int(bld, 31));
b = nir_ineg(bld, q);
q = nir_bcsel(bld, r, b, q);
}
assert(alu->dest.dest.is_ssa);
nir_ssa_def_rewrite_uses(&alu->dest.dest.ssa, nir_src_for_ssa(q));
-}
-
-static bool
-convert_block(nir_block *block, void *state)
-{
- nir_builder *b = state;
-
- nir_foreach_instr_safe(block, instr) {
- if (instr->type == nir_instr_type_alu)
- convert_instr(b, nir_instr_as_alu(instr));
- }
return true;
}
-static void
+static bool
convert_impl(nir_function_impl *impl)
{
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)
+ progress |= convert_instr(&b, nir_instr_as_alu(instr));
+ }
+ }
- nir_foreach_block(impl, convert_block, &b);
nir_metadata_preserve(impl, nir_metadata_block_index |
nir_metadata_dominance);
+
+ return progress;
}
-void
+bool
nir_lower_idiv(nir_shader *shader)
{
- nir_foreach_function(shader, function) {
+ bool progress = false;
+
+ nir_foreach_function(function, shader) {
if (function->impl)
- convert_impl(function->impl);
+ progress |= convert_impl(function->impl);
}
+
+ return progress;
}