<commit_before>/*
 * Copyright (C) 2005 <NAME>.
 *
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

/**
 * \file
 *
 * \author <NAME> <<EMAIL>>
 *
 * \author <NAME> <<EMAIL>>
 *
 * \todo Depth write, WPOS/FOGC inputs
 *
 * \todo FogOption
 *
 * \todo Verify results of opcodes for accuracy, I've only checked them in
 * specific cases.
 */

#include "glheader.h"
#include "macros.h"
#include "enums.h"
#include "shader/prog_instruction.h"
#include "shader/prog_parameter.h"
#include "shader/prog_print.h"

#include "r300_context.h"
#include "r300_fragprog.h"
#include "r300_reg.h"
#include "r300_state.h"

/*
 * Usefull macros and values
 */
#define ERROR(fmt, args...) do {			\
		fprintf(stderr, "%s::%s(): " fmt "\n",	\
			__FILE__, __FUNCTION__, ##args);	\
		fp->error = GL_TRUE;			\
	} while(0)

#define PFS_INVAL 0xFFFFFFFF
#define COMPILE_STATE struct r300_pfs_compile_state *cs = fp->cs

#define SWIZZLE_XYZ		0
#define SWIZZLE_XXX		1
#define SWIZZLE_YYY		2
#define SWIZZLE_ZZZ		3
#define SWIZZLE_WWW		4
#define SWIZZLE_YZX		5
#define SWIZZLE_ZXY		6
#define SWIZZLE_WZY		7
#define SWIZZLE_111		8
#define SWIZZLE_000		9
#define SWIZZLE_HHH		10

#define swizzle(r, x, y, z, w) do_swizzle(fp, r,		\
					  ((SWIZZLE_##x<<0)|	\
					   (SWIZZLE_##y<<3)|	\
					   (SWIZZLE_##z<<6)|	\
					   (SWIZZLE_##w<<9)),	\
					  0)

#define REG_TYPE_INPUT		0
#define REG_TYPE_OUTPUT		1
#define REG_TYPE_TEMP		2
#define REG_TYPE_CONST		3

#define REG_TYPE_SHIFT		0
#define REG_INDEX_SHIFT		2
#define REG_VSWZ_SHIFT		8
#define REG_SSWZ_SHIFT		13
#define REG_NEGV_SHIFT		18
#define REG_NEGS_SHIFT		19
#define REG_ABS_SHIFT		20
#define REG_NO_USE_SHIFT	21	// Hack for refcounting
#define REG_VALID_SHIFT		22	// Does the register contain a defined value?
#define REG_BUILTIN_SHIFT   23	// Is it a builtin (like all zero/all one)?

#define REG_TYPE_MASK		(0x03 << REG_TYPE_SHIFT)
#define REG_INDEX_MASK		(0x3F << REG_INDEX_SHIFT)
#define REG_VSWZ_MASK		(0x1F << REG_VSWZ_SHIFT)
#define REG_SSWZ_MASK		(0x1F << REG_SSWZ_SHIFT)
#define REG_NEGV_MASK		(0x01 << REG_NEGV_SHIFT)
#define REG_NEGS_MASK		(0x01 << REG_NEGS_SHIFT)
#define REG_ABS_MASK		(0x01 << REG_ABS_SHIFT)
#define REG_NO_USE_MASK		(0x01 << REG_NO_USE_SHIFT)
#define REG_VALID_MASK		(0x01 << REG_VALID_SHIFT)
#define REG_BUILTIN_MASK	(0x01 << REG_BUILTIN_SHIFT)

#define REG(type, index, vswz, sswz, nouse, valid, builtin)	\
	(((type << REG_TYPE_SHIFT) & REG_TYPE_MASK) |			\
	 ((index << REG_INDEX_SHIFT) & REG_INDEX_MASK) |		\
	 ((nouse << REG_NO_USE_SHIFT) & REG_NO_USE_MASK) |		\
	 ((valid << REG_VALID_SHIFT) & REG_VALID_MASK) |		\
	 ((builtin << REG_BUILTIN_SHIFT) & REG_BUILTIN_MASK) |	\
	 ((vswz << REG_VSWZ_SHIFT) & REG_VSWZ_MASK) |			\
	 ((sswz << REG_SSWZ_SHIFT) & REG_SSWZ_MASK))
#define REG_GET_TYPE(reg)						\
	((reg & REG_TYPE_MASK) >> REG_TYPE_SHIFT)
#define REG_GET_INDEX(reg)						\
	((reg & REG_INDEX_MASK) >> REG_INDEX_SHIFT)
#define REG_GET_VSWZ(reg)						\
	((reg & REG_VSWZ_MASK) >> REG_VSWZ_SHIFT)
#define REG_GET_SSWZ(reg)						\
	((reg & REG_SSWZ_MASK) >> REG_SSWZ_SHIFT)
#define REG_GET_NO_USE(reg)						\
	((reg & REG_NO_USE_MASK) >> REG_NO_USE_SHIFT)
#define REG_GET_VALID(reg)						\
	((reg & REG_VALID_MASK) >> REG_VALID_SHIFT)
#define REG_GET_BUILTIN(reg)						\
	((reg & REG_BUILTIN_MASK) >> REG_BUILTIN_SHIFT)
#define REG_SET_TYPE(reg, type)						\
	reg = ((reg & ~REG_TYPE_MASK) |					\
	       ((type << REG_TYPE_SHIFT) & REG_TYPE_MASK))
#define REG_SET_INDEX(reg, index)					\
	reg = ((reg & ~REG_INDEX_MASK) |				\
	       ((index << REG_INDEX_SHIFT) & REG_INDEX_MASK))
#define REG_SET_VSWZ(reg, vswz)						\
	reg = ((reg & ~REG_VSWZ_MASK) |					\
	       ((vswz << REG_VSWZ_SHIFT) & REG_VSWZ_MASK))
#define REG_SET_SSWZ(reg, sswz)						\
	reg = ((reg & ~REG_SSWZ_MASK) |					\
	       ((sswz << REG_SSWZ_SHIFT) & REG_SSWZ_MASK))
#define REG_SET_NO_USE(reg, nouse)					\
	reg = ((reg & ~REG_NO_USE_MASK) |				\
	       ((nouse << REG_NO_USE_SHIFT) & REG_NO_USE_MASK))
#define REG_SET_VALID(reg, valid)					\
	reg = ((reg & ~REG_VALID_MASK) |				\
	       ((valid << REG_VALID_SHIFT) & REG_VALID_MASK))
#define REG_SET_BUILTIN(reg, builtin)					\
	reg = ((reg & ~REG_BUILTIN_MASK) |				\
	       ((builtin << REG_BUILTIN_SHIFT) & REG_BUILTIN_MASK))
#define REG_ABS(reg)							\
	reg = (reg | REG_ABS_MASK)
#define REG_NEGV(reg)							\
	reg = (reg | REG_NEGV_MASK)
#define REG_NEGS(reg)							\
	reg = (reg | REG_NEGS_MASK)

/*
 * Datas structures for fragment program generation
 */

/* description of r300 native hw instructions */
static const struct {
	const char *name;
	int argc;
	int v_op;
	int s_op;
} r300_fpop[] = {
	/* *INDENT-OFF* */
	{"MAD", 3, R300_FPI0_OUTC_MAD, R300_FPI2_OUTA_MAD},
	{"DP3", 2, R300_FPI0_OUTC_DP3, R300_FPI2_OUTA_DP4},
	{"DP4", 2, R300_FPI0_OUTC_DP4, R300_FPI2_OUTA_DP4},
	{"MIN", 2, R300_FPI0_OUTC_MIN, R300_FPI2_OUTA_MIN},
	{"MAX", 2, R300_FPI0_OUTC_MAX, R300_FPI2_OUTA_MAX},
	{"CMP", 3, R300_FPI0_OUTC_CMP, R300_FPI2_OUTA_CMP},
	{"FRC", 1, R300_FPI0_OUTC_FRC, R300_FPI2_OUTA_FRC},
	{"EX2", 1, R300_FPI0_OUTC_REPL_ALPHA, R300_FPI2_OUTA_EX2},
	{"LG2", 1, R300_FPI0_OUTC_REPL_ALPHA, R300_FPI2_OUTA_LG2},
	{"RCP", 1, R300_FPI0_OUTC_REPL_ALPHA, R300_FPI2_OUTA_RCP},
	{"RSQ", 1, R300_FPI0_OUTC_REPL_ALPHA, R300_FPI2_OUTA_RSQ},
	{"REPL_ALPHA", 1, R300_FPI0_OUTC_REPL_ALPHA, PFS_INVAL},
	{"CMPH", 3, R300_FPI0_OUTC_CMPH, PFS_INVAL},
	/* *INDENT-ON* */
};

/* vector swizzles r300 can support natively, with a couple of
 * cases we handle specially
 *
 * REG_VSWZ/REG_SSWZ is an index into this table
 */

/* mapping from SWIZZLE_* to r300 native values for scalar insns */
#define SWIZZLE_HALF 6

#define MAKE_SWZ3(x, y, z) (MAKE_SWIZZLE4(SWIZZLE_##x, \
					  SWIZZLE_##y, \
					  SWIZZLE_##z, \
					  SWIZZLE_ZERO))
/* native swizzles */
static const struct r300_pfs_swizzle {
	GLuint hash;		/* swizzle value this matches */
	GLuint base;		/* base value for hw swizzle */
	GLuint stride;		/* difference in base between arg0/1/2 */
	GLuint flags;
} v_swiz[] = {
	/* *INDENT-OFF* */
	{MAKE_SWZ3(X, Y, Z), R300_FPI0_ARGC_SRC0C_XYZ, 4, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(X, X, X), R300_FPI0_ARGC_SRC0C_XXX, 4, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(Y, Y, Y), R300_FPI0_ARGC_SRC0C_YYY, 4, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(Z, Z, Z), R300_FPI0_ARGC_SRC0C_ZZZ, 4, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(W, W, W), R300_FPI0_ARGC_SRC0A, 1, SLOT_SRC_SCALAR},
	{MAKE_SWZ3(Y, Z, X), R300_FPI0_ARGC_SRC0C_YZX, 1, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(Z, X, Y), R300_FPI0_ARGC_SRC0C_ZXY, 1, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(W, Z, Y), R300_FPI0_ARGC_SRC0CA_WZY, 1, SLOT_SRC_BOTH},
	{MAKE_SWZ3(ONE, ONE, ONE), R300_FPI0_ARGC_ONE, 0, 0},
	{MAKE_SWZ3(ZERO, ZERO, ZERO), R300_FPI0_ARGC_ZERO, 0, 0},
	{MAKE_SWZ3(HALF, HALF, HALF), R300_FPI0_ARGC_HALF, 0, 0},
	{PFS_INVAL, 0, 0, 0},
	/* *INDENT-ON* */
};

/* used during matching of non-native swizzles */
#define SWZ_X_MASK (7 << 0)
#define SWZ_Y_MASK (7 << 3)
#define SWZ_Z_MASK (7 << 6)
#define SWZ_W_MASK (7 << 9)
static const struct {
	GLuint hash;		/* used to mask matching swizzle components */
	int mask;		/* actual outmask */
	int count;		/* count of components matched */
} s_mask[] = {
	/* *INDENT-OFF* */
	{SWZ_X_MASK | SWZ_Y_MASK | SWZ_Z_MASK, 1 | 2 | 4, 3},
	{SWZ_X_MASK | SWZ_Y_MASK, 1 | 2, 2},
	{SWZ_X_MASK | SWZ_Z_MASK, 1 | 4, 2},
	{SWZ_Y_MASK | SWZ_Z_MASK, 2 | 4, 2},
	{SWZ_X_MASK, 1, 1},
	{SWZ_Y_MASK, 2, 1},
	{SWZ_Z_MASK, 4, 1},
	{PFS_INVAL, PFS_INVAL, PFS_INVAL}
	/* *INDENT-ON* */
};

static const struct {
	int base;		/* hw value of swizzle */
	int stride;		/* difference between SRC0/1/2 */
	GLuint flags;
} s_swiz[] = {
	/* *INDENT-OFF* */
	{R300_FPI2_ARGA_SRC0C_X, 3, SLOT_SRC_VECTOR},
	{R300_FPI2_ARGA_SRC0C_Y, 3, SLOT_SRC_VECTOR},
	{R300_FPI2_ARGA_SRC0C_Z, 3, SLOT_SRC_VECTOR},
	{R300_FPI2_ARGA_SRC0A, 1, SLOT_SRC_SCALAR},
	{R300_FPI2_ARGA_ZERO, 0, 0},
	{R300_FPI2_ARGA_ONE, 0, 0},
	{R300_FPI2_ARGA_HALF, 0, 0}
	/* *INDENT-ON* */
};

/* boiler-plate reg, for convenience */
static const GLuint undef = REG(REG_TYPE_TEMP,
				0,
				SWIZZLE_XYZ,
				SWIZZLE_W,
				GL_FALSE,
				GL_FALSE,
				GL_FALSE);

/* constant one source */
static const GLuint pfs_one = REG(REG_TYPE_CONST,
				  0,
				  SWIZZLE_111,
				  SWIZZLE_ONE,
				  GL_FALSE,
				  GL_TRUE,
				  GL_TRUE);

/* constant half source */
static const GLuint pfs_half = REG(REG_TYPE_CONST,
				   0,
				   SWIZZLE_HHH,
				   SWIZZLE_HALF,
				   GL_FALSE,
				   GL_TRUE,
				   GL_TRUE);

/* constant zero source */
static const GLuint pfs_zero = REG(REG_TYPE_CONST,
				   0,
				   SWIZZLE_000,
				   SWIZZLE_ZERO,
				   GL_FALSE,
				   GL_TRUE,
				   GL_TRUE);

/*
 * Common functions prototypes
 */
static void dump_program(struct r300_fragment_program *fp);
static void emit_arith(struct r300_fragment_program *fp, int op,
		       GLuint dest, int mask,
		       GLuint src0, GLuint src1, GLuint src2, int flags);

/**
 * Get an R300 temporary that can be written to in the given slot.
 */
static int get_hw_temp(struct r300_fragment_program *fp, int slot)
{
	COMPILE_STATE;
	int r;

	for (r = 0; r < PFS_NUM_TEMP_REGS; ++r) {
		if (cs->hwtemps[r].free >= 0 && cs->hwtemps[r].free <= slot)
			break;
	}

	if (r >= PFS_NUM_TEMP_REGS) {
		ERROR("Out of hardware temps\n");
		return 0;
	}
	// Reserved is used to avoid the following scenario:
	//  R300 temporary X is first assigned to Mesa temporary Y during vector ops
	//  R300 temporary X is then assigned to Mesa temporary Z for further vector ops
	//  Then scalar ops on Mesa temporary Z are emitted and move back in time
	//  to overwrite the value of temporary Y.
	// End scenario.
	cs->hwtemps[r].reserved = cs->hwtemps[r].free;
	cs->hwtemps[r].free = -1;

	// Reset to some value that won't mess things up when the user
	// tries to read from a temporary that hasn't been assigned a value yet.
	// In the normal case, vector_valid and scalar_valid should be set to
	// a sane value by the first emit that writes to this temporary.
	cs->hwtemps[r].vector_valid = 0;
	cs->hwtemps[r].scalar_valid = 0;

	if (r > fp->max_temp_idx)
		fp->max_temp_idx = r;

	return r;
}

/**
 * Get an R300 temporary that will act as a TEX destination register.
 */
static int get_hw_temp_tex(struct r300_fragment_program *fp)
{
	COMPILE_STATE;
	int r;

	for (r = 0; r < PFS_NUM_TEMP_REGS; ++r) {
		if (cs->used_in_node & (1 << r))
			continue;

		// Note: Be very careful here
		if (cs->hwtemps[r].free >= 0 && cs->hwtemps[r].free <= 0)
			break;
	}

	if (r >= PFS_NUM_TEMP_REGS)
		return get_hw_temp(fp, 0);	/* Will cause an indirection */

	cs->hwtemps[r].reserved = cs->hwtemps[r].free;
	cs->hwtemps[r].free = -1;

	// Reset to some value that won't mess things up when the user
	// tries to read from a temporary that hasn't been assigned a value yet.
	// In the normal case, vector_valid and scalar_valid should be set to
	// a sane value by the first emit that writes to this temporary.
	cs->hwtemps[r].vector_valid = cs->nrslots;
	cs->hwtemps[r].scalar_valid = cs->nrslots;

	if (r > fp->max_temp_idx)
		fp->max_temp_idx = r;

	return r;
}

/**
 * Mark the given hardware register as free.
 */
static void free_hw_temp(struct r300_fragment_program *fp, int idx)
{
	COMPILE_STATE;

	// Be very careful here. Consider sequences like
	//  MAD r0, r1,r2,r3
	//  TEX r4, ...
	// The TEX instruction may be moved in front of the MAD instruction
	// due to the way nodes work. We don't want to alias r1 and r4 in
	// this case.
	// I'm certain the register allocation could be further sanitized,
	// but it's tricky because of stuff that can happen inside emit_tex
	// and emit_arith.
	cs->hwtemps[idx].free = cs->nrslots + 1;
}

/**
 * Create a new Mesa temporary register.
 */
static GLuint get_temp_reg(struct r300_fragment_program *fp)
{
	COMPILE_STATE;
	GLuint r = undef;
	GLuint index;

	index = ffs(~cs->temp_in_use);
	if (!index) {
		ERROR("Out of program temps\n");
		return r;
	}

	cs->temp_in_use |= (1 << --index);
	cs->temps[index].refcount = 0xFFFFFFFF;
	cs->temps[index].reg = -1;

	REG_SET_TYPE(r, REG_TYPE_TEMP);
	REG_SET_INDEX(r, index);
	REG_SET_VALID(r, GL_TRUE);
	return r;
}

/**
 * Create a new Mesa temporary register that will act as the destination
 * register for a texture read.
 */
static GLuint get_temp_reg_tex(struct r300_fragment_program *fp)
{
	COMPILE_STATE;
	GLuint r = undef;
	GLuint index;

	index = ffs(~cs->temp_in_use);
	if (!index) {
		ERROR("Out of program temps\n");
		return r;
	}

	cs->temp_in_use |= (1 << --index);
	cs->temps[index].refcount = 0xFFFFFFFF;
	cs->temps[index].reg = get_hw_temp_tex(fp);

	REG_SET_TYPE(r, REG_TYPE_TEMP);
	REG_SET_INDEX(r, index);
	REG_SET_VALID(r, GL_TRUE);
	return r;
}

/**
 * Free a Mesa temporary and the associated R300 temporary.
 */
static void free_temp(struct r300_fragment_program *fp, GLuint r)
{
	COMPILE_STATE;
	GLuint index = REG_GET_INDEX(r);

	if (!(cs->temp_in_use & (1 << index)))
		return;

	if (REG_GET_TYPE(r) == REG_TYPE_TEMP) {
		free_hw_temp(fp, cs->temps[index].reg);
		cs->temps[index].reg = -1;
		cs->temp_in_use &= ~(1 << index);
	} else if (REG_GET_TYPE(r) == REG_TYPE_INPUT) {
		free_hw_temp(fp, cs->inputs[index].reg);
		cs->inputs[index].reg = -1;
	}
}

/**
 * Emit a hardware constant/parameter.
 *
 * \p cp Stable pointer to an array of 4 floats.
 *  The pointer must be stable in the sense that it remains to be valid
 *  and hold the contents of the constant/parameter throughout the lifetime
 *  of the fragment program (actually, up until the next time the fragment
 *  program is translated).
 */
static GLuint emit_const4fv(struct r300_fragment_program *fp,
			    const GLfloat * cp)
{
	GLuint reg = undef;
	int index;

	for (index = 0; index < fp->const_nr; ++index) {
		if (fp->constant[index] == cp)
			break;
	}

	if (index >= fp->const_nr) {
		if (index >= PFS_NUM_CONST_REGS) {
			ERROR("Out of hw constants!\n");
			return reg;
		}

		fp->const_nr++;
		fp->constant[index] = cp;
	}

	REG_SET_TYPE(reg, REG_TYPE_CONST);
	REG_SET_INDEX(reg, index);
	REG_SET_VALID(reg, GL_TRUE);
	return reg;
}

static inline GLuint negate(GLuint r)
{
	REG_NEGS(r);
	REG_NEGV(r);
	return r;
}

/* Hack, to prevent clobbering sources used multiple times when
 * emulating non-native instructions
 */
static inline GLuint keep(GLuint r)
{
	REG_SET_NO_USE(r, GL_TRUE);
	return r;
}

static inline GLuint absolute(GLuint r)
{
	REG_ABS(r);
	return r;
}

static int swz_native(struct r300_fragment_program *fp,
		      GLuint src, GLuint * r, GLuint arbneg)
{
	/* Native swizzle, handle negation */
	src = (src & ~REG_NEGS_MASK) | (((arbneg >> 3) & 1) << REG_NEGS_SHIFT);

	if ((arbneg & 0x7) == 0x0) {
		src = src & ~REG_NEGV_MASK;
		*r = src;
	} else if ((arbneg & 0x7) == 0x7) {
		src |= REG_NEGV_MASK;
		*r = src;
	} else {
		if (!REG_GET_VALID(*r))
			*r = get_temp_reg(fp);
		src |= REG_NEGV_MASK;
		emit_arith(fp,
			   PFS_OP_MAD,
			   *r, arbneg & 0x7, keep(src), pfs_one, pfs_zero, 0);
		src = src & ~REG_NEGV_MASK;
		emit_arith(fp,
			   PFS_OP_MAD,
			   *r,
			   (arbneg ^ 0x7) | WRITEMASK_W,
			   src, pfs_one, pfs_zero, 0);
	}

	return 3;
}

static int swz_emit_partial(struct r300_fragment_program *fp,
			    GLuint src,
			    GLuint * r, int mask, int mc, GLuint arbneg)
{
	GLuint tmp;
	GLuint wmask = 0;

	if (!REG_GET_VALID(*r))
		*r = get_temp_reg(fp);

	/* A partial match, VSWZ/mask define what parts of the
	 * desired swizzle we match
	 */
	if (mc + s_mask[mask].count == 3) {
		wmask = WRITEMASK_W;
		src |= ((arbneg >> 3) & 1) << REG_NEGS_SHIFT;
	}

	tmp = arbneg & s_mask[mask].mask;
	if (tmp) {
		tmp = tmp ^ s_mask[mask].mask;
		if (tmp) {
			emit_arith(fp,
				   PFS_OP_MAD,
				   *r,
				   arbneg & s_mask[mask].mask,
				   keep(src) | REG_NEGV_MASK,
				   pfs_one, pfs_zero, 0);
			if (!wmask) {
				REG_SET_NO_USE(src, GL_TRUE);
			} else {
				REG_SET_NO_USE(src, GL_FALSE);
			}
			emit_arith(fp,
				   PFS_OP_MAD,
				   *r, tmp | wmask, src, pfs_one, pfs_zero, 0);
		} else {
			if (!wmask) {
				REG_SET_NO_USE(src, GL_TRUE);
			} else {
				REG_SET_NO_USE(src, GL_FALSE);
			}
			emit_arith(fp,
				   PFS_OP_MAD,
				   *r,
				   (arbneg & s_mask[mask].mask) | wmask,
				   src | REG_NEGV_MASK, pfs_one, pfs_zero, 0);
		}
	} else {
		if (!wmask) {
			REG_SET_NO_USE(src, GL_TRUE);
		} else {
			REG_SET_NO_USE(src, GL_FALSE);
		}
		emit_arith(fp, PFS_OP_MAD,
			   *r,
			   s_mask[mask].mask | wmask,
			   src, pfs_one, pfs_zero, 0);
	}

	return s_mask[mask].count;
}

static GLuint do_swizzle(struct r300_fragment_program *fp,
			 GLuint src, GLuint arbswz, GLuint arbneg)
{
	GLuint r = undef;
	GLuint vswz;
	int c_mask = 0;
	int v_match = 0;

	/* If swizzling from something without an XYZW native swizzle,
	 * emit result to a temp, and do new swizzle from the temp.
	 */
#if 0
	if (REG_GET_VSWZ(src) != SWIZZLE_XYZ || REG_GET_SSWZ(src) != SWIZZLE_W) {
		GLuint temp = get_temp_reg(fp);
		emit_arith(fp,
			   PFS_OP_MAD,
			   temp, WRITEMASK_XYZW, src, pfs_one, pfs_zero, 0);
		src = temp;
	}
#endif

	if (REG_GET_VSWZ(src) != SWIZZLE_XYZ || REG_GET_SSWZ(src) != SWIZZLE_W) {
		GLuint vsrcswz =
		    (v_swiz[REG_GET_VSWZ(src)].
		     hash & (SWZ_X_MASK | SWZ_Y_MASK | SWZ_Z_MASK)) |
		    REG_GET_SSWZ(src) << 9;
		GLint i;

		GLuint newswz = 0;
		GLuint offset;
		for (i = 0; i < 4; ++i) {
			offset = GET_SWZ(arbswz, i);

			newswz |=
			    (offset <= 3) ? GET_SWZ(vsrcswz,
						    offset) << i *
			    3 : offset << i * 3;
		}

		arbswz = newswz & (SWZ_X_MASK | SWZ_Y_MASK | SWZ_Z_MASK);
		REG_SET_SSWZ(src, GET_SWZ(newswz, 3));
	} else {
		/* set scalar swizzling */
		REG_SET_SSWZ(src, GET_SWZ(arbswz, 3));

	}
	do {
		vswz = REG_GET_VSWZ(src);
		do {
			int chash;

			REG_SET_VSWZ(src, vswz);
			chash = v_swiz[REG_GET_VSWZ(src)].hash &
			    s_mask[c_mask].hash;

			if (chash == (arbswz & s_mask[c_mask].hash)) {
				if (s_mask[c_mask].count == 3) {
					v_match += swz_native(fp,
							      src, &r, arbneg);
				} else {
					v_match += swz_emit_partial(fp,
								    src,
								    &r,
								    c_mask,
								    v_match,
								    arbneg);
				}

				if (v_match == 3)
					return r;

				/* Fill with something invalid.. all 0's was
				 * wrong before, matched SWIZZLE_X.  So all
				 * 1's will be okay for now
				 */
				arbswz |= (PFS_INVAL & s_mask[c_mask].hash);
			}
		} while (v_swiz[++vswz].hash != PFS_INVAL);
		REG_SET_VSWZ(src, SWIZZLE_XYZ);
	} while (s_mask[++c_mask].hash != PFS_INVAL);

	ERROR("should NEVER get here\n");
	return r;
}

static GLuint t_src(struct r300_fragment_program *fp,
		    struct prog_src_register fpsrc)
{
	GLuint r = undef;

	switch (fpsrc.File) {
	case PROGRAM_TEMPORARY:
		REG_SET_INDEX(r, fpsrc.Index);
		REG_SET_VALID(r, GL_TRUE);
		REG_SET_TYPE(r, REG_TYPE_TEMP);
		break;
	case PROGRAM_INPUT:
		REG_SET_INDEX(r, fpsrc.Index);
		REG_SET_VALID(r, GL_TRUE);
		REG_SET_TYPE(r, REG_TYPE_INPUT);
		break;
	case PROGRAM_LOCAL_PARAM:
		r = emit_const4fv(fp,
				  fp->mesa_program.Base.LocalParams[fpsrc.
								    Index]);
		break;
	case PROGRAM_ENV_PARAM:
		r = emit_const4fv(fp,
				  fp->ctx->FragmentProgram.Parameters[fpsrc.
								      Index]);
		break;
	case PROGRAM_STATE_VAR:
	case PROGRAM_NAMED_PARAM:
		r = emit_const4fv(fp,
				  fp->mesa_program.Base.Parameters->
				  ParameterValues[fpsrc.Index]);
		break;
	default:
		ERROR("unknown SrcReg->File %x\n", fpsrc.File);
		return r;
	}

	/* no point swizzling ONE/ZERO/HALF constants... */
	if (REG_GET_VSWZ(r) < SWIZZLE_111 || REG_GET_SSWZ(r) < SWIZZLE_ZERO)
		r = do_swizzle(fp, r, fpsrc.Swizzle, fpsrc.NegateBase);
	return r;
}

static GLuint t_scalar_src(struct r300_fragment_program *fp,
			   struct prog_src_register fpsrc)
{
	struct prog_src_register src = fpsrc;
	int sc = GET_SWZ(fpsrc.Swizzle, 0);	/* X */

	src.Swizzle = ((sc << 0) | (sc << 3) | (sc << 6) | (sc << 9));

	return t_src(fp, src);
}

static GLuint t_dst(struct r300_fragment_program *fp,
		    struct prog_dst_register dest)
{
	GLuint r = undef;

	switch (dest.File) {
	case PROGRAM_TEMPORARY:
		REG_SET_INDEX(r, dest.Index);
		REG_SET_VALID(r, GL_TRUE);
		REG_SET_TYPE(r, REG_TYPE_TEMP);
		return r;
	case PROGRAM_OUTPUT:
		REG_SET_TYPE(r, REG_TYPE_OUTPUT);
		switch (dest.Index) {
		case FRAG_RESULT_COLR:
		case FRAG_RESULT_DEPR:
			REG_SET_INDEX(r, dest.Index);
			REG_SET_VALID(r, GL_TRUE);
			return r;
		default:
			ERROR("Bad DstReg->Index 0x%x\n", dest.Index);
			return r;
		}
	default:
		ERROR("Bad DstReg->File 0x%x\n", dest.File);
		return r;
	}
}

static int t_hw_src(struct r300_fragment_program *fp, GLuint src, GLboolean tex)
{
	COMPILE_STATE;
	int idx;
	int index = REG_GET_INDEX(src);

	switch (REG_GET_TYPE(src)) {
	case REG_TYPE_TEMP:
		/* NOTE: if reg==-1 here, a source is being read that
		 *       hasn't been written to. Undefined results.
		 */
		if (cs->temps[index].reg == -1)
			cs->temps[index].reg = get_hw_temp(fp, cs->nrslots);

		idx = cs->temps[index].reg;

		if (!REG_GET_NO_USE(src) && (--cs->temps[index].refcount == 0))
			free_temp(fp, src);
		break;
	case REG_TYPE_INPUT:
		idx = cs->inputs[index].reg;

		if (!REG_GET_NO_USE(src) && (--cs->inputs[index].refcount == 0))
			free_hw_temp(fp, cs->inputs[index].reg);
		break;
	case REG_TYPE_CONST:
		return (index | SRC_CONST);
	default:
		ERROR("Invalid type for source reg\n");
		return (0 | SRC_CONST);
	}

	if (!tex)
		cs->used_in_node |= (1 << idx);

	return idx;
}

static int t_hw_dst(struct r300_fragment_program *fp,
		    GLuint dest, GLboolean tex, int slot)
{
	COMPILE_STATE;
	int idx;
	GLuint index = REG_GET_INDEX(dest);
	assert(REG_GET_VALID(dest));

	switch (REG_GET_TYPE(dest)) {
	case REG_TYPE_TEMP:
		if (cs->temps[REG_GET_INDEX(dest)].reg == -1) {
			if (!tex) {
				cs->temps[index].reg = get_hw_temp(fp, slot);
			} else {
				cs->temps[index].reg = get_hw_temp_tex(fp);
			}
		}
		idx = cs->temps[index].reg;

		if (!REG_GET_NO_USE(dest) && (--cs->temps[index].refcount == 0))
			free_temp(fp, dest);

		cs->dest_in_node |= (1 << idx);
		cs->used_in_node |= (1 << idx);
		break;
	case REG_TYPE_OUTPUT:
		switch (index) {
		case FRAG_RESULT_COLR:
			fp->node[fp->cur_node].flags |=
			    R300_PFS_NODE_OUTPUT_COLOR;
			break;
		case FRAG_RESULT_DEPR:
			fp->node[fp->cur_node].flags |=
			    R300_PFS_NODE_OUTPUT_DEPTH;
			break;
		}
		return index;
		break;
	default:
		ERROR("invalid dest reg type %d\n", REG_GET_TYPE(dest));
		return 0;
	}

	return idx;
}

static void emit_nop(struct r300_fragment_program *fp)
{
	COMPILE_STATE;

	if (cs->nrslots >= PFS_MAX_ALU_INST) {
		ERROR("Out of ALU instruction slots\n");
		return;
	}

	fp->alu.inst[cs->nrslots].inst0 = NOP_INST0;
	fp->alu.inst[cs->nrslots].inst1 = NOP_INST1;
	fp->alu.inst[cs->nrslots].inst2 = NOP_INST2;
	fp->alu.inst[cs->nrslots].inst3 = NOP_INST3;
	cs->nrslots++;
}

static void emit_tex(struct r300_fragment_program *fp,
		     struct prog_instruction *fpi, int opcode)
{
	COMPILE_STATE;
	GLuint coord = t_src(fp, fpi->SrcReg[0]);
	GLuint dest = undef, rdest = undef;
	GLuint din, uin;
	int unit = fpi->TexSrcUnit;
	int hwsrc, hwdest;
	GLuint tempreg = 0;

	uin = cs->used_in_node;
	din = cs->dest_in_node;

	/* Resolve source/dest to hardware registers */
	if (opcode != R300_FPITX_OP_KIL) {
		if (fpi->TexSrcTarget == TEXTURE_RECT_INDEX) {
			/**
			 * Hardware uses [0..1]x[0..1] range for rectangle textures
			 * instead of [0..Width]x[0..Height].
			 * Add a scaling instruction.
			 *
			 * \todo Refactor this once we have proper rewriting/optimization
			 * support for programs.
			 */
			gl_state_index tokens[STATE_LENGTH] = {
				STATE_INTERNAL, STATE_R300_TEXRECT_FACTOR, 0, 0,
				0
			};
			int factor_index;
			GLuint factorreg;

			tokens[2] = unit;
			factor_index =
			    _mesa_add_state_reference(fp->mesa_program.Base.
						      Parameters, tokens);
			factorreg =
			    emit_const4fv(fp,
					  fp->mesa_program.Base.Parameters->
					  ParameterValues[factor_index]);
			tempreg = keep(get_temp_reg(fp));

			emit_arith(fp, PFS_OP_MAD, tempreg, WRITEMASK_XYZW,
				   coord, factorreg, pfs_zero, 0);

			/* Ensure correct node indirection */
			uin = cs->used_in_node;
			din = cs->dest_in_node;

			hwsrc = t_hw_src(fp, tempreg, GL_TRUE);
		} else {
			hwsrc = t_hw_src(fp, coord, GL_TRUE);
		}

		dest = t_dst(fp, fpi->DstReg);

		/* r300 doesn't seem to be able to do TEX->output reg */
		if (REG_GET_TYPE(dest) == REG_TYPE_OUTPUT) {
			rdest = dest;
			dest = get_temp_reg_tex(fp);
		}
		hwdest =
		    t_hw_dst(fp, dest, GL_TRUE,
			     fp->node[fp->cur_node].alu_offset);

		/* Use a temp that hasn't been used in this node, rather
		 * than causing an indirection
		 */
		if (uin & (1 << hwdest)) {
			free_hw_temp(fp, hwdest);
			hwdest = get_hw_temp_tex(fp);
			cs->temps[REG_GET_INDEX(dest)].reg = hwdest;
		}
	} else {
		hwdest = 0;
		unit = 0;
		hwsrc = t_hw_src(fp, coord, GL_TRUE);
	}

	/* Indirection if source has been written in this node, or if the
	 * dest has been read/written in this node
	 */
	if ((REG_GET_TYPE(coord) != REG_TYPE_CONST &&
	     (din & (1 << hwsrc))) || (uin & (1 << hwdest))) {

		/* Finish off current node */
		if (fp->node[fp->cur_node].alu_offset == cs->nrslots)
			emit_nop(fp);

		fp->node[fp->cur_node].alu_end =
		    cs->nrslots - fp->node[fp->cur_node].alu_offset - 1;
		assert(fp->node[fp->cur_node].alu_end >= 0);

		if (++fp->cur_node >= PFS_MAX_TEX_INDIRECT) {
			ERROR("too many levels of texture indirection\n");
			return;
		}

		/* Start new node */
		fp->node[fp->cur_node].tex_offset = fp->tex.length;
		fp->node[fp->cur_node].alu_offset = cs->nrslots;
		fp->node[fp->cur_node].tex_end = -1;
		fp->node[fp->cur_node].alu_end = -1;
		fp->node[fp->cur_node].flags = 0;
		cs->used_in_node = 0;
		cs->dest_in_node = 0;
	}

	if (fp->cur_node == 0)
		fp->first_node_has_tex = 1;

	fp->tex.inst[fp->tex.length++] = 0 | (hwsrc << R300_FPITX_SRC_SHIFT)
	    | (hwdest << R300_FPITX_DST_SHIFT)
	    | (unit << R300_FPITX_IMAGE_SHIFT)
	    /* not entirely sure about this */
	    | (opcode << R300_FPITX_OPCODE_SHIFT);

	cs->dest_in_node |= (1 << hwdest);
	if (REG_GET_TYPE(coord) != REG_TYPE_CONST)
		cs->used_in_node |= (1 << hwsrc);

	fp->node[fp->cur_node].tex_end++;

	/* Copy from temp to output if needed */
	if (REG_GET_VALID(rdest)) {
		emit_arith(fp, PFS_OP_MAD, rdest, WRITEMASK_XYZW, dest,
			   pfs_one, pfs_zero, 0);
		free_temp(fp, dest);
	}

	/* Free temp register */
	if (tempreg != 0)
		free_temp(fp, tempreg);
}

/**
 * Returns the first slot where we could possibly allow writing to dest,
 * according to register allocation.
 */
static int get_earliest_allowed_write(struct r300_fragment_program *fp,
				      GLuint dest, int mask)
{
	COMPILE_STATE;<commit_msg>r300: fragprog tex instruction now take writemask into acount.<commit_after>/*
 * Copyright (C) 2005 <NAME>.
 *
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */

/**
 * \file
 *
 * \author <NAME> <<EMAIL>>
 *
 * \author <NAME> <<EMAIL>>
 *
 * \todo Depth write, WPOS/FOGC inputs
 *
 * \todo FogOption
 *
 * \todo Verify results of opcodes for accuracy, I've only checked them in
 * specific cases.
 */

#include "glheader.h"
#include "macros.h"
#include "enums.h"
#include "shader/prog_instruction.h"
#include "shader/prog_parameter.h"
#include "shader/prog_print.h"

#include "r300_context.h"
#include "r300_fragprog.h"
#include "r300_reg.h"
#include "r300_state.h"

/*
 * Usefull macros and values
 */
#define ERROR(fmt, args...) do {			\
		fprintf(stderr, "%s::%s(): " fmt "\n",	\
			__FILE__, __FUNCTION__, ##args);	\
		fp->error = GL_TRUE;			\
	} while(0)

#define PFS_INVAL 0xFFFFFFFF
#define COMPILE_STATE struct r300_pfs_compile_state *cs = fp->cs

#define SWIZZLE_XYZ		0
#define SWIZZLE_XXX		1
#define SWIZZLE_YYY		2
#define SWIZZLE_ZZZ		3
#define SWIZZLE_WWW		4
#define SWIZZLE_YZX		5
#define SWIZZLE_ZXY		6
#define SWIZZLE_WZY		7
#define SWIZZLE_111		8
#define SWIZZLE_000		9
#define SWIZZLE_HHH		10

#define swizzle(r, x, y, z, w) do_swizzle(fp, r,		\
					  ((SWIZZLE_##x<<0)|	\
					   (SWIZZLE_##y<<3)|	\
					   (SWIZZLE_##z<<6)|	\
					   (SWIZZLE_##w<<9)),	\
					  0)

#define REG_TYPE_INPUT		0
#define REG_TYPE_OUTPUT		1
#define REG_TYPE_TEMP		2
#define REG_TYPE_CONST		3

#define REG_TYPE_SHIFT		0
#define REG_INDEX_SHIFT		2
#define REG_VSWZ_SHIFT		8
#define REG_SSWZ_SHIFT		13
#define REG_NEGV_SHIFT		18
#define REG_NEGS_SHIFT		19
#define REG_ABS_SHIFT		20
#define REG_NO_USE_SHIFT	21	// Hack for refcounting
#define REG_VALID_SHIFT		22	// Does the register contain a defined value?
#define REG_BUILTIN_SHIFT   23	// Is it a builtin (like all zero/all one)?

#define REG_TYPE_MASK		(0x03 << REG_TYPE_SHIFT)
#define REG_INDEX_MASK		(0x3F << REG_INDEX_SHIFT)
#define REG_VSWZ_MASK		(0x1F << REG_VSWZ_SHIFT)
#define REG_SSWZ_MASK		(0x1F << REG_SSWZ_SHIFT)
#define REG_NEGV_MASK		(0x01 << REG_NEGV_SHIFT)
#define REG_NEGS_MASK		(0x01 << REG_NEGS_SHIFT)
#define REG_ABS_MASK		(0x01 << REG_ABS_SHIFT)
#define REG_NO_USE_MASK		(0x01 << REG_NO_USE_SHIFT)
#define REG_VALID_MASK		(0x01 << REG_VALID_SHIFT)
#define REG_BUILTIN_MASK	(0x01 << REG_BUILTIN_SHIFT)

#define REG(type, index, vswz, sswz, nouse, valid, builtin)	\
	(((type << REG_TYPE_SHIFT) & REG_TYPE_MASK) |			\
	 ((index << REG_INDEX_SHIFT) & REG_INDEX_MASK) |		\
	 ((nouse << REG_NO_USE_SHIFT) & REG_NO_USE_MASK) |		\
	 ((valid << REG_VALID_SHIFT) & REG_VALID_MASK) |		\
	 ((builtin << REG_BUILTIN_SHIFT) & REG_BUILTIN_MASK) |	\
	 ((vswz << REG_VSWZ_SHIFT) & REG_VSWZ_MASK) |			\
	 ((sswz << REG_SSWZ_SHIFT) & REG_SSWZ_MASK))
#define REG_GET_TYPE(reg)						\
	((reg & REG_TYPE_MASK) >> REG_TYPE_SHIFT)
#define REG_GET_INDEX(reg)						\
	((reg & REG_INDEX_MASK) >> REG_INDEX_SHIFT)
#define REG_GET_VSWZ(reg)						\
	((reg & REG_VSWZ_MASK) >> REG_VSWZ_SHIFT)
#define REG_GET_SSWZ(reg)						\
	((reg & REG_SSWZ_MASK) >> REG_SSWZ_SHIFT)
#define REG_GET_NO_USE(reg)						\
	((reg & REG_NO_USE_MASK) >> REG_NO_USE_SHIFT)
#define REG_GET_VALID(reg)						\
	((reg & REG_VALID_MASK) >> REG_VALID_SHIFT)
#define REG_GET_BUILTIN(reg)						\
	((reg & REG_BUILTIN_MASK) >> REG_BUILTIN_SHIFT)
#define REG_SET_TYPE(reg, type)						\
	reg = ((reg & ~REG_TYPE_MASK) |					\
	       ((type << REG_TYPE_SHIFT) & REG_TYPE_MASK))
#define REG_SET_INDEX(reg, index)					\
	reg = ((reg & ~REG_INDEX_MASK) |				\
	       ((index << REG_INDEX_SHIFT) & REG_INDEX_MASK))
#define REG_SET_VSWZ(reg, vswz)						\
	reg = ((reg & ~REG_VSWZ_MASK) |					\
	       ((vswz << REG_VSWZ_SHIFT) & REG_VSWZ_MASK))
#define REG_SET_SSWZ(reg, sswz)						\
	reg = ((reg & ~REG_SSWZ_MASK) |					\
	       ((sswz << REG_SSWZ_SHIFT) & REG_SSWZ_MASK))
#define REG_SET_NO_USE(reg, nouse)					\
	reg = ((reg & ~REG_NO_USE_MASK) |				\
	       ((nouse << REG_NO_USE_SHIFT) & REG_NO_USE_MASK))
#define REG_SET_VALID(reg, valid)					\
	reg = ((reg & ~REG_VALID_MASK) |				\
	       ((valid << REG_VALID_SHIFT) & REG_VALID_MASK))
#define REG_SET_BUILTIN(reg, builtin)					\
	reg = ((reg & ~REG_BUILTIN_MASK) |				\
	       ((builtin << REG_BUILTIN_SHIFT) & REG_BUILTIN_MASK))
#define REG_ABS(reg)							\
	reg = (reg | REG_ABS_MASK)
#define REG_NEGV(reg)							\
	reg = (reg | REG_NEGV_MASK)
#define REG_NEGS(reg)							\
	reg = (reg | REG_NEGS_MASK)

/*
 * Datas structures for fragment program generation
 */

/* description of r300 native hw instructions */
static const struct {
	const char *name;
	int argc;
	int v_op;
	int s_op;
} r300_fpop[] = {
	/* *INDENT-OFF* */
	{"MAD", 3, R300_FPI0_OUTC_MAD, R300_FPI2_OUTA_MAD},
	{"DP3", 2, R300_FPI0_OUTC_DP3, R300_FPI2_OUTA_DP4},
	{"DP4", 2, R300_FPI0_OUTC_DP4, R300_FPI2_OUTA_DP4},
	{"MIN", 2, R300_FPI0_OUTC_MIN, R300_FPI2_OUTA_MIN},
	{"MAX", 2, R300_FPI0_OUTC_MAX, R300_FPI2_OUTA_MAX},
	{"CMP", 3, R300_FPI0_OUTC_CMP, R300_FPI2_OUTA_CMP},
	{"FRC", 1, R300_FPI0_OUTC_FRC, R300_FPI2_OUTA_FRC},
	{"EX2", 1, R300_FPI0_OUTC_REPL_ALPHA, R300_FPI2_OUTA_EX2},
	{"LG2", 1, R300_FPI0_OUTC_REPL_ALPHA, R300_FPI2_OUTA_LG2},
	{"RCP", 1, R300_FPI0_OUTC_REPL_ALPHA, R300_FPI2_OUTA_RCP},
	{"RSQ", 1, R300_FPI0_OUTC_REPL_ALPHA, R300_FPI2_OUTA_RSQ},
	{"REPL_ALPHA", 1, R300_FPI0_OUTC_REPL_ALPHA, PFS_INVAL},
	{"CMPH", 3, R300_FPI0_OUTC_CMPH, PFS_INVAL},
	/* *INDENT-ON* */
};

/* vector swizzles r300 can support natively, with a couple of
 * cases we handle specially
 *
 * REG_VSWZ/REG_SSWZ is an index into this table
 */

/* mapping from SWIZZLE_* to r300 native values for scalar insns */
#define SWIZZLE_HALF 6

#define MAKE_SWZ3(x, y, z) (MAKE_SWIZZLE4(SWIZZLE_##x, \
					  SWIZZLE_##y, \
					  SWIZZLE_##z, \
					  SWIZZLE_ZERO))
/* native swizzles */
static const struct r300_pfs_swizzle {
	GLuint hash;		/* swizzle value this matches */
	GLuint base;		/* base value for hw swizzle */
	GLuint stride;		/* difference in base between arg0/1/2 */
	GLuint flags;
} v_swiz[] = {
	/* *INDENT-OFF* */
	{MAKE_SWZ3(X, Y, Z), R300_FPI0_ARGC_SRC0C_XYZ, 4, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(X, X, X), R300_FPI0_ARGC_SRC0C_XXX, 4, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(Y, Y, Y), R300_FPI0_ARGC_SRC0C_YYY, 4, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(Z, Z, Z), R300_FPI0_ARGC_SRC0C_ZZZ, 4, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(W, W, W), R300_FPI0_ARGC_SRC0A, 1, SLOT_SRC_SCALAR},
	{MAKE_SWZ3(Y, Z, X), R300_FPI0_ARGC_SRC0C_YZX, 1, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(Z, X, Y), R300_FPI0_ARGC_SRC0C_ZXY, 1, SLOT_SRC_VECTOR},
	{MAKE_SWZ3(W, Z, Y), R300_FPI0_ARGC_SRC0CA_WZY, 1, SLOT_SRC_BOTH},
	{MAKE_SWZ3(ONE, ONE, ONE), R300_FPI0_ARGC_ONE, 0, 0},
	{MAKE_SWZ3(ZERO, ZERO, ZERO), R300_FPI0_ARGC_ZERO, 0, 0},
	{MAKE_SWZ3(HALF, HALF, HALF), R300_FPI0_ARGC_HALF, 0, 0},
	{PFS_INVAL, 0, 0, 0},
	/* *INDENT-ON* */
};

/* used during matching of non-native swizzles */
#define SWZ_X_MASK (7 << 0)
#define SWZ_Y_MASK (7 << 3)
#define SWZ_Z_MASK (7 << 6)
#define SWZ_W_MASK (7 << 9)
static const struct {
	GLuint hash;		/* used to mask matching swizzle components */
	int mask;		/* actual outmask */
	int count;		/* count of components matched */
} s_mask[] = {
	/* *INDENT-OFF* */
	{SWZ_X_MASK | SWZ_Y_MASK | SWZ_Z_MASK, 1 | 2 | 4, 3},
	{SWZ_X_MASK | SWZ_Y_MASK, 1 | 2, 2},
	{SWZ_X_MASK | SWZ_Z_MASK, 1 | 4, 2},
	{SWZ_Y_MASK | SWZ_Z_MASK, 2 | 4, 2},
	{SWZ_X_MASK, 1, 1},
	{SWZ_Y_MASK, 2, 1},
	{SWZ_Z_MASK, 4, 1},
	{PFS_INVAL, PFS_INVAL, PFS_INVAL}
	/* *INDENT-ON* */
};

static const struct {
	int base;		/* hw value of swizzle */
	int stride;		/* difference between SRC0/1/2 */
	GLuint flags;
} s_swiz[] = {
	/* *INDENT-OFF* */
	{R300_FPI2_ARGA_SRC0C_X, 3, SLOT_SRC_VECTOR},
	{R300_FPI2_ARGA_SRC0C_Y, 3, SLOT_SRC_VECTOR},
	{R300_FPI2_ARGA_SRC0C_Z, 3, SLOT_SRC_VECTOR},
	{R300_FPI2_ARGA_SRC0A, 1, SLOT_SRC_SCALAR},
	{R300_FPI2_ARGA_ZERO, 0, 0},
	{R300_FPI2_ARGA_ONE, 0, 0},
	{R300_FPI2_ARGA_HALF, 0, 0}
	/* *INDENT-ON* */
};

/* boiler-plate reg, for convenience */
static const GLuint undef = REG(REG_TYPE_TEMP,
				0,
				SWIZZLE_XYZ,
				SWIZZLE_W,
				GL_FALSE,
				GL_FALSE,
				GL_FALSE);

/* constant one source */
static const GLuint pfs_one = REG(REG_TYPE_CONST,
				  0,
				  SWIZZLE_111,
				  SWIZZLE_ONE,
				  GL_FALSE,
				  GL_TRUE,
				  GL_TRUE);

/* constant half source */
static const GLuint pfs_half = REG(REG_TYPE_CONST,
				   0,
				   SWIZZLE_HHH,
				   SWIZZLE_HALF,
				   GL_FALSE,
				   GL_TRUE,
				   GL_TRUE);

/* constant zero source */
static const GLuint pfs_zero = REG(REG_TYPE_CONST,
				   0,
				   SWIZZLE_000,
				   SWIZZLE_ZERO,
				   GL_FALSE,
				   GL_TRUE,
				   GL_TRUE);

/*
 * Common functions prototypes
 */
static void dump_program(struct r300_fragment_program *fp);
static void emit_arith(struct r300_fragment_program *fp, int op,
		       GLuint dest, int mask,
		       GLuint src0, GLuint src1, GLuint src2, int flags);

/**
 * Get an R300 temporary that can be written to in the given slot.
 */
static int get_hw_temp(struct r300_fragment_program *fp, int slot)
{
	COMPILE_STATE;
	int r;

	for (r = 0; r < PFS_NUM_TEMP_REGS; ++r) {
		if (cs->hwtemps[r].free >= 0 && cs->hwtemps[r].free <= slot)
			break;
	}

	if (r >= PFS_NUM_TEMP_REGS) {
		ERROR("Out of hardware temps\n");
		return 0;
	}
	// Reserved is used to avoid the following scenario:
	//  R300 temporary X is first assigned to Mesa temporary Y during vector ops
	//  R300 temporary X is then assigned to Mesa temporary Z for further vector ops
	//  Then scalar ops on Mesa temporary Z are emitted and move back in time
	//  to overwrite the value of temporary Y.
	// End scenario.
	cs->hwtemps[r].reserved = cs->hwtemps[r].free;
	cs->hwtemps[r].free = -1;

	// Reset to some value that won't mess things up when the user
	// tries to read from a temporary that hasn't been assigned a value yet.
	// In the normal case, vector_valid and scalar_valid should be set to
	// a sane value by the first emit that writes to this temporary.
	cs->hwtemps[r].vector_valid = 0;
	cs->hwtemps[r].scalar_valid = 0;

	if (r > fp->max_temp_idx)
		fp->max_temp_idx = r;

	return r;
}

/**
 * Get an R300 temporary that will act as a TEX destination register.
 */
static int get_hw_temp_tex(struct r300_fragment_program *fp)
{
	COMPILE_STATE;
	int r;

	for (r = 0; r < PFS_NUM_TEMP_REGS; ++r) {
		if (cs->used_in_node & (1 << r))
			continue;

		// Note: Be very careful here
		if (cs->hwtemps[r].free >= 0 && cs->hwtemps[r].free <= 0)
			break;
	}

	if (r >= PFS_NUM_TEMP_REGS)
		return get_hw_temp(fp, 0);	/* Will cause an indirection */

	cs->hwtemps[r].reserved = cs->hwtemps[r].free;
	cs->hwtemps[r].free = -1;

	// Reset to some value that won't mess things up when the user
	// tries to read from a temporary that hasn't been assigned a value yet.
	// In the normal case, vector_valid and scalar_valid should be set to
	// a sane value by the first emit that writes to this temporary.
	cs->hwtemps[r].vector_valid = cs->nrslots;
	cs->hwtemps[r].scalar_valid = cs->nrslots;

	if (r > fp->max_temp_idx)
		fp->max_temp_idx = r;

	return r;
}

/**
 * Mark the given hardware register as free.
 */
static void free_hw_temp(struct r300_fragment_program *fp, int idx)
{
	COMPILE_STATE;

	// Be very careful here. Consider sequences like
	//  MAD r0, r1,r2,r3
	//  TEX r4, ...
	// The TEX instruction may be moved in front of the MAD instruction
	// due to the way nodes work. We don't want to alias r1 and r4 in
	// this case.
	// I'm certain the register allocation could be further sanitized,
	// but it's tricky because of stuff that can happen inside emit_tex
	// and emit_arith.
	cs->hwtemps[idx].free = cs->nrslots + 1;
}

/**
 * Create a new Mesa temporary register.
 */
static GLuint get_temp_reg(struct r300_fragment_program *fp)
{
	COMPILE_STATE;
	GLuint r = undef;
	GLuint index;

	index = ffs(~cs->temp_in_use);
	if (!index) {
		ERROR("Out of program temps\n");
		return r;
	}

	cs->temp_in_use |= (1 << --index);
	cs->temps[index].refcount = 0xFFFFFFFF;
	cs->temps[index].reg = -1;

	REG_SET_TYPE(r, REG_TYPE_TEMP);
	REG_SET_INDEX(r, index);
	REG_SET_VALID(r, GL_TRUE);
	return r;
}

/**
 * Create a new Mesa temporary register that will act as the destination
 * register for a texture read.
 */
static GLuint get_temp_reg_tex(struct r300_fragment_program *fp)
{
	COMPILE_STATE;
	GLuint r = undef;
	GLuint index;

	index = ffs(~cs->temp_in_use);
	if (!index) {
		ERROR("Out of program temps\n");
		return r;
	}

	cs->temp_in_use |= (1 << --index);
	cs->temps[index].refcount = 0xFFFFFFFF;
	cs->temps[index].reg = get_hw_temp_tex(fp);

	REG_SET_TYPE(r, REG_TYPE_TEMP);
	REG_SET_INDEX(r, index);
	REG_SET_VALID(r, GL_TRUE);
	return r;
}

/**
 * Free a Mesa temporary and the associated R300 temporary.
 */
static void free_temp(struct r300_fragment_program *fp, GLuint r)
{
	COMPILE_STATE;
	GLuint index = REG_GET_INDEX(r);

	if (!(cs->temp_in_use & (1 << index)))
		return;

	if (REG_GET_TYPE(r) == REG_TYPE_TEMP) {
		free_hw_temp(fp, cs->temps[index].reg);
		cs->temps[index].reg = -1;
		cs->temp_in_use &= ~(1 << index);
	} else if (REG_GET_TYPE(r) == REG_TYPE_INPUT) {
		free_hw_temp(fp, cs->inputs[index].reg);
		cs->inputs[index].reg = -1;
	}
}

/**
 * Emit a hardware constant/parameter.
 *
 * \p cp Stable pointer to an array of 4 floats.
 *  The pointer must be stable in the sense that it remains to be valid
 *  and hold the contents of the constant/parameter throughout the lifetime
 *  of the fragment program (actually, up until the next time the fragment
 *  program is translated).
 */
static GLuint emit_const4fv(struct r300_fragment_program *fp,
			    const GLfloat * cp)
{
	GLuint reg = undef;
	int index;

	for (index = 0; index < fp->const_nr; ++index) {
		if (fp->constant[index] == cp)
			break;
	}

	if (index >= fp->const_nr) {
		if (index >= PFS_NUM_CONST_REGS) {
			ERROR("Out of hw constants!\n");
			return reg;
		}

		fp->const_nr++;
		fp->constant[index] = cp;
	}

	REG_SET_TYPE(reg, REG_TYPE_CONST);
	REG_SET_INDEX(reg, index);
	REG_SET_VALID(reg, GL_TRUE);
	return reg;
}

static inline GLuint negate(GLuint r)
{
	REG_NEGS(r);
	REG_NEGV(r);
	return r;
}

/* Hack, to prevent clobbering sources used multiple times when
 * emulating non-native instructions
 */
static inline GLuint keep(GLuint r)
{
	REG_SET_NO_USE(r, GL_TRUE);
	return r;
}

static inline GLuint absolute(GLuint r)
{
	REG_ABS(r);
	return r;
}

static int swz_native(struct r300_fragment_program *fp,
		      GLuint src, GLuint * r, GLuint arbneg)
{
	/* Native swizzle, handle negation */
	src = (src & ~REG_NEGS_MASK) | (((arbneg >> 3) & 1) << REG_NEGS_SHIFT);

	if ((arbneg & 0x7) == 0x0) {
		src = src & ~REG_NEGV_MASK;
		*r = src;
	} else if ((arbneg & 0x7) == 0x7) {
		src |= REG_NEGV_MASK;
		*r = src;
	} else {
		if (!REG_GET_VALID(*r))
			*r = get_temp_reg(fp);
		src |= REG_NEGV_MASK;
		emit_arith(fp,
			   PFS_OP_MAD,
			   *r, arbneg & 0x7, keep(src), pfs_one, pfs_zero, 0);
		src = src & ~REG_NEGV_MASK;
		emit_arith(fp,
			   PFS_OP_MAD,
			   *r,
			   (arbneg ^ 0x7) | WRITEMASK_W,
			   src, pfs_one, pfs_zero, 0);
	}

	return 3;
}

static int swz_emit_partial(struct r300_fragment_program *fp,
			    GLuint src,
			    GLuint * r, int mask, int mc, GLuint arbneg)
{
	GLuint tmp;
	GLuint wmask = 0;

	if (!REG_GET_VALID(*r))
		*r = get_temp_reg(fp);

	/* A partial match, VSWZ/mask define what parts of the
	 * desired swizzle we match
	 */
	if (mc + s_mask[mask].count == 3) {
		wmask = WRITEMASK_W;
		src |= ((arbneg >> 3) & 1) << REG_NEGS_SHIFT;
	}

	tmp = arbneg & s_mask[mask].mask;
	if (tmp) {
		tmp = tmp ^ s_mask[mask].mask;
		if (tmp) {
			emit_arith(fp,
				   PFS_OP_MAD,
				   *r,
				   arbneg & s_mask[mask].mask,
				   keep(src) | REG_NEGV_MASK,
				   pfs_one, pfs_zero, 0);
			if (!wmask) {
				REG_SET_NO_USE(src, GL_TRUE);
			} else {
				REG_SET_NO_USE(src, GL_FALSE);
			}
			emit_arith(fp,
				   PFS_OP_MAD,
				   *r, tmp | wmask, src, pfs_one, pfs_zero, 0);
		} else {
			if (!wmask) {
				REG_SET_NO_USE(src, GL_TRUE);
			} else {
				REG_SET_NO_USE(src, GL_FALSE);
			}
			emit_arith(fp,
				   PFS_OP_MAD,
				   *r,
				   (arbneg & s_mask[mask].mask) | wmask,
				   src | REG_NEGV_MASK, pfs_one, pfs_zero, 0);
		}
	} else {
		if (!wmask) {
			REG_SET_NO_USE(src, GL_TRUE);
		} else {
			REG_SET_NO_USE(src, GL_FALSE);
		}
		emit_arith(fp, PFS_OP_MAD,
			   *r,
			   s_mask[mask].mask | wmask,
			   src, pfs_one, pfs_zero, 0);
	}

	return s_mask[mask].count;
}

static GLuint do_swizzle(struct r300_fragment_program *fp,
			 GLuint src, GLuint arbswz, GLuint arbneg)
{
	GLuint r = undef;
	GLuint vswz;
	int c_mask = 0;
	int v_match = 0;

	/* If swizzling from something without an XYZW native swizzle,
	 * emit result to a temp, and do new swizzle from the temp.
	 */
#if 0
	if (REG_GET_VSWZ(src) != SWIZZLE_XYZ || REG_GET_SSWZ(src) != SWIZZLE_W) {
		GLuint temp = get_temp_reg(fp);
		emit_arith(fp,
			   PFS_OP_MAD,
			   temp, WRITEMASK_XYZW, src, pfs_one, pfs_zero, 0);
		src = temp;
	}
#endif

	if (REG_GET_VSWZ(src) != SWIZZLE_XYZ || REG_GET_SSWZ(src) != SWIZZLE_W) {
		GLuint vsrcswz =
		    (v_swiz[REG_GET_VSWZ(src)].
		     hash & (SWZ_X_MASK | SWZ_Y_MASK | SWZ_Z_MASK)) |
		    REG_GET_SSWZ(src) << 9;
		GLint i;

		GLuint newswz = 0;
		GLuint offset;
		for (i = 0; i < 4; ++i) {
			offset = GET_SWZ(arbswz, i);

			newswz |=
			    (offset <= 3) ? GET_SWZ(vsrcswz,
						    offset) << i *
			    3 : offset << i * 3;
		}

		arbswz = newswz & (SWZ_X_MASK | SWZ_Y_MASK | SWZ_Z_MASK);
		REG_SET_SSWZ(src, GET_SWZ(newswz, 3));
	} else {
		/* set scalar swizzling */
		REG_SET_SSWZ(src, GET_SWZ(arbswz, 3));

	}
	do {
		vswz = REG_GET_VSWZ(src);
		do {
			int chash;

			REG_SET_VSWZ(src, vswz);
			chash = v_swiz[REG_GET_VSWZ(src)].hash &
			    s_mask[c_mask].hash;

			if (chash == (arbswz & s_mask[c_mask].hash)) {
				if (s_mask[c_mask].count == 3) {
					v_match += swz_native(fp,
							      src, &r, arbneg);
				} else {
					v_match += swz_emit_partial(fp,
								    src,
								    &r,
								    c_mask,
								    v_match,
								    arbneg);
				}

				if (v_match == 3)
					return r;

				/* Fill with something invalid.. all 0's was
				 * wrong before, matched SWIZZLE_X.  So all
				 * 1's will be okay for now
				 */
				arbswz |= (PFS_INVAL & s_mask[c_mask].hash);
			}
		} while (v_swiz[++vswz].hash != PFS_INVAL);
		REG_SET_VSWZ(src, SWIZZLE_XYZ);
	} while (s_mask[++c_mask].hash != PFS_INVAL);

	ERROR("should NEVER get here\n");
	return r;
}

static GLuint t_src(struct r300_fragment_program *fp,
		    struct prog_src_register fpsrc)
{
	GLuint r = undef;

	switch (fpsrc.File) {
	case PROGRAM_TEMPORARY:
		REG_SET_INDEX(r, fpsrc.Index);
		REG_SET_VALID(r, GL_TRUE);
		REG_SET_TYPE(r, REG_TYPE_TEMP);
		break;
	case PROGRAM_INPUT:
		REG_SET_INDEX(r, fpsrc.Index);
		REG_SET_VALID(r, GL_TRUE);
		REG_SET_TYPE(r, REG_TYPE_INPUT);
		break;
	case PROGRAM_LOCAL_PARAM:
		r = emit_const4fv(fp,
				  fp->mesa_program.Base.LocalParams[fpsrc.
								    Index]);
		break;
	case PROGRAM_ENV_PARAM:
		r = emit_const4fv(fp,
				  fp->ctx->FragmentProgram.Parameters[fpsrc.
								      Index]);
		break;
	case PROGRAM_STATE_VAR:
	case PROGRAM_NAMED_PARAM:
		r = emit_const4fv(fp,
				  fp->mesa_program.Base.Parameters->
				  ParameterValues[fpsrc.Index]);
		break;
	default:
		ERROR("unknown SrcReg->File %x\n", fpsrc.File);
		return r;
	}

	/* no point swizzling ONE/ZERO/HALF constants... */
	if (REG_GET_VSWZ(r) < SWIZZLE_111 || REG_GET_SSWZ(r) < SWIZZLE_ZERO)
		r = do_swizzle(fp, r, fpsrc.Swizzle, fpsrc.NegateBase);
	return r;
}

static GLuint t_scalar_src(struct r300_fragment_program *fp,
			   struct prog_src_register fpsrc)
{
	struct prog_src_register src = fpsrc;
	int sc = GET_SWZ(fpsrc.Swizzle, 0);	/* X */

	src.Swizzle = ((sc << 0) | (sc << 3) | (sc << 6) | (sc << 9));

	return t_src(fp, src);
}

static GLuint t_dst(struct r300_fragment_program *fp,
		    struct prog_dst_register dest)
{
	GLuint r = undef;

	switch (dest.File) {
	case PROGRAM_TEMPORARY:
		REG_SET_INDEX(r, dest.Index);
		REG_SET_VALID(r, GL_TRUE);
		REG_SET_TYPE(r, REG_TYPE_TEMP);
		return r;
	case PROGRAM_OUTPUT:
		REG_SET_TYPE(r, REG_TYPE_OUTPUT);
		switch (dest.Index) {
		case FRAG_RESULT_COLR:
		case FRAG_RESULT_DEPR:
			REG_SET_INDEX(r, dest.Index);
			REG_SET_VALID(r, GL_TRUE);
			return r;
		default:
			ERROR("Bad DstReg->Index 0x%x\n", dest.Index);
			return r;
		}
	default:
		ERROR("Bad DstReg->File 0x%x\n", dest.File);
		return r;
	}
}

static int t_hw_src(struct r300_fragment_program *fp, GLuint src, GLboolean tex)
{
	COMPILE_STATE;
	int idx;
	int index = REG_GET_INDEX(src);

	switch (REG_GET_TYPE(src)) {
	case REG_TYPE_TEMP:
		/* NOTE: if reg==-1 here, a source is being read that
		 *       hasn't been written to. Undefined results.
		 */
		if (cs->temps[index].reg == -1)
			cs->temps[index].reg = get_hw_temp(fp, cs->nrslots);

		idx = cs->temps[index].reg;

		if (!REG_GET_NO_USE(src) && (--cs->temps[index].refcount == 0))
			free_temp(fp, src);
		break;
	case REG_TYPE_INPUT:
		idx = cs->inputs[index].reg;

		if (!REG_GET_NO_USE(src) && (--cs->inputs[index].refcount == 0))
			free_hw_temp(fp, cs->inputs[index].reg);
		break;
	case REG_TYPE_CONST:
		return (index | SRC_CONST);
	default:
		ERROR("Invalid type for source reg\n");
		return (0 | SRC_CONST);
	}

	if (!tex)
		cs->used_in_node |= (1 << idx);

	return idx;
}

static int t_hw_dst(struct r300_fragment_program *fp,
		    GLuint dest, GLboolean tex, int slot)
{
	COMPILE_STATE;
	int idx;
	GLuint index = REG_GET_INDEX(dest);
	assert(REG_GET_VALID(dest));

	switch (REG_GET_TYPE(dest)) {
	case REG_TYPE_TEMP:
		if (cs->temps[REG_GET_INDEX(dest)].reg == -1) {
			if (!tex) {
				cs->temps[index].reg = get_hw_temp(fp, slot);
			} else {
				cs->temps[index].reg = get_hw_temp_tex(fp);
			}
		}
		idx = cs->temps[index].reg;

		if (!REG_GET_NO_USE(dest) && (--cs->temps[index].refcount == 0))
			free_temp(fp, dest);

		cs->dest_in_node |= (1 << idx);
		cs->used_in_node |= (1 << idx);
		break;
	case REG_TYPE_OUTPUT:
		switch (index) {
		case FRAG_RESULT_COLR:
			fp->node[fp->cur_node].flags |=
			    R300_PFS_NODE_OUTPUT_COLOR;
			break;
		case FRAG_RESULT_DEPR:
			fp->node[fp->cur_node].flags |=
			    R300_PFS_NODE_OUTPUT_DEPTH;
			break;
		}
		return index;
		break;
	default:
		ERROR("invalid dest reg type %d\n", REG_GET_TYPE(dest));
		return 0;
	}

	return idx;
}

static void emit_nop(struct r300_fragment_program *fp)
{
	COMPILE_STATE;

	if (cs->nrslots >= PFS_MAX_ALU_INST) {
		ERROR("Out of ALU instruction slots\n");
		return;
	}

	fp->alu.inst[cs->nrslots].inst0 = NOP_INST0;
	fp->alu.inst[cs->nrslots].inst1 = NOP_INST1;
	fp->alu.inst[cs->nrslots].inst2 = NOP_INST2;
	fp->alu.inst[cs->nrslots].inst3 = NOP_INST3;
	cs->nrslots++;
}

static void emit_tex(struct r300_fragment_program *fp,
		     struct prog_instruction *fpi, int opcode)
{
	COMPILE_STATE;
	GLuint coord = t_src(fp, fpi->SrcReg[0]);
	GLuint dest = undef, rdest = undef;
	GLuint din, uin;
	int unit = fpi->TexSrcUnit;
	int hwsrc, hwdest;
	GLuint tempreg = 0;

	uin = cs->used_in_node;
	din = cs->dest_in_node;

	/* Resolve source/dest to hardware registers */
	if (opcode != R300_FPITX_OP_KIL) {
		if (fpi->TexSrcTarget == TEXTURE_RECT_INDEX) {
			/**
			 * Hardware uses [0..1]x[0..1] range for rectangle textures
			 * instead of [0..Width]x[0..Height].
			 * Add a scaling instruction.
			 *
			 * \todo Refactor this once we have proper rewriting/optimization
			 * support for programs.
			 */
			gl_state_index tokens[STATE_LENGTH] = {
				STATE_INTERNAL, STATE_R300_TEXRECT_FACTOR, 0, 0,
				0
			};
			int factor_index;
			GLuint factorreg;

			tokens[2] = unit;
			factor_index =
			    _mesa_add_state_reference(fp->mesa_program.Base.
						      Parameters, tokens);
			factorreg =
			    emit_const4fv(fp,
					  fp->mesa_program.Base.Parameters->
					  ParameterValues[factor_index]);
			tempreg = keep(get_temp_reg(fp));

			emit_arith(fp, PFS_OP_MAD, tempreg, WRITEMASK_XYZW,
				   coord, factorreg, pfs_zero, 0);

			/* Ensure correct node indirection */
			uin = cs->used_in_node;
			din = cs->dest_in_node;

			hwsrc = t_hw_src(fp, tempreg, GL_TRUE);
		} else {
			hwsrc = t_hw_src(fp, coord, GL_TRUE);
		}

		dest = t_dst(fp, fpi->DstReg);

		/* r300 doesn't seem to be able to do TEX->output reg */
		if (REG_GET_TYPE(dest) == REG_TYPE_OUTPUT) {
			rdest = dest;
			dest = get_temp_reg_tex(fp);
		} else if (fpi->DstReg.WriteMask != WRITEMASK_XYZW) {
			/* in case write mask isn't XYZW */
			rdest = dest;
			dest = get_temp_reg_tex(fp);
		}
		hwdest =
		    t_hw_dst(fp, dest, GL_TRUE,
			     fp->node[fp->cur_node].alu_offset);

		/* Use a temp that hasn't been used in this node, rather
		 * than causing an indirection
		 */
		if (uin & (1 << hwdest)) {
			free_hw_temp(fp, hwdest);
			hwdest = get_hw_temp_tex(fp);
			cs->temps[REG_GET_INDEX(dest)].reg = hwdest;
		}
	} else {
		hwdest = 0;
		unit = 0;
		hwsrc = t_hw_src(fp, coord, GL_TRUE);
	}

	/* Indirection if source has been written in this node, or if the
	 * dest has been read/written in this node
	 */
	if ((REG_GET_TYPE(coord) != REG_TYPE_CONST &&
	     (din & (1 << hwsrc))) || (uin & (1 << hwdest))) {

		/* Finish off current node */
		if (fp->node[fp->cur_node].alu_offset == cs->nrslots)
			emit_nop(fp);

		fp->node[fp->cur_node].alu_end =
		    cs->nrslots - fp->node[fp->cur_node].alu_offset - 1;
		assert(fp->node[fp->cur_node].alu_end >= 0);

		if (++fp->cur_node >= PFS_MAX_TEX_INDIRECT) {
			ERROR("too many levels of texture indirection\n");
			return;
		}

		/* Start new node */
		fp->node[fp->cur_node].tex_offset = fp->tex.length;
		fp->node[fp->cur_node].alu_offset = cs->nrslots;
		fp->node[fp->cur_node].tex_end = -1;
		fp->node[fp->cur_node].alu_end = -1;
		fp->node[fp->cur_node].flags = 0;
		cs->used_in_node = 0;
		cs->dest_in_node = 0;
	}

	if (fp->cur_node == 0)
		fp->first_node_has_tex = 1;

	fp->tex.inst[fp->tex.length++] = 0 | (hwsrc << R300_FPITX_SRC_SHIFT)
	    | (hwdest << R300_FPITX_DST_SHIFT)
	    | (unit << R300_FPITX_IMAGE_SHIFT)
	    /* not entirely sure about this */
	    | (opcode << R300_FPITX_OPCODE_SHIFT);

	cs->dest_in_node |= (1 << hwdest);
	if (REG_GET_TYPE(coord) != REG_TYPE_CONST)
		cs->used_in_node |= (1 << hwsrc);

	fp->node[fp->cur_node].tex_end++;

	/* Copy from temp to output if needed */
	if (REG_GET_VALID(rdest)) {
		emit_arith(fp, PFS_OP_MAD, rdest, fpi->DstReg.WriteMask, dest,
			   pfs_one, pfs_zero, 0);
		free_temp(fp, dest);
	}

	/* Free temp register */
	if (tempreg != 0)
		free_temp(fp, tempreg);
}

/**
 * Returns the first slot where we could possibly allow writing to dest,
 * according to register allocation.
 */
static int get_earliest_allowed_write(struct r300_fragment_program *fp,
				      GLuint dest, int mask)
{
	COMPILE_STATE;
{'fraction_non_alphanumeric': 0.13408092735258118, 'fraction_numerical': 0.023021815825473396, 'mean_word_length': 3.5102289332683876, 'pattern_counts': {'":': 0, '<': 267, '<?xml version=': 0, '>': 337, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 6, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4542891', 'n_tokens_mistral': 25816, 'n_tokens_neox': 23068, 'n_words': 5335}