From 4ee0f6d1fbf62438c69b1fe17ecf029e888414a0 Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Thu, 16 Feb 2023 18:17:35 +0100 Subject: [PATCH] ir3: Allow propagation of normal->shared copies Copies from normal to shared registers are only allowed architecturally if all of the active threads have the same value for the normal register, which means that they can normally be propagated into e.g. ALU instructions or other copies. However, there are a few instruction types where this is not (currently) allowed, namely the scan macro where the source is tied to a shared destination and the collect/split macros where the lowering doesn't currently allow differently-typed sources and destinations (although we may want to allow that in the future), so we need to clean up ir3_valid_flags() to catch that. Part-of: --- src/freedreno/ir3/ir3.c | 10 ++++++++-- src/freedreno/ir3/ir3.h | 10 ++-------- src/freedreno/ir3/ir3_cp.c | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/freedreno/ir3/ir3.c b/src/freedreno/ir3/ir3.c index 66479bd68a2..381136ddc57 100644 --- a/src/freedreno/ir3/ir3.c +++ b/src/freedreno/ir3/ir3.c @@ -1078,7 +1078,10 @@ ir3_valid_flags(struct ir3_instruction *instr, unsigned n, unsigned flags) if (flags & ~(IR3_REG_IMMED | IR3_REG_CONST | IR3_REG_SHARED)) return false; - if ((flags & IR3_REG_SHARED) && !(instr->dsts[0]->flags & IR3_REG_SHARED)) + /* Except for immed/const sources, source and dest shared-ness must match. + */ + if (!(flags & (IR3_REG_IMMED | IR3_REG_CONST)) && + (flags & IR3_REG_SHARED) != (instr->dsts[0]->flags & IR3_REG_SHARED)) return false; return true; @@ -1096,7 +1099,10 @@ ir3_valid_flags(struct ir3_instruction *instr, unsigned n, unsigned flags) valid_flags = IR3_REG_SHARED; break; case OPC_SCAN_MACRO: - return flags == 0; + if (n == 0) + return flags == 0; + else + return flags == IR3_REG_SHARED; break; case OPC_SCAN_CLUSTERS_MACRO: if (n == 0) diff --git a/src/freedreno/ir3/ir3.h b/src/freedreno/ir3/ir3.h index 89fd12729a4..2caad8ea8e2 100644 --- a/src/freedreno/ir3/ir3.h +++ b/src/freedreno/ir3/ir3.h @@ -917,14 +917,8 @@ is_same_type_reg(struct ir3_register *dst, struct ir3_register *src) unsigned dst_type = (dst->flags & IR3_REG_HALF); unsigned src_type = (src->flags & IR3_REG_HALF); - /* Treat shared->normal copies as same-type, because they can generally be - * folded, but not normal->shared copies. - */ - if (dst_type != src_type || - ((dst->flags & IR3_REG_SHARED) && !(src->flags & IR3_REG_SHARED))) - return false; - else - return true; + /* Treat shared->normal copies and normal->shared copies as same-type. */ + return dst_type == src_type; } /* Is it a non-transformative (ie. not type changing) mov? This can diff --git a/src/freedreno/ir3/ir3_cp.c b/src/freedreno/ir3/ir3_cp.c index e2c569fbacc..8f3133e18e1 100644 --- a/src/freedreno/ir3/ir3_cp.c +++ b/src/freedreno/ir3/ir3_cp.c @@ -116,7 +116,7 @@ combine_flags(unsigned *dstflags, struct ir3_instruction *src) if (srcflags & IR3_REG_BNOT) *dstflags ^= IR3_REG_BNOT; - *dstflags &= ~IR3_REG_SSA; + *dstflags &= ~(IR3_REG_SSA | IR3_REG_SHARED); *dstflags |= srcflags & IR3_REG_SSA; *dstflags |= srcflags & IR3_REG_CONST; *dstflags |= srcflags & IR3_REG_IMMED;