i965/fs: Add a concept of a width to fs_reg
authorJason Ekstrand <jason.ekstrand@intel.com>
Wed, 13 Aug 2014 19:25:58 +0000 (12:25 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Tue, 30 Sep 2014 17:29:14 +0000 (10:29 -0700)
Every register in i965 assembly implicitly has a concept of a "width".
Usually, this is derived from the execution size of the instruction.
However, when writing a compiler it turns out that it is frequently a
useful to have the width explicitly in the register and derive the
execution size of the instruction from the widths of the registers used in
it.

This commit adds a width field to fs_reg along with an effective_width()
helper function.  The effective_width() function tells you how wide the
register effectively is when used in an instruction.  For example, uniform
values have width 1 since the data is not actually repeated, but when used
in an instruction they take on the width of the instruction.  However, for
some instructions (LOAD_PAYLOAD being the notable exception), the width is
not the same.

Signed-off-by: Jason Ekstrand <jason.ekstrand@intel.com>
Reviewed-by: Matt Turner <mattst88@gmail.com>
src/mesa/drivers/dri/i965/brw_fs.cpp
src/mesa/drivers/dri/i965/brw_fs.h

index 99a33bd06477c622e44ff12fe2a4487d81bf3dbc..80fa4f3dd9af31c842a9fe1a3ef6699bd51b34d6 100644 (file)
@@ -422,6 +422,7 @@ fs_reg::fs_reg(float f)
    this->file = IMM;
    this->type = BRW_REGISTER_TYPE_F;
    this->fixed_hw_reg.dw1.f = f;
+   this->width = 1;
 }
 
 /** Immediate value constructor. */
@@ -431,6 +432,7 @@ fs_reg::fs_reg(int32_t i)
    this->file = IMM;
    this->type = BRW_REGISTER_TYPE_D;
    this->fixed_hw_reg.dw1.d = i;
+   this->width = 1;
 }
 
 /** Immediate value constructor. */
@@ -440,6 +442,7 @@ fs_reg::fs_reg(uint32_t u)
    this->file = IMM;
    this->type = BRW_REGISTER_TYPE_UD;
    this->fixed_hw_reg.dw1.ud = u;
+   this->width = 1;
 }
 
 /** Fixed brw_reg. */
@@ -449,6 +452,7 @@ fs_reg::fs_reg(struct brw_reg fixed_hw_reg)
    this->file = HW_REG;
    this->fixed_hw_reg = fixed_hw_reg;
    this->type = fixed_hw_reg.type;
+   this->width = 1 << fixed_hw_reg.width;
 }
 
 bool
@@ -462,11 +466,33 @@ fs_reg::equals(const fs_reg &r) const
            negate == r.negate &&
            abs == r.abs &&
            !reladdr && !r.reladdr &&
-           memcmp(&fixed_hw_reg, &r.fixed_hw_reg,
-                  sizeof(fixed_hw_reg)) == 0 &&
+           memcmp(&fixed_hw_reg, &r.fixed_hw_reg, sizeof(fixed_hw_reg)) == 0 &&
+           width == r.width &&
            stride == r.stride);
 }
 
+uint8_t
+fs_reg::effective_width(const fs_visitor *v) const
+{
+   switch (this->file) {
+   case BAD_FILE:
+      return 8;
+   case UNIFORM:
+   case IMM:
+      assert(this->width == 1);
+      return v->dispatch_width;
+   case GRF:
+   case HW_REG:
+      assert(this->width > 1 && this->width <= v->dispatch_width);
+      assert(this->width % 8 == 0);
+      return this->width;
+   case MRF:
+      unreachable("MRF registers cannot be used as sources");
+   default:
+      unreachable("Invalid register file");
+   }
+}
+
 fs_reg &
 fs_reg::apply_stride(unsigned stride)
 {
@@ -880,6 +906,14 @@ fs_reg::fs_reg(enum register_file file, int reg)
    this->file = file;
    this->reg = reg;
    this->type = BRW_REGISTER_TYPE_F;
+
+   switch (file) {
+   case UNIFORM:
+      this->width = 1;
+      break;
+   default:
+      this->width = 8;
+   }
 }
 
 /** Fixed HW reg constructor. */
@@ -889,10 +923,29 @@ fs_reg::fs_reg(enum register_file file, int reg, enum brw_reg_type type)
    this->file = file;
    this->reg = reg;
    this->type = type;
+
+   switch (file) {
+   case UNIFORM:
+      this->width = 1;
+      break;
+   default:
+      this->width = 8;
+   }
+}
+
+/** Fixed HW reg constructor. */
+fs_reg::fs_reg(enum register_file file, int reg, enum brw_reg_type type,
+               uint8_t width)
+{
+   init();
+   this->file = file;
+   this->reg = reg;
+   this->type = type;
+   this->width = width;
 }
 
 /** Automatic reg constructor. */
-fs_reg::fs_reg(class fs_visitor *v, const struct glsl_type *type)
+fs_reg::fs_reg(fs_visitor *v, const struct glsl_type *type)
 {
    init();
 
@@ -900,6 +953,8 @@ fs_reg::fs_reg(class fs_visitor *v, const struct glsl_type *type)
    this->reg = v->virtual_grf_alloc(v->type_size(type));
    this->reg_offset = 0;
    this->type = brw_type_for_base_type(type);
+   this->width = v->dispatch_width;
+   assert(this->width == 8 || this->width == 16);
 }
 
 fs_reg *
index 1cdbf311977e7050fd3f1e8da0dc469c94c06070..30cce40dd2bc724e1119a4d330e969dba8766c14 100644 (file)
@@ -62,6 +62,8 @@ namespace brw {
    class fs_live_variables;
 }
 
+class fs_visitor;
+
 class fs_reg : public backend_reg {
 public:
    DECLARE_RALLOC_CXX_OPERATORS(fs_reg)
@@ -75,7 +77,8 @@ public:
    fs_reg(struct brw_reg fixed_hw_reg);
    fs_reg(enum register_file file, int reg);
    fs_reg(enum register_file file, int reg, enum brw_reg_type type);
-   fs_reg(class fs_visitor *v, const struct glsl_type *type);
+   fs_reg(enum register_file file, int reg, enum brw_reg_type type, uint8_t width);
+   fs_reg(fs_visitor *v, const struct glsl_type *type);
 
    bool equals(const fs_reg &r) const;
    bool is_valid_3src() const;
@@ -93,6 +96,22 @@ public:
 
    fs_reg *reladdr;
 
+   /**
+    * The register width.  This indicates how many hardware values are
+    * represented by each virtual value.  Valid values are 1, 8, or 16.
+    * For immediate values, this is 1.  Most of the rest of the time, it
+    * will be equal to the dispatch width.
+    */
+   uint8_t width;
+
+   /**
+    * Returns the effective register width when used as a source in the
+    * given instruction.  Registers such as uniforms and immediates
+    * effectively take on the width of the instruction in which they are
+    * used.
+    */
+   uint8_t effective_width(const fs_visitor *v) const;
+
    /** Register region horizontal stride */
    uint8_t stride;
 };