+ assert(nir_op_infos[instr->op].num_inputs + 1 == func->num_params);
+ for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) {
+ assert(i + 1 < ARRAY_SIZE(params));
+ params[i + 1] = nir_mov_alu(b, instr->src[i], 1);
+ }
+
+ nir_inline_function_impl(b, func->impl, params);
+
+ return nir_load_deref(b, ret_deref);
+}
+
+nir_lower_doubles_options
+nir_lower_doubles_op_to_options_mask(nir_op opcode)
+{
+ switch (opcode) {
+ case nir_op_frcp: return nir_lower_drcp;
+ case nir_op_fsqrt: return nir_lower_dsqrt;
+ case nir_op_frsq: return nir_lower_drsq;
+ case nir_op_ftrunc: return nir_lower_dtrunc;
+ case nir_op_ffloor: return nir_lower_dfloor;
+ case nir_op_fceil: return nir_lower_dceil;
+ case nir_op_ffract: return nir_lower_dfract;
+ case nir_op_fround_even: return nir_lower_dround_even;
+ case nir_op_fmod: return nir_lower_dmod;
+ case nir_op_fsub: return nir_lower_dsub;
+ case nir_op_fdiv: return nir_lower_ddiv;
+ default: return 0;
+ }
+}
+
+struct lower_doubles_data {
+ const nir_shader *softfp64;
+ nir_lower_doubles_options options;
+};
+
+static bool
+should_lower_double_instr(const nir_instr *instr, const void *_data)
+{
+ const struct lower_doubles_data *data = _data;
+ const nir_lower_doubles_options options = data->options;
+
+ if (instr->type != nir_instr_type_alu)
+ return false;
+
+ const nir_alu_instr *alu = nir_instr_as_alu(instr);
+
+ assert(alu->dest.dest.is_ssa);
+ bool is_64 = alu->dest.dest.ssa.bit_size == 64;
+
+ unsigned num_srcs = nir_op_infos[alu->op].num_inputs;
+ for (unsigned i = 0; i < num_srcs; i++) {
+ is_64 |= (nir_src_bit_size(alu->src[i].src) == 64);
+ }
+
+ if (!is_64)
+ return false;
+
+ if (options & nir_lower_fp64_full_software)
+ return true;
+
+ return options & nir_lower_doubles_op_to_options_mask(alu->op);
+}
+
+static nir_ssa_def *
+lower_doubles_instr(nir_builder *b, nir_instr *instr, void *_data)
+{
+ const struct lower_doubles_data *data = _data;
+ const nir_lower_doubles_options options = data->options;
+ nir_alu_instr *alu = nir_instr_as_alu(instr);
+
+ nir_ssa_def *soft_def =
+ lower_doubles_instr_to_soft(b, alu, data->softfp64, options);
+ if (soft_def)
+ return soft_def;
+
+ if (!(options & nir_lower_doubles_op_to_options_mask(alu->op)))
+ return NULL;
+
+ nir_ssa_def *src = nir_mov_alu(b, alu->src[0],
+ alu->dest.dest.ssa.num_components);
+
+ switch (alu->op) {