[Mesa-dev] [PATCH 2/3] i965/fs: Fix comparisions with uint negation.
Ian Romanick
idr at freedesktop.org
Mon Oct 3 16:34:28 PDT 2011
On 10/03/2011 03:41 PM, Eric Anholt wrote:
> The condmod instruction ends up generating garbage condition codes,
> because apparently the comparison happens on the accumulator value (33
> bits for UD), not the truncated value that would be written.
>
> Fixes fs-op-neg-*
> ---
> src/mesa/drivers/dri/i965/brw_fs.cpp | 13 +++++++++++++
> src/mesa/drivers/dri/i965/brw_fs.h | 1 +
> src/mesa/drivers/dri/i965/brw_fs_emit.cpp | 10 ++++++++++
> src/mesa/drivers/dri/i965/brw_fs_visitor.cpp | 25 +++++++++++++++++++++++++
> 4 files changed, 49 insertions(+), 0 deletions(-)
>
> diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp
> index 2000180..555d26d 100644
> --- a/src/mesa/drivers/dri/i965/brw_fs.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp
> @@ -1347,6 +1347,19 @@ fs_visitor::register_coalesce()
> interfered = true;
> break;
> }
> +
> + /* The accumulator result appears to get used for the
> + * conditional modifier generation. When negating a UD
> + * value, there is a 33rd bit generated for the sign in the
> + * accumulator value, so now you can't check, for example,
> + * equality with a 32-bit value. See piglit fs-op-neg-uint.
> + */
> + if (scan_inst->conditional_mod&&
> + inst->src[0].negate&&
> + inst->src[0].type == BRW_REGISTER_TYPE_UD) {
> + interfered = true;
> + break;
> + }
> }
> if (interfered) {
> continue;
> diff --git a/src/mesa/drivers/dri/i965/brw_fs.h b/src/mesa/drivers/dri/i965/brw_fs.h
> index 56181a3..7a89413 100644
> --- a/src/mesa/drivers/dri/i965/brw_fs.h
> +++ b/src/mesa/drivers/dri/i965/brw_fs.h
> @@ -534,6 +534,7 @@ public:
> fs_inst *last_rhs_inst);
> void emit_assignment_writes(fs_reg&l, fs_reg&r,
> const glsl_type *type, bool predicated);
> + void resolve_ud_negate(fs_reg *reg);
>
> struct brw_reg interp_reg(int location, int channel);
> int setup_uniform_values(int loc, const glsl_type *type);
> diff --git a/src/mesa/drivers/dri/i965/brw_fs_emit.cpp b/src/mesa/drivers/dri/i965/brw_fs_emit.cpp
> index 4c158fe..7025347 100644
> --- a/src/mesa/drivers/dri/i965/brw_fs_emit.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_fs_emit.cpp
> @@ -636,6 +636,16 @@ fs_visitor::generate_code()
>
> for (unsigned int i = 0; i< 3; i++) {
> src[i] = brw_reg_from_fs_reg(&inst->src[i]);
> +
> + /* The accumulator result appears to get used for the
> + * conditional modifier generation. When negating a UD
> + * value, there is a 33rd bit generated for the sign in the
> + * accumulator value, so now you can't check, for example,
> + * equality with a 32-bit value. See piglit fs-op-neg-uvec4.
> + */
> + assert(!inst->conditional_mod ||
> + inst->src[i].type != BRW_REGISTER_TYPE_UD ||
> + !inst->src[i].negate);
> }
> dst = brw_reg_from_fs_reg(&inst->dst);
>
> diff --git a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
> index 07ea84f..24cc23c 100644
> --- a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
> @@ -317,6 +317,9 @@ fs_visitor::visit(ir_expression *ir)
> if (intel->gen< 5)
> temp.type = op[0].type;
>
> + resolve_ud_negate(&op[0]);
> + resolve_ud_negate(&op[1]);
> +
> inst = emit(BRW_OPCODE_CMP, temp, op[0], op[1]);
> inst->conditional_mod = brw_conditional_for_comparison(ir->operation);
> emit(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1));
> @@ -377,6 +380,8 @@ fs_visitor::visit(ir_expression *ir)
> if (intel->gen< 5)
> temp.type = op[0].type;
>
> + resolve_ud_negate(&op[0]);
> +
> inst = emit(BRW_OPCODE_CMP, temp, op[0], fs_reg(0.0f));
> inst->conditional_mod = BRW_CONDITIONAL_NZ;
> inst = emit(BRW_OPCODE_AND, this->result, this->result, fs_reg(1));
> @@ -401,6 +406,9 @@ fs_visitor::visit(ir_expression *ir)
> break;
>
> case ir_binop_min:
> + resolve_ud_negate(&op[0]);
> + resolve_ud_negate(&op[1]);
> +
> if (intel->gen>= 6) {
> inst = emit(BRW_OPCODE_SEL, this->result, op[0], op[1]);
> inst->conditional_mod = BRW_CONDITIONAL_L;
> @@ -416,6 +424,9 @@ fs_visitor::visit(ir_expression *ir)
> }
> break;
> case ir_binop_max:
> + resolve_ud_negate(&op[0]);
> + resolve_ud_negate(&op[1]);
> +
> if (intel->gen>= 6) {
> inst = emit(BRW_OPCODE_SEL, this->result, op[0], op[1]);
> inst->conditional_mod = BRW_CONDITIONAL_GE;
> @@ -1369,6 +1380,8 @@ fs_visitor::emit_bool_to_cond_code(ir_rvalue *ir)
>
> expr->operands[i]->accept(this);
> op[i] = this->result;
> +
> + resolve_ud_negate(&op[i]);
> }
>
> switch (expr->operation) {
> @@ -1984,3 +1997,15 @@ fs_visitor::emit_fb_writes()
>
> this->current_annotation = NULL;
> }
> +
> +void
> +fs_visitor::resolve_ud_negate(fs_reg *reg)
> +{
> + if (reg->type != BRW_REGISTER_TYPE_UD ||
> + !reg->negate)
> + return;
> +
> + fs_reg temp = fs_reg(this, glsl_type::uint_type);
> + emit(BRW_OPCODE_MOV, temp, *reg);
> + *reg = temp;
> +}
I suspect I know the answer, but are we sure that a later optimization
pass won't copy propagate this extra move away?
More information about the mesa-dev
mailing list