1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub
8bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom
9bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci#include "radeon_compiler.h"
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci#include <stdbool.h>
26bf215546Sopenharmony_ci#include <stdio.h>
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "r300_reg.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "radeon_compiler_util.h"
31bf215546Sopenharmony_ci#include "radeon_dataflow.h"
32bf215546Sopenharmony_ci#include "radeon_program.h"
33bf215546Sopenharmony_ci#include "radeon_program_alu.h"
34bf215546Sopenharmony_ci#include "radeon_swizzle.h"
35bf215546Sopenharmony_ci#include "radeon_emulate_branches.h"
36bf215546Sopenharmony_ci#include "radeon_remove_constants.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci#include "util/compiler.h"
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci/*
41bf215546Sopenharmony_ci * Take an already-setup and valid source then swizzle it appropriately to
42bf215546Sopenharmony_ci * obtain a constant ZERO or ONE source.
43bf215546Sopenharmony_ci */
44bf215546Sopenharmony_ci#define __CONST(x, y)	\
45bf215546Sopenharmony_ci	(PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[x]),	\
46bf215546Sopenharmony_ci			   t_swizzle(y),	\
47bf215546Sopenharmony_ci			   t_swizzle(y),	\
48bf215546Sopenharmony_ci			   t_swizzle(y),	\
49bf215546Sopenharmony_ci			   t_swizzle(y),	\
50bf215546Sopenharmony_ci			   t_src_class(vpi->SrcReg[x].File), \
51bf215546Sopenharmony_ci			   RC_MASK_NONE) | (vpi->SrcReg[x].RelAddr << 4))
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_cistatic unsigned long t_dst_mask(unsigned int mask)
55bf215546Sopenharmony_ci{
56bf215546Sopenharmony_ci	/* RC_MASK_* is equivalent to VSF_FLAG_* */
57bf215546Sopenharmony_ci	return mask & RC_MASK_XYZW;
58bf215546Sopenharmony_ci}
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_cistatic unsigned long t_dst_class(rc_register_file file)
61bf215546Sopenharmony_ci{
62bf215546Sopenharmony_ci	switch (file) {
63bf215546Sopenharmony_ci	default:
64bf215546Sopenharmony_ci		fprintf(stderr, "%s: Bad register file %i\n", __FUNCTION__, file);
65bf215546Sopenharmony_ci		FALLTHROUGH;
66bf215546Sopenharmony_ci	case RC_FILE_TEMPORARY:
67bf215546Sopenharmony_ci		return PVS_DST_REG_TEMPORARY;
68bf215546Sopenharmony_ci	case RC_FILE_OUTPUT:
69bf215546Sopenharmony_ci		return PVS_DST_REG_OUT;
70bf215546Sopenharmony_ci	case RC_FILE_ADDRESS:
71bf215546Sopenharmony_ci		return PVS_DST_REG_A0;
72bf215546Sopenharmony_ci	}
73bf215546Sopenharmony_ci}
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_cistatic unsigned long t_dst_index(struct r300_vertex_program_code *vp,
76bf215546Sopenharmony_ci				 struct rc_dst_register *dst)
77bf215546Sopenharmony_ci{
78bf215546Sopenharmony_ci	if (dst->File == RC_FILE_OUTPUT)
79bf215546Sopenharmony_ci		return vp->outputs[dst->Index];
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci	return dst->Index;
82bf215546Sopenharmony_ci}
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_cistatic unsigned long t_src_class(rc_register_file file)
85bf215546Sopenharmony_ci{
86bf215546Sopenharmony_ci	switch (file) {
87bf215546Sopenharmony_ci	default:
88bf215546Sopenharmony_ci		fprintf(stderr, "%s: Bad register file %i\n", __FUNCTION__, file);
89bf215546Sopenharmony_ci		FALLTHROUGH;
90bf215546Sopenharmony_ci	case RC_FILE_NONE:
91bf215546Sopenharmony_ci	case RC_FILE_TEMPORARY:
92bf215546Sopenharmony_ci		return PVS_SRC_REG_TEMPORARY;
93bf215546Sopenharmony_ci	case RC_FILE_INPUT:
94bf215546Sopenharmony_ci		return PVS_SRC_REG_INPUT;
95bf215546Sopenharmony_ci	case RC_FILE_CONSTANT:
96bf215546Sopenharmony_ci		return PVS_SRC_REG_CONSTANT;
97bf215546Sopenharmony_ci	}
98bf215546Sopenharmony_ci}
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_cistatic int t_src_conflict(struct rc_src_register a, struct rc_src_register b)
101bf215546Sopenharmony_ci{
102bf215546Sopenharmony_ci	unsigned long aclass = t_src_class(a.File);
103bf215546Sopenharmony_ci	unsigned long bclass = t_src_class(b.File);
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci	if (aclass != bclass)
106bf215546Sopenharmony_ci		return 0;
107bf215546Sopenharmony_ci	if (aclass == PVS_SRC_REG_TEMPORARY)
108bf215546Sopenharmony_ci		return 0;
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci	if (a.RelAddr || b.RelAddr)
111bf215546Sopenharmony_ci		return 1;
112bf215546Sopenharmony_ci	if (a.Index != b.Index)
113bf215546Sopenharmony_ci		return 1;
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci	return 0;
116bf215546Sopenharmony_ci}
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_cistatic inline unsigned long t_swizzle(unsigned int swizzle)
119bf215546Sopenharmony_ci{
120bf215546Sopenharmony_ci	/* this is in fact a NOP as the Mesa RC_SWIZZLE_* are all identical to VSF_IN_COMPONENT_* */
121bf215546Sopenharmony_ci	return swizzle;
122bf215546Sopenharmony_ci}
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_cistatic unsigned long t_src_index(struct r300_vertex_program_code *vp,
125bf215546Sopenharmony_ci				 struct rc_src_register *src)
126bf215546Sopenharmony_ci{
127bf215546Sopenharmony_ci	if (src->File == RC_FILE_INPUT) {
128bf215546Sopenharmony_ci		assert(vp->inputs[src->Index] != -1);
129bf215546Sopenharmony_ci		return vp->inputs[src->Index];
130bf215546Sopenharmony_ci	} else {
131bf215546Sopenharmony_ci		if (src->Index < 0) {
132bf215546Sopenharmony_ci			fprintf(stderr,
133bf215546Sopenharmony_ci				"negative offsets for indirect addressing do not work.\n");
134bf215546Sopenharmony_ci			return 0;
135bf215546Sopenharmony_ci		}
136bf215546Sopenharmony_ci		return src->Index;
137bf215546Sopenharmony_ci	}
138bf215546Sopenharmony_ci}
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci/* these two functions should probably be merged... */
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_cistatic unsigned long t_src(struct r300_vertex_program_code *vp,
143bf215546Sopenharmony_ci			   struct rc_src_register *src)
144bf215546Sopenharmony_ci{
145bf215546Sopenharmony_ci	/* src->Negate uses the RC_MASK_ flags from program_instruction.h,
146bf215546Sopenharmony_ci	 * which equal our VSF_FLAGS_ values, so it's safe to just pass it here.
147bf215546Sopenharmony_ci	 */
148bf215546Sopenharmony_ci	return PVS_SRC_OPERAND(t_src_index(vp, src),
149bf215546Sopenharmony_ci			       t_swizzle(GET_SWZ(src->Swizzle, 0)),
150bf215546Sopenharmony_ci			       t_swizzle(GET_SWZ(src->Swizzle, 1)),
151bf215546Sopenharmony_ci			       t_swizzle(GET_SWZ(src->Swizzle, 2)),
152bf215546Sopenharmony_ci			       t_swizzle(GET_SWZ(src->Swizzle, 3)),
153bf215546Sopenharmony_ci			       t_src_class(src->File),
154bf215546Sopenharmony_ci			       src->Negate) |
155bf215546Sopenharmony_ci	       (src->RelAddr << 4) | (src->Abs << 3);
156bf215546Sopenharmony_ci}
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_cistatic unsigned long t_src_scalar(struct r300_vertex_program_code *vp,
159bf215546Sopenharmony_ci				  struct rc_src_register *src)
160bf215546Sopenharmony_ci{
161bf215546Sopenharmony_ci	/* src->Negate uses the RC_MASK_ flags from program_instruction.h,
162bf215546Sopenharmony_ci	 * which equal our VSF_FLAGS_ values, so it's safe to just pass it here.
163bf215546Sopenharmony_ci	 */
164bf215546Sopenharmony_ci	unsigned int swz = rc_get_scalar_src_swz(src->Swizzle);
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci	return PVS_SRC_OPERAND(t_src_index(vp, src),
167bf215546Sopenharmony_ci			       t_swizzle(swz),
168bf215546Sopenharmony_ci			       t_swizzle(swz),
169bf215546Sopenharmony_ci			       t_swizzle(swz),
170bf215546Sopenharmony_ci			       t_swizzle(swz),
171bf215546Sopenharmony_ci			       t_src_class(src->File),
172bf215546Sopenharmony_ci			       src->Negate ? RC_MASK_XYZW : RC_MASK_NONE) |
173bf215546Sopenharmony_ci	       (src->RelAddr << 4) | (src->Abs << 3);
174bf215546Sopenharmony_ci}
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_cistatic int valid_dst(struct r300_vertex_program_code *vp,
177bf215546Sopenharmony_ci			   struct rc_dst_register *dst)
178bf215546Sopenharmony_ci{
179bf215546Sopenharmony_ci	if (dst->File == RC_FILE_OUTPUT && vp->outputs[dst->Index] == -1) {
180bf215546Sopenharmony_ci		return 0;
181bf215546Sopenharmony_ci	} else if (dst->File == RC_FILE_ADDRESS) {
182bf215546Sopenharmony_ci		assert(dst->Index == 0);
183bf215546Sopenharmony_ci	}
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci	return 1;
186bf215546Sopenharmony_ci}
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_cistatic void ei_vector1(struct r300_vertex_program_code *vp,
189bf215546Sopenharmony_ci				unsigned int hw_opcode,
190bf215546Sopenharmony_ci				struct rc_sub_instruction *vpi,
191bf215546Sopenharmony_ci				unsigned int * inst)
192bf215546Sopenharmony_ci{
193bf215546Sopenharmony_ci	inst[0] = PVS_OP_DST_OPERAND(hw_opcode,
194bf215546Sopenharmony_ci				     0,
195bf215546Sopenharmony_ci				     0,
196bf215546Sopenharmony_ci				     t_dst_index(vp, &vpi->DstReg),
197bf215546Sopenharmony_ci				     t_dst_mask(vpi->DstReg.WriteMask),
198bf215546Sopenharmony_ci				     t_dst_class(vpi->DstReg.File),
199bf215546Sopenharmony_ci                                     vpi->SaturateMode == RC_SATURATE_ZERO_ONE);
200bf215546Sopenharmony_ci	inst[1] = t_src(vp, &vpi->SrcReg[0]);
201bf215546Sopenharmony_ci	inst[2] = __CONST(0, RC_SWIZZLE_ZERO);
202bf215546Sopenharmony_ci	inst[3] = __CONST(0, RC_SWIZZLE_ZERO);
203bf215546Sopenharmony_ci}
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_cistatic void ei_vector2(struct r300_vertex_program_code *vp,
206bf215546Sopenharmony_ci				unsigned int hw_opcode,
207bf215546Sopenharmony_ci				struct rc_sub_instruction *vpi,
208bf215546Sopenharmony_ci				unsigned int * inst)
209bf215546Sopenharmony_ci{
210bf215546Sopenharmony_ci	inst[0] = PVS_OP_DST_OPERAND(hw_opcode,
211bf215546Sopenharmony_ci				     0,
212bf215546Sopenharmony_ci				     0,
213bf215546Sopenharmony_ci				     t_dst_index(vp, &vpi->DstReg),
214bf215546Sopenharmony_ci				     t_dst_mask(vpi->DstReg.WriteMask),
215bf215546Sopenharmony_ci				     t_dst_class(vpi->DstReg.File),
216bf215546Sopenharmony_ci                                     vpi->SaturateMode == RC_SATURATE_ZERO_ONE);
217bf215546Sopenharmony_ci	inst[1] = t_src(vp, &vpi->SrcReg[0]);
218bf215546Sopenharmony_ci	inst[2] = t_src(vp, &vpi->SrcReg[1]);
219bf215546Sopenharmony_ci	inst[3] = __CONST(1, RC_SWIZZLE_ZERO);
220bf215546Sopenharmony_ci}
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_cistatic void ei_math1(struct r300_vertex_program_code *vp,
223bf215546Sopenharmony_ci				unsigned int hw_opcode,
224bf215546Sopenharmony_ci				struct rc_sub_instruction *vpi,
225bf215546Sopenharmony_ci				unsigned int * inst)
226bf215546Sopenharmony_ci{
227bf215546Sopenharmony_ci	inst[0] = PVS_OP_DST_OPERAND(hw_opcode,
228bf215546Sopenharmony_ci				     1,
229bf215546Sopenharmony_ci				     0,
230bf215546Sopenharmony_ci				     t_dst_index(vp, &vpi->DstReg),
231bf215546Sopenharmony_ci				     t_dst_mask(vpi->DstReg.WriteMask),
232bf215546Sopenharmony_ci				     t_dst_class(vpi->DstReg.File),
233bf215546Sopenharmony_ci                                     vpi->SaturateMode == RC_SATURATE_ZERO_ONE);
234bf215546Sopenharmony_ci	inst[1] = t_src_scalar(vp, &vpi->SrcReg[0]);
235bf215546Sopenharmony_ci	inst[2] = __CONST(0, RC_SWIZZLE_ZERO);
236bf215546Sopenharmony_ci	inst[3] = __CONST(0, RC_SWIZZLE_ZERO);
237bf215546Sopenharmony_ci}
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_cistatic void ei_lit(struct r300_vertex_program_code *vp,
240bf215546Sopenharmony_ci				      struct rc_sub_instruction *vpi,
241bf215546Sopenharmony_ci				      unsigned int * inst)
242bf215546Sopenharmony_ci{
243bf215546Sopenharmony_ci	//LIT TMP 1.Y Z TMP 1{} {X W Z Y} TMP 1{} {Y W Z X} TMP 1{} {Y X Z W}
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci	inst[0] = PVS_OP_DST_OPERAND(ME_LIGHT_COEFF_DX,
246bf215546Sopenharmony_ci				     1,
247bf215546Sopenharmony_ci				     0,
248bf215546Sopenharmony_ci				     t_dst_index(vp, &vpi->DstReg),
249bf215546Sopenharmony_ci				     t_dst_mask(vpi->DstReg.WriteMask),
250bf215546Sopenharmony_ci				     t_dst_class(vpi->DstReg.File),
251bf215546Sopenharmony_ci                                     vpi->SaturateMode == RC_SATURATE_ZERO_ONE);
252bf215546Sopenharmony_ci	/* NOTE: Users swizzling might not work. */
253bf215546Sopenharmony_ci	inst[1] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)),	// X
254bf215546Sopenharmony_ci				  t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)),	// W
255bf215546Sopenharmony_ci				  PVS_SRC_SELECT_FORCE_0,	// Z
256bf215546Sopenharmony_ci				  t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)),	// Y
257bf215546Sopenharmony_ci				  t_src_class(vpi->SrcReg[0].File),
258bf215546Sopenharmony_ci				  vpi->SrcReg[0].Negate ? RC_MASK_XYZW : RC_MASK_NONE) |
259bf215546Sopenharmony_ci	    (vpi->SrcReg[0].RelAddr << 4);
260bf215546Sopenharmony_ci	inst[2] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)),	// Y
261bf215546Sopenharmony_ci				  t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)),	// W
262bf215546Sopenharmony_ci				  PVS_SRC_SELECT_FORCE_0,	// Z
263bf215546Sopenharmony_ci				  t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)),	// X
264bf215546Sopenharmony_ci				  t_src_class(vpi->SrcReg[0].File),
265bf215546Sopenharmony_ci				  vpi->SrcReg[0].Negate ? RC_MASK_XYZW : RC_MASK_NONE) |
266bf215546Sopenharmony_ci	    (vpi->SrcReg[0].RelAddr << 4);
267bf215546Sopenharmony_ci	inst[3] = PVS_SRC_OPERAND(t_src_index(vp, &vpi->SrcReg[0]), t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 1)),	// Y
268bf215546Sopenharmony_ci				  t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 0)),	// X
269bf215546Sopenharmony_ci				  PVS_SRC_SELECT_FORCE_0,	// Z
270bf215546Sopenharmony_ci				  t_swizzle(GET_SWZ(vpi->SrcReg[0].Swizzle, 3)),	// W
271bf215546Sopenharmony_ci				  t_src_class(vpi->SrcReg[0].File),
272bf215546Sopenharmony_ci				  vpi->SrcReg[0].Negate ? RC_MASK_XYZW : RC_MASK_NONE) |
273bf215546Sopenharmony_ci	    (vpi->SrcReg[0].RelAddr << 4);
274bf215546Sopenharmony_ci}
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_cistatic void ei_mad(struct r300_vertex_program_code *vp,
277bf215546Sopenharmony_ci				      struct rc_sub_instruction *vpi,
278bf215546Sopenharmony_ci				      unsigned int * inst)
279bf215546Sopenharmony_ci{
280bf215546Sopenharmony_ci	unsigned int i;
281bf215546Sopenharmony_ci	/* Remarks about hardware limitations of MAD
282bf215546Sopenharmony_ci	 * (please preserve this comment, as this information is _NOT_
283bf215546Sopenharmony_ci	 * in the documentation provided by AMD).
284bf215546Sopenharmony_ci	 *
285bf215546Sopenharmony_ci	 * As described in the documentation, MAD with three unique temporary
286bf215546Sopenharmony_ci	 * source registers requires the use of the macro version.
287bf215546Sopenharmony_ci	 *
288bf215546Sopenharmony_ci	 * However (and this is not mentioned in the documentation), apparently
289bf215546Sopenharmony_ci	 * the macro version is _NOT_ a full superset of the normal version.
290bf215546Sopenharmony_ci	 * In particular, the macro version does not always work when relative
291bf215546Sopenharmony_ci	 * addressing is used in the source operands.
292bf215546Sopenharmony_ci	 *
293bf215546Sopenharmony_ci	 * This limitation caused incorrect rendering in Sauerbraten's OpenGL
294bf215546Sopenharmony_ci	 * assembly shader path when using medium quality animations
295bf215546Sopenharmony_ci	 * (i.e. animations with matrix blending instead of quaternion blending).
296bf215546Sopenharmony_ci	 *
297bf215546Sopenharmony_ci	 * Unfortunately, I (nha) have been unable to extract a Piglit regression
298bf215546Sopenharmony_ci	 * test for this issue - for some reason, it is possible to have vertex
299bf215546Sopenharmony_ci	 * programs whose prefix is *exactly* the same as the prefix of the
300bf215546Sopenharmony_ci	 * offending program in Sauerbraten up to the offending instruction
301bf215546Sopenharmony_ci	 * without causing any trouble.
302bf215546Sopenharmony_ci	 *
303bf215546Sopenharmony_ci	 * Bottom line: Only use the macro version only when really necessary;
304bf215546Sopenharmony_ci	 * according to AMD docs, this should improve performance by one clock
305bf215546Sopenharmony_ci	 * as a nice side bonus.
306bf215546Sopenharmony_ci	 */
307bf215546Sopenharmony_ci	if (vpi->SrcReg[0].File == RC_FILE_TEMPORARY &&
308bf215546Sopenharmony_ci	    vpi->SrcReg[1].File == RC_FILE_TEMPORARY &&
309bf215546Sopenharmony_ci	    vpi->SrcReg[2].File == RC_FILE_TEMPORARY &&
310bf215546Sopenharmony_ci	    vpi->SrcReg[0].Index != vpi->SrcReg[1].Index &&
311bf215546Sopenharmony_ci	    vpi->SrcReg[0].Index != vpi->SrcReg[2].Index &&
312bf215546Sopenharmony_ci	    vpi->SrcReg[1].Index != vpi->SrcReg[2].Index) {
313bf215546Sopenharmony_ci		inst[0] = PVS_OP_DST_OPERAND(PVS_MACRO_OP_2CLK_MADD,
314bf215546Sopenharmony_ci				0,
315bf215546Sopenharmony_ci				1,
316bf215546Sopenharmony_ci				t_dst_index(vp, &vpi->DstReg),
317bf215546Sopenharmony_ci				t_dst_mask(vpi->DstReg.WriteMask),
318bf215546Sopenharmony_ci				t_dst_class(vpi->DstReg.File),
319bf215546Sopenharmony_ci                                vpi->SaturateMode == RC_SATURATE_ZERO_ONE);
320bf215546Sopenharmony_ci	} else {
321bf215546Sopenharmony_ci		inst[0] = PVS_OP_DST_OPERAND(VE_MULTIPLY_ADD,
322bf215546Sopenharmony_ci				0,
323bf215546Sopenharmony_ci				0,
324bf215546Sopenharmony_ci				t_dst_index(vp, &vpi->DstReg),
325bf215546Sopenharmony_ci				t_dst_mask(vpi->DstReg.WriteMask),
326bf215546Sopenharmony_ci				t_dst_class(vpi->DstReg.File),
327bf215546Sopenharmony_ci                                vpi->SaturateMode == RC_SATURATE_ZERO_ONE);
328bf215546Sopenharmony_ci
329bf215546Sopenharmony_ci		/* Arguments with constant swizzles still count as a unique
330bf215546Sopenharmony_ci		 * temporary, so we should make sure these arguments share a
331bf215546Sopenharmony_ci		 * register index with one of the other arguments. */
332bf215546Sopenharmony_ci		for (i = 0; i < 3; i++) {
333bf215546Sopenharmony_ci			unsigned int j;
334bf215546Sopenharmony_ci			if (vpi->SrcReg[i].File != RC_FILE_NONE)
335bf215546Sopenharmony_ci				continue;
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_ci			for (j = 0; j < 3; j++) {
338bf215546Sopenharmony_ci				if (i != j) {
339bf215546Sopenharmony_ci					vpi->SrcReg[i].Index =
340bf215546Sopenharmony_ci						vpi->SrcReg[j].Index;
341bf215546Sopenharmony_ci					break;
342bf215546Sopenharmony_ci				}
343bf215546Sopenharmony_ci			}
344bf215546Sopenharmony_ci		}
345bf215546Sopenharmony_ci	}
346bf215546Sopenharmony_ci	inst[1] = t_src(vp, &vpi->SrcReg[0]);
347bf215546Sopenharmony_ci	inst[2] = t_src(vp, &vpi->SrcReg[1]);
348bf215546Sopenharmony_ci	inst[3] = t_src(vp, &vpi->SrcReg[2]);
349bf215546Sopenharmony_ci}
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_cistatic void ei_pow(struct r300_vertex_program_code *vp,
352bf215546Sopenharmony_ci				      struct rc_sub_instruction *vpi,
353bf215546Sopenharmony_ci				      unsigned int * inst)
354bf215546Sopenharmony_ci{
355bf215546Sopenharmony_ci	inst[0] = PVS_OP_DST_OPERAND(ME_POWER_FUNC_FF,
356bf215546Sopenharmony_ci				     1,
357bf215546Sopenharmony_ci				     0,
358bf215546Sopenharmony_ci				     t_dst_index(vp, &vpi->DstReg),
359bf215546Sopenharmony_ci				     t_dst_mask(vpi->DstReg.WriteMask),
360bf215546Sopenharmony_ci				     t_dst_class(vpi->DstReg.File),
361bf215546Sopenharmony_ci                                     vpi->SaturateMode == RC_SATURATE_ZERO_ONE);
362bf215546Sopenharmony_ci	inst[1] = t_src_scalar(vp, &vpi->SrcReg[0]);
363bf215546Sopenharmony_ci	inst[2] = __CONST(0, RC_SWIZZLE_ZERO);
364bf215546Sopenharmony_ci	inst[3] = t_src_scalar(vp, &vpi->SrcReg[1]);
365bf215546Sopenharmony_ci}
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_cistatic void translate_vertex_program(struct radeon_compiler *c, void *user)
368bf215546Sopenharmony_ci{
369bf215546Sopenharmony_ci	struct r300_vertex_program_compiler *compiler = (struct r300_vertex_program_compiler*)c;
370bf215546Sopenharmony_ci	struct rc_instruction *rci;
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_ci	unsigned loops[R500_PVS_MAX_LOOP_DEPTH] = {};
373bf215546Sopenharmony_ci	unsigned loop_depth = 0;
374bf215546Sopenharmony_ci	bool last_input_read_at_loop_end = false;
375bf215546Sopenharmony_ci	bool last_pos_write_at_loop_end = false;
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci	compiler->code->pos_end = 0;	/* Not supported yet */
378bf215546Sopenharmony_ci	compiler->code->length = 0;
379bf215546Sopenharmony_ci	compiler->code->num_temporaries = 0;
380bf215546Sopenharmony_ci	compiler->code->last_input_read = 0;
381bf215546Sopenharmony_ci	compiler->code->last_pos_write = 0;
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci	compiler->SetHwInputOutput(compiler);
384bf215546Sopenharmony_ci
385bf215546Sopenharmony_ci	for(rci = compiler->Base.Program.Instructions.Next; rci != &compiler->Base.Program.Instructions; rci = rci->Next) {
386bf215546Sopenharmony_ci		struct rc_sub_instruction *vpi = &rci->U.I;
387bf215546Sopenharmony_ci		unsigned int *inst = compiler->code->body.d + compiler->code->length;
388bf215546Sopenharmony_ci		const struct rc_opcode_info *info = rc_get_opcode_info(vpi->Opcode);
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_ci		/* Skip instructions writing to non-existing destination */
391bf215546Sopenharmony_ci		if (!valid_dst(compiler->code, &vpi->DstReg))
392bf215546Sopenharmony_ci			continue;
393bf215546Sopenharmony_ci
394bf215546Sopenharmony_ci		if (info->HasDstReg) {
395bf215546Sopenharmony_ci			/* Neither is Saturate. */
396bf215546Sopenharmony_ci			if (vpi->SaturateMode != RC_SATURATE_NONE && !c->is_r500) {
397bf215546Sopenharmony_ci				rc_error(&compiler->Base, "Vertex program does not support the Saturate "
398bf215546Sopenharmony_ci					 "modifier (yet).\n");
399bf215546Sopenharmony_ci			}
400bf215546Sopenharmony_ci		}
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_ci		if (compiler->code->length >= c->max_alu_insts * 4) {
403bf215546Sopenharmony_ci			rc_error(&compiler->Base, "Vertex program has too many instructions\n");
404bf215546Sopenharmony_ci			return;
405bf215546Sopenharmony_ci		}
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci		assert(compiler->Base.is_r500 ||
408bf215546Sopenharmony_ci		       (vpi->Opcode != RC_OPCODE_SEQ &&
409bf215546Sopenharmony_ci			vpi->Opcode != RC_OPCODE_SNE));
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci		switch (vpi->Opcode) {
412bf215546Sopenharmony_ci		case RC_OPCODE_ADD: ei_vector2(compiler->code, VE_ADD, vpi, inst); break;
413bf215546Sopenharmony_ci		case RC_OPCODE_ARL: ei_vector1(compiler->code, VE_FLT2FIX_DX, vpi, inst); break;
414bf215546Sopenharmony_ci		case RC_OPCODE_ARR: ei_vector1(compiler->code, VE_FLT2FIX_DX_RND, vpi, inst); break;
415bf215546Sopenharmony_ci		case RC_OPCODE_COS: ei_math1(compiler->code, ME_COS, vpi, inst); break;
416bf215546Sopenharmony_ci		case RC_OPCODE_DP4: ei_vector2(compiler->code, VE_DOT_PRODUCT, vpi, inst); break;
417bf215546Sopenharmony_ci		case RC_OPCODE_DST: ei_vector2(compiler->code, VE_DISTANCE_VECTOR, vpi, inst); break;
418bf215546Sopenharmony_ci		case RC_OPCODE_EX2: ei_math1(compiler->code, ME_EXP_BASE2_FULL_DX, vpi, inst); break;
419bf215546Sopenharmony_ci		case RC_OPCODE_EXP: ei_math1(compiler->code, ME_EXP_BASE2_DX, vpi, inst); break;
420bf215546Sopenharmony_ci		case RC_OPCODE_FRC: ei_vector1(compiler->code, VE_FRACTION, vpi, inst); break;
421bf215546Sopenharmony_ci		case RC_OPCODE_LG2: ei_math1(compiler->code, ME_LOG_BASE2_FULL_DX, vpi, inst); break;
422bf215546Sopenharmony_ci		case RC_OPCODE_LIT: ei_lit(compiler->code, vpi, inst); break;
423bf215546Sopenharmony_ci		case RC_OPCODE_LOG: ei_math1(compiler->code, ME_LOG_BASE2_DX, vpi, inst); break;
424bf215546Sopenharmony_ci		case RC_OPCODE_MAD: ei_mad(compiler->code, vpi, inst); break;
425bf215546Sopenharmony_ci		case RC_OPCODE_MAX: ei_vector2(compiler->code, VE_MAXIMUM, vpi, inst); break;
426bf215546Sopenharmony_ci		case RC_OPCODE_MIN: ei_vector2(compiler->code, VE_MINIMUM, vpi, inst); break;
427bf215546Sopenharmony_ci		case RC_OPCODE_MOV: ei_vector1(compiler->code, VE_ADD, vpi, inst); break;
428bf215546Sopenharmony_ci		case RC_OPCODE_MUL: ei_vector2(compiler->code, VE_MULTIPLY, vpi, inst); break;
429bf215546Sopenharmony_ci		case RC_OPCODE_POW: ei_pow(compiler->code, vpi, inst); break;
430bf215546Sopenharmony_ci		case RC_OPCODE_RCP: ei_math1(compiler->code, ME_RECIP_DX, vpi, inst); break;
431bf215546Sopenharmony_ci		case RC_OPCODE_RSQ: ei_math1(compiler->code, ME_RECIP_SQRT_DX, vpi, inst); break;
432bf215546Sopenharmony_ci		case RC_OPCODE_SEQ: ei_vector2(compiler->code, VE_SET_EQUAL, vpi, inst); break;
433bf215546Sopenharmony_ci		case RC_OPCODE_SGE: ei_vector2(compiler->code, VE_SET_GREATER_THAN_EQUAL, vpi, inst); break;
434bf215546Sopenharmony_ci		case RC_OPCODE_SIN: ei_math1(compiler->code, ME_SIN, vpi, inst); break;
435bf215546Sopenharmony_ci		case RC_OPCODE_SLT: ei_vector2(compiler->code, VE_SET_LESS_THAN, vpi, inst); break;
436bf215546Sopenharmony_ci		case RC_OPCODE_SNE: ei_vector2(compiler->code, VE_SET_NOT_EQUAL, vpi, inst); break;
437bf215546Sopenharmony_ci		case RC_OPCODE_BGNLOOP:
438bf215546Sopenharmony_ci		{
439bf215546Sopenharmony_ci			if ((!compiler->Base.is_r500
440bf215546Sopenharmony_ci				&& loop_depth >= R300_VS_MAX_LOOP_DEPTH)
441bf215546Sopenharmony_ci				|| loop_depth >= R500_PVS_MAX_LOOP_DEPTH) {
442bf215546Sopenharmony_ci				rc_error(&compiler->Base,
443bf215546Sopenharmony_ci						"Loops are nested too deep.");
444bf215546Sopenharmony_ci				return;
445bf215546Sopenharmony_ci			}
446bf215546Sopenharmony_ci			loops[loop_depth++] = ((compiler->code->length)/ 4) + 1;
447bf215546Sopenharmony_ci			break;
448bf215546Sopenharmony_ci		}
449bf215546Sopenharmony_ci		case RC_OPCODE_ENDLOOP:
450bf215546Sopenharmony_ci		{
451bf215546Sopenharmony_ci			unsigned int act_addr;
452bf215546Sopenharmony_ci			unsigned int last_addr;
453bf215546Sopenharmony_ci			unsigned int ret_addr;
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_ci			if (loop_depth == 1 && last_input_read_at_loop_end) {
456bf215546Sopenharmony_ci				compiler->code->last_input_read = compiler->code->length / 4;
457bf215546Sopenharmony_ci				last_input_read_at_loop_end = false;
458bf215546Sopenharmony_ci			}
459bf215546Sopenharmony_ci			if (loop_depth == 1 && last_pos_write_at_loop_end) {
460bf215546Sopenharmony_ci				compiler->code->last_pos_write = compiler->code->length / 4;
461bf215546Sopenharmony_ci				last_pos_write_at_loop_end = false;
462bf215546Sopenharmony_ci			}
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_ci			ret_addr = loops[--loop_depth];
465bf215546Sopenharmony_ci			act_addr = ret_addr - 1;
466bf215546Sopenharmony_ci			last_addr = (compiler->code->length / 4) - 1;
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci			if (loop_depth >= R300_VS_MAX_FC_OPS) {
469bf215546Sopenharmony_ci				rc_error(&compiler->Base,
470bf215546Sopenharmony_ci					"Too many flow control instructions.");
471bf215546Sopenharmony_ci				return;
472bf215546Sopenharmony_ci			}
473bf215546Sopenharmony_ci			if (compiler->Base.is_r500) {
474bf215546Sopenharmony_ci				compiler->code->fc_op_addrs.r500
475bf215546Sopenharmony_ci					[compiler->code->num_fc_ops].lw =
476bf215546Sopenharmony_ci					R500_PVS_FC_ACT_ADRS(act_addr)
477bf215546Sopenharmony_ci					| R500_PVS_FC_LOOP_CNT_JMP_INST(0x00ff)
478bf215546Sopenharmony_ci					;
479bf215546Sopenharmony_ci				compiler->code->fc_op_addrs.r500
480bf215546Sopenharmony_ci					[compiler->code->num_fc_ops].uw =
481bf215546Sopenharmony_ci					R500_PVS_FC_LAST_INST(last_addr)
482bf215546Sopenharmony_ci					| R500_PVS_FC_RTN_INST(ret_addr)
483bf215546Sopenharmony_ci					;
484bf215546Sopenharmony_ci			} else {
485bf215546Sopenharmony_ci				compiler->code->fc_op_addrs.r300
486bf215546Sopenharmony_ci					[compiler->code->num_fc_ops] =
487bf215546Sopenharmony_ci					R300_PVS_FC_ACT_ADRS(act_addr)
488bf215546Sopenharmony_ci					| R300_PVS_FC_LOOP_CNT_JMP_INST(0xff)
489bf215546Sopenharmony_ci					| R300_PVS_FC_LAST_INST(last_addr)
490bf215546Sopenharmony_ci					| R300_PVS_FC_RTN_INST(ret_addr)
491bf215546Sopenharmony_ci					;
492bf215546Sopenharmony_ci			}
493bf215546Sopenharmony_ci			compiler->code->fc_loop_index[compiler->code->num_fc_ops] =
494bf215546Sopenharmony_ci				R300_PVS_FC_LOOP_INIT_VAL(0x0)
495bf215546Sopenharmony_ci				| R300_PVS_FC_LOOP_STEP_VAL(0x1)
496bf215546Sopenharmony_ci				;
497bf215546Sopenharmony_ci			compiler->code->fc_ops |= R300_VAP_PVS_FC_OPC_LOOP(
498bf215546Sopenharmony_ci						compiler->code->num_fc_ops);
499bf215546Sopenharmony_ci			compiler->code->num_fc_ops++;
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_ci			break;
502bf215546Sopenharmony_ci		}
503bf215546Sopenharmony_ci
504bf215546Sopenharmony_ci		case RC_ME_PRED_SET_CLR:
505bf215546Sopenharmony_ci			ei_math1(compiler->code, ME_PRED_SET_CLR, vpi, inst);
506bf215546Sopenharmony_ci			break;
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci		case RC_ME_PRED_SET_INV:
509bf215546Sopenharmony_ci			ei_math1(compiler->code, ME_PRED_SET_INV, vpi, inst);
510bf215546Sopenharmony_ci			break;
511bf215546Sopenharmony_ci
512bf215546Sopenharmony_ci		case RC_ME_PRED_SET_POP:
513bf215546Sopenharmony_ci			ei_math1(compiler->code, ME_PRED_SET_POP, vpi, inst);
514bf215546Sopenharmony_ci			break;
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_ci		case RC_ME_PRED_SET_RESTORE:
517bf215546Sopenharmony_ci			ei_math1(compiler->code, ME_PRED_SET_RESTORE, vpi, inst);
518bf215546Sopenharmony_ci			break;
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci		case RC_ME_PRED_SEQ:
521bf215546Sopenharmony_ci			ei_math1(compiler->code, ME_PRED_SET_EQ, vpi, inst);
522bf215546Sopenharmony_ci			break;
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ci		case RC_ME_PRED_SNEQ:
525bf215546Sopenharmony_ci			ei_math1(compiler->code, ME_PRED_SET_NEQ, vpi, inst);
526bf215546Sopenharmony_ci			break;
527bf215546Sopenharmony_ci
528bf215546Sopenharmony_ci		case RC_VE_PRED_SNEQ_PUSH:
529bf215546Sopenharmony_ci			ei_vector2(compiler->code, VE_PRED_SET_NEQ_PUSH,
530bf215546Sopenharmony_ci								vpi, inst);
531bf215546Sopenharmony_ci			break;
532bf215546Sopenharmony_ci
533bf215546Sopenharmony_ci		default:
534bf215546Sopenharmony_ci			rc_error(&compiler->Base, "Unknown opcode %s\n", info->Name);
535bf215546Sopenharmony_ci			return;
536bf215546Sopenharmony_ci		}
537bf215546Sopenharmony_ci
538bf215546Sopenharmony_ci		if (vpi->DstReg.Pred != RC_PRED_DISABLED) {
539bf215546Sopenharmony_ci			inst[0] |= (PVS_DST_PRED_ENABLE_MASK
540bf215546Sopenharmony_ci						<< PVS_DST_PRED_ENABLE_SHIFT);
541bf215546Sopenharmony_ci			if (vpi->DstReg.Pred == RC_PRED_SET) {
542bf215546Sopenharmony_ci				inst[0] |= (PVS_DST_PRED_SENSE_MASK
543bf215546Sopenharmony_ci						<< PVS_DST_PRED_SENSE_SHIFT);
544bf215546Sopenharmony_ci			}
545bf215546Sopenharmony_ci		}
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci		/* Update the number of temporaries. */
548bf215546Sopenharmony_ci		if (info->HasDstReg && vpi->DstReg.File == RC_FILE_TEMPORARY &&
549bf215546Sopenharmony_ci		    vpi->DstReg.Index >= compiler->code->num_temporaries)
550bf215546Sopenharmony_ci			compiler->code->num_temporaries = vpi->DstReg.Index + 1;
551bf215546Sopenharmony_ci
552bf215546Sopenharmony_ci		/* last instruction that writes position */
553bf215546Sopenharmony_ci		if (info->HasDstReg && vpi->DstReg.File == RC_FILE_OUTPUT &&
554bf215546Sopenharmony_ci		    t_dst_index(compiler->code, &vpi->DstReg) == 0) {
555bf215546Sopenharmony_ci			if (loop_depth == 0)
556bf215546Sopenharmony_ci				compiler->code->last_pos_write = compiler->code->length / 4;
557bf215546Sopenharmony_ci			else
558bf215546Sopenharmony_ci				last_pos_write_at_loop_end = true;
559bf215546Sopenharmony_ci		}
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci		for (unsigned i = 0; i < info->NumSrcRegs; i++) {
562bf215546Sopenharmony_ci			if (vpi->SrcReg[i].File == RC_FILE_TEMPORARY &&
563bf215546Sopenharmony_ci			    vpi->SrcReg[i].Index >= compiler->code->num_temporaries)
564bf215546Sopenharmony_ci				compiler->code->num_temporaries = vpi->SrcReg[i].Index + 1;
565bf215546Sopenharmony_ci			if (vpi->SrcReg[i].File == RC_FILE_INPUT) {
566bf215546Sopenharmony_ci				if (loop_depth == 0)
567bf215546Sopenharmony_ci					compiler->code->last_input_read = compiler->code->length / 4;
568bf215546Sopenharmony_ci				else
569bf215546Sopenharmony_ci					last_input_read_at_loop_end = true;
570bf215546Sopenharmony_ci			}
571bf215546Sopenharmony_ci
572bf215546Sopenharmony_ci		}
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci
575bf215546Sopenharmony_ci		if (compiler->code->num_temporaries > compiler->Base.max_temp_regs) {
576bf215546Sopenharmony_ci			rc_error(&compiler->Base, "Too many temporaries.\n");
577bf215546Sopenharmony_ci			return;
578bf215546Sopenharmony_ci		}
579bf215546Sopenharmony_ci
580bf215546Sopenharmony_ci		compiler->code->length += 4;
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ci		if (compiler->Base.Error)
583bf215546Sopenharmony_ci			return;
584bf215546Sopenharmony_ci	}
585bf215546Sopenharmony_ci}
586bf215546Sopenharmony_ci
587bf215546Sopenharmony_cistruct temporary_allocation {
588bf215546Sopenharmony_ci	unsigned int Allocated:1;
589bf215546Sopenharmony_ci	unsigned int HwTemp:15;
590bf215546Sopenharmony_ci	struct rc_instruction * LastRead;
591bf215546Sopenharmony_ci};
592bf215546Sopenharmony_ci
593bf215546Sopenharmony_cistatic int get_reg(struct radeon_compiler *c, struct temporary_allocation *ta, bool *hwtemps,
594bf215546Sopenharmony_ci                   unsigned int orig)
595bf215546Sopenharmony_ci{
596bf215546Sopenharmony_ci    if (!ta[orig].Allocated) {
597bf215546Sopenharmony_ci        int j;
598bf215546Sopenharmony_ci        for (j = 0; j < c->max_temp_regs; ++j)
599bf215546Sopenharmony_ci        {
600bf215546Sopenharmony_ci            if (!hwtemps[j])
601bf215546Sopenharmony_ci                break;
602bf215546Sopenharmony_ci        }
603bf215546Sopenharmony_ci        ta[orig].Allocated = 1;
604bf215546Sopenharmony_ci        ta[orig].HwTemp = j;
605bf215546Sopenharmony_ci        hwtemps[ta[orig].HwTemp] = true;
606bf215546Sopenharmony_ci    }
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci    return ta[orig].HwTemp;
609bf215546Sopenharmony_ci}
610bf215546Sopenharmony_ci
611bf215546Sopenharmony_cistatic void allocate_temporary_registers(struct radeon_compiler *c, void *user)
612bf215546Sopenharmony_ci{
613bf215546Sopenharmony_ci	struct r300_vertex_program_compiler *compiler = (struct r300_vertex_program_compiler*)c;
614bf215546Sopenharmony_ci	struct rc_instruction *inst;
615bf215546Sopenharmony_ci	struct rc_instruction *end_loop = NULL;
616bf215546Sopenharmony_ci	unsigned int num_orig_temps = 0;
617bf215546Sopenharmony_ci	bool hwtemps[RC_REGISTER_MAX_INDEX];
618bf215546Sopenharmony_ci	struct temporary_allocation * ta;
619bf215546Sopenharmony_ci	unsigned int i;
620bf215546Sopenharmony_ci
621bf215546Sopenharmony_ci	memset(hwtemps, 0, sizeof(hwtemps));
622bf215546Sopenharmony_ci
623bf215546Sopenharmony_ci	rc_recompute_ips(c);
624bf215546Sopenharmony_ci
625bf215546Sopenharmony_ci	/* Pass 1: Count original temporaries. */
626bf215546Sopenharmony_ci	for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) {
627bf215546Sopenharmony_ci		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
628bf215546Sopenharmony_ci
629bf215546Sopenharmony_ci		for (i = 0; i < opcode->NumSrcRegs; ++i) {
630bf215546Sopenharmony_ci			if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) {
631bf215546Sopenharmony_ci				if (inst->U.I.SrcReg[i].Index >= num_orig_temps)
632bf215546Sopenharmony_ci					num_orig_temps = inst->U.I.SrcReg[i].Index + 1;
633bf215546Sopenharmony_ci			}
634bf215546Sopenharmony_ci		}
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci		if (opcode->HasDstReg) {
637bf215546Sopenharmony_ci			if (inst->U.I.DstReg.File == RC_FILE_TEMPORARY) {
638bf215546Sopenharmony_ci				if (inst->U.I.DstReg.Index >= num_orig_temps)
639bf215546Sopenharmony_ci					num_orig_temps = inst->U.I.DstReg.Index + 1;
640bf215546Sopenharmony_ci			}
641bf215546Sopenharmony_ci		}
642bf215546Sopenharmony_ci	}
643bf215546Sopenharmony_ci
644bf215546Sopenharmony_ci	ta = (struct temporary_allocation*)memory_pool_malloc(&compiler->Base.Pool,
645bf215546Sopenharmony_ci			sizeof(struct temporary_allocation) * num_orig_temps);
646bf215546Sopenharmony_ci	memset(ta, 0, sizeof(struct temporary_allocation) * num_orig_temps);
647bf215546Sopenharmony_ci
648bf215546Sopenharmony_ci	/* Pass 2: Determine original temporary lifetimes */
649bf215546Sopenharmony_ci	for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) {
650bf215546Sopenharmony_ci		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
651bf215546Sopenharmony_ci		/* Instructions inside of loops need to use the ENDLOOP
652bf215546Sopenharmony_ci		 * instruction as their LastRead. */
653bf215546Sopenharmony_ci		if (!end_loop && inst->U.I.Opcode == RC_OPCODE_BGNLOOP)
654bf215546Sopenharmony_ci			end_loop = rc_match_bgnloop(inst);
655bf215546Sopenharmony_ci
656bf215546Sopenharmony_ci		if (inst == end_loop) {
657bf215546Sopenharmony_ci			end_loop = NULL;
658bf215546Sopenharmony_ci			continue;
659bf215546Sopenharmony_ci		}
660bf215546Sopenharmony_ci
661bf215546Sopenharmony_ci		for (i = 0; i < opcode->NumSrcRegs; ++i) {
662bf215546Sopenharmony_ci			if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) {
663bf215546Sopenharmony_ci				ta[inst->U.I.SrcReg[i].Index].LastRead = end_loop ? end_loop : inst;
664bf215546Sopenharmony_ci			}
665bf215546Sopenharmony_ci		}
666bf215546Sopenharmony_ci	}
667bf215546Sopenharmony_ci
668bf215546Sopenharmony_ci	/* Pass 3: Register allocation */
669bf215546Sopenharmony_ci	for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) {
670bf215546Sopenharmony_ci		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
671bf215546Sopenharmony_ci
672bf215546Sopenharmony_ci		for (i = 0; i < opcode->NumSrcRegs; ++i) {
673bf215546Sopenharmony_ci			if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) {
674bf215546Sopenharmony_ci				unsigned int orig = inst->U.I.SrcReg[i].Index;
675bf215546Sopenharmony_ci				inst->U.I.SrcReg[i].Index = get_reg(c, ta, hwtemps, orig);
676bf215546Sopenharmony_ci
677bf215546Sopenharmony_ci				if (ta[orig].Allocated && inst == ta[orig].LastRead)
678bf215546Sopenharmony_ci					hwtemps[ta[orig].HwTemp] = false;
679bf215546Sopenharmony_ci			}
680bf215546Sopenharmony_ci		}
681bf215546Sopenharmony_ci
682bf215546Sopenharmony_ci		if (opcode->HasDstReg) {
683bf215546Sopenharmony_ci			if (inst->U.I.DstReg.File == RC_FILE_TEMPORARY) {
684bf215546Sopenharmony_ci				unsigned int orig = inst->U.I.DstReg.Index;
685bf215546Sopenharmony_ci				inst->U.I.DstReg.Index = get_reg(c, ta, hwtemps, orig);
686bf215546Sopenharmony_ci			}
687bf215546Sopenharmony_ci		}
688bf215546Sopenharmony_ci	}
689bf215546Sopenharmony_ci}
690bf215546Sopenharmony_ci
691bf215546Sopenharmony_ci/**
692bf215546Sopenharmony_ci * R3xx-R4xx vertex engine does not support the Absolute source operand modifier
693bf215546Sopenharmony_ci * and the Saturate opcode modifier. Only Absolute is currently transformed.
694bf215546Sopenharmony_ci */
695bf215546Sopenharmony_cistatic int transform_nonnative_modifiers(
696bf215546Sopenharmony_ci	struct radeon_compiler *c,
697bf215546Sopenharmony_ci	struct rc_instruction *inst,
698bf215546Sopenharmony_ci	void* unused)
699bf215546Sopenharmony_ci{
700bf215546Sopenharmony_ci	const struct rc_opcode_info *opcode = rc_get_opcode_info(inst->U.I.Opcode);
701bf215546Sopenharmony_ci	unsigned i;
702bf215546Sopenharmony_ci
703bf215546Sopenharmony_ci	/* Transform ABS(a) to MAX(a, -a). */
704bf215546Sopenharmony_ci	for (i = 0; i < opcode->NumSrcRegs; i++) {
705bf215546Sopenharmony_ci		if (inst->U.I.SrcReg[i].Abs) {
706bf215546Sopenharmony_ci			struct rc_instruction *new_inst;
707bf215546Sopenharmony_ci			unsigned temp;
708bf215546Sopenharmony_ci
709bf215546Sopenharmony_ci			inst->U.I.SrcReg[i].Abs = 0;
710bf215546Sopenharmony_ci
711bf215546Sopenharmony_ci			temp = rc_find_free_temporary(c);
712bf215546Sopenharmony_ci
713bf215546Sopenharmony_ci			new_inst = rc_insert_new_instruction(c, inst->Prev);
714bf215546Sopenharmony_ci			new_inst->U.I.Opcode = RC_OPCODE_MAX;
715bf215546Sopenharmony_ci			new_inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
716bf215546Sopenharmony_ci			new_inst->U.I.DstReg.Index = temp;
717bf215546Sopenharmony_ci			new_inst->U.I.SrcReg[0] = inst->U.I.SrcReg[i];
718bf215546Sopenharmony_ci			new_inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
719bf215546Sopenharmony_ci			new_inst->U.I.SrcReg[1] = inst->U.I.SrcReg[i];
720bf215546Sopenharmony_ci			new_inst->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZW;
721bf215546Sopenharmony_ci			new_inst->U.I.SrcReg[1].Negate ^= RC_MASK_XYZW;
722bf215546Sopenharmony_ci
723bf215546Sopenharmony_ci			inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY;
724bf215546Sopenharmony_ci			inst->U.I.SrcReg[i].Index = temp;
725bf215546Sopenharmony_ci			inst->U.I.SrcReg[i].RelAddr = 0;
726bf215546Sopenharmony_ci		}
727bf215546Sopenharmony_ci	}
728bf215546Sopenharmony_ci	return 1;
729bf215546Sopenharmony_ci}
730bf215546Sopenharmony_ci
731bf215546Sopenharmony_ci/**
732bf215546Sopenharmony_ci * Vertex engine cannot read two inputs or two constants at the same time.
733bf215546Sopenharmony_ci * Introduce intermediate MOVs to temporary registers to account for this.
734bf215546Sopenharmony_ci */
735bf215546Sopenharmony_cistatic int transform_source_conflicts(
736bf215546Sopenharmony_ci	struct radeon_compiler *c,
737bf215546Sopenharmony_ci	struct rc_instruction* inst,
738bf215546Sopenharmony_ci	void* unused)
739bf215546Sopenharmony_ci{
740bf215546Sopenharmony_ci	const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
741bf215546Sopenharmony_ci
742bf215546Sopenharmony_ci	if (opcode->NumSrcRegs == 3) {
743bf215546Sopenharmony_ci		if (t_src_conflict(inst->U.I.SrcReg[1], inst->U.I.SrcReg[2])
744bf215546Sopenharmony_ci		    || t_src_conflict(inst->U.I.SrcReg[0], inst->U.I.SrcReg[2])) {
745bf215546Sopenharmony_ci			int tmpreg = rc_find_free_temporary(c);
746bf215546Sopenharmony_ci			struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev);
747bf215546Sopenharmony_ci			inst_mov->U.I.Opcode = RC_OPCODE_MOV;
748bf215546Sopenharmony_ci			inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
749bf215546Sopenharmony_ci			inst_mov->U.I.DstReg.Index = tmpreg;
750bf215546Sopenharmony_ci			inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[2];
751bf215546Sopenharmony_ci			inst_mov->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
752bf215546Sopenharmony_ci			inst_mov->U.I.SrcReg[0].Negate = 0;
753bf215546Sopenharmony_ci			inst_mov->U.I.SrcReg[0].Abs = 0;
754bf215546Sopenharmony_ci
755bf215546Sopenharmony_ci			inst->U.I.SrcReg[2].File = RC_FILE_TEMPORARY;
756bf215546Sopenharmony_ci			inst->U.I.SrcReg[2].Index = tmpreg;
757bf215546Sopenharmony_ci			inst->U.I.SrcReg[2].RelAddr = false;
758bf215546Sopenharmony_ci		}
759bf215546Sopenharmony_ci	}
760bf215546Sopenharmony_ci
761bf215546Sopenharmony_ci	if (opcode->NumSrcRegs >= 2) {
762bf215546Sopenharmony_ci		if (t_src_conflict(inst->U.I.SrcReg[1], inst->U.I.SrcReg[0])) {
763bf215546Sopenharmony_ci			int tmpreg = rc_find_free_temporary(c);
764bf215546Sopenharmony_ci			struct rc_instruction * inst_mov = rc_insert_new_instruction(c, inst->Prev);
765bf215546Sopenharmony_ci			inst_mov->U.I.Opcode = RC_OPCODE_MOV;
766bf215546Sopenharmony_ci			inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
767bf215546Sopenharmony_ci			inst_mov->U.I.DstReg.Index = tmpreg;
768bf215546Sopenharmony_ci			inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[1];
769bf215546Sopenharmony_ci			inst_mov->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
770bf215546Sopenharmony_ci			inst_mov->U.I.SrcReg[0].Negate = 0;
771bf215546Sopenharmony_ci			inst_mov->U.I.SrcReg[0].Abs = 0;
772bf215546Sopenharmony_ci
773bf215546Sopenharmony_ci			inst->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
774bf215546Sopenharmony_ci			inst->U.I.SrcReg[1].Index = tmpreg;
775bf215546Sopenharmony_ci			inst->U.I.SrcReg[1].RelAddr = false;
776bf215546Sopenharmony_ci		}
777bf215546Sopenharmony_ci	}
778bf215546Sopenharmony_ci
779bf215546Sopenharmony_ci	return 1;
780bf215546Sopenharmony_ci}
781bf215546Sopenharmony_ci
782bf215546Sopenharmony_cistatic void rc_vs_add_artificial_outputs(struct radeon_compiler *c, void *user)
783bf215546Sopenharmony_ci{
784bf215546Sopenharmony_ci	struct r300_vertex_program_compiler * compiler = (struct r300_vertex_program_compiler*)c;
785bf215546Sopenharmony_ci	int i;
786bf215546Sopenharmony_ci
787bf215546Sopenharmony_ci	for(i = 0; i < 32; ++i) {
788bf215546Sopenharmony_ci		if ((compiler->RequiredOutputs & (1U << i)) &&
789bf215546Sopenharmony_ci		    !(compiler->Base.Program.OutputsWritten & (1U << i))) {
790bf215546Sopenharmony_ci			struct rc_instruction * inst = rc_insert_new_instruction(&compiler->Base, compiler->Base.Program.Instructions.Prev);
791bf215546Sopenharmony_ci			inst->U.I.Opcode = RC_OPCODE_MOV;
792bf215546Sopenharmony_ci
793bf215546Sopenharmony_ci			inst->U.I.DstReg.File = RC_FILE_OUTPUT;
794bf215546Sopenharmony_ci			inst->U.I.DstReg.Index = i;
795bf215546Sopenharmony_ci			inst->U.I.DstReg.WriteMask = RC_MASK_XYZW;
796bf215546Sopenharmony_ci
797bf215546Sopenharmony_ci			inst->U.I.SrcReg[0].File = RC_FILE_CONSTANT;
798bf215546Sopenharmony_ci			inst->U.I.SrcReg[0].Index = 0;
799bf215546Sopenharmony_ci			inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
800bf215546Sopenharmony_ci
801bf215546Sopenharmony_ci			compiler->Base.Program.OutputsWritten |= 1U << i;
802bf215546Sopenharmony_ci		}
803bf215546Sopenharmony_ci	}
804bf215546Sopenharmony_ci}
805bf215546Sopenharmony_ci
806bf215546Sopenharmony_cistatic int swizzle_is_native(rc_opcode opcode, struct rc_src_register reg)
807bf215546Sopenharmony_ci{
808bf215546Sopenharmony_ci	(void) opcode;
809bf215546Sopenharmony_ci	(void) reg;
810bf215546Sopenharmony_ci
811bf215546Sopenharmony_ci	return 1;
812bf215546Sopenharmony_ci}
813bf215546Sopenharmony_ci
814bf215546Sopenharmony_cistatic void transform_negative_addressing(struct r300_vertex_program_compiler *c,
815bf215546Sopenharmony_ci					  struct rc_instruction *arl,
816bf215546Sopenharmony_ci					  struct rc_instruction *end,
817bf215546Sopenharmony_ci					  int min_offset)
818bf215546Sopenharmony_ci{
819bf215546Sopenharmony_ci	struct rc_instruction *inst, *add;
820bf215546Sopenharmony_ci	unsigned const_swizzle;
821bf215546Sopenharmony_ci
822bf215546Sopenharmony_ci	/* Transform ARL/ARR */
823bf215546Sopenharmony_ci	add = rc_insert_new_instruction(&c->Base, arl->Prev);
824bf215546Sopenharmony_ci	add->U.I.Opcode = RC_OPCODE_ADD;
825bf215546Sopenharmony_ci	add->U.I.DstReg.File = RC_FILE_TEMPORARY;
826bf215546Sopenharmony_ci	add->U.I.DstReg.Index = rc_find_free_temporary(&c->Base);
827bf215546Sopenharmony_ci	add->U.I.DstReg.WriteMask = RC_MASK_X;
828bf215546Sopenharmony_ci	add->U.I.SrcReg[0] = arl->U.I.SrcReg[0];
829bf215546Sopenharmony_ci	add->U.I.SrcReg[1].File = RC_FILE_CONSTANT;
830bf215546Sopenharmony_ci	add->U.I.SrcReg[1].Index = rc_constants_add_immediate_scalar(&c->Base.Program.Constants,
831bf215546Sopenharmony_ci								     min_offset, &const_swizzle);
832bf215546Sopenharmony_ci	add->U.I.SrcReg[1].Swizzle = const_swizzle;
833bf215546Sopenharmony_ci
834bf215546Sopenharmony_ci	arl->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
835bf215546Sopenharmony_ci	arl->U.I.SrcReg[0].Index = add->U.I.DstReg.Index;
836bf215546Sopenharmony_ci	arl->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XXXX;
837bf215546Sopenharmony_ci
838bf215546Sopenharmony_ci	/* Rewrite offsets up to and excluding inst. */
839bf215546Sopenharmony_ci	for (inst = arl->Next; inst != end; inst = inst->Next) {
840bf215546Sopenharmony_ci		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
841bf215546Sopenharmony_ci
842bf215546Sopenharmony_ci		for (unsigned i = 0; i < opcode->NumSrcRegs; i++)
843bf215546Sopenharmony_ci			if (inst->U.I.SrcReg[i].RelAddr)
844bf215546Sopenharmony_ci				inst->U.I.SrcReg[i].Index -= min_offset;
845bf215546Sopenharmony_ci	}
846bf215546Sopenharmony_ci}
847bf215546Sopenharmony_ci
848bf215546Sopenharmony_cistatic void rc_emulate_negative_addressing(struct radeon_compiler *compiler, void *user)
849bf215546Sopenharmony_ci{
850bf215546Sopenharmony_ci	struct r300_vertex_program_compiler * c = (struct r300_vertex_program_compiler*)compiler;
851bf215546Sopenharmony_ci	struct rc_instruction *inst, *lastARL = NULL;
852bf215546Sopenharmony_ci	int min_offset = 0;
853bf215546Sopenharmony_ci
854bf215546Sopenharmony_ci	for (inst = c->Base.Program.Instructions.Next; inst != &c->Base.Program.Instructions; inst = inst->Next) {
855bf215546Sopenharmony_ci		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
856bf215546Sopenharmony_ci
857bf215546Sopenharmony_ci		if (inst->U.I.Opcode == RC_OPCODE_ARL || inst->U.I.Opcode == RC_OPCODE_ARR) {
858bf215546Sopenharmony_ci			if (lastARL != NULL && min_offset < 0)
859bf215546Sopenharmony_ci				transform_negative_addressing(c, lastARL, inst, min_offset);
860bf215546Sopenharmony_ci
861bf215546Sopenharmony_ci			lastARL = inst;
862bf215546Sopenharmony_ci			min_offset = 0;
863bf215546Sopenharmony_ci			continue;
864bf215546Sopenharmony_ci		}
865bf215546Sopenharmony_ci
866bf215546Sopenharmony_ci		for (unsigned i = 0; i < opcode->NumSrcRegs; i++) {
867bf215546Sopenharmony_ci			if (inst->U.I.SrcReg[i].RelAddr &&
868bf215546Sopenharmony_ci			    inst->U.I.SrcReg[i].Index < 0) {
869bf215546Sopenharmony_ci				/* ARL must precede any indirect addressing. */
870bf215546Sopenharmony_ci				if (!lastARL) {
871bf215546Sopenharmony_ci					rc_error(&c->Base, "Vertex shader: Found relative addressing without ARL/ARR.");
872bf215546Sopenharmony_ci					return;
873bf215546Sopenharmony_ci				}
874bf215546Sopenharmony_ci
875bf215546Sopenharmony_ci				if (inst->U.I.SrcReg[i].Index < min_offset)
876bf215546Sopenharmony_ci					min_offset = inst->U.I.SrcReg[i].Index;
877bf215546Sopenharmony_ci			}
878bf215546Sopenharmony_ci		}
879bf215546Sopenharmony_ci	}
880bf215546Sopenharmony_ci
881bf215546Sopenharmony_ci	if (lastARL != NULL && min_offset < 0)
882bf215546Sopenharmony_ci		transform_negative_addressing(c, lastARL, inst, min_offset);
883bf215546Sopenharmony_ci}
884bf215546Sopenharmony_ci
885bf215546Sopenharmony_ciconst struct rc_swizzle_caps r300_vertprog_swizzle_caps = {
886bf215546Sopenharmony_ci	.IsNative = &swizzle_is_native,
887bf215546Sopenharmony_ci	.Split = NULL /* should never be called */
888bf215546Sopenharmony_ci};
889bf215546Sopenharmony_ci
890bf215546Sopenharmony_civoid r3xx_compile_vertex_program(struct r300_vertex_program_compiler *c)
891bf215546Sopenharmony_ci{
892bf215546Sopenharmony_ci	int is_r500 = c->Base.is_r500;
893bf215546Sopenharmony_ci	int opt = !c->Base.disable_optimizations;
894bf215546Sopenharmony_ci
895bf215546Sopenharmony_ci	/* Lists of instruction transformations. */
896bf215546Sopenharmony_ci	struct radeon_program_transformation alu_rewrite_r500[] = {
897bf215546Sopenharmony_ci		{ &r300_transform_vertex_alu, NULL },
898bf215546Sopenharmony_ci		{ &r300_transform_trig_scale_vertex, NULL },
899bf215546Sopenharmony_ci		{ NULL, NULL }
900bf215546Sopenharmony_ci	};
901bf215546Sopenharmony_ci
902bf215546Sopenharmony_ci	struct radeon_program_transformation alu_rewrite_r300[] = {
903bf215546Sopenharmony_ci		{ &r300_transform_vertex_alu, NULL },
904bf215546Sopenharmony_ci		{ &r300_transform_trig_simple, NULL },
905bf215546Sopenharmony_ci		{ NULL, NULL }
906bf215546Sopenharmony_ci	};
907bf215546Sopenharmony_ci
908bf215546Sopenharmony_ci	/* Note: These passes have to be done seperately from ALU rewrite,
909bf215546Sopenharmony_ci	 * otherwise non-native ALU instructions with source conflits
910bf215546Sopenharmony_ci	 * or non-native modifiers will not be treated properly.
911bf215546Sopenharmony_ci	 */
912bf215546Sopenharmony_ci	struct radeon_program_transformation emulate_modifiers[] = {
913bf215546Sopenharmony_ci		{ &transform_nonnative_modifiers, NULL },
914bf215546Sopenharmony_ci		{ NULL, NULL }
915bf215546Sopenharmony_ci	};
916bf215546Sopenharmony_ci
917bf215546Sopenharmony_ci	struct radeon_program_transformation resolve_src_conflicts[] = {
918bf215546Sopenharmony_ci		{ &transform_source_conflicts, NULL },
919bf215546Sopenharmony_ci		{ NULL, NULL }
920bf215546Sopenharmony_ci	};
921bf215546Sopenharmony_ci
922bf215546Sopenharmony_ci	/* List of compiler passes. */
923bf215546Sopenharmony_ci	struct radeon_compiler_pass vs_list[] = {
924bf215546Sopenharmony_ci		/* NAME				DUMP PREDICATE	FUNCTION			PARAM */
925bf215546Sopenharmony_ci		{"add artificial outputs",	0, 1,		rc_vs_add_artificial_outputs,	NULL},
926bf215546Sopenharmony_ci		{"emulate branches",		1, !is_r500,	rc_emulate_branches,		NULL},
927bf215546Sopenharmony_ci		{"emulate negative addressing", 1, 1,		rc_emulate_negative_addressing,	NULL},
928bf215546Sopenharmony_ci		{"native rewrite",		1, is_r500,	rc_local_transform,		alu_rewrite_r500},
929bf215546Sopenharmony_ci		{"native rewrite",		1, !is_r500,	rc_local_transform,		alu_rewrite_r300},
930bf215546Sopenharmony_ci		{"emulate modifiers",		1, !is_r500,	rc_local_transform,		emulate_modifiers},
931bf215546Sopenharmony_ci		{"deadcode",			1, opt,		rc_dataflow_deadcode,		NULL},
932bf215546Sopenharmony_ci		{"dataflow optimize",		1, opt,		rc_optimize,			NULL},
933bf215546Sopenharmony_ci		/* This pass must be done after optimizations. */
934bf215546Sopenharmony_ci		{"source conflict resolve",	1, 1,		rc_local_transform,		resolve_src_conflicts},
935bf215546Sopenharmony_ci		{"register allocation",		1, opt,		allocate_temporary_registers,	NULL},
936bf215546Sopenharmony_ci		{"dead constants",		1, 1,		rc_remove_unused_constants,	&c->code->constants_remap_table},
937bf215546Sopenharmony_ci		{"lower control flow opcodes",	1, is_r500,	rc_vert_fc,			NULL},
938bf215546Sopenharmony_ci		{"final code validation",	0, 1,		rc_validate_final_shader,	NULL},
939bf215546Sopenharmony_ci		{"machine code generation",	0, 1,		translate_vertex_program,	NULL},
940bf215546Sopenharmony_ci		{"dump machine code",		0, c->Base.Debug & RC_DBG_LOG, r300_vertex_program_dump,	NULL},
941bf215546Sopenharmony_ci		{NULL, 0, 0, NULL, NULL}
942bf215546Sopenharmony_ci	};
943bf215546Sopenharmony_ci
944bf215546Sopenharmony_ci	c->Base.type = RC_VERTEX_PROGRAM;
945bf215546Sopenharmony_ci	c->Base.SwizzleCaps = &r300_vertprog_swizzle_caps;
946bf215546Sopenharmony_ci
947bf215546Sopenharmony_ci	rc_run_compiler(&c->Base, vs_list);
948bf215546Sopenharmony_ci
949bf215546Sopenharmony_ci	c->code->InputsRead = c->Base.Program.InputsRead;
950bf215546Sopenharmony_ci	c->code->OutputsWritten = c->Base.Program.OutputsWritten;
951bf215546Sopenharmony_ci	rc_constants_copy(&c->code->constants, &c->Base.Program.Constants);
952bf215546Sopenharmony_ci}
953