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 <stdarg.h>
26bf215546Sopenharmony_ci#include <stdio.h>
27bf215546Sopenharmony_ci#include <stdlib.h>
28bf215546Sopenharmony_ci#include <string.h>
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "util/u_debug.h"
31bf215546Sopenharmony_ci#include "pipe/p_state.h"
32bf215546Sopenharmony_ci#include "radeon_dataflow.h"
33bf215546Sopenharmony_ci#include "radeon_program.h"
34bf215546Sopenharmony_ci#include "radeon_program_pair.h"
35bf215546Sopenharmony_ci#include "radeon_regalloc.h"
36bf215546Sopenharmony_ci#include "radeon_compiler_util.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_civoid rc_init(struct radeon_compiler * c, const struct rc_regalloc_state *rs)
40bf215546Sopenharmony_ci{
41bf215546Sopenharmony_ci	memset(c, 0, sizeof(*c));
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci	memory_pool_init(&c->Pool);
44bf215546Sopenharmony_ci	c->Program.Instructions.Prev = &c->Program.Instructions;
45bf215546Sopenharmony_ci	c->Program.Instructions.Next = &c->Program.Instructions;
46bf215546Sopenharmony_ci	c->Program.Instructions.U.I.Opcode = RC_OPCODE_ILLEGAL_OPCODE;
47bf215546Sopenharmony_ci	c->regalloc_state = rs;
48bf215546Sopenharmony_ci}
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_civoid rc_destroy(struct radeon_compiler * c)
51bf215546Sopenharmony_ci{
52bf215546Sopenharmony_ci	rc_constants_destroy(&c->Program.Constants);
53bf215546Sopenharmony_ci	memory_pool_destroy(&c->Pool);
54bf215546Sopenharmony_ci	free(c->ErrorMsg);
55bf215546Sopenharmony_ci}
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_civoid rc_debug(struct radeon_compiler * c, const char * fmt, ...)
58bf215546Sopenharmony_ci{
59bf215546Sopenharmony_ci	va_list ap;
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci	if (!(c->Debug & RC_DBG_LOG))
62bf215546Sopenharmony_ci		return;
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci	va_start(ap, fmt);
65bf215546Sopenharmony_ci	vfprintf(stderr, fmt, ap);
66bf215546Sopenharmony_ci	va_end(ap);
67bf215546Sopenharmony_ci}
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_civoid rc_error(struct radeon_compiler * c, const char * fmt, ...)
70bf215546Sopenharmony_ci{
71bf215546Sopenharmony_ci	va_list ap;
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_ci	c->Error = 1;
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci	if (!c->ErrorMsg) {
76bf215546Sopenharmony_ci		/* Only remember the first error */
77bf215546Sopenharmony_ci		char buf[1024];
78bf215546Sopenharmony_ci		int written;
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci		va_start(ap, fmt);
81bf215546Sopenharmony_ci		written = vsnprintf(buf, sizeof(buf), fmt, ap);
82bf215546Sopenharmony_ci		va_end(ap);
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci		if (written < sizeof(buf)) {
85bf215546Sopenharmony_ci			c->ErrorMsg = strdup(buf);
86bf215546Sopenharmony_ci		} else {
87bf215546Sopenharmony_ci			c->ErrorMsg = malloc(written + 1);
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci			va_start(ap, fmt);
90bf215546Sopenharmony_ci			vsnprintf(c->ErrorMsg, written + 1, fmt, ap);
91bf215546Sopenharmony_ci			va_end(ap);
92bf215546Sopenharmony_ci		}
93bf215546Sopenharmony_ci	}
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci	if (c->Debug & RC_DBG_LOG) {
96bf215546Sopenharmony_ci		fprintf(stderr, "r300compiler error: ");
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci		va_start(ap, fmt);
99bf215546Sopenharmony_ci		vfprintf(stderr, fmt, ap);
100bf215546Sopenharmony_ci		va_end(ap);
101bf215546Sopenharmony_ci	}
102bf215546Sopenharmony_ci}
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ciint rc_if_fail_helper(struct radeon_compiler * c, const char * file, int line, const char * assertion)
105bf215546Sopenharmony_ci{
106bf215546Sopenharmony_ci	rc_error(c, "ICE at %s:%i: assertion failed: %s\n", file, line, assertion);
107bf215546Sopenharmony_ci	return 1;
108bf215546Sopenharmony_ci}
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci/**
111bf215546Sopenharmony_ci * Recompute c->Program.InputsRead and c->Program.OutputsWritten
112bf215546Sopenharmony_ci * based on which inputs and outputs are actually referenced
113bf215546Sopenharmony_ci * in program instructions.
114bf215546Sopenharmony_ci */
115bf215546Sopenharmony_civoid rc_calculate_inputs_outputs(struct radeon_compiler * c)
116bf215546Sopenharmony_ci{
117bf215546Sopenharmony_ci	struct rc_instruction *inst;
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci	c->Program.InputsRead = 0;
120bf215546Sopenharmony_ci	c->Program.OutputsWritten = 0;
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci	for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next)
123bf215546Sopenharmony_ci	{
124bf215546Sopenharmony_ci		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
125bf215546Sopenharmony_ci		int i;
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci		for (i = 0; i < opcode->NumSrcRegs; ++i) {
128bf215546Sopenharmony_ci			if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT)
129bf215546Sopenharmony_ci				c->Program.InputsRead |= 1U << inst->U.I.SrcReg[i].Index;
130bf215546Sopenharmony_ci		}
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci		if (opcode->HasDstReg) {
133bf215546Sopenharmony_ci			if (inst->U.I.DstReg.File == RC_FILE_OUTPUT)
134bf215546Sopenharmony_ci				c->Program.OutputsWritten |= 1U << inst->U.I.DstReg.Index;
135bf215546Sopenharmony_ci		}
136bf215546Sopenharmony_ci	}
137bf215546Sopenharmony_ci}
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci/**
140bf215546Sopenharmony_ci * Rewrite the program such that a given output is duplicated.
141bf215546Sopenharmony_ci */
142bf215546Sopenharmony_civoid rc_copy_output(struct radeon_compiler * c, unsigned output, unsigned dup_output)
143bf215546Sopenharmony_ci{
144bf215546Sopenharmony_ci	unsigned tempreg = rc_find_free_temporary(c);
145bf215546Sopenharmony_ci	struct rc_instruction * inst;
146bf215546Sopenharmony_ci	struct rc_instruction * insert_pos = c->Program.Instructions.Prev;
147bf215546Sopenharmony_ci	struct rc_instruction * last_write_inst = NULL;
148bf215546Sopenharmony_ci	unsigned branch_depth = 0;
149bf215546Sopenharmony_ci	unsigned loop_depth = 0;
150bf215546Sopenharmony_ci	bool emit_after_control_flow = false;
151bf215546Sopenharmony_ci	unsigned num_writes = 0;
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci	for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) {
154bf215546Sopenharmony_ci		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci		if (inst->U.I.Opcode == RC_OPCODE_BGNLOOP)
157bf215546Sopenharmony_ci			loop_depth++;
158bf215546Sopenharmony_ci		if (inst->U.I.Opcode == RC_OPCODE_IF)
159bf215546Sopenharmony_ci			branch_depth++;
160bf215546Sopenharmony_ci		if ((inst->U.I.Opcode == RC_OPCODE_ENDLOOP && loop_depth--) ||
161bf215546Sopenharmony_ci		    (inst->U.I.Opcode == RC_OPCODE_ENDIF && branch_depth--))
162bf215546Sopenharmony_ci			if (emit_after_control_flow && loop_depth == 0 && branch_depth == 0) {
163bf215546Sopenharmony_ci				insert_pos = inst;
164bf215546Sopenharmony_ci				emit_after_control_flow = false;
165bf215546Sopenharmony_ci			}
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci		if (opcode->HasDstReg) {
168bf215546Sopenharmony_ci			if (inst->U.I.DstReg.File == RC_FILE_OUTPUT && inst->U.I.DstReg.Index == output) {
169bf215546Sopenharmony_ci				num_writes++;
170bf215546Sopenharmony_ci				inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
171bf215546Sopenharmony_ci				inst->U.I.DstReg.Index = tempreg;
172bf215546Sopenharmony_ci				insert_pos = inst;
173bf215546Sopenharmony_ci				last_write_inst = inst;
174bf215546Sopenharmony_ci				if (loop_depth != 0 && branch_depth != 0)
175bf215546Sopenharmony_ci					emit_after_control_flow = true;
176bf215546Sopenharmony_ci			}
177bf215546Sopenharmony_ci		}
178bf215546Sopenharmony_ci	}
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci	/* If there is only a single write, just duplicate the whole instruction instead.
181bf215546Sopenharmony_ci	 * We can do this even when the single write was is a control flow.
182bf215546Sopenharmony_ci	 */
183bf215546Sopenharmony_ci	if (num_writes == 1) {
184bf215546Sopenharmony_ci		last_write_inst->U.I.DstReg.File = RC_FILE_OUTPUT;
185bf215546Sopenharmony_ci		last_write_inst->U.I.DstReg.Index = output;
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci		inst = rc_insert_new_instruction(c, last_write_inst);
188bf215546Sopenharmony_ci		struct rc_instruction * prev = inst->Prev;
189bf215546Sopenharmony_ci		struct rc_instruction * next = inst->Next;
190bf215546Sopenharmony_ci		memcpy(inst, last_write_inst, sizeof(struct rc_instruction));
191bf215546Sopenharmony_ci		inst->Prev = prev;
192bf215546Sopenharmony_ci		inst->Next = next;
193bf215546Sopenharmony_ci		inst->U.I.DstReg.Index = dup_output;
194bf215546Sopenharmony_ci	} else {
195bf215546Sopenharmony_ci		inst = rc_insert_new_instruction(c, insert_pos);
196bf215546Sopenharmony_ci		inst->U.I.Opcode = RC_OPCODE_MOV;
197bf215546Sopenharmony_ci		inst->U.I.DstReg.File = RC_FILE_OUTPUT;
198bf215546Sopenharmony_ci		inst->U.I.DstReg.Index = output;
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci		inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
201bf215546Sopenharmony_ci		inst->U.I.SrcReg[0].Index = tempreg;
202bf215546Sopenharmony_ci		inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci		inst = rc_insert_new_instruction(c, inst);
205bf215546Sopenharmony_ci		inst->U.I.Opcode = RC_OPCODE_MOV;
206bf215546Sopenharmony_ci		inst->U.I.DstReg.File = RC_FILE_OUTPUT;
207bf215546Sopenharmony_ci		inst->U.I.DstReg.Index = dup_output;
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_ci		inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
210bf215546Sopenharmony_ci		inst->U.I.SrcReg[0].Index = tempreg;
211bf215546Sopenharmony_ci		inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
212bf215546Sopenharmony_ci	}
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci	c->Program.OutputsWritten |= 1U << dup_output;
215bf215546Sopenharmony_ci}
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci/**
219bf215546Sopenharmony_ci * Introduce standard code fragment to deal with fragment.position.
220bf215546Sopenharmony_ci */
221bf215546Sopenharmony_civoid rc_transform_fragment_wpos(struct radeon_compiler * c, unsigned wpos, unsigned new_input,
222bf215546Sopenharmony_ci                                int full_vtransform)
223bf215546Sopenharmony_ci{
224bf215546Sopenharmony_ci	unsigned tempregi = rc_find_free_temporary(c);
225bf215546Sopenharmony_ci	struct rc_instruction * inst_rcp;
226bf215546Sopenharmony_ci	struct rc_instruction * inst_mul;
227bf215546Sopenharmony_ci	struct rc_instruction * inst_mad;
228bf215546Sopenharmony_ci	struct rc_instruction * inst;
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci	c->Program.InputsRead &= ~(1U << wpos);
231bf215546Sopenharmony_ci	c->Program.InputsRead |= 1U << new_input;
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci	/* perspective divide */
234bf215546Sopenharmony_ci	inst_rcp = rc_insert_new_instruction(c, &c->Program.Instructions);
235bf215546Sopenharmony_ci	inst_rcp->U.I.Opcode = RC_OPCODE_RCP;
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci	inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY;
238bf215546Sopenharmony_ci	inst_rcp->U.I.DstReg.Index = tempregi;
239bf215546Sopenharmony_ci	inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W;
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci	inst_rcp->U.I.SrcReg[0].File = RC_FILE_INPUT;
242bf215546Sopenharmony_ci	inst_rcp->U.I.SrcReg[0].Index = new_input;
243bf215546Sopenharmony_ci	inst_rcp->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_WWWW;
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci	inst_mul = rc_insert_new_instruction(c, inst_rcp);
246bf215546Sopenharmony_ci	inst_mul->U.I.Opcode = RC_OPCODE_MUL;
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci	inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
249bf215546Sopenharmony_ci	inst_mul->U.I.DstReg.Index = tempregi;
250bf215546Sopenharmony_ci	inst_mul->U.I.DstReg.WriteMask = RC_MASK_XYZ;
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci	inst_mul->U.I.SrcReg[0].File = RC_FILE_INPUT;
253bf215546Sopenharmony_ci	inst_mul->U.I.SrcReg[0].Index = new_input;
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci	inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
256bf215546Sopenharmony_ci	inst_mul->U.I.SrcReg[1].Index = tempregi;
257bf215546Sopenharmony_ci	inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW;
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci	/* viewport transformation */
260bf215546Sopenharmony_ci	inst_mad = rc_insert_new_instruction(c, inst_mul);
261bf215546Sopenharmony_ci	inst_mad->U.I.Opcode = RC_OPCODE_MAD;
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci	inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY;
264bf215546Sopenharmony_ci	inst_mad->U.I.DstReg.Index = tempregi;
265bf215546Sopenharmony_ci	inst_mad->U.I.DstReg.WriteMask = RC_MASK_XYZ;
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci	inst_mad->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
268bf215546Sopenharmony_ci	inst_mad->U.I.SrcReg[0].Index = tempregi;
269bf215546Sopenharmony_ci	inst_mad->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0;
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci	inst_mad->U.I.SrcReg[1].File = RC_FILE_CONSTANT;
272bf215546Sopenharmony_ci	inst_mad->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZ0;
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci	inst_mad->U.I.SrcReg[2].File = RC_FILE_CONSTANT;
275bf215546Sopenharmony_ci	inst_mad->U.I.SrcReg[2].Swizzle = RC_SWIZZLE_XYZ0;
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci	if (full_vtransform) {
278bf215546Sopenharmony_ci		inst_mad->U.I.SrcReg[1].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_VIEWPORT_SCALE, 0);
279bf215546Sopenharmony_ci		inst_mad->U.I.SrcReg[2].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_VIEWPORT_OFFSET, 0);
280bf215546Sopenharmony_ci	} else {
281bf215546Sopenharmony_ci		inst_mad->U.I.SrcReg[1].Index =
282bf215546Sopenharmony_ci		inst_mad->U.I.SrcReg[2].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_WINDOW_DIMENSION, 0);
283bf215546Sopenharmony_ci	}
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci	for (inst = inst_mad->Next; inst != &c->Program.Instructions; inst = inst->Next) {
286bf215546Sopenharmony_ci		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
287bf215546Sopenharmony_ci		unsigned i;
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci		for(i = 0; i < opcode->NumSrcRegs; i++) {
290bf215546Sopenharmony_ci			if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT &&
291bf215546Sopenharmony_ci			    inst->U.I.SrcReg[i].Index == wpos) {
292bf215546Sopenharmony_ci				inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY;
293bf215546Sopenharmony_ci				inst->U.I.SrcReg[i].Index = tempregi;
294bf215546Sopenharmony_ci			}
295bf215546Sopenharmony_ci		}
296bf215546Sopenharmony_ci	}
297bf215546Sopenharmony_ci}
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_ci/**
301bf215546Sopenharmony_ci * The FACE input in hardware contains 1 if it's a back face, 0 otherwise.
302bf215546Sopenharmony_ci * Gallium and OpenGL define it the other way around.
303bf215546Sopenharmony_ci *
304bf215546Sopenharmony_ci * So let's just negate FACE at the beginning of the shader and rewrite the rest
305bf215546Sopenharmony_ci * of the shader to read from the newly allocated temporary.
306bf215546Sopenharmony_ci */
307bf215546Sopenharmony_civoid rc_transform_fragment_face(struct radeon_compiler *c, unsigned face)
308bf215546Sopenharmony_ci{
309bf215546Sopenharmony_ci	unsigned tempregi = rc_find_free_temporary(c);
310bf215546Sopenharmony_ci	struct rc_instruction *inst_add;
311bf215546Sopenharmony_ci	struct rc_instruction *inst;
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci	/* perspective divide */
314bf215546Sopenharmony_ci	inst_add = rc_insert_new_instruction(c, &c->Program.Instructions);
315bf215546Sopenharmony_ci	inst_add->U.I.Opcode = RC_OPCODE_ADD;
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_ci	inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY;
318bf215546Sopenharmony_ci	inst_add->U.I.DstReg.Index = tempregi;
319bf215546Sopenharmony_ci	inst_add->U.I.DstReg.WriteMask = RC_MASK_X;
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci	inst_add->U.I.SrcReg[0].File = RC_FILE_NONE;
322bf215546Sopenharmony_ci	inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111;
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci	inst_add->U.I.SrcReg[1].File = RC_FILE_INPUT;
325bf215546Sopenharmony_ci	inst_add->U.I.SrcReg[1].Index = face;
326bf215546Sopenharmony_ci	inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XXXX;
327bf215546Sopenharmony_ci	inst_add->U.I.SrcReg[1].Negate = RC_MASK_XYZW;
328bf215546Sopenharmony_ci
329bf215546Sopenharmony_ci	for (inst = inst_add->Next; inst != &c->Program.Instructions; inst = inst->Next) {
330bf215546Sopenharmony_ci		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
331bf215546Sopenharmony_ci		unsigned i;
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci		for(i = 0; i < opcode->NumSrcRegs; i++) {
334bf215546Sopenharmony_ci			if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT &&
335bf215546Sopenharmony_ci			    inst->U.I.SrcReg[i].Index == face) {
336bf215546Sopenharmony_ci				inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY;
337bf215546Sopenharmony_ci				inst->U.I.SrcReg[i].Index = tempregi;
338bf215546Sopenharmony_ci			}
339bf215546Sopenharmony_ci		}
340bf215546Sopenharmony_ci	}
341bf215546Sopenharmony_ci}
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_cistatic void reg_count_callback(void * userdata, struct rc_instruction * inst,
344bf215546Sopenharmony_ci		rc_register_file file, unsigned int index, unsigned int mask)
345bf215546Sopenharmony_ci{
346bf215546Sopenharmony_ci	struct rc_program_stats *s = userdata;
347bf215546Sopenharmony_ci	if (file == RC_FILE_TEMPORARY)
348bf215546Sopenharmony_ci		(int)index > s->num_temp_regs ? s->num_temp_regs = index : 0;
349bf215546Sopenharmony_ci	if (file == RC_FILE_INLINE)
350bf215546Sopenharmony_ci		s->num_inline_literals++;
351bf215546Sopenharmony_ci	if (file == RC_FILE_CONSTANT)
352bf215546Sopenharmony_ci		s->num_consts = MAX2(s->num_consts, index + 1);
353bf215546Sopenharmony_ci}
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_civoid rc_get_stats(struct radeon_compiler *c, struct rc_program_stats *s)
356bf215546Sopenharmony_ci{
357bf215546Sopenharmony_ci	struct rc_instruction * tmp;
358bf215546Sopenharmony_ci	memset(s, 0, sizeof(*s));
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_ci	for(tmp = c->Program.Instructions.Next; tmp != &c->Program.Instructions;
361bf215546Sopenharmony_ci							tmp = tmp->Next){
362bf215546Sopenharmony_ci		const struct rc_opcode_info * info;
363bf215546Sopenharmony_ci		rc_for_all_reads_mask(tmp, reg_count_callback, s);
364bf215546Sopenharmony_ci		if (tmp->Type == RC_INSTRUCTION_NORMAL) {
365bf215546Sopenharmony_ci			info = rc_get_opcode_info(tmp->U.I.Opcode);
366bf215546Sopenharmony_ci			if (info->Opcode == RC_OPCODE_BEGIN_TEX)
367bf215546Sopenharmony_ci				continue;
368bf215546Sopenharmony_ci			if (tmp->U.I.PreSub.Opcode != RC_PRESUB_NONE)
369bf215546Sopenharmony_ci				s->num_presub_ops++;
370bf215546Sopenharmony_ci		} else {
371bf215546Sopenharmony_ci			if (tmp->U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Used)
372bf215546Sopenharmony_ci				s->num_presub_ops++;
373bf215546Sopenharmony_ci			if (tmp->U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Used)
374bf215546Sopenharmony_ci				s->num_presub_ops++;
375bf215546Sopenharmony_ci			/* Assuming alpha will never be a flow control or
376bf215546Sopenharmony_ci			 * a tex instruction. */
377bf215546Sopenharmony_ci			if (tmp->U.P.Alpha.Opcode != RC_OPCODE_NOP)
378bf215546Sopenharmony_ci				s->num_alpha_insts++;
379bf215546Sopenharmony_ci			if (tmp->U.P.RGB.Opcode != RC_OPCODE_NOP)
380bf215546Sopenharmony_ci				s->num_rgb_insts++;
381bf215546Sopenharmony_ci			if (tmp->U.P.RGB.Omod != RC_OMOD_MUL_1 &&
382bf215546Sopenharmony_ci				tmp->U.P.RGB.Omod != RC_OMOD_DISABLE) {
383bf215546Sopenharmony_ci				s->num_omod_ops++;
384bf215546Sopenharmony_ci			}
385bf215546Sopenharmony_ci			if (tmp->U.P.Alpha.Omod != RC_OMOD_MUL_1 &&
386bf215546Sopenharmony_ci				tmp->U.P.Alpha.Omod != RC_OMOD_DISABLE) {
387bf215546Sopenharmony_ci				s->num_omod_ops++;
388bf215546Sopenharmony_ci			}
389bf215546Sopenharmony_ci			info = rc_get_opcode_info(tmp->U.P.RGB.Opcode);
390bf215546Sopenharmony_ci		}
391bf215546Sopenharmony_ci		if (info->IsFlowControl) {
392bf215546Sopenharmony_ci			s->num_fc_insts++;
393bf215546Sopenharmony_ci			if (info->Opcode == RC_OPCODE_BGNLOOP)
394bf215546Sopenharmony_ci				s->num_loops++;
395bf215546Sopenharmony_ci		}
396bf215546Sopenharmony_ci		/* VS flow control was already translated to the predicate instructions */
397bf215546Sopenharmony_ci		if (c->type == RC_VERTEX_PROGRAM)
398bf215546Sopenharmony_ci			if (strstr(info->Name, "PRED") != NULL)
399bf215546Sopenharmony_ci				s->num_pred_insts++;
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_ci		if (info->HasTexture)
402bf215546Sopenharmony_ci			s->num_tex_insts++;
403bf215546Sopenharmony_ci		s->num_insts++;
404bf215546Sopenharmony_ci	}
405bf215546Sopenharmony_ci	/* Increment here because the reg_count_callback store the max
406bf215546Sopenharmony_ci	 * temporary reg index in s->nun_temp_regs. */
407bf215546Sopenharmony_ci	s->num_temp_regs++;
408bf215546Sopenharmony_ci}
409bf215546Sopenharmony_ci
410bf215546Sopenharmony_cistatic void print_stats(struct radeon_compiler * c)
411bf215546Sopenharmony_ci{
412bf215546Sopenharmony_ci	struct rc_program_stats s;
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci	rc_get_stats(c, &s);
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_ci	/* Note that we print some dummy values for instruction categories that
417bf215546Sopenharmony_ci	 * only the FS has, becasue shader-db's report.py wants all shaders to
418bf215546Sopenharmony_ci	 * have the same set.
419bf215546Sopenharmony_ci	 */
420bf215546Sopenharmony_ci	util_debug_message(c->debug, SHADER_INFO, "%s shader: %u inst, %u vinst, %u sinst, %u predicate, %u flowcontrol, %u loops, %u tex, %u presub, %u omod, %u temps, %u consts, %u lits",
421bf215546Sopenharmony_ci	                   c->type == RC_VERTEX_PROGRAM ? "VS" : "FS",
422bf215546Sopenharmony_ci	                   s.num_insts, s.num_rgb_insts, s.num_alpha_insts, s.num_pred_insts,
423bf215546Sopenharmony_ci	                   s.num_fc_insts, s.num_loops, s.num_tex_insts, s.num_presub_ops,
424bf215546Sopenharmony_ci	                   s.num_omod_ops, s.num_temp_regs, s.num_consts, s.num_inline_literals);
425bf215546Sopenharmony_ci}
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_cistatic const char *shader_name[RC_NUM_PROGRAM_TYPES] = {
428bf215546Sopenharmony_ci	"Vertex Program",
429bf215546Sopenharmony_ci	"Fragment Program"
430bf215546Sopenharmony_ci};
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_cibool rc_run_compiler_passes(struct radeon_compiler *c, struct radeon_compiler_pass *list)
433bf215546Sopenharmony_ci{
434bf215546Sopenharmony_ci	for (unsigned i = 0; list[i].name; i++) {
435bf215546Sopenharmony_ci		if (list[i].predicate) {
436bf215546Sopenharmony_ci			list[i].run(c, list[i].user);
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_ci			if (c->Error)
439bf215546Sopenharmony_ci				return false;
440bf215546Sopenharmony_ci
441bf215546Sopenharmony_ci			if ((c->Debug & RC_DBG_LOG) && list[i].dump) {
442bf215546Sopenharmony_ci				fprintf(stderr, "%s: after '%s'\n", shader_name[c->type], list[i].name);
443bf215546Sopenharmony_ci				rc_print_program(&c->Program);
444bf215546Sopenharmony_ci			}
445bf215546Sopenharmony_ci		}
446bf215546Sopenharmony_ci	}
447bf215546Sopenharmony_ci	return true;
448bf215546Sopenharmony_ci}
449bf215546Sopenharmony_ci
450bf215546Sopenharmony_ci/* Executes a list of compiler passes given in the parameter 'list'. */
451bf215546Sopenharmony_civoid rc_run_compiler(struct radeon_compiler *c, struct radeon_compiler_pass *list)
452bf215546Sopenharmony_ci{
453bf215546Sopenharmony_ci	if (c->Debug & RC_DBG_LOG) {
454bf215546Sopenharmony_ci		fprintf(stderr, "%s: before compilation\n", shader_name[c->type]);
455bf215546Sopenharmony_ci		rc_print_program(&c->Program);
456bf215546Sopenharmony_ci	}
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_ci	if(rc_run_compiler_passes(c, list)) {
459bf215546Sopenharmony_ci		print_stats(c);
460bf215546Sopenharmony_ci	}
461bf215546Sopenharmony_ci}
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_civoid rc_validate_final_shader(struct radeon_compiler *c, void *user)
464bf215546Sopenharmony_ci{
465bf215546Sopenharmony_ci	/* Check the number of constants. */
466bf215546Sopenharmony_ci	if (c->Program.Constants.Count > c->max_constants) {
467bf215546Sopenharmony_ci		rc_error(c, "Too many constants. Max: %i, Got: %i\n",
468bf215546Sopenharmony_ci			 c->max_constants, c->Program.Constants.Count);
469bf215546Sopenharmony_ci	}
470bf215546Sopenharmony_ci}
471