i965/fs: Try to emit LINE instructions on Gen <= 5.
authorMatt Turner <mattst88@gmail.com>
Tue, 1 Apr 2014 23:49:13 +0000 (16:49 -0700)
committerMatt Turner <mattst88@gmail.com>
Sat, 6 Dec 2014 00:43:31 +0000 (16:43 -0800)
The LINE instruction performs a multiply-add instruction (a * b + c)
where b and c are scalar arguments. It reads b and c from offsets in
src0 such that you can load them (it they're representable) as a
vector-float immediate with a single instruction.

Hurts some programs, but that'll all get better once we CSE the
vector-float MOVs in the next patch.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=77544
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
src/mesa/drivers/dri/i965/brw_fs.h
src/mesa/drivers/dri/i965/brw_fs_visitor.cpp

index daaa89fe98fb6ab4618f17c4c5e2df7ae918465b..807001bc91cc09be139842b224df71532c18ea95 100644 (file)
@@ -508,6 +508,7 @@ public:
    void emit_minmax(enum brw_conditional_mod conditionalmod, const fs_reg &dst,
                     const fs_reg &src0, const fs_reg &src1);
    bool try_emit_saturate(ir_expression *ir);
+   bool try_emit_line(ir_expression *ir);
    bool try_emit_mad(ir_expression *ir);
    void try_replace_with_sel();
    bool opt_peephole_sel();
index e4296ce9787727d634172588da4f878612c12a19..b4f8f37bfa28f7cedcdb53907778ee28abdd76b2 100644 (file)
@@ -295,6 +295,59 @@ fs_visitor::try_emit_saturate(ir_expression *ir)
    return false;
 }
 
+bool
+fs_visitor::try_emit_line(ir_expression *ir)
+{
+   /* LINE's src0 must be of type float. */
+   if (ir->type != glsl_type::float_type)
+      return false;
+
+   ir_rvalue *nonmul = ir->operands[1];
+   ir_expression *mul = ir->operands[0]->as_expression();
+
+   if (!mul || mul->operation != ir_binop_mul) {
+      nonmul = ir->operands[0];
+      mul = ir->operands[1]->as_expression();
+
+      if (!mul || mul->operation != ir_binop_mul)
+         return false;
+   }
+
+   ir_constant *const_add = nonmul->as_constant();
+   if (!const_add)
+      return false;
+
+   int add_operand_vf = brw_float_to_vf(const_add->value.f[0]);
+   if (add_operand_vf == -1)
+      return false;
+
+   ir_rvalue *non_const_mul = mul->operands[1];
+   ir_constant *const_mul = mul->operands[0]->as_constant();
+   if (!const_mul) {
+      const_mul = mul->operands[1]->as_constant();
+
+      if (!const_mul)
+         return false;
+
+      non_const_mul = mul->operands[0];
+   }
+
+   int mul_operand_vf = brw_float_to_vf(const_mul->value.f[0]);
+   if (mul_operand_vf == -1)
+      return false;
+
+   non_const_mul->accept(this);
+   fs_reg src1 = this->result;
+
+   fs_reg src0 = fs_reg(this, ir->type);
+   emit(BRW_OPCODE_MOV, src0,
+        fs_reg((uint8_t)mul_operand_vf, 0, 0, (uint8_t)add_operand_vf));
+
+   this->result = fs_reg(this, ir->type);
+   emit(BRW_OPCODE_LINE, this->result, src0, src1);
+   return true;
+}
+
 bool
 fs_visitor::try_emit_mad(ir_expression *ir)
 {
@@ -482,6 +535,8 @@ fs_visitor::visit(ir_expression *ir)
    /* Deal with the real oddball stuff first */
    switch (ir->operation) {
    case ir_binop_add:
+      if (brw->gen <= 5 && try_emit_line(ir))
+         return;
       if (try_emit_mad(ir))
          return;
       break;