• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22 
23 #include "radeon_compiler.h"
24 
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 
29 #include "radeon_dataflow.h"
30 #include "radeon_program.h"
31 #include "radeon_program_pair.h"
32 #include "radeon_regalloc.h"
33 #include "radeon_compiler_util.h"
34 
35 
rc_init(struct radeon_compiler * c,const struct rc_regalloc_state * rs)36 void rc_init(struct radeon_compiler * c, const struct rc_regalloc_state *rs)
37 {
38 	memset(c, 0, sizeof(*c));
39 
40 	memory_pool_init(&c->Pool);
41 	c->Program.Instructions.Prev = &c->Program.Instructions;
42 	c->Program.Instructions.Next = &c->Program.Instructions;
43 	c->Program.Instructions.U.I.Opcode = RC_OPCODE_ILLEGAL_OPCODE;
44 	c->regalloc_state = rs;
45 }
46 
rc_destroy(struct radeon_compiler * c)47 void rc_destroy(struct radeon_compiler * c)
48 {
49 	rc_constants_destroy(&c->Program.Constants);
50 	memory_pool_destroy(&c->Pool);
51 	free(c->ErrorMsg);
52 }
53 
rc_debug(struct radeon_compiler * c,const char * fmt,...)54 void rc_debug(struct radeon_compiler * c, const char * fmt, ...)
55 {
56 	va_list ap;
57 
58 	if (!(c->Debug & RC_DBG_LOG))
59 		return;
60 
61 	va_start(ap, fmt);
62 	vfprintf(stderr, fmt, ap);
63 	va_end(ap);
64 }
65 
rc_error(struct radeon_compiler * c,const char * fmt,...)66 void rc_error(struct radeon_compiler * c, const char * fmt, ...)
67 {
68 	va_list ap;
69 
70 	c->Error = 1;
71 
72 	if (!c->ErrorMsg) {
73 		/* Only remember the first error */
74 		char buf[1024];
75 		int written;
76 
77 		va_start(ap, fmt);
78 		written = vsnprintf(buf, sizeof(buf), fmt, ap);
79 		va_end(ap);
80 
81 		if (written < sizeof(buf)) {
82 			c->ErrorMsg = strdup(buf);
83 		} else {
84 			c->ErrorMsg = malloc(written + 1);
85 
86 			va_start(ap, fmt);
87 			vsnprintf(c->ErrorMsg, written + 1, fmt, ap);
88 			va_end(ap);
89 		}
90 	}
91 
92 	if (c->Debug & RC_DBG_LOG) {
93 		fprintf(stderr, "r300compiler error: ");
94 
95 		va_start(ap, fmt);
96 		vfprintf(stderr, fmt, ap);
97 		va_end(ap);
98 	}
99 }
100 
rc_if_fail_helper(struct radeon_compiler * c,const char * file,int line,const char * assertion)101 int rc_if_fail_helper(struct radeon_compiler * c, const char * file, int line, const char * assertion)
102 {
103 	rc_error(c, "ICE at %s:%i: assertion failed: %s\n", file, line, assertion);
104 	return 1;
105 }
106 
107 /**
108  * Recompute c->Program.InputsRead and c->Program.OutputsWritten
109  * based on which inputs and outputs are actually referenced
110  * in program instructions.
111  */
rc_calculate_inputs_outputs(struct radeon_compiler * c)112 void rc_calculate_inputs_outputs(struct radeon_compiler * c)
113 {
114 	struct rc_instruction *inst;
115 
116 	c->Program.InputsRead = 0;
117 	c->Program.OutputsWritten = 0;
118 
119 	for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next)
120 	{
121 		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
122 		int i;
123 
124 		for (i = 0; i < opcode->NumSrcRegs; ++i) {
125 			if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT)
126 				c->Program.InputsRead |= 1U << inst->U.I.SrcReg[i].Index;
127 		}
128 
129 		if (opcode->HasDstReg) {
130 			if (inst->U.I.DstReg.File == RC_FILE_OUTPUT)
131 				c->Program.OutputsWritten |= 1U << inst->U.I.DstReg.Index;
132 		}
133 	}
134 }
135 
136 /**
137  * Rewrite the program such that everything that source the given input
138  * register will source new_input instead.
139  */
rc_move_input(struct radeon_compiler * c,unsigned input,struct rc_src_register new_input)140 void rc_move_input(struct radeon_compiler * c, unsigned input, struct rc_src_register new_input)
141 {
142 	struct rc_instruction * inst;
143 
144 	c->Program.InputsRead &= ~(1U << input);
145 
146 	for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) {
147 		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
148 		unsigned i;
149 
150 		for(i = 0; i < opcode->NumSrcRegs; ++i) {
151 			if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT && inst->U.I.SrcReg[i].Index == input) {
152 				inst->U.I.SrcReg[i].File = new_input.File;
153 				inst->U.I.SrcReg[i].Index = new_input.Index;
154 				inst->U.I.SrcReg[i].Swizzle = combine_swizzles(new_input.Swizzle, inst->U.I.SrcReg[i].Swizzle);
155 				if (!inst->U.I.SrcReg[i].Abs) {
156 					inst->U.I.SrcReg[i].Negate ^= new_input.Negate;
157 					inst->U.I.SrcReg[i].Abs = new_input.Abs;
158 				}
159 
160 				c->Program.InputsRead |= 1U << new_input.Index;
161 			}
162 		}
163 	}
164 }
165 
166 
167 /**
168  * Rewrite the program such that everything that writes into the given
169  * output register will instead write to new_output. The new_output
170  * writemask is honoured.
171  */
rc_move_output(struct radeon_compiler * c,unsigned output,unsigned new_output,unsigned writemask)172 void rc_move_output(struct radeon_compiler * c, unsigned output, unsigned new_output, unsigned writemask)
173 {
174 	struct rc_instruction * inst;
175 
176 	c->Program.OutputsWritten &= ~(1U << output);
177 
178 	for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) {
179 		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
180 
181 		if (opcode->HasDstReg) {
182 			if (inst->U.I.DstReg.File == RC_FILE_OUTPUT && inst->U.I.DstReg.Index == output) {
183 				inst->U.I.DstReg.Index = new_output;
184 				inst->U.I.DstReg.WriteMask &= writemask;
185 
186 				c->Program.OutputsWritten |= 1U << new_output;
187 			}
188 		}
189 	}
190 }
191 
192 
193 /**
194  * Rewrite the program such that a given output is duplicated.
195  */
rc_copy_output(struct radeon_compiler * c,unsigned output,unsigned dup_output)196 void rc_copy_output(struct radeon_compiler * c, unsigned output, unsigned dup_output)
197 {
198 	unsigned tempreg = rc_find_free_temporary(c);
199 	struct rc_instruction * inst;
200 
201 	for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) {
202 		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
203 
204 		if (opcode->HasDstReg) {
205 			if (inst->U.I.DstReg.File == RC_FILE_OUTPUT && inst->U.I.DstReg.Index == output) {
206 				inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
207 				inst->U.I.DstReg.Index = tempreg;
208 			}
209 		}
210 	}
211 
212 	inst = rc_insert_new_instruction(c, c->Program.Instructions.Prev);
213 	inst->U.I.Opcode = RC_OPCODE_MOV;
214 	inst->U.I.DstReg.File = RC_FILE_OUTPUT;
215 	inst->U.I.DstReg.Index = output;
216 
217 	inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
218 	inst->U.I.SrcReg[0].Index = tempreg;
219 	inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
220 
221 	inst = rc_insert_new_instruction(c, c->Program.Instructions.Prev);
222 	inst->U.I.Opcode = RC_OPCODE_MOV;
223 	inst->U.I.DstReg.File = RC_FILE_OUTPUT;
224 	inst->U.I.DstReg.Index = dup_output;
225 
226 	inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
227 	inst->U.I.SrcReg[0].Index = tempreg;
228 	inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
229 
230 	c->Program.OutputsWritten |= 1U << dup_output;
231 }
232 
233 
234 /**
235  * Introduce standard code fragment to deal with fragment.position.
236  */
rc_transform_fragment_wpos(struct radeon_compiler * c,unsigned wpos,unsigned new_input,int full_vtransform)237 void rc_transform_fragment_wpos(struct radeon_compiler * c, unsigned wpos, unsigned new_input,
238                                 int full_vtransform)
239 {
240 	unsigned tempregi = rc_find_free_temporary(c);
241 	struct rc_instruction * inst_rcp;
242 	struct rc_instruction * inst_mul;
243 	struct rc_instruction * inst_mad;
244 	struct rc_instruction * inst;
245 
246 	c->Program.InputsRead &= ~(1U << wpos);
247 	c->Program.InputsRead |= 1U << new_input;
248 
249 	/* perspective divide */
250 	inst_rcp = rc_insert_new_instruction(c, &c->Program.Instructions);
251 	inst_rcp->U.I.Opcode = RC_OPCODE_RCP;
252 
253 	inst_rcp->U.I.DstReg.File = RC_FILE_TEMPORARY;
254 	inst_rcp->U.I.DstReg.Index = tempregi;
255 	inst_rcp->U.I.DstReg.WriteMask = RC_MASK_W;
256 
257 	inst_rcp->U.I.SrcReg[0].File = RC_FILE_INPUT;
258 	inst_rcp->U.I.SrcReg[0].Index = new_input;
259 	inst_rcp->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_WWWW;
260 
261 	inst_mul = rc_insert_new_instruction(c, inst_rcp);
262 	inst_mul->U.I.Opcode = RC_OPCODE_MUL;
263 
264 	inst_mul->U.I.DstReg.File = RC_FILE_TEMPORARY;
265 	inst_mul->U.I.DstReg.Index = tempregi;
266 	inst_mul->U.I.DstReg.WriteMask = RC_MASK_XYZ;
267 
268 	inst_mul->U.I.SrcReg[0].File = RC_FILE_INPUT;
269 	inst_mul->U.I.SrcReg[0].Index = new_input;
270 
271 	inst_mul->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
272 	inst_mul->U.I.SrcReg[1].Index = tempregi;
273 	inst_mul->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_WWWW;
274 
275 	/* viewport transformation */
276 	inst_mad = rc_insert_new_instruction(c, inst_mul);
277 	inst_mad->U.I.Opcode = RC_OPCODE_MAD;
278 
279 	inst_mad->U.I.DstReg.File = RC_FILE_TEMPORARY;
280 	inst_mad->U.I.DstReg.Index = tempregi;
281 	inst_mad->U.I.DstReg.WriteMask = RC_MASK_XYZ;
282 
283 	inst_mad->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
284 	inst_mad->U.I.SrcReg[0].Index = tempregi;
285 	inst_mad->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZ0;
286 
287 	inst_mad->U.I.SrcReg[1].File = RC_FILE_CONSTANT;
288 	inst_mad->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XYZ0;
289 
290 	inst_mad->U.I.SrcReg[2].File = RC_FILE_CONSTANT;
291 	inst_mad->U.I.SrcReg[2].Swizzle = RC_SWIZZLE_XYZ0;
292 
293 	if (full_vtransform) {
294 		inst_mad->U.I.SrcReg[1].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_VIEWPORT_SCALE, 0);
295 		inst_mad->U.I.SrcReg[2].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_VIEWPORT_OFFSET, 0);
296 	} else {
297 		inst_mad->U.I.SrcReg[1].Index =
298 		inst_mad->U.I.SrcReg[2].Index = rc_constants_add_state(&c->Program.Constants, RC_STATE_R300_WINDOW_DIMENSION, 0);
299 	}
300 
301 	for (inst = inst_mad->Next; inst != &c->Program.Instructions; inst = inst->Next) {
302 		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
303 		unsigned i;
304 
305 		for(i = 0; i < opcode->NumSrcRegs; i++) {
306 			if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT &&
307 			    inst->U.I.SrcReg[i].Index == wpos) {
308 				inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY;
309 				inst->U.I.SrcReg[i].Index = tempregi;
310 			}
311 		}
312 	}
313 }
314 
315 
316 /**
317  * The FACE input in hardware contains 1 if it's a back face, 0 otherwise.
318  * Gallium and OpenGL define it the other way around.
319  *
320  * So let's just negate FACE at the beginning of the shader and rewrite the rest
321  * of the shader to read from the newly allocated temporary.
322  */
rc_transform_fragment_face(struct radeon_compiler * c,unsigned face)323 void rc_transform_fragment_face(struct radeon_compiler *c, unsigned face)
324 {
325 	unsigned tempregi = rc_find_free_temporary(c);
326 	struct rc_instruction *inst_add;
327 	struct rc_instruction *inst;
328 
329 	/* perspective divide */
330 	inst_add = rc_insert_new_instruction(c, &c->Program.Instructions);
331 	inst_add->U.I.Opcode = RC_OPCODE_ADD;
332 
333 	inst_add->U.I.DstReg.File = RC_FILE_TEMPORARY;
334 	inst_add->U.I.DstReg.Index = tempregi;
335 	inst_add->U.I.DstReg.WriteMask = RC_MASK_X;
336 
337 	inst_add->U.I.SrcReg[0].File = RC_FILE_NONE;
338 	inst_add->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_1111;
339 
340 	inst_add->U.I.SrcReg[1].File = RC_FILE_INPUT;
341 	inst_add->U.I.SrcReg[1].Index = face;
342 	inst_add->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_XXXX;
343 	inst_add->U.I.SrcReg[1].Negate = RC_MASK_XYZW;
344 
345 	for (inst = inst_add->Next; inst != &c->Program.Instructions; inst = inst->Next) {
346 		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
347 		unsigned i;
348 
349 		for(i = 0; i < opcode->NumSrcRegs; i++) {
350 			if (inst->U.I.SrcReg[i].File == RC_FILE_INPUT &&
351 			    inst->U.I.SrcReg[i].Index == face) {
352 				inst->U.I.SrcReg[i].File = RC_FILE_TEMPORARY;
353 				inst->U.I.SrcReg[i].Index = tempregi;
354 			}
355 		}
356 	}
357 }
358 
reg_count_callback(void * userdata,struct rc_instruction * inst,rc_register_file file,unsigned int index,unsigned int mask)359 static void reg_count_callback(void * userdata, struct rc_instruction * inst,
360 		rc_register_file file, unsigned int index, unsigned int mask)
361 {
362 	struct rc_program_stats *s = userdata;
363 	if (file == RC_FILE_TEMPORARY)
364 		(int)index > s->num_temp_regs ? s->num_temp_regs = index : 0;
365 	if (file == RC_FILE_INLINE)
366 		s->num_inline_literals++;
367 }
368 
rc_get_stats(struct radeon_compiler * c,struct rc_program_stats * s)369 void rc_get_stats(struct radeon_compiler *c, struct rc_program_stats *s)
370 {
371 	struct rc_instruction * tmp;
372 	memset(s, 0, sizeof(*s));
373 
374 	for(tmp = c->Program.Instructions.Next; tmp != &c->Program.Instructions;
375 							tmp = tmp->Next){
376 		const struct rc_opcode_info * info;
377 		rc_for_all_reads_mask(tmp, reg_count_callback, s);
378 		if (tmp->Type == RC_INSTRUCTION_NORMAL) {
379 			info = rc_get_opcode_info(tmp->U.I.Opcode);
380 			if (info->Opcode == RC_OPCODE_BEGIN_TEX)
381 				continue;
382 			if (tmp->U.I.PreSub.Opcode != RC_PRESUB_NONE)
383 				s->num_presub_ops++;
384 		} else {
385 			if (tmp->U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Used)
386 				s->num_presub_ops++;
387 			if (tmp->U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Used)
388 				s->num_presub_ops++;
389 			/* Assuming alpha will never be a flow control or
390 			 * a tex instruction. */
391 			if (tmp->U.P.Alpha.Opcode != RC_OPCODE_NOP)
392 				s->num_alpha_insts++;
393 			if (tmp->U.P.RGB.Opcode != RC_OPCODE_NOP)
394 				s->num_rgb_insts++;
395 			if (tmp->U.P.RGB.Omod != RC_OMOD_MUL_1 &&
396 				tmp->U.P.RGB.Omod != RC_OMOD_DISABLE) {
397 				s->num_omod_ops++;
398 			}
399 			if (tmp->U.P.Alpha.Omod != RC_OMOD_MUL_1 &&
400 				tmp->U.P.Alpha.Omod != RC_OMOD_DISABLE) {
401 				s->num_omod_ops++;
402 			}
403 			info = rc_get_opcode_info(tmp->U.P.RGB.Opcode);
404 		}
405 		if (info->IsFlowControl)
406 			s->num_fc_insts++;
407 		if (info->HasTexture)
408 			s->num_tex_insts++;
409 		s->num_insts++;
410 	}
411 	/* Increment here because the reg_count_callback store the max
412 	 * temporary reg index in s->nun_temp_regs. */
413 	s->num_temp_regs++;
414 }
415 
print_stats(struct radeon_compiler * c)416 static void print_stats(struct radeon_compiler * c)
417 {
418 	struct rc_program_stats s;
419 
420 	if (c->initial_num_insts <= 5)
421 		return;
422 
423 	rc_get_stats(c, &s);
424 
425 	switch (c->type) {
426 	case RC_VERTEX_PROGRAM:
427 		fprintf(stderr,"~~~~~~~~~ VERTEX PROGRAM ~~~~~~~~\n"
428 			       "~%4u Instructions\n"
429 			       "~%4u Flow Control Instructions\n"
430 			       "~%4u Temporary Registers\n"
431 			       "~~~~~~~~~~~~~~ END ~~~~~~~~~~~~~~\n",
432 			       s.num_insts, s.num_fc_insts, s.num_temp_regs);
433 		break;
434 
435 	case RC_FRAGMENT_PROGRAM:
436 		fprintf(stderr,"~~~~~~~~ FRAGMENT PROGRAM ~~~~~~~\n"
437 			       "~%4u Instructions\n"
438 			       "~%4u Vector Instructions (RGB)\n"
439 			       "~%4u Scalar Instructions (Alpha)\n"
440 			       "~%4u Flow Control Instructions\n"
441 			       "~%4u Texture Instructions\n"
442 			       "~%4u Presub Operations\n"
443 			       "~%4u OMOD Operations\n"
444 			       "~%4u Temporary Registers\n"
445 			       "~%4u Inline Literals\n"
446 			       "~~~~~~~~~~~~~~ END ~~~~~~~~~~~~~~\n",
447 			       s.num_insts, s.num_rgb_insts, s.num_alpha_insts,
448 			       s.num_fc_insts, s.num_tex_insts, s.num_presub_ops,
449 			       s.num_omod_ops, s.num_temp_regs, s.num_inline_literals);
450 		break;
451 	default:
452 		assert(0);
453 	}
454 }
455 
456 static const char *shader_name[RC_NUM_PROGRAM_TYPES] = {
457 	"Vertex Program",
458 	"Fragment Program"
459 };
460 
rc_run_compiler_passes(struct radeon_compiler * c,struct radeon_compiler_pass * list)461 void rc_run_compiler_passes(struct radeon_compiler *c, struct radeon_compiler_pass *list)
462 {
463 	for (unsigned i = 0; list[i].name; i++) {
464 		if (list[i].predicate) {
465 			list[i].run(c, list[i].user);
466 
467 			if (c->Error)
468 				return;
469 
470 			if ((c->Debug & RC_DBG_LOG) && list[i].dump) {
471 				fprintf(stderr, "%s: after '%s'\n", shader_name[c->type], list[i].name);
472 				rc_print_program(&c->Program);
473 			}
474 		}
475 	}
476 }
477 
478 /* Executes a list of compiler passes given in the parameter 'list'. */
rc_run_compiler(struct radeon_compiler * c,struct radeon_compiler_pass * list)479 void rc_run_compiler(struct radeon_compiler *c, struct radeon_compiler_pass *list)
480 {
481 	struct rc_program_stats s;
482 
483 	rc_get_stats(c, &s);
484 	c->initial_num_insts = s.num_insts;
485 
486 	if (c->Debug & RC_DBG_LOG) {
487 		fprintf(stderr, "%s: before compilation\n", shader_name[c->type]);
488 		rc_print_program(&c->Program);
489 	}
490 
491 	rc_run_compiler_passes(c, list);
492 
493 	if (c->Debug & RC_DBG_STATS)
494 		print_stats(c);
495 }
496 
rc_validate_final_shader(struct radeon_compiler * c,void * user)497 void rc_validate_final_shader(struct radeon_compiler *c, void *user)
498 {
499 	/* Check the number of constants. */
500 	if (c->Program.Constants.Count > c->max_constants) {
501 		rc_error(c, "Too many constants. Max: %i, Got: %i\n",
502 			 c->max_constants, c->Program.Constants.Count);
503 	}
504 }
505