summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <[email protected]>2011-08-15 22:36:18 -0700
committerEric Anholt <[email protected]>2011-08-17 11:51:01 -0700
commit3f78f719732b87e6707f94c187ad6e263c6c2ef0 (patch)
treee9e4e5eeef91afe0ae779845fd3bc296175d9277
parent34980cd153050111edc545545ddff11f5b68347e (diff)
i965/fs: Fix 32-bit integer multiplication.
The MUL opcode does a 16bit * 32bit multiply, and we need to do the MACH to get the top 16bit * 32bit added in. Fixes fs-op-mult-int-*, fs-op-mult-ivec* Reviewed-by: Kenneth Graunke <[email protected]>
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs_emit.cpp5
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs_visitor.cpp18
2 files changed, 22 insertions, 1 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_fs_emit.cpp b/src/mesa/drivers/dri/i965/brw_fs_emit.cpp
index 7367ccaa7e0..482d250c333 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_emit.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_emit.cpp
@@ -630,6 +630,11 @@ fs_visitor::generate_code()
case BRW_OPCODE_MUL:
brw_MUL(p, dst, src[0], src[1]);
break;
+ case BRW_OPCODE_MACH:
+ brw_set_acc_write_control(p, 1);
+ brw_MACH(p, dst, src[0], src[1]);
+ brw_set_acc_write_control(p, 0);
+ break;
case BRW_OPCODE_FRC:
brw_FRC(p, dst, src[0]);
diff --git a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
index 8b4f5bbac15..2dc9132cec6 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
@@ -287,7 +287,23 @@ fs_visitor::visit(ir_expression *ir)
break;
case ir_binop_mul:
- emit(BRW_OPCODE_MUL, this->result, op[0], op[1]);
+ if (ir->type->is_integer()) {
+ /* For integer multiplication, the MUL uses the low 16 bits
+ * of one of the operands (src0 on gen6, src1 on gen7). The
+ * MACH accumulates in the contribution of the upper 16 bits
+ * of that operand.
+ *
+ * FINISHME: Emit just the MUL if we know an operand is small
+ * enough.
+ */
+ struct brw_reg acc = retype(brw_acc_reg(), BRW_REGISTER_TYPE_D);
+
+ emit(BRW_OPCODE_MUL, acc, op[0], op[1]);
+ emit(BRW_OPCODE_MACH, reg_null_d, op[0], op[1]);
+ emit(BRW_OPCODE_MOV, this->result, fs_reg(acc));
+ } else {
+ emit(BRW_OPCODE_MUL, this->result, op[0], op[1]);
+ }
break;
case ir_binop_div:
assert(!"not reached: should be handled by ir_div_to_mul_rcp");