#include "brw_vec4.h"
#include "brw_cfg.h"
-extern "C" {
-#include "main/macros.h"
-}
+#include "brw_eu.h"
namespace brw {
{
return (inst->opcode == BRW_OPCODE_MOV &&
!inst->predicate &&
- inst->dst.file == GRF &&
+ inst->dst.file == VGRF &&
!inst->dst.reladdr &&
!inst->src[0].reladdr &&
(inst->dst.type == inst->src[0].type ||
const src_reg *src = values[ch];
/* consider GRF only */
- assert(inst->dst.file == GRF);
- if (!src || src->file != GRF)
+ assert(inst->dst.file == VGRF);
+ if (!src || src->file != VGRF)
return false;
return (src->in_range(inst->dst, inst->regs_written) &&
inst->dst.writemask & (1 << BRW_GET_SWZ(src->swizzle, ch)));
}
-static unsigned
-swizzle_vf_imm(unsigned vf4, unsigned swizzle)
-{
- union {
- unsigned vf4;
- uint8_t vf[4];
- } v = { vf4 }, ret;
-
- ret.vf[0] = v.vf[BRW_GET_SWZ(swizzle, 0)];
- ret.vf[1] = v.vf[BRW_GET_SWZ(swizzle, 1)];
- ret.vf[2] = v.vf[BRW_GET_SWZ(swizzle, 2)];
- ret.vf[3] = v.vf[BRW_GET_SWZ(swizzle, 3)];
-
- return ret.vf4;
-}
-
static bool
is_logic_op(enum opcode opcode)
{
opcode == BRW_OPCODE_NOT);
}
+/**
+ * Get the origin of a copy as a single register if all components present in
+ * the given readmask originate from the same register and have compatible
+ * regions, otherwise return a BAD_FILE register.
+ */
+static src_reg
+get_copy_value(const copy_entry &entry, unsigned readmask)
+{
+ unsigned swz[4] = {};
+ src_reg value;
+
+ for (unsigned i = 0; i < 4; i++) {
+ if (readmask & (1 << i)) {
+ if (entry.value[i]) {
+ src_reg src = *entry.value[i];
+
+ if (src.file == IMM) {
+ swz[i] = i;
+ } else {
+ swz[i] = BRW_GET_SWZ(src.swizzle, i);
+ /* Overwrite the original swizzle so the src_reg::equals call
+ * below doesn't care about it, the correct swizzle will be
+ * calculated once the swizzles of all components are known.
+ */
+ src.swizzle = BRW_SWIZZLE_XYZW;
+ }
+
+ if (value.file == BAD_FILE) {
+ value = src;
+ } else if (!value.equals(src)) {
+ return src_reg();
+ }
+ } else {
+ return src_reg();
+ }
+ }
+ }
+
+ return swizzle(value,
+ brw_compose_swizzle(brw_swizzle_for_mask(readmask),
+ BRW_SWIZZLE4(swz[0], swz[1],
+ swz[2], swz[3])));
+}
+
static bool
-try_constant_propagate(struct brw_context *brw, vec4_instruction *inst,
- int arg, struct copy_entry *entry)
+try_constant_propagate(const struct brw_device_info *devinfo,
+ vec4_instruction *inst,
+ int arg, const copy_entry *entry)
{
/* For constant propagation, we only handle the same constant
* across all 4 channels. Some day, we should handle the 8-bit
* float vector format, which would let us constant propagate
* vectors better.
+ * We could be more aggressive here -- some channels might not get used
+ * based on the destination writemask.
*/
- src_reg value = *entry->value[0];
- for (int i = 1; i < 4; i++) {
- if (!value.equals(*entry->value[i]))
- return false;
- }
+ src_reg value =
+ get_copy_value(*entry,
+ brw_apply_inv_swizzle_to_mask(inst->src[arg].swizzle,
+ WRITEMASK_XYZW));
if (value.file != IMM)
return false;
}
if (inst->src[arg].abs) {
- if ((brw->gen >= 8 && is_logic_op(inst->opcode)) ||
- !brw_abs_immediate(value.type, &value.fixed_hw_reg)) {
+ if ((devinfo->gen >= 8 && is_logic_op(inst->opcode)) ||
+ !brw_abs_immediate(value.type, &value.as_brw_reg())) {
return false;
}
}
if (inst->src[arg].negate) {
- if ((brw->gen >= 8 && is_logic_op(inst->opcode)) ||
- !brw_negate_immediate(value.type, &value.fixed_hw_reg)) {
+ if ((devinfo->gen >= 8 && is_logic_op(inst->opcode)) ||
+ !brw_negate_immediate(value.type, &value.as_brw_reg())) {
return false;
}
}
- if (value.type == BRW_REGISTER_TYPE_VF)
- value.fixed_hw_reg.dw1.ud = swizzle_vf_imm(value.fixed_hw_reg.dw1.ud,
- inst->src[arg].swizzle);
+ value = swizzle(value, inst->src[arg].swizzle);
switch (inst->opcode) {
case BRW_OPCODE_MOV:
+ case SHADER_OPCODE_BROADCAST:
inst->src[arg] = value;
return true;
case SHADER_OPCODE_POW:
case SHADER_OPCODE_INT_QUOTIENT:
case SHADER_OPCODE_INT_REMAINDER:
- if (brw->gen < 8)
+ if (devinfo->gen < 8)
break;
/* fallthrough */
case BRW_OPCODE_DP2:
case BRW_OPCODE_MACH:
case BRW_OPCODE_MUL:
+ case SHADER_OPCODE_MULH:
case BRW_OPCODE_ADD:
case BRW_OPCODE_OR:
case BRW_OPCODE_AND:
return true;
}
break;
+ case GS_OPCODE_SET_WRITE_OFFSET:
+ /* This is just a multiply by a constant with special strides.
+ * The generator will handle immediates in both arguments (generating
+ * a single MOV of the product). So feel free to propagate in src0.
+ */
+ inst->src[arg] = value;
+ return true;
case BRW_OPCODE_CMP:
if (arg == 1) {
}
static bool
-try_copy_propagate(struct brw_context *brw, vec4_instruction *inst,
- int arg, struct copy_entry *entry)
+try_copy_propagate(const struct brw_device_info *devinfo,
+ vec4_instruction *inst, int arg,
+ const copy_entry *entry, int attributes_per_reg)
{
- /* For constant propagation, we only handle the same constant
- * across all 4 channels. Some day, we should handle the 8-bit
- * float vector format, which would let us constant propagate
- * vectors better.
- */
- src_reg value = *entry->value[0];
- for (int i = 1; i < 4; i++) {
- /* This is equals() except we don't care about the swizzle. */
- if (value.file != entry->value[i]->file ||
- value.reg != entry->value[i]->reg ||
- value.reg_offset != entry->value[i]->reg_offset ||
- value.type != entry->value[i]->type ||
- value.negate != entry->value[i]->negate ||
- value.abs != entry->value[i]->abs) {
- return false;
- }
- }
-
- /* Compute the swizzle of the original register by swizzling the
- * component loaded from each value according to the swizzle of
- * operand we're going to change.
+ /* Build up the value we are propagating as if it were the source of a
+ * single MOV
*/
- int s[4];
- for (int i = 0; i < 4; i++) {
- s[i] = BRW_GET_SWZ(entry->value[i]->swizzle, i);
- }
- value.swizzle = brw_compose_swizzle(inst->src[arg].swizzle,
- BRW_SWIZZLE4(s[0], s[1], s[2], s[3]));
+ src_reg value =
+ get_copy_value(*entry,
+ brw_apply_inv_swizzle_to_mask(inst->src[arg].swizzle,
+ WRITEMASK_XYZW));
+ /* Check that we can propagate that value */
if (value.file != UNIFORM &&
- value.file != GRF &&
+ value.file != VGRF &&
value.file != ATTR)
return false;
- if (brw->gen >= 8 && (value.negate || value.abs) &&
+ if (devinfo->gen >= 8 && (value.negate || value.abs) &&
is_logic_op(inst->opcode)) {
return false;
}
- if (inst->src[arg].abs) {
- value.negate = false;
- value.abs = true;
- }
- if (inst->src[arg].negate)
- value.negate = !value.negate;
-
bool has_source_modifiers = value.negate || value.abs;
/* gen6 math and gen7+ SENDs from GRFs ignore source modifiers on
* instructions.
*/
if ((has_source_modifiers || value.file == UNIFORM ||
- value.swizzle != BRW_SWIZZLE_XYZW) && !inst->can_do_source_mods(brw))
+ value.swizzle != BRW_SWIZZLE_XYZW) && !inst->can_do_source_mods(devinfo))
return false;
- if (has_source_modifiers && value.type != inst->src[arg].type)
+ if (has_source_modifiers &&
+ value.type != inst->src[arg].type &&
+ !inst->can_change_types())
return false;
if (has_source_modifiers &&
inst->opcode == SHADER_OPCODE_GEN4_SCRATCH_WRITE)
return false;
- if (inst->is_3src() && value.file == UNIFORM)
+ unsigned composed_swizzle = brw_compose_swizzle(inst->src[arg].swizzle,
+ value.swizzle);
+ if (inst->is_3src(devinfo) &&
+ (value.file == UNIFORM ||
+ (value.file == ATTR && attributes_per_reg != 1)) &&
+ !brw_is_single_value_swizzle(composed_swizzle))
return false;
if (inst->is_send_from_grf())
inst->src[0].type != BRW_REGISTER_TYPE_F ||
inst->src[1].file != IMM ||
inst->src[1].type != BRW_REGISTER_TYPE_F ||
- inst->src[1].fixed_hw_reg.dw1.f < 0.0 ||
- inst->src[1].fixed_hw_reg.dw1.f > 1.0) {
+ inst->src[1].f < 0.0 ||
+ inst->src[1].f > 1.0) {
return false;
}
if (!inst->saturate)
}
}
- value.type = inst->src[arg].type;
+ /* Build the final value */
+ if (inst->src[arg].abs) {
+ value.negate = false;
+ value.abs = true;
+ }
+ if (inst->src[arg].negate)
+ value.negate = !value.negate;
+
+ value.swizzle = composed_swizzle;
+ if (has_source_modifiers &&
+ value.type != inst->src[arg].type) {
+ assert(inst->can_change_types());
+ for (int i = 0; i < 3; i++) {
+ inst->src[i].type = value.type;
+ }
+ inst->dst.type = value.type;
+ } else {
+ value.type = inst->src[arg].type;
+ }
+
inst->src[arg] = value;
return true;
}
bool
vec4_visitor::opt_copy_propagation(bool do_constant_prop)
{
+ /* If we are in dual instanced or single mode, then attributes are going
+ * to be interleaved, so one register contains two attribute slots.
+ */
+ const int attributes_per_reg =
+ prog_data->dispatch_mode == DISPATCH_MODE_4X2_DUAL_OBJECT ? 1 : 2;
bool progress = false;
struct copy_entry entries[alloc.total_size];
}
/* For each source arg, see if each component comes from a copy
- * from the same type file (IMM, GRF, UNIFORM), and try
+ * from the same type file (IMM, VGRF, UNIFORM), and try
* optimizing out access to the copy result
*/
for (int i = 2; i >= 0; i--) {
/* Copied values end up in GRFs, and we don't track reladdr
* accesses.
*/
- if (inst->src[i].file != GRF ||
+ if (inst->src[i].file != VGRF ||
inst->src[i].reladdr)
continue;
if (inst->regs_read(i) != 1)
continue;
- int reg = (alloc.offsets[inst->src[i].reg] +
- inst->src[i].reg_offset);
-
- /* Find the regs that each swizzle component came from.
- */
- struct copy_entry entry;
- memset(&entry, 0, sizeof(copy_entry));
- int c;
- for (c = 0; c < 4; c++) {
- int channel = BRW_GET_SWZ(inst->src[i].swizzle, c);
- entry.value[c] = entries[reg].value[channel];
-
- /* If there's no available copy for this channel, bail.
- * We could be more aggressive here -- some channels might
- * not get used based on the destination writemask.
- */
- if (!entry.value[c])
- break;
+ const unsigned reg = (alloc.offsets[inst->src[i].nr] +
+ inst->src[i].reg_offset);
+ const copy_entry &entry = entries[reg];
- entry.saturatemask |=
- (entries[reg].saturatemask & (1 << channel) ? 1 : 0) << c;
-
- /* We'll only be able to copy propagate if the sources are
- * all from the same file -- there's no ability to swizzle
- * 0 or 1 constants in with source registers like in i915.
- */
- if (c > 0 && entry.value[c - 1]->file != entry.value[c]->file)
- break;
- }
-
- if (c != 4)
- continue;
-
- if (do_constant_prop && try_constant_propagate(brw, inst, i, &entry))
+ if (do_constant_prop && try_constant_propagate(devinfo, inst, i, &entry))
progress = true;
-
- if (try_copy_propagate(brw, inst, i, &entry))
+ else if (try_copy_propagate(devinfo, inst, i, &entry, attributes_per_reg))
progress = true;
}
/* Track available source registers. */
- if (inst->dst.file == GRF) {
+ if (inst->dst.file == VGRF) {
const int reg =
- alloc.offsets[inst->dst.reg] + inst->dst.reg_offset;
+ alloc.offsets[inst->dst.nr] + inst->dst.reg_offset;
/* Update our destination's current channel values. For a direct copy,
* the value is the newly propagated source. Otherwise, we don't know