Mesa (master): freedreno/ir3: fix up cat6 instruction encodings

Rob Clark robclark at kemper.freedesktop.org
Tue Mar 3 15:41:16 UTC 2015


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

Author: Rob Clark <robclark at freedesktop.org>
Date:   Thu Feb 26 13:35:31 2015 -0500

freedreno/ir3: fix up cat6 instruction encodings

I think there is at least one more sub-encoding, but these two should be
enough to cover the common load/store instructions.

Signed-off-by: Rob Clark <robclark at freedesktop.org>

---

 src/gallium/drivers/freedreno/ir3/disasm-a3xx.c |  157 +++++++++++------------
 src/gallium/drivers/freedreno/ir3/instr-a3xx.h  |   41 +++---
 src/gallium/drivers/freedreno/ir3/ir3.c         |   62 ++++-----
 3 files changed, 121 insertions(+), 139 deletions(-)

diff --git a/src/gallium/drivers/freedreno/ir3/disasm-a3xx.c b/src/gallium/drivers/freedreno/ir3/disasm-a3xx.c
index 602be65..bed9aca 100644
--- a/src/gallium/drivers/freedreno/ir3/disasm-a3xx.c
+++ b/src/gallium/drivers/freedreno/ir3/disasm-a3xx.c
@@ -448,117 +448,114 @@ static void print_instr_cat5(instr_t *instr)
 	}
 }
 
-static int32_t u2i(uint32_t val, int nbits)
-{
-	return ((val >> (nbits-1)) * ~((1 << nbits) - 1)) | val;
-}
-
 static void print_instr_cat6(instr_t *instr)
 {
 	instr_cat6_t *cat6 = &instr->cat6;
+	char sd = 0, ss = 0;  /* dst/src address space */
+	bool full = type_size(cat6->type) == 32;
+	bool nodst = false;
 
 	printf(".%s ", type[cat6->type]);
 
 	switch (cat6->opc) {
+	case OPC_STG:
+		sd = 'g';
+		break;
+	case OPC_STP:
+		sd = 'p';
+		break;
+	case OPC_STL:
+	case OPC_STLW:
+		sd = 'l';
+		break;
+
 	case OPC_LDG:
+		ss = 'g';
+		break;
 	case OPC_LDP:
+		ss = 'p';
+		break;
 	case OPC_LDL:
 	case OPC_LDLW:
 	case OPC_LDLV:
-		/* load instructions: */
-		print_reg_dst((reg_t)(cat6->a.dst), type_size(cat6->type) == 32, false);
-		printf(",");
-		switch (cat6->opc) {
-		case OPC_LDG:
-			printf("g");
-			break;
-		case OPC_LDP:
-			printf("p");
-			break;
-		case OPC_LDL:
-		case OPC_LDLW:
-		case OPC_LDLV:
-			printf("l");
-			break;
-		}
-		printf("[");
-		print_reg_src((reg_t)(cat6->a.src), true,
-				false, false, false, false, false, false);
-		if (cat6->a.off)
-			printf("%+d", cat6->a.off);
-		printf("]");
+		ss = 'l';
 		break;
-	case OPC_PREFETCH:
-		/* similar to load instructions: */
-		printf("g[");
-		print_reg_src((reg_t)(cat6->a.src), true,
-				false, false, false, false, false, false);
-		if (cat6->a.off)
-			printf("%+d", cat6->a.off);
-		printf("]");
+
+	case OPC_L2G:
+		ss = 'l';
+		sd = 'g';
 		break;
-	case OPC_STG:
-	case OPC_STP:
-	case OPC_STL:
-	case OPC_STLW:
-		/* store instructions: */
-		switch (cat6->opc) {
-		case OPC_STG:
-			printf("g");
-			break;
-		case OPC_STP:
-			printf("p");
-			break;
-		case OPC_STL:
-		case OPC_STLW:
-			printf("l");
-			break;
-		}
-		printf("[");
-		print_reg_dst((reg_t)(cat6->b.dst), true, false);
-		if (cat6->b.off || cat6->b.off_hi)
-			printf("%+d", u2i((cat6->b.off_hi << 8) | cat6->b.off, 13));
-		printf("]");
-		printf(",");
-		print_reg_src((reg_t)(cat6->b.src), type_size(cat6->type) == 32,
-				false, false, false, false, false, false);
 
+	case OPC_G2L:
+		ss = 'g';
+		sd = 'l';
 		break;
+
+	case OPC_PREFETCH:
+		ss = 'g';
+		nodst = true;
+		break;
+
 	case OPC_STI:
-		/* sti has same encoding as other store instructions, but
-		 * slightly different syntax:
-		 */
-		print_reg_dst((reg_t)(cat6->b.dst), false /* XXX is it always half? */, false);
-		if (cat6->b.off || cat6->b.off_hi)
-			printf("%+d", u2i((cat6->b.off_hi << 8) | cat6->b.off, 13));
-		printf(",");
-		print_reg_src((reg_t)(cat6->b.src), type_size(cat6->type) == 32,
-				false, false, false, false, false, false);
+		full = false;  // XXX or inverts??
 		break;
 	}
 
-	printf(", %d", cat6->iim_val);
+	if (cat6->has_off) {
+		if (!nodst) {
+			if (sd)
+				printf("%c[", sd);
+			print_reg_dst((reg_t)(cat6->a.dst), full, false);
+			if (sd)
+				printf("]");
+			printf(", ");
+		}
+		if (ss)
+			printf("%c[", ss);
+		print_reg_src((reg_t)(cat6->a.src1), true,
+				false, false, cat6->a.src1_im, false, false, false);
+		printf("%+d", cat6->a.off);
+		if (ss)
+			printf("]");
+		printf(", ");
+		print_reg_src((reg_t)(cat6->a.src2), full,
+				false, false, cat6->a.src2_im, false, false, false);
+	} else {
+		if (!nodst) {
+			if (sd)
+				printf("%c[", sd);
+			print_reg_dst((reg_t)(cat6->b.dst), full, false);
+			if (sd)
+				printf("]");
+			printf(", ");
+		}
+		if (ss)
+			printf("%c[", ss);
+		print_reg_src((reg_t)(cat6->b.src1), true,
+				false, false, cat6->b.src1_im, false, false, false);
+		if (ss)
+			printf("]");
+		printf(", ");
+		print_reg_src((reg_t)(cat6->b.src2), full,
+				false, false, cat6->b.src2_im, false, false, false);
+	}
 
 	if (debug & PRINT_VERBOSE) {
 		switch (cat6->opc) {
 		case OPC_LDG:
 		case OPC_LDP:
 			/* load instructions: */
-			if (cat6->a.dummy1|cat6->a.dummy2|cat6->a.dummy3)
-				printf("\t{6: %x,%x,%x}", cat6->a.dummy1, cat6->a.dummy2, cat6->a.dummy3);
-			if ((cat6->a.must_be_one1 != 1) || (cat6->a.must_be_one2 != 1))
-				printf("{?? %d,%d ??}", cat6->a.must_be_one1, cat6->a.must_be_one2);
+			if (cat6->a.dummy2|cat6->a.dummy3)
+				printf("\t{6: %x,%x}", cat6->a.dummy2, cat6->a.dummy3);
 			break;
 		case OPC_STG:
 		case OPC_STP:
 		case OPC_STI:
 			/* store instructions: */
-			if (cat6->b.dummy1|cat6->b.dummy2)
-				printf("\t{6: %x,%x}", cat6->b.dummy1, cat6->b.dummy2);
-			if ((cat6->b.must_be_one1 != 1) || (cat6->b.must_be_one2 != 1) ||
-					(cat6->b.must_be_zero1 != 0))
-				printf("{?? %d,%d,%d ??}", cat6->b.must_be_one1, cat6->b.must_be_one2,
-						cat6->b.must_be_zero1);
+			if (cat6->b.dummy2|cat6->b.dummy2)
+				printf("\t{6: %x,%x}", cat6->b.dummy2, cat6->b.dummy3);
+			if (cat6->b.ignore0)
+				printf("\t{?? %x}", cat6->b.ignore0);
 			break;
 		}
 	}
diff --git a/src/gallium/drivers/freedreno/ir3/instr-a3xx.h b/src/gallium/drivers/freedreno/ir3/instr-a3xx.h
index c67f103..b7e19c8 100644
--- a/src/gallium/drivers/freedreno/ir3/instr-a3xx.h
+++ b/src/gallium/drivers/freedreno/ir3/instr-a3xx.h
@@ -572,15 +572,15 @@ typedef struct PACKED {
 	uint32_t opc_cat  : 3;
 } instr_cat5_t;
 
-/* used for load instructions: */
+/* [src1 + off], src2: */
 typedef struct PACKED {
 	/* dword0: */
-	uint32_t must_be_one1 : 1;
-	int16_t  off      : 13;
-	uint32_t src      : 8;
-	uint32_t dummy1   : 1;
-	uint32_t must_be_one2 : 1;
-	int32_t  iim_val  : 8;
+	uint32_t mustbe1  : 1;
+	int32_t  off      : 13;
+	uint32_t src1     : 8;
+	uint32_t src1_im  : 1;
+	uint32_t src2_im  : 1;
+	uint32_t src2     : 8;
 
 	/* dword1: */
 	uint32_t dst      : 8;
@@ -593,35 +593,38 @@ typedef struct PACKED {
 	uint32_t opc_cat  : 3;
 } instr_cat6a_t;
 
-/* used for store instructions: */
+/* [src1], src2: */
 typedef struct PACKED {
 	/* dword0: */
-	uint32_t must_be_zero1 : 1;
-	uint32_t src      : 8;
-	uint32_t off_hi   : 5;   /* high bits of 'off'... ugly! */
-	uint32_t dummy1   : 9;
-	uint32_t must_be_one1 : 1;
-	int32_t  iim_val  : 8;
+	uint32_t mustbe0  : 1;
+	uint32_t src1     : 8;
+	uint32_t ignore0  : 13;
+	uint32_t src1_im  : 1;
+	uint32_t src2_im  : 1;
+	uint32_t src2     : 8;
 
 	/* dword1: */
-	uint16_t off      : 8;
-	uint32_t must_be_one2 : 1;
 	uint32_t dst      : 8;
+	uint32_t dummy2   : 9;
 	uint32_t type     : 3;
-	uint32_t dummy2   : 2;
+	uint32_t dummy3   : 2;
 	uint32_t opc      : 5;
 	uint32_t jmp_tgt  : 1;
 	uint32_t sync     : 1;
 	uint32_t opc_cat  : 3;
 } instr_cat6b_t;
 
+/* I think some of the other cat6 instructions use additional
+ * sub-encodings..
+ */
+
 typedef union PACKED {
 	instr_cat6a_t a;
 	instr_cat6b_t b;
 	struct PACKED {
 		/* dword0: */
-		uint32_t pad1     : 24;
-		int32_t  iim_val  : 8;
+		uint32_t has_off  : 1;
+		uint32_t pad1     : 31;
 
 		/* dword1: */
 		uint32_t pad2     : 17;
diff --git a/src/gallium/drivers/freedreno/ir3/ir3.c b/src/gallium/drivers/freedreno/ir3/ir3.c
index 095085a..a02b06f 100644
--- a/src/gallium/drivers/freedreno/ir3/ir3.c
+++ b/src/gallium/drivers/freedreno/ir3/ir3.c
@@ -474,58 +474,40 @@ static int emit_cat5(struct ir3_instruction *instr, void *ptr,
 static int emit_cat6(struct ir3_instruction *instr, void *ptr,
 		struct ir3_info *info)
 {
-	struct ir3_register *dst = instr->regs[0];
-	struct ir3_register *src = instr->regs[1];
+	struct ir3_register *dst  = instr->regs[0];
+	struct ir3_register *src1 = instr->regs[1];
+	struct ir3_register *src2 = (instr->regs_count >= 3) ? instr->regs[2] : NULL;
 	instr_cat6_t *cat6 = ptr;
 
-	iassert(instr->regs_count == 2);
+	iassert(instr->regs_count >= 2);
 
-	switch (instr->opc) {
-	/* load instructions: */
-	case OPC_LDG:
-	case OPC_LDP:
-	case OPC_LDL:
-	case OPC_LDLW:
-	case OPC_LDLV:
-	case OPC_PREFETCH: {
+	if (instr->cat6.offset) {
 		instr_cat6a_t *cat6a = ptr;
 
-		iassert(!((dst->flags ^ type_flags(instr->cat6.type)) & IR3_REG_HALF));
+		cat6->has_off = true;
 
-		cat6a->must_be_one1  = 1;
-		cat6a->must_be_one2  = 1;
-		cat6a->off = instr->cat6.offset;
-		cat6a->src = reg(src, info, instr->repeat, 0);
 		cat6a->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
-		break;
-	}
-	/* store instructions: */
-	case OPC_STG:
-	case OPC_STP:
-	case OPC_STL:
-	case OPC_STLW:
-	case OPC_STI: {
+		cat6a->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED);
+		cat6a->src1_im = !!(src1->flags & IR3_REG_IMMED);
+		if (src2) {
+			cat6a->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+			cat6a->src2_im = !!(src2->flags & IR3_REG_IMMED);
+		}
+		cat6a->off = instr->cat6.offset;
+	} else {
 		instr_cat6b_t *cat6b = ptr;
-		uint32_t src_flags = type_flags(instr->cat6.type);
-		uint32_t dst_flags = (instr->opc == OPC_STI) ? IR3_REG_HALF : 0;
-
-		iassert(!((src->flags ^ src_flags) & IR3_REG_HALF));
 
-		cat6b->must_be_one1  = 1;
-		cat6b->must_be_one2  = 1;
-		cat6b->src    = reg(src, info, instr->repeat, src_flags);
-		cat6b->off_hi = instr->cat6.offset >> 8;
-		cat6b->off    = instr->cat6.offset;
-		cat6b->dst    = reg(dst, info, instr->repeat, IR3_REG_R | dst_flags);
+		cat6->has_off = false;
 
-		break;
-	}
-	default:
-		// TODO
-		break;
+		cat6b->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
+		cat6b->src1 = reg(src1, info, instr->repeat, IR3_REG_IMMED);
+		cat6b->src1_im = !!(src1->flags & IR3_REG_IMMED);
+		if (src2) {
+			cat6b->src2 = reg(src2, info, instr->repeat, IR3_REG_IMMED);
+			cat6b->src2_im = !!(src2->flags & IR3_REG_IMMED);
+		}
 	}
 
-	cat6->iim_val  = instr->cat6.iim_val;
 	cat6->type     = instr->cat6.type;
 	cat6->opc      = instr->opc;
 	cat6->jmp_tgt  = !!(instr->flags & IR3_INSTR_JP);




More information about the mesa-commit mailing list