+/* ported from LLVM's AMDGPUTargetLowering::LowerSDIVREM */
+static nir_ssa_def *
+emit_idiv(nir_builder *bld, nir_ssa_def *numer, nir_ssa_def *denom, nir_op op)
+{
+ nir_ssa_def *lh_sign = nir_ilt(bld, numer, nir_imm_int(bld, 0));
+ nir_ssa_def *rh_sign = nir_ilt(bld, denom, nir_imm_int(bld, 0));
+ lh_sign = nir_bcsel(bld, lh_sign, nir_imm_int(bld, -1), nir_imm_int(bld, 0));
+ rh_sign = nir_bcsel(bld, rh_sign, nir_imm_int(bld, -1), nir_imm_int(bld, 0));
+
+ nir_ssa_def *lhs = nir_iadd(bld, numer, lh_sign);
+ nir_ssa_def *rhs = nir_iadd(bld, denom, rh_sign);
+ lhs = nir_ixor(bld, lhs, lh_sign);
+ rhs = nir_ixor(bld, rhs, rh_sign);
+
+ if (op == nir_op_idiv) {
+ nir_ssa_def *d_sign = nir_ixor(bld, lh_sign, rh_sign);
+ nir_ssa_def *res = emit_udiv(bld, lhs, rhs, false);
+ res = nir_ixor(bld, res, d_sign);
+ return nir_isub(bld, res, d_sign);
+ } else {
+ nir_ssa_def *res = emit_udiv(bld, lhs, rhs, true);
+ res = nir_ixor(bld, res, lh_sign);
+ res = nir_isub(bld, res, lh_sign);
+ if (op == nir_op_imod) {
+ nir_ssa_def *cond = nir_ieq(bld, res, nir_imm_int(bld, 0));
+ cond = nir_ior(bld, nir_ieq(bld, lh_sign, rh_sign), cond);
+ res = nir_bcsel(bld, cond, res, nir_iadd(bld, res, denom));
+ }
+ return res;
+ }
+}
+
+static bool
+convert_instr_precise(nir_builder *bld, nir_alu_instr *alu)
+{
+ nir_op op = alu->op;
+
+ if ((op != nir_op_idiv) &&
+ (op != nir_op_imod) &&
+ (op != nir_op_irem) &&
+ (op != nir_op_udiv) &&
+ (op != nir_op_umod))
+ return false;
+
+ 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, nir_src_for_ssa(res));
+
+ return true;
+}
+
+static bool
+convert_impl(nir_function_impl *impl, enum nir_lower_idiv_path path)