i965/fs: Add a concept of a width to fs_reg

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>
This commit is contained in:
Jason Ekstrand
2014-08-13 12:25:58 -07:00
parent 1030ee6e9b
commit 24d023b9fe
2 changed files with 78 additions and 4 deletions
+58 -3
View 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 *
+20 -1
View 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;
};