unreachable("ir3_block_get_pred_index() invalid predecessor");
}
-static struct ir3_instruction *instr_create(struct ir3_block *block, int nreg)
+static struct ir3_instruction *instr_create(struct ir3_block *block,
+ opc_t opc, int nreg)
{
+ /* Add an extra source for array destinations */
+ if (1 <= opc_cat(opc))
+ nreg++;
struct ir3_instruction *instr;
unsigned sz = sizeof(*instr) + (nreg * sizeof(instr->regs[0]));
char *ptr = ir3_alloc(block->shader, sz);
struct ir3_instruction * ir3_instr_create(struct ir3_block *block,
opc_t opc, int nreg)
{
- struct ir3_instruction *instr = instr_create(block, nreg);
+ struct ir3_instruction *instr = instr_create(block, opc, nreg);
instr->block = block;
instr->opc = opc;
insert_instr(block, instr);
struct ir3_instruction * ir3_instr_clone(struct ir3_instruction *instr)
{
- struct ir3_instruction *new_instr = instr_create(instr->block,
+ struct ir3_instruction *new_instr = instr_create(instr->block, instr->opc,
instr->regs_count);
struct ir3_register **regs;
unsigned i;
return new_reg;
}
+
+void ir3_reg_set_last_array(struct ir3_instruction *instr,
+ struct ir3_register *reg,
+ struct ir3_register *last_write)
+{
+ assert(reg->flags & IR3_REG_ARRAY);
+ assert(reg->flags & IR3_REG_DEST);
+ struct ir3_register *new_reg = ir3_reg_create(instr, 0, 0);
+ *new_reg = *reg;
+ new_reg->flags &= ~IR3_REG_DEST;
+ new_reg->def = last_write;
+ ir3_reg_tie(reg, new_reg);
+}
+
void
ir3_instr_set_address(struct ir3_instruction *instr,
struct ir3_instruction *addr)
static inline void ir3_reg_tie(struct ir3_register *dst, struct ir3_register *src)
{
+ assert(!dst->tied && !src->tied);
dst->tied = src;
src->tied = dst;
}
+void ir3_reg_set_last_array(struct ir3_instruction *instr,
+ struct ir3_register *reg,
+ struct ir3_register *last_write);
+
void ir3_instr_set_address(struct ir3_instruction *instr,
struct ir3_instruction *addr);
for (unsigned i = 0; i < instr->regs_count; i++) {
struct ir3_register *reg = instr->regs[i];
if ((reg->flags & IR3_REG_ARRAY) &&
- (!reg->def || reg->def->instr->block != block)) {
- reg->def = NULL;
+ (((reg->flags & IR3_REG_DEST) && !reg->tied) ||
+ (!(reg->flags & IR3_REG_DEST) && !reg->def))) {
struct ir3_array *arr = ir3_lookup_array(ir, reg->array.id);
/* Construct any phi nodes necessary to read this value */
for (unsigned i = 0; i < instr->regs_count; i++) {
struct ir3_register *reg = instr->regs[i];
if ((reg->flags & IR3_REG_ARRAY)) {
- if (!reg->def) {
- /* It is assumed that before calling
- * ir3_array_to_ssa(), reg->def was set to the
- * previous writer of the array within the current
- * block (if any). The reg->def of the first write
- * to an array within a block was cleared in the
- * loop calling read_value_beginning() above.
- */
+ /* It is assumed that before calling
+ * ir3_array_to_ssa(), reg->def was set to the
+ * previous writer of the array within the current
+ * block or NULL if none.
+ */
+ if (!(reg->flags & IR3_REG_DEST) && !reg->def) {
reg->def = lookup_live_in(&ctx, block, reg->array.id);
+ } else if ((reg->flags & IR3_REG_DEST) && !reg->tied) {
+ struct ir3_register *def =
+ lookup_live_in(&ctx, block, reg->array.id);
+ if (def)
+ ir3_reg_set_last_array(instr, reg, def);
}
reg->flags |= IR3_REG_SSA;
}
__ssa_dst(mov)->flags |= flags;
src = ir3_reg_create(mov, 0, IR3_REG_ARRAY |
COND(address, IR3_REG_RELATIV) | flags);
- src->def = arr->last_write;
+ src->def = (arr->last_write && arr->last_write->instr->block == block) ?
+ arr->last_write : NULL;
src->size = arr->length;
src->array.id = arr->id;
src->array.offset = n;
src->barrier_conflict |= IR3_BARRIER_ARRAY_R | IR3_BARRIER_ARRAY_W;
dst->flags |= IR3_REG_ARRAY;
- dst->def = arr->last_write;
dst->size = arr->length;
dst->array.id = arr->id;
dst->array.offset = n;
dst->array.base = INVALID_REG;
+ if (arr->last_write && arr->last_write->instr->block == src->block)
+ ir3_reg_set_last_array(src, dst, arr->last_write);
+
arr->last_write = dst;
array_insert(block, block->keeps, src);
dst = ir3_reg_create(mov, 0, IR3_REG_DEST | IR3_REG_SSA | IR3_REG_ARRAY |
flags |
COND(address, IR3_REG_RELATIV));
- dst->def = arr->last_write;
dst->instr = mov;
dst->size = arr->length;
dst->array.id = arr->id;
dst->array.base = INVALID_REG;
ir3_reg_create(mov, 0, IR3_REG_SSA | flags)->def = src->regs[0];
+ if (arr->last_write && arr->last_write->instr->block == block)
+ ir3_reg_set_last_array(mov, dst, arr->last_write);
+
if (address)
ir3_instr_set_address(mov, address);
}
} while (progress);
- if (instr->regs[0]->flags & IR3_REG_ARRAY) {
- struct ir3_instruction *src = ssa(instr->regs[0]);
- if (src)
- instr_cp(ctx, src);
- }
-
if (instr->address) {
instr_cp(ctx, instr->address);
ir3_instr_set_address(instr, eliminate_output_mov(ctx, instr->address));
print_ssa_name(stream, reg, reg->flags & IR3_REG_DEST);
mesa_log_stream_printf(stream, ":");
}
- mesa_log_stream_printf(stream, SYN_ARRAY("arr[id=%u, offset=%d, size=%u"), reg->array.id,
+ mesa_log_stream_printf(stream, SYN_ARRAY("arr[id=%u, offset=%d, size=%u]"), reg->array.id,
reg->array.offset, reg->size);
- if (reg->flags & IR3_REG_DEST) {
- mesa_log_stream_printf(stream, SYN_ARRAY(", "));
- print_ssa_name(stream, reg, false);
- }
- mesa_log_stream_printf(stream, SYN_ARRAY("]"));
if (reg->array.base != INVALID_REG)
mesa_log_stream_printf(stream, "("SYN_REG("r%u.%c")")", reg->array.base >> 2,
"xyzw"[reg->array.base & 0x3]);
struct ra_interval *interval = &ctx->intervals[src->def->name];
struct ra_file *file = ra_get_file(ctx, src);
- bool array_rmw = ra_reg_is_array_rmw(src);
-
struct ir3_register *tied = src->tied;
physreg_t physreg;
if (tied) {
if (src->flags & IR3_REG_FIRST_KILL)
ra_file_remove(file, interval);
-
- /* This source is also a destination. */
- if (array_rmw) {
- struct ra_interval *dst_interval = &ctx->intervals[src->name];
- ra_interval_init(dst_interval, src);
- dst_interval->physreg_start = physreg;
- dst_interval->physreg_end = physreg + src->size * reg_elem_size(src);
- ra_file_insert(file, dst_interval);
- }
}
/* Insert a parallel copy instruction before the instruction with the parallel
/* Allocate the destination. */
ra_foreach_dst(dst, instr) {
- if (ra_reg_is_array_rmw(dst))
- continue;
allocate_dst(ctx, dst);
}
/* Now finally insert the destination into the map. */
ra_foreach_dst(dst, instr) {
- if (ra_reg_is_array_rmw(dst))
- continue;
insert_dst(ctx, dst);
}
def_is_gpr(reg->def);
}
-/* Array destinations can act as a source, reading the previous array and then
- * modifying it. Return true when the register is an array destination that
- * acts like a source.
- */
-static inline bool
-ra_reg_is_array_rmw(const struct ir3_register *reg)
-{
- return ((reg->flags & IR3_REG_ARRAY) && (reg->flags & IR3_REG_DEST) && reg->def);
-}
-
static inline bool
ra_reg_is_dst(const struct ir3_register *reg)
{
*/
ra_foreach_dst(dst, instr) {
- if (!ra_reg_is_array_rmw(dst)) {
- struct ir3_register *tied_src = dst->tied;
- if (tied_src && !(tied_src->flags & IR3_REG_FIRST_KILL))
- insert_dst(ctx, dst);
- }
+ struct ir3_register *tied_src = dst->tied;
+ if (tied_src && !(tied_src->flags & IR3_REG_FIRST_KILL))
+ insert_dst(ctx, dst);
}
update_max_pressure(ctx);
* bindless, irrespective of the precision of other srcs. The
* tex/samp src is the first src reg when .s2en is set
*/
- if ((instr->flags & IR3_INSTR_S2EN) && (n < 2)) {
+ if (reg->tied) {
+ /* must have the same size as the destination, handled in
+ * validate_reg().
+ */
+ } else if ((instr->flags & IR3_INSTR_S2EN) && (n < 2)) {
if (n == 0) {
if (instr->flags & IR3_INSTR_B)
validate_assert(ctx, !(reg->flags & IR3_REG_HALF));