commit 78f4b96b9b874e487571b59cec22e683f23d2e3e
Author: chr <chr@ECHELON.(none)>
Date:   Sat May 16 15:33:34 2009 +0200

    - Introduce argument negation for MUL, MAD, ADD, DP3, DP4 and POW.
      This is now done via a negation bitmask in nv50_pc that is checked
      in the emit functions, the 'neg' member of nv50_reg is obsolete
      with this.
      (maybe I should have used it instead, but I completely forgot
       about it and went with this way ...)
    
    - changed emit_sub and emit_msb to use negated emit_add and emit_mad

diff --git a/src/gallium/drivers/nv50/nv50_program.c b/src/gallium/drivers/nv50/nv50_program.c
index 6e279bd..ed9e20b 100644
--- a/src/gallium/drivers/nv50/nv50_program.c
+++ b/src/gallium/drivers/nv50/nv50_program.c
@@ -117,6 +117,7 @@ struct nv50_pc {
 	unsigned insn_cur;
 	unsigned insn_nr;
 
+	unsigned negate;
 	boolean allow32; /* TRUE when half insns are allowed */
 };
 
@@ -531,6 +532,8 @@ emit_mov(struct nv50_pc *pc, struct nv50_reg *dst, struct nv50_reg *src)
 	emit(pc, e);
 }
 
+#define BITS_0_1_SWAPPED(x) ((x & 1) << 1) | ((x & 2) >> 1)
+
 static boolean
 check_swap_src_0_1(struct nv50_pc *pc,
 		   struct nv50_reg **s0, struct nv50_reg **s1)
@@ -628,14 +631,6 @@ set_src_2(struct nv50_pc *pc, struct nv50_reg *src, struct nv50_program_exec *e)
 	e->inst[1] |= (src->hw << 14);
 }
 
-static boolean
-requires_long(struct nv50_program_exec *e, struct nv50_reg *src)
-{
-	if (is_long(e) || src->type == P_IMMD || src->type == P_CONST)
-		return TRUE;
-	return FALSE;
-}
-
 static void
 emit_mul(struct nv50_pc *pc, struct nv50_reg *dst, struct nv50_reg *src0,
 	 struct nv50_reg *src1)
@@ -650,6 +645,13 @@ emit_mul(struct nv50_pc *pc, struct nv50_reg *dst, struct nv50_reg *src0,
 	set_src_0(pc, src0, e);
 	set_src_1(pc, src1, e);
 
+	if (pc->negate & 1) {
+		if (is_long(e))
+			e->inst[1] |= 0x08000000;
+		else
+			e->inst[0] |= 0x00008000;
+	}
+
 	emit(pc, e);
 }
 
@@ -658,18 +660,25 @@ emit_add(struct nv50_pc *pc, struct nv50_reg *dst,
 	 struct nv50_reg *src0, struct nv50_reg *src1)
 {
 	struct nv50_program_exec *e = exec(pc);
+	unsigned neg = pc->negate;
 
 	e->inst[0] |= 0xb0000000;
 
-	check_swap_src_0_1(pc, &src0, &src1);
+	if (check_swap_src_0_1(pc, &src0, &src1))
+		neg = BITS_0_1_SWAPPED(neg);
+	if (!pc->allow32 || neg) {
+		set_long(pc, e);
+		e->inst[1] |= (neg << 26);
+	}
+
 	set_dst(pc, dst, e);
 	set_src_0(pc, src0, e);
-	if (!is_long(e) && src1->type == P_IMMD && pc->allow32)
-		set_immd(pc, src1, e);
-	else
-	if (requires_long(e, src1))
+	if (src1->type == P_CONST || is_long(e))
 		set_src_2(pc, src1, e);
 	else
+	if (src1->type == P_IMMD)
+		set_immd(pc, src1, e);
+	else
 		set_src_1(pc, src1, e);
 
 	emit(pc, e);
@@ -693,25 +702,13 @@ emit_minmax(struct nv50_pc *pc, unsigned sub, struct nv50_reg *dst,
 	emit(pc, e);
 }
 
-static void
+static INLINE void
 emit_sub(struct nv50_pc *pc, struct nv50_reg *dst, struct nv50_reg *src0,
 	 struct nv50_reg *src1)
 {
-	struct nv50_program_exec *e = exec(pc);
-
-	e->inst[0] |= 0xb0000000;
-
-	set_long(pc, e);
-	if (check_swap_src_0_1(pc, &src0, &src1))
-		e->inst[1] |= 0x04000000;
-	else
-		e->inst[1] |= 0x08000000;
-
-	set_dst(pc, dst, e);
-	set_src_0(pc, src0, e);
-	set_src_2(pc, src1, e);
-
-	emit(pc, e);
+	pc->negate ^= 2;
+	emit_add(pc, dst, src0, src1);
+	pc->negate ^= 2;
 }
 
 static void
@@ -728,26 +725,21 @@ emit_mad(struct nv50_pc *pc, struct nv50_reg *dst, struct nv50_reg *src0,
 	set_src_1(pc, src1, e);
 	set_src_2(pc, src2, e);
 
+	if (pc->negate & 1)
+		e->inst[1] |= 0x04000000;
+	if (pc->negate & 2)
+		e->inst[1] |= 0x08000000;
+
 	emit(pc, e);
 }
 
-static void
+static INLINE void
 emit_msb(struct nv50_pc *pc, struct nv50_reg *dst, struct nv50_reg *src0,
 	 struct nv50_reg *src1, struct nv50_reg *src2)
 {
-	struct nv50_program_exec *e = exec(pc);
-
-	e->inst[0] |= 0xe0000000;
-	set_long(pc, e);
-	e->inst[1] |= 0x08000000; /* src0 * src1 - src2 */
-
-	check_swap_src_0_1(pc, &src0, &src1);
-	set_dst(pc, dst, e);
-	set_src_0(pc, src0, e);
-	set_src_1(pc, src1, e);
-	set_src_2(pc, src2, e);
-
-	emit(pc, e);
+	pc->negate ^= 2;
+	emit_mad(pc, dst, src0, src1, src2);
+	pc->negate ^= 2;
 }
 
 static void
@@ -1012,8 +1004,15 @@ convert_to_long(struct nv50_pc *pc, struct nv50_program_exec *e)
 			if (e->inst[0] & 0x02000000)
 				q = 0x00020000;
 			break;
+		case 0xB:
+			/* ADD */
+			m = ~(127 << 16);
+			q = ((e->inst[0] & (~m)) >> 2);
+			break;
 		case 0xC:
 			/* MUL */
+			m = ~0x00008000;
+			q = ((e->inst[0] & (~m)) << 12);
 			break;
 		case 0x9:
 			/* RCP */
@@ -1090,8 +1089,33 @@ tgsi_dst(struct nv50_pc *pc, int c, const struct tgsi_full_dst_register *dst)
 	return NULL;
 }
 
+/* Returns bit with which to XOR pc->negate on negation, or -1 if negation
+ * is not supported for the instruction. This is used in tgsi_src, and set
+ * to -2 in tx_insn to indicate XOR has already been taken care of in c 0.
+ */
+static int
+negate_supported(const struct tgsi_full_instruction *insn, int i)
+{
+	switch (insn->Instruction.Opcode) {
+	case TGSI_OPCODE_DP3:
+	case TGSI_OPCODE_DP4:
+	case TGSI_OPCODE_MUL:
+		return 0;
+	case TGSI_OPCODE_ADD:
+	case TGSI_OPCODE_SUB:
+		return i;
+	case TGSI_OPCODE_MAD:
+		return (i == 2) ? 1 : 0;
+	case TGSI_OPCODE_POW:
+		return (i == 1) ? 0 : -1;
+	default:
+		return -1;
+	}
+}
+
 static struct nv50_reg *
-tgsi_src(struct nv50_pc *pc, int chan, const struct tgsi_full_src_register *src)
+tgsi_src(struct nv50_pc *pc, int chan, const struct tgsi_full_src_register *src,
+	int neg)
 {
 	struct nv50_reg *r = NULL;
 	struct nv50_reg *temp;
@@ -1146,9 +1170,12 @@ tgsi_src(struct nv50_pc *pc, int chan, const struct tgsi_full_src_register *src)
 		r = temp;
 		break;
 	case TGSI_UTIL_SIGN_TOGGLE:
-		temp = temp_temp(pc);
-		emit_neg(pc, temp, r);
-		r = temp;
+		if (neg == -1) {
+			temp = temp_temp(pc);
+			emit_neg(pc, temp, r);
+			r = temp;
+		} else if (neg >= 0)
+			pc->negate ^= (1 << neg);
 		break;
 	case TGSI_UTIL_SIGN_SET:
 		temp = temp_temp(pc);
@@ -1202,6 +1229,7 @@ nv50_program_tx_insn(struct nv50_pc *pc, const union tgsi_full_token *tok)
 
 	mask = inst->FullDstRegisters[0].DstRegister.WriteMask;
 	sat = inst->Instruction.Saturate == TGSI_SAT_ZERO_ONE;
+	pc->negate = 0;
 
 	for (c = 0; c < 4; c++) {
 		if (mask & (1 << c))
@@ -1218,12 +1246,16 @@ nv50_program_tx_insn(struct nv50_pc *pc, const union tgsi_full_token *tok)
 
 	for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
 		const struct tgsi_full_src_register *fs = &inst->FullSrcRegisters[i];
+		int neg = negate_supported(inst, i);
 
 		if (fs->SrcRegister.File == TGSI_FILE_SAMPLER)
 			unit = fs->SrcRegister.Index;
 
-		for (c = 0; c < 4; c++)
-			src[i][c] = tgsi_src(pc, c, fs);
+		for (c = 0; c < 4; c++) {
+			src[i][c] = tgsi_src(pc, c, fs, neg);
+			if (neg >= 0)
+				neg = -2; /* already negated */
+		}
 	}
 
 	if (sat) {
