summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorConnor Abbott <cwabbott0@gmail.com>2021-06-17 15:14:05 +0200
committerMarge Bot <eric+marge@anholt.net>2021-06-23 17:20:29 +0000
commitcc649453364dd1ea3a8efff8f3bc4290ba80e34b (patch)
tree880b7fb901478739c48331ad17ebe5c4348c9bb7 /src
parentf953dc2cedaa412ecf56ee804ac19d4dee3b47db (diff)
ir3: Make tied sources/destinations part of the IR
Previously this was hard-coded for a6xx atomic instructions. However we'll need a way for array destinations to point to the source with the previous value of the array when we split them up. This is conceptually the same as tied source/destinations for a6xx atomics, except that array writes sometimes won't have a previous value to point to. So move this into the IR so that it can be more dynamic. As a bonus we can move the knowledge of a6xx atomics out of RA, where it's out-of-place, and into the a6xx-specific code that creates them. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11469>
Diffstat (limited to 'src')
-rw-r--r--src/freedreno/ir3/ir3.h12
-rw-r--r--src/freedreno/ir3/ir3_a6xx.c2
-rw-r--r--src/freedreno/ir3/ir3_print.c7
-rw-r--r--src/freedreno/ir3/ir3_ra.c4
-rw-r--r--src/freedreno/ir3/ir3_ra.h27
-rw-r--r--src/freedreno/ir3/ir3_ra_validate.c2
-rw-r--r--src/freedreno/ir3/ir3_spill.c3
-rw-r--r--src/freedreno/ir3/ir3_validate.c31
8 files changed, 57 insertions, 31 deletions
diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h
index 8e78f9beced..97c36f53bd8 100644
--- a/src/freedreno/ir3/ir3.h
+++ b/src/freedreno/ir3/ir3.h
@@ -185,6 +185,12 @@ struct ir3_register {
*/
struct ir3_register *def;
+ /* Pointer to another register in the instruction that must share the same
+ * physical register. Each destination can be tied with one source, and
+ * they must have "tied" pointing to each other.
+ */
+ struct ir3_register *tied;
+
unsigned merge_set_offset;
struct ir3_merge_set *merge_set;
unsigned interval_start, interval_end;
@@ -603,6 +609,12 @@ struct ir3_register * ir3_reg_create(struct ir3_instruction *instr,
struct ir3_register * ir3_reg_clone(struct ir3 *shader,
struct ir3_register *reg);
+static inline void ir3_reg_tie(struct ir3_register *dst, struct ir3_register *src)
+{
+ dst->tied = src;
+ src->tied = dst;
+}
+
void ir3_instr_set_address(struct ir3_instruction *instr,
struct ir3_instruction *addr);
diff --git a/src/freedreno/ir3/ir3_a6xx.c b/src/freedreno/ir3/ir3_a6xx.c
index 1ce1a81f14e..9f3efa35114 100644
--- a/src/freedreno/ir3/ir3_a6xx.c
+++ b/src/freedreno/ir3/ir3_a6xx.c
@@ -194,6 +194,7 @@ emit_intrinsic_atomic_ssbo(struct ir3_context *ctx, nir_intrinsic_instr *intr)
array_insert(b, b->keeps, atomic);
atomic->regs[0]->wrmask = src1->regs[0]->wrmask;
+ ir3_reg_tie(atomic->regs[0], atomic->regs[3]);
struct ir3_instruction *split;
ir3_split_dest(b, &split, atomic, 0, 1);
return split;
@@ -345,6 +346,7 @@ emit_intrinsic_atomic_image(struct ir3_context *ctx, nir_intrinsic_instr *intr)
array_insert(b, b->keeps, atomic);
atomic->regs[0]->wrmask = src1->regs[0]->wrmask;
+ ir3_reg_tie(atomic->regs[0], atomic->regs[3]);
struct ir3_instruction *split;
ir3_split_dest(b, &split, atomic, 0, 1);
return split;
diff --git a/src/freedreno/ir3/ir3_print.c b/src/freedreno/ir3/ir3_print.c
index 6e163da9c36..9c6cb284acd 100644
--- a/src/freedreno/ir3/ir3_print.c
+++ b/src/freedreno/ir3/ir3_print.c
@@ -203,6 +203,13 @@ static void print_reg_name(struct log_stream *stream, struct ir3_instruction *in
if (reg->flags & IR3_REG_R)
mesa_log_stream_printf(stream, "(r)");
+ /* Right now all instructions that use tied registers only have one
+ * destination register, so we can just print (tied) as if it's a flag,
+ * although it's more convenient for RA if it's a pointer.
+ */
+ if (reg->tied)
+ printf("(tied)");
+
if (reg->flags & IR3_REG_SHARED)
mesa_log_stream_printf(stream, "s");
if (reg->flags & IR3_REG_HALF)
diff --git a/src/freedreno/ir3/ir3_ra.c b/src/freedreno/ir3/ir3_ra.c
index afbb8172089..34540fe2a58 100644
--- a/src/freedreno/ir3/ir3_ra.c
+++ b/src/freedreno/ir3/ir3_ra.c
@@ -1097,7 +1097,7 @@ allocate_dst(struct ra_ctx *ctx, struct ir3_register *dst)
{
struct ra_file *file = ra_get_file(ctx, dst);
- struct ir3_register *tied = ra_dst_get_tied_src(ctx->compiler, dst);
+ struct ir3_register *tied = dst->tied;
if (tied) {
struct ra_interval *tied_interval = &ctx->intervals[tied->def->name];
struct ra_interval *dst_interval = &ctx->intervals[dst->name];
@@ -1138,7 +1138,7 @@ assign_src(struct ra_ctx *ctx, struct ir3_instruction *instr, struct ir3_registe
bool array_rmw = ra_reg_is_array_rmw(src);
- struct ir3_register *tied = ra_src_get_tied_dst(ctx->compiler, instr, src);
+ struct ir3_register *tied = src->tied;
physreg_t physreg;
if (tied) {
struct ra_interval *tied_interval = &ctx->intervals[tied->name];
diff --git a/src/freedreno/ir3/ir3_ra.h b/src/freedreno/ir3/ir3_ra.h
index 7e5b0638259..a3404df052c 100644
--- a/src/freedreno/ir3/ir3_ra.h
+++ b/src/freedreno/ir3/ir3_ra.h
@@ -109,20 +109,6 @@ ra_reg_is_dst(const struct ir3_register *reg)
((reg->flags & IR3_REG_ARRAY) || reg->wrmask);
}
-static inline struct ir3_register *
-ra_dst_get_tied_src(const struct ir3_compiler *compiler, struct ir3_register *dst)
-{
- /* With the a6xx new cat6 encoding, the same register is used for the
- * value and destination of atomic operations.
- */
- if (compiler->gpu_id >= 600 && is_atomic(dst->instr->opc) &&
- (dst->instr->flags & IR3_INSTR_G)) {
- return dst->instr->regs[3];
- }
-
- return NULL;
-}
-
/* Iterators for sources and destinations which:
* - Don't include fake sources (irrelevant for RA)
* - Don't include non-SSA sources (immediates and constants, also irrelevant)
@@ -144,19 +130,6 @@ ra_dst_get_tied_src(const struct ir3_compiler *compiler, struct ir3_register *ds
for (unsigned __cnt = (__instr)->regs_count, __i = 0; __i < __cnt; __i++) \
if (ra_reg_is_dst((__srcreg = (__instr)->regs[__i])))
-static inline struct ir3_register *
-ra_src_get_tied_dst(const struct ir3_compiler *compiler,
- struct ir3_instruction *instr,
- struct ir3_register *src)
-{
- if (compiler->gpu_id >= 600 && is_atomic(instr->opc) &&
- (instr->flags & IR3_INSTR_G) && src == instr->regs[3]) {
- return instr->regs[0];
- }
-
- return NULL;
-}
-
#define RA_HALF_SIZE (4 * 48)
#define RA_FULL_SIZE (4 * 48 * 2)
diff --git a/src/freedreno/ir3/ir3_ra_validate.c b/src/freedreno/ir3/ir3_ra_validate.c
index b9d3e818cb2..932a2bec6d8 100644
--- a/src/freedreno/ir3/ir3_ra_validate.c
+++ b/src/freedreno/ir3/ir3_ra_validate.c
@@ -139,6 +139,8 @@ validate_simple(struct ra_val_ctx *ctx, struct ir3_instruction *instr)
ra_foreach_dst (dst, instr) {
unsigned dst_max = ra_reg_get_physreg(dst) + reg_size(dst);
validate_assert(ctx, dst_max <= get_file_size(ctx, dst));
+ if (dst->tied)
+ validate_assert(ctx, ra_reg_get_num(dst) == ra_reg_get_num(dst->tied));
}
ra_foreach_src (src, instr) {
diff --git a/src/freedreno/ir3/ir3_spill.c b/src/freedreno/ir3/ir3_spill.c
index 7342c9bb0de..94bd85e9b9e 100644
--- a/src/freedreno/ir3/ir3_spill.c
+++ b/src/freedreno/ir3/ir3_spill.c
@@ -251,8 +251,7 @@ handle_instr(struct ra_spill_ctx *ctx, struct ir3_instruction *instr)
ra_foreach_dst(dst, instr) {
if (!ra_reg_is_array_rmw(dst)) {
- struct ir3_register *tied_src =
- ra_dst_get_tied_src(ctx->compiler, dst);
+ struct ir3_register *tied_src = dst->tied;
if (tied_src && !(tied_src->flags & IR3_REG_FIRST_KILL))
insert_dst(ctx, dst);
}
diff --git a/src/freedreno/ir3/ir3_validate.c b/src/freedreno/ir3/ir3_validate.c
index 4220b3ef529..779edc2d563 100644
--- a/src/freedreno/ir3/ir3_validate.c
+++ b/src/freedreno/ir3/ir3_validate.c
@@ -98,6 +98,31 @@ validate_phi(struct ir3_validate_ctx *ctx, struct ir3_instruction *phi)
validate_assert(ctx, writes_gpr(phi));
}
+static void
+validate_reg(struct ir3_validate_ctx *ctx, struct ir3_instruction *instr,
+ struct ir3_register *reg)
+{
+ if (reg->tied) {
+ validate_assert(ctx, reg->tied->tied == reg);
+ validate_assert(ctx, (reg->tied->flags & IR3_REG_DEST) !=
+ (reg->flags & IR3_REG_DEST));
+ validate_assert(ctx, reg_class_flags(reg->tied) == reg_class_flags(reg));
+ validate_assert(ctx, reg->tied->wrmask == reg->wrmask);
+ if (reg->flags & IR3_REG_ARRAY) {
+ validate_assert(ctx, reg->tied->array.base == reg->array.base);
+ validate_assert(ctx, reg->tied->size == reg->size);
+ }
+ bool found = false;
+ for (unsigned i = 0; i < instr->regs_count; i++) {
+ if (instr->regs[i] == reg->tied) {
+ found = true;
+ break;
+ }
+ }
+ validate_assert(ctx, found && "tied register not in the same instruction");
+ }
+}
+
#define validate_reg_size(ctx, reg, type) \
validate_assert(ctx, type_size(type) == (((reg)->flags & IR3_REG_HALF) ? 16 : 32))
@@ -142,6 +167,12 @@ validate_instr(struct ir3_validate_ctx *ctx, struct ir3_instruction *instr)
last_reg = reg;
}
+
+ for (unsigned i = 0; i < instr->regs_count; i++) {
+ struct ir3_register *reg = instr->regs[i];
+
+ validate_reg(ctx, instr, reg);
+ }
_mesa_set_add(ctx->defs, instr);