/**
 * Count which (input, temporary) register is read and written how often,
 * and scan the instruction stream to find dependencies.
 */
static void scan_instructions(struct pair_state *s)
{
	struct prog_instruction *inst;
	struct pair_state_instruction *pairinst;
	GLuint ip;

	for(inst = s->Program->Instructions, pairinst = s->Instructions, ip = 0;
	    inst->Opcode != OPCODE_END;
	    ++inst, ++pairinst, ++ip) {
		final_rewrite(s, inst);
		classify_instruction(s, inst, pairinst);

		int nsrc = _mesa_num_inst_src_regs(inst->Opcode);
		int j;
		for(j = 0; j < nsrc; j++) {
			struct pair_register_translation *t =
				get_register(s, inst->SrcReg[j].File, inst->SrcReg[j].Index);
			if (!t)
				continue;

			t->RefCount++;

			if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
				int i;
				for(i = 0; i < 4; ++i) {
					GLuint swz = GET_SWZ(inst->SrcReg[j].Swizzle, i);
					if (swz >= 4)
						continue; /* constant or NIL swizzle */
					if (!t->Value[swz])
						continue; /* this is an undefined read */

					/* Do not add a dependency if this instruction
					 * also rewrites the value. The code below adds
					 * a dependency for the DstReg, which is a superset
					 * of the SrcReg dependency. */
					if (inst->DstReg.File == PROGRAM_TEMPORARY &&
					    inst->DstReg.Index == inst->SrcReg[j].Index &&
					    GET_BIT(inst->DstReg.WriteMask, swz))
						continue;

					struct reg_value_reader* r = &s->ReaderPool[s->ReaderPoolUsed++];
					pairinst->NumDependencies++;
					t->Value[swz]->NumReaders++;
					r->IP = ip;
					r->Next = t->Value[swz]->Readers;
					t->Value[swz]->Readers = r;
				}
			}
		}

		int ndst = _mesa_num_inst_dst_regs(inst->Opcode);
		if (ndst) {
			struct pair_register_translation *t =
				get_register(s, inst->DstReg.File, inst->DstReg.Index);
			if (t) {
				t->RefCount++;

				if (inst->DstReg.File == PROGRAM_TEMPORARY) {
					int j;
					for(j = 0; j < 4; ++j) {
						if (!GET_BIT(inst->DstReg.WriteMask, j))
							continue;

						struct reg_value* v = &s->ValuePool[s->ValuePoolUsed++];
						v->IP = ip;
						if (t->Value[j]) {
							pairinst->NumDependencies++;
							t->Value[j]->Next = v;
						}
						t->Value[j] = v;
						pairinst->Values[j] = v;
					}
				}
			}
		}

		if (s->Verbose)
			_mesa_printf("scan(%i): NumDeps = %i\n", ip, pairinst->NumDependencies);

		if (!pairinst->NumDependencies)
			instruction_ready(s, ip);
	}

	/* Clear the PROGRAM_TEMPORARY state */
	int i, j;
	for(i = 0; i < MAX_PROGRAM_TEMPS; ++i) {
		for(j = 0; j < 4; ++j)
			s->Temps[i].Value[j] = 0;
	}
}
/**
 * Fill the given ALU instruction's opcodes and source operands into the given pair,
 * if possible.
 */
static void set_pair_instruction(struct r300_fragment_program_compiler *c,
	struct rc_pair_instruction * pair,
	struct rc_sub_instruction * inst)
{
	memset(pair, 0, sizeof(struct rc_pair_instruction));

	int needrgb, needalpha, istranscendent;
	classify_instruction(inst, &needrgb, &needalpha, &istranscendent);

	if (needrgb) {
		if (istranscendent)
			pair->RGB.Opcode = RC_OPCODE_REPL_ALPHA;
		else
			pair->RGB.Opcode = inst->Opcode;
		if (inst->SaturateMode == RC_SATURATE_ZERO_ONE)
			pair->RGB.Saturate = 1;
	}
	if (needalpha) {
		pair->Alpha.Opcode = inst->Opcode;
		if (inst->SaturateMode == RC_SATURATE_ZERO_ONE)
			pair->Alpha.Saturate = 1;
	}

	const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
	int nargs = opcode->NumSrcRegs;
	int i;

	/* Special case for DDX/DDY (MDH/MDV). */
	if (inst->Opcode == RC_OPCODE_DDX || inst->Opcode == RC_OPCODE_DDY) {
		nargs++;
	}

	for(i = 0; i < opcode->NumSrcRegs; ++i) {
		int source;
		if (needrgb && !istranscendent) {
			unsigned int srcrgb = 0;
			unsigned int srcalpha = 0;
			int j;
			for(j = 0; j < 3; ++j) {
				unsigned int swz = GET_SWZ(inst->SrcReg[i].Swizzle, j);
				if (swz < 3)
					srcrgb = 1;
				else if (swz < 4)
					srcalpha = 1;
			}
			source = rc_pair_alloc_source(pair, srcrgb, srcalpha,
							inst->SrcReg[i].File, inst->SrcReg[i].Index);
			pair->RGB.Arg[i].Source = source;
			pair->RGB.Arg[i].Swizzle = inst->SrcReg[i].Swizzle & 0x1ff;
			pair->RGB.Arg[i].Abs = inst->SrcReg[i].Abs;
			pair->RGB.Arg[i].Negate = !!(inst->SrcReg[i].Negate & (RC_MASK_X | RC_MASK_Y | RC_MASK_Z));
		}
		if (needalpha) {
			unsigned int srcrgb = 0;
			unsigned int srcalpha = 0;
			unsigned int swz = GET_SWZ(inst->SrcReg[i].Swizzle, istranscendent ? 0 : 3);
			if (swz < 3)
				srcrgb = 1;
			else if (swz < 4)
				srcalpha = 1;
			source = rc_pair_alloc_source(pair, srcrgb, srcalpha,
							inst->SrcReg[i].File, inst->SrcReg[i].Index);
			pair->Alpha.Arg[i].Source = source;
			pair->Alpha.Arg[i].Swizzle = swz;
			pair->Alpha.Arg[i].Abs = inst->SrcReg[i].Abs;
			pair->Alpha.Arg[i].Negate = !!(inst->SrcReg[i].Negate & RC_MASK_W);
		}
	}

	/* Destination handling */
	if (inst->DstReg.File == RC_FILE_OUTPUT) {
        if (inst->DstReg.Index == c->OutputDepth) {
            pair->Alpha.DepthWriteMask |= GET_BIT(inst->DstReg.WriteMask, 3);
        } else {
            for (i = 0; i < 4; i++) {
                if (inst->DstReg.Index == c->OutputColor[i]) {
                    pair->RGB.Target = i;
                    pair->Alpha.Target = i;
                    pair->RGB.OutputWriteMask |=
                        inst->DstReg.WriteMask & RC_MASK_XYZ;
                    pair->Alpha.OutputWriteMask |=
                        GET_BIT(inst->DstReg.WriteMask, 3);
                    break;
                }
            }
        }
	} else {
		if (needrgb) {
			pair->RGB.DestIndex = inst->DstReg.Index;
			pair->RGB.WriteMask |= inst->DstReg.WriteMask & RC_MASK_XYZ;
		}
		if (needalpha) {
			pair->Alpha.DestIndex = inst->DstReg.Index;
			pair->Alpha.WriteMask |= GET_BIT(inst->DstReg.WriteMask, 3);
		}
	}

	if (inst->WriteALUResult) {
		pair->WriteALUResult = inst->WriteALUResult;
		pair->ALUResultCompare = inst->ALUResultCompare;
	}
}