+ emit(MOV(dst, src_reg(tmp_dst)));
+}
+
+/**
+ * Try to use an immediate value for a source
+ *
+ * In cases of flow control, constant propagation is sometimes unable to
+ * determine that a register contains a constant value. To work around this,
+ * try to emit a literal as one of the sources. If \c try_src0_also is set,
+ * \c op[0] will also be tried for an immediate value.
+ *
+ * If \c op[0] is modified, the operands will be exchanged so that \c op[1]
+ * will always be the immediate value.
+ *
+ * \return The index of the source that was modified, 0 or 1, if successful.
+ * Otherwise, -1.
+ *
+ * \param op - Operands to the instruction
+ * \param try_src0_also - True if \c op[0] should also be a candidate for
+ * getting an immediate value. This should only be set
+ * for commutative operations.
+ */
+static int
+try_immediate_source(const nir_alu_instr *instr, src_reg *op,
+ bool try_src0_also,
+ ASSERTED const gen_device_info *devinfo)
+{
+ unsigned idx;
+
+ /* MOV should be the only single-source instruction passed to this
+ * function. Any other unary instruction with a constant source should
+ * have been constant-folded away!
+ */
+ assert(nir_op_infos[instr->op].num_inputs > 1 ||
+ instr->op == nir_op_mov);
+
+ if (instr->op != nir_op_mov &&
+ nir_src_bit_size(instr->src[1].src) == 32 &&
+ nir_src_is_const(instr->src[1].src)) {
+ idx = 1;
+ } else if (try_src0_also &&
+ nir_src_bit_size(instr->src[0].src) == 32 &&
+ nir_src_is_const(instr->src[0].src)) {
+ idx = 0;
+ } else {
+ return -1;
+ }
+
+ const enum brw_reg_type old_type = op[idx].type;
+
+ switch (old_type) {
+ case BRW_REGISTER_TYPE_D:
+ case BRW_REGISTER_TYPE_UD: {
+ int first_comp = -1;
+ int d = 0;
+
+ for (unsigned i = 0; i < NIR_MAX_VEC_COMPONENTS; i++) {
+ if (nir_alu_instr_channel_used(instr, idx, i)) {
+ if (first_comp < 0) {
+ first_comp = i;
+ d = nir_src_comp_as_int(instr->src[idx].src,
+ instr->src[idx].swizzle[i]);
+ } else if (d != nir_src_comp_as_int(instr->src[idx].src,
+ instr->src[idx].swizzle[i])) {
+ return -1;
+ }
+ }
+ }
+
+ assert(first_comp >= 0);
+
+ if (op[idx].abs)
+ d = MAX2(-d, d);
+
+ if (op[idx].negate) {
+ /* On Gen8+ a negation source modifier on a logical operation means
+ * something different. Nothing should generate this, so assert that
+ * it does not occur.
+ */
+ assert(devinfo->gen < 8 || (instr->op != nir_op_iand &&
+ instr->op != nir_op_ior &&
+ instr->op != nir_op_ixor));
+ d = -d;
+ }
+
+ op[idx] = retype(src_reg(brw_imm_d(d)), old_type);
+ break;
+ }
+
+ case BRW_REGISTER_TYPE_F: {
+ int first_comp = -1;
+ float f[NIR_MAX_VEC_COMPONENTS] = { 0.0f };
+ bool is_scalar = true;
+
+ for (unsigned i = 0; i < NIR_MAX_VEC_COMPONENTS; i++) {
+ if (nir_alu_instr_channel_used(instr, idx, i)) {
+ f[i] = nir_src_comp_as_float(instr->src[idx].src,
+ instr->src[idx].swizzle[i]);
+ if (first_comp < 0) {
+ first_comp = i;
+ } else if (f[first_comp] != f[i]) {
+ is_scalar = false;
+ }
+ }
+ }
+
+ if (is_scalar) {
+ if (op[idx].abs)
+ f[first_comp] = fabs(f[first_comp]);
+
+ if (op[idx].negate)
+ f[first_comp] = -f[first_comp];
+
+ op[idx] = src_reg(brw_imm_f(f[first_comp]));
+ assert(op[idx].type == old_type);
+ } else {
+ uint8_t vf_values[4] = { 0, 0, 0, 0 };
+
+ for (unsigned i = 0; i < ARRAY_SIZE(vf_values); i++) {
+
+ if (op[idx].abs)
+ f[i] = fabs(f[i]);
+
+ if (op[idx].negate)
+ f[i] = -f[i];
+
+ const int vf = brw_float_to_vf(f[i]);
+ if (vf == -1)
+ return -1;
+
+ vf_values[i] = vf;
+ }
+
+ op[idx] = src_reg(brw_imm_vf4(vf_values[0], vf_values[1],
+ vf_values[2], vf_values[3]));
+ }
+ break;
+ }
+
+ default:
+ unreachable("Non-32bit type.");
+ }
+
+ /* If the instruction has more than one source, the instruction format only
+ * allows source 1 to be an immediate value. If the immediate value was
+ * source 0, then the sources must be exchanged.
+ */
+ if (idx == 0 && instr->op != nir_op_mov) {
+ src_reg tmp = op[0];
+ op[0] = op[1];
+ op[1] = tmp;
+ }
+
+ return idx;
+}
+
+void
+vec4_visitor::fix_float_operands(src_reg op[3], nir_alu_instr *instr)
+{
+ bool fixed[3] = { false, false, false };
+
+ for (unsigned i = 0; i < 2; i++) {
+ if (!nir_src_is_const(instr->src[i].src))
+ continue;
+
+ for (unsigned j = i + 1; j < 3; j++) {
+ if (fixed[j])
+ continue;
+
+ if (!nir_src_is_const(instr->src[j].src))
+ continue;
+
+ if (nir_alu_srcs_equal(instr, instr, i, j)) {
+ if (!fixed[i])
+ op[i] = fix_3src_operand(op[i]);
+
+ op[j] = op[i];
+
+ fixed[i] = true;
+ fixed[j] = true;
+ } else if (nir_alu_srcs_negative_equal(instr, instr, i, j)) {
+ if (!fixed[i])
+ op[i] = fix_3src_operand(op[i]);
+
+ op[j] = op[i];
+ op[j].negate = !op[j].negate;
+
+ fixed[i] = true;
+ fixed[j] = true;
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < 3; i++) {
+ if (!fixed[i])
+ op[i] = fix_3src_operand(op[i]);
+ }
+}
+
+static bool
+const_src_fits_in_16_bits(const nir_src &src, brw_reg_type type)
+{
+ assert(nir_src_is_const(src));
+ if (type_is_unsigned_int(type)) {
+ return nir_src_comp_as_uint(src, 0) <= UINT16_MAX;
+ } else {
+ const int64_t c = nir_src_comp_as_int(src, 0);
+ return c <= INT16_MAX && c >= INT16_MIN;
+ }