void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c)
{
	rewrite_depth_out(c);

	if (c->is_r500) {
		struct radeon_program_transformation transformations[] = {
			{ &r500_transform_TEX, c },
			{ &r500_transform_IF, 0 },
			{ &radeonTransformALU, 0 },
			{ &radeonTransformDeriv, 0 },
			{ &radeonTransformTrigScale, 0 }
		};
		radeonLocalTransform(&c->Base, 5, transformations);

		c->Base.SwizzleCaps = &r500_swizzle_caps;
	} else {
		struct radeon_program_transformation transformations[] = {
			{ &r300_transform_TEX, c },
			{ &radeonTransformALU, 0 },
			{ &radeonTransformTrigSimple, 0 }
		};
		radeonLocalTransform(&c->Base, 3, transformations);

		c->Base.SwizzleCaps = &r300_swizzle_caps;
	}

	if (c->Base.Debug) {
		fprintf(stderr, "Fragment Program: After native rewrite:\n");
		rc_print_program(&c->Base.Program);
		fflush(stderr);
	}

	rc_dataflow_deadcode(&c->Base, &dataflow_outputs_mark_use, c);
	if (c->Base.Error)
		return;

	if (c->Base.Debug) {
		fprintf(stderr, "Fragment Program: After deadcode:\n");
		rc_print_program(&c->Base.Program);
		fflush(stderr);
	}

	rc_dataflow_swizzles(&c->Base);
	if (c->Base.Error)
		return;

	if (c->Base.Debug) {
		fprintf(stderr, "Compiler: after dataflow passes:\n");
		rc_print_program(&c->Base.Program);
		fflush(stderr);
	}

	rc_pair_translate(c);
	if (c->Base.Error)
		return;

	if (c->Base.Debug) {
		fprintf(stderr, "Compiler: after pair translate:\n");
		rc_print_program(&c->Base.Program);
		fflush(stderr);
	}

	rc_pair_schedule(c);
	if (c->Base.Error)
		return;

	if (c->Base.Debug) {
		fprintf(stderr, "Compiler: after pair scheduling:\n");
		rc_print_program(&c->Base.Program);
		fflush(stderr);
	}

	if (c->is_r500)
		rc_pair_regalloc(c, 128);
	else
		rc_pair_regalloc(c, R300_PFS_NUM_TEMP_REGS);

	if (c->Base.Error)
		return;

	if (c->Base.Debug) {
		fprintf(stderr, "Compiler: after pair register allocation:\n");
		rc_print_program(&c->Base.Program);
		fflush(stderr);
	}

	if (c->is_r500) {
		r500BuildFragmentProgramHwCode(c);
	} else {
		r300BuildFragmentProgramHwCode(c);
	}

	rc_constants_copy(&c->code->constants, &c->Base.Program.Constants);

	if (c->Base.Debug) {
		if (c->is_r500) {
			r500FragmentProgramDump(c->code);
		} else {
			r300FragmentProgramDump(c->code);
		}
	}
}
/**
 * Handle one instruction.
 */
static void process_instruction(struct nqssadce_state* s)
{
	struct prog_instruction *inst = s->Program->Instructions + s->IP;

	if (inst->Opcode == OPCODE_END)
		return;

	if (inst->Opcode != OPCODE_KIL) {
		if (s->Descr->RewriteDepthOut) {
			if (inst->DstReg.File == PROGRAM_OUTPUT && inst->DstReg.Index == FRAG_RESULT_DEPR)
				rewrite_depth_out(inst);
		}

		struct register_state *regstate = get_reg_state(s, inst->DstReg.File, inst->DstReg.Index);
		if (!regstate) {
			_mesa_problem(s->Ctx, "NqssaDce: bad destination register (%i[%i])\n",
				inst->DstReg.File, inst->DstReg.Index);
			return;
		}

		inst->DstReg.WriteMask &= regstate->Sourced;
		regstate->Sourced &= ~inst->DstReg.WriteMask;

		if (inst->DstReg.WriteMask == 0) {
			_mesa_delete_instructions(s->Program, s->IP, 1);
			return;
		}

		if (inst->DstReg.File == PROGRAM_TEMPORARY && !regstate->Sourced)
			unalias_temporary(s, inst->DstReg.Index);
	}

	/* Attention: Due to swizzle emulation code, the following
	 * might change the instruction stream under us, so we have
	 * to be careful with the inst pointer. */
	switch (inst->Opcode) {
	case OPCODE_DDX:
	case OPCODE_DDY:
	case OPCODE_FRC:
	case OPCODE_MOV:
		inst = track_used_srcreg(s, inst, 0, inst->DstReg.WriteMask);
		break;
	case OPCODE_ADD:
	case OPCODE_MAX:
	case OPCODE_MIN:
	case OPCODE_MUL:
		inst = track_used_srcreg(s, inst, 0, inst->DstReg.WriteMask);
		inst = track_used_srcreg(s, inst, 1, inst->DstReg.WriteMask);
		break;
	case OPCODE_CMP:
	case OPCODE_MAD:
		inst = track_used_srcreg(s, inst, 0, inst->DstReg.WriteMask);
		inst = track_used_srcreg(s, inst, 1, inst->DstReg.WriteMask);
		inst = track_used_srcreg(s, inst, 2, inst->DstReg.WriteMask);
		break;
	case OPCODE_COS:
	case OPCODE_EX2:
	case OPCODE_LG2:
	case OPCODE_RCP:
	case OPCODE_RSQ:
	case OPCODE_SIN:
		inst = track_used_srcreg(s, inst, 0, 0x1);
		break;
	case OPCODE_DP3:
		inst = track_used_srcreg(s, inst, 0, 0x7);
		inst = track_used_srcreg(s, inst, 1, 0x7);
		break;
	case OPCODE_DP4:
		inst = track_used_srcreg(s, inst, 0, 0xf);
		inst = track_used_srcreg(s, inst, 1, 0xf);
		break;
	case OPCODE_KIL:
	case OPCODE_TEX:
	case OPCODE_TXB:
	case OPCODE_TXP:
		inst = track_used_srcreg(s, inst, 0, 0xf);
		break;
	default:
		_mesa_problem(s->Ctx, "NqssaDce: Unknown opcode %d\n", inst->Opcode);
		return;
	}
}