+static void
+emit_find_msb_using_lzd(const vec4_builder &bld,
+ const dst_reg &dst,
+ const src_reg &src,
+ bool is_signed)
+{
+ vec4_instruction *inst;
+ src_reg temp = src;
+
+ if (is_signed) {
+ /* LZD of an absolute value source almost always does the right
+ * thing. There are two problem values:
+ *
+ * * 0x80000000. Since abs(0x80000000) == 0x80000000, LZD returns
+ * 0. However, findMSB(int(0x80000000)) == 30.
+ *
+ * * 0xffffffff. Since abs(0xffffffff) == 1, LZD returns
+ * 31. Section 8.8 (Integer Functions) of the GLSL 4.50 spec says:
+ *
+ * For a value of zero or negative one, -1 will be returned.
+ *
+ * * Negative powers of two. LZD(abs(-(1<<x))) returns x, but
+ * findMSB(-(1<<x)) should return x-1.
+ *
+ * For all negative number cases, including 0x80000000 and
+ * 0xffffffff, the correct value is obtained from LZD if instead of
+ * negating the (already negative) value the logical-not is used. A
+ * conditonal logical-not can be achieved in two instructions.
+ */
+ temp = src_reg(bld.vgrf(BRW_REGISTER_TYPE_D));
+
+ bld.ASR(dst_reg(temp), src, brw_imm_d(31));
+ bld.XOR(dst_reg(temp), temp, src);
+ }
+
+ bld.LZD(retype(dst, BRW_REGISTER_TYPE_UD),
+ retype(temp, BRW_REGISTER_TYPE_UD));
+
+ /* LZD counts from the MSB side, while GLSL's findMSB() wants the count
+ * from the LSB side. Subtract the result from 31 to convert the MSB count
+ * into an LSB count. If no bits are set, LZD will return 32. 31-32 = -1,
+ * which is exactly what findMSB() is supposed to return.
+ */
+ inst = bld.ADD(dst, retype(src_reg(dst), BRW_REGISTER_TYPE_D),
+ brw_imm_d(31));
+ inst->src[0].negate = true;
+}
+
+void
+vec4_visitor::emit_conversion_from_double(dst_reg dst, src_reg src,
+ bool saturate,
+ brw_reg_type single_type)
+{
+ /* BDW PRM vol 15 - workarounds:
+ * DF->f format conversion for Align16 has wrong emask calculation when
+ * source is immediate.
+ */
+ if (devinfo->gen == 8 && single_type == BRW_REGISTER_TYPE_F &&
+ src.file == BRW_IMMEDIATE_VALUE) {
+ vec4_instruction *inst = emit(MOV(dst, brw_imm_f(src.df)));
+ inst->saturate = saturate;
+ return;
+ }
+
+ dst_reg temp = dst_reg(this, glsl_type::dvec4_type);
+ emit(MOV(temp, src));
+
+ dst_reg temp2 = dst_reg(this, glsl_type::dvec4_type);
+ temp2 = retype(temp2, single_type);
+ emit(VEC4_OPCODE_FROM_DOUBLE, temp2, src_reg(temp))
+ ->size_written = 2 * REG_SIZE;
+
+ vec4_instruction *inst = emit(MOV(dst, src_reg(temp2)));
+ inst->saturate = saturate;
+}
+
+void
+vec4_visitor::emit_conversion_to_double(dst_reg dst, src_reg src,
+ bool saturate,
+ brw_reg_type single_type)
+{
+ dst_reg tmp_dst = dst_reg(src_reg(this, glsl_type::dvec4_type));
+ src_reg tmp_src = retype(src_reg(this, glsl_type::vec4_type), single_type);
+ emit(MOV(dst_reg(tmp_src), retype(src, single_type)));
+ emit(VEC4_OPCODE_TO_DOUBLE, tmp_dst, tmp_src);
+ vec4_instruction *inst = emit(MOV(dst, src_reg(tmp_dst)));
+ inst->saturate = saturate;
+}
+