Mesa (master): freedreno/afuc: Handle xmov modifiers

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Aug 18 16:27:31 UTC 2020


Module: Mesa
Branch: master
Commit: 66dd248593b5fa54680b84032f382551ed7c3cf7
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=66dd248593b5fa54680b84032f382551ed7c3cf7

Author: Connor Abbott <cwabbott0 at gmail.com>
Date:   Mon Aug 17 19:44:14 2020 +0200

freedreno/afuc: Handle xmov modifiers

Although it's kind-of similar to "(rptN)" in the shader ISA, I called it
"xmov" to make it clear that it's completely orthogonal to "(rep)",
although you certainly can use both modifiers on the same instruction.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6368>

---

 src/freedreno/afuc/afuc.h   |  3 ++-
 src/freedreno/afuc/asm.c    | 10 +++++++++
 src/freedreno/afuc/asm.h    |  1 +
 src/freedreno/afuc/disasm.c | 52 ++++++++++++++++++++++++++++++++++++++++++++-
 src/freedreno/afuc/lexer.l  |  1 +
 src/freedreno/afuc/parser.y |  2 ++
 6 files changed, 67 insertions(+), 2 deletions(-)

diff --git a/src/freedreno/afuc/afuc.h b/src/freedreno/afuc/afuc.h
index 8233db04402..6ec268e3dcc 100644
--- a/src/freedreno/afuc/afuc.h
+++ b/src/freedreno/afuc/afuc.h
@@ -129,7 +129,8 @@ typedef union PACKED {
 	} movi;
 	struct PACKED {
 		uint32_t alu     : 5;
-		uint32_t pad     : 6;
+		uint32_t pad     : 4;
+		uint32_t xmov    : 2; /* execute eXtra mov's based on $rem */
 		uint32_t dst     : 5;
 		uint32_t src2    : 5;
 		uint32_t src1    : 5;
diff --git a/src/freedreno/afuc/asm.c b/src/freedreno/afuc/asm.c
index a03a89a31fa..cb11439b979 100644
--- a/src/freedreno/afuc/asm.c
+++ b/src/freedreno/afuc/asm.c
@@ -170,6 +170,10 @@ static void emit_instructions(int outfd)
 			if (ai->has_immed) {
 				/* MSB overlaps with STORE */
 				assert(ai->tok != T_OP_MSB);
+				if (ai->xmov) {
+					fprintf(stderr, "ALU instruction cannot have immediate and xmov\n");
+					exit(1);
+				}
 				opc = tok2alu(ai->tok);
 				instr.alui.dst = ai->dst;
 				instr.alui.src = ai->src1;
@@ -179,6 +183,7 @@ static void emit_instructions(int outfd)
 				instr.alu.dst  = ai->dst;
 				instr.alu.src1 = ai->src1;
 				instr.alu.src2 = ai->src2;
+				instr.alu.xmov = ai->xmov;
 				instr.alu.alu = tok2alu(ai->tok);
 			}
 			break;
@@ -186,6 +191,10 @@ static void emit_instructions(int outfd)
 			/* move can either be encoded as movi (ie. move w/ immed) or
 			 * an alu instruction
 			 */
+			if ((ai->has_immed || ai->label) && ai->xmov) {
+				fprintf(stderr, "ALU instruction cannot have immediate and xmov\n");
+				exit(1);
+			}
 			if (ai->has_immed) {
 				opc = OPC_MOVI;
 				instr.movi.dst = ai->dst;
@@ -206,6 +215,7 @@ static void emit_instructions(int outfd)
 				instr.alu.dst  = ai->dst;
 				instr.alu.src1 = 0x00;      /* $00 reads-back 0 */
 				instr.alu.src2 = ai->src1;
+				instr.alu.xmov = ai->xmov;
 				instr.alu.alu = OPC_OR;
 			}
 			break;
diff --git a/src/freedreno/afuc/asm.h b/src/freedreno/afuc/asm.h
index 03fb1508907..e0e6033e9e8 100644
--- a/src/freedreno/afuc/asm.h
+++ b/src/freedreno/afuc/asm.h
@@ -44,6 +44,7 @@ struct asm_instruction {
 	int immed;
 	int shift;
 	int bit;
+	int xmov;
 	uint32_t literal;
 	const char *label;
 
diff --git a/src/freedreno/afuc/disasm.c b/src/freedreno/afuc/disasm.c
index f687058f615..0e013f59a3a 100644
--- a/src/freedreno/afuc/disasm.c
+++ b/src/freedreno/afuc/disasm.c
@@ -506,6 +506,8 @@ static void disasm(uint32_t *buf, int sizedwords)
 
 			if (rep)
 				printf("(rep)");
+			if (instr->alu.xmov)
+				printf("(xmov%d)", instr->alu.xmov);
 
 			/* special case mnemonics:
 			 *   reading $00 seems to always yield zero, and so:
@@ -531,10 +533,58 @@ static void disasm(uint32_t *buf, int sizedwords)
 			/* print out unexpected bits: */
 			if (verbose) {
 				if (instr->alu.pad)
-					printerr("  (pad=%03x)", instr->alu.pad);
+					printerr("  (pad=%01x)", instr->alu.pad);
 				if (instr->alu.src1 && !src1)
 					printerr("  (src1=%02x)", instr->alu.src1);
 			}
+
+			/* xmov is a modifier that makes the processor execute up to 3
+			 * extra mov's after the current instruction. Given an ALU
+			 * instruction:
+			 *
+			 * (xmovN) alu $dst, $src1, $src2
+			 *
+			 * In all of the uses in the firmware blob, $dst and $src2 are one
+			 * of the "special" registers $data, $addr, $addr2. I've observed
+			 * that if $dst isn't "special" then it's replaced with $00
+			 * instead of $data, but I haven't checked what happens if $src2
+			 * isn't "special".  Anyway, in the usual case, the HW produces a
+			 * count M = min(N, $rem) and then does the following:
+			 *
+			 * M = 1:
+			 * mov $data, $src2
+			 *
+			 * M = 2:
+			 * mov $data, $src2
+			 * mov $data, $src2
+			 *
+			 * M = 3:
+			 * mov $data, $src2
+			 * mov $dst, $src2 (special case for CP_CONTEXT_REG_BUNCH)
+			 * mov $data, $src2
+			 *
+			 * It seems to be frequently used in combination with (rep) to
+			 * provide a kind of hardware-based loop unrolling, and there's
+			 * even a special case in the ISA to be able to do this with
+			 * CP_CONTEXT_REG_BUNCH. However (rep) isn't required.
+			 *
+			 * This dumps the expected extra instructions, assuming that $rem
+			 * isn't too small.
+			 */
+			if (verbose && instr->alu.xmov) {
+				for (int i = 0; i < instr->alu.xmov; i++) {
+					printf("\n        ; mov ");
+					if (instr->alu.dst < 0x1d)
+						printf("$00");
+					else if (instr->alu.xmov == 3 && i == 1)
+						print_dst(instr->alu.dst);
+					else
+						printf("$data");
+					printf(", ");
+					print_src(instr->alu.src2);
+				}
+			}
+
 			break;
 		}
 		case OPC_CWRITE6:
diff --git a/src/freedreno/afuc/lexer.l b/src/freedreno/afuc/lexer.l
index 6b1ec07cade..8c3113d1c16 100644
--- a/src/freedreno/afuc/lexer.l
+++ b/src/freedreno/afuc/lexer.l
@@ -86,6 +86,7 @@ extern YYSTYPE yylval;
 "setsecure"			  return TOKEN(T_OP_SETSECURE);
 "<<"                              return TOKEN(T_LSHIFT);
 "(rep)"                           return TOKEN(T_REP);
+"(xmov"[1-3]")"	                  yylval.num = yytext[5] - '\0'; return T_XMOV;
 
 ","                               return ',';
 "["                               return '[';
diff --git a/src/freedreno/afuc/parser.y b/src/freedreno/afuc/parser.y
index 657524a1f6c..5a8164e59fe 100644
--- a/src/freedreno/afuc/parser.y
+++ b/src/freedreno/afuc/parser.y
@@ -161,6 +161,7 @@ label(const char *str)
 %token <tok> T_OP_SETSECURE
 %token <tok> T_LSHIFT
 %token <tok> T_REP
+%token <num> T_XMOV
 
 %type <num> reg
 %type <num> immediate
@@ -182,6 +183,7 @@ instr_or_label:    instr_r
 
 /* instructions that can optionally have (rep) flag: */
 instr_r:           alu_instr
+|                  T_XMOV alu_instr { instr->xmov = $1; }
 |                  config_instr
 
 /* need to special case:



More information about the mesa-commit mailing list