diff options
author | Eric Anholt <eric@anholt.net> | 2010-10-14 11:27:17 -0700 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2010-10-14 12:02:54 -0700 |
commit | 5dd07b442e02696bf0ec5d4e3b4be1674519664a (patch) | |
tree | f80e5216781b8abc78cfcc1cdc9a8060f8212ec6 | |
parent | d5599c0b6a22cd0bbc475ec715824660144d02a0 (diff) |
i965: Add peepholing of conditional mod generation from expressions.
This cuts usually 2 out of 3 instructions for flag reg generation (if
statements, conditional assignment) by producing the conditional mod
in the expression representing the boolean value.
Fixes glsl-fs-vec4-indexing-temp-dst-in-nested-loop-combined (register
allocation no longer fails for the conditional generation
proliferation)
-rw-r--r-- | src/mesa/drivers/dri/i965/brw_fs.cpp | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp index c92bb54960..d5ebccbfd9 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp @@ -717,6 +717,9 @@ fs_visitor::visit(ir_expression *ir) switch (ir->operation) { case ir_unop_logic_not: + /* Note that BRW_OPCODE_NOT is not appropriate here, since it is + * ones complement of the whole register, not just bit 0. + */ emit(fs_inst(BRW_OPCODE_ADD, this->result, op[0], fs_reg(-1))); break; case ir_unop_neg: @@ -1342,6 +1345,91 @@ fs_visitor::visit(ir_constant *ir) void fs_visitor::emit_bool_to_cond_code(ir_rvalue *ir) { + ir_expression *expr = ir->as_expression(); + + if (expr) { + fs_reg op[2]; + fs_inst *inst; + + for (unsigned int i = 0; i < expr->get_num_operands(); i++) { + assert(expr->operands[i]->type->is_scalar()); + + expr->operands[i]->accept(this); + op[i] = this->result; + } + + switch (expr->operation) { + case ir_unop_logic_not: + inst = emit(fs_inst(BRW_OPCODE_ADD, reg_null, op[0], fs_reg(-1))); + inst->conditional_mod = BRW_CONDITIONAL_NZ; + break; + + case ir_binop_logic_xor: + inst = emit(fs_inst(BRW_OPCODE_XOR, reg_null, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_NZ; + break; + + case ir_binop_logic_or: + inst = emit(fs_inst(BRW_OPCODE_OR, reg_null, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_NZ; + break; + + case ir_binop_logic_and: + inst = emit(fs_inst(BRW_OPCODE_AND, reg_null, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_NZ; + break; + + case ir_unop_f2b: + if (intel->gen >= 6) { + inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], fs_reg(0.0f))); + } else { + inst = emit(fs_inst(BRW_OPCODE_MOV, reg_null, op[0])); + } + inst->conditional_mod = BRW_CONDITIONAL_NZ; + break; + + case ir_unop_i2b: + if (intel->gen >= 6) { + inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], fs_reg(0))); + } else { + inst = emit(fs_inst(BRW_OPCODE_MOV, reg_null, op[0])); + } + inst->conditional_mod = BRW_CONDITIONAL_NZ; + break; + + case ir_binop_greater: + inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_G; + break; + case ir_binop_gequal: + inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_GE; + break; + case ir_binop_less: + inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_L; + break; + case ir_binop_lequal: + inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_LE; + break; + case ir_binop_equal: + case ir_binop_all_equal: + inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_Z; + break; + case ir_binop_nequal: + case ir_binop_any_nequal: + inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], op[1])); + inst->conditional_mod = BRW_CONDITIONAL_NZ; + break; + default: + assert(!"not reached"); + this->fail = true; + break; + } + return; + } ir->accept(this); |