r300/compiler: move util functions to radeon_compiler_util
[mesa.git] / src / mesa / drivers / dri / r300 / compiler / r500_fragprog.c
1 /*
2 * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com>
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28 #include "r500_fragprog.h"
29
30 #include <stdio.h>
31
32 #include "radeon_compiler_util.h"
33 #include "../r300_reg.h"
34
35 /**
36 * Rewrite IF instructions to use the ALU result special register.
37 */
38 int r500_transform_IF(
39 struct radeon_compiler * c,
40 struct rc_instruction * inst,
41 void* data)
42 {
43 struct rc_instruction * inst_mov;
44
45 if (inst->U.I.Opcode != RC_OPCODE_IF)
46 return 0;
47
48 inst_mov = rc_insert_new_instruction(c, inst->Prev);
49 inst_mov->U.I.Opcode = RC_OPCODE_MOV;
50 inst_mov->U.I.DstReg.WriteMask = 0;
51 inst_mov->U.I.WriteALUResult = RC_ALURESULT_W;
52 inst_mov->U.I.ALUResultCompare = RC_COMPARE_FUNC_NOTEQUAL;
53 inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
54 inst_mov->U.I.SrcReg[0].Swizzle = combine_swizzles4(inst_mov->U.I.SrcReg[0].Swizzle,
55 RC_SWIZZLE_UNUSED, RC_SWIZZLE_UNUSED, RC_SWIZZLE_UNUSED, RC_SWIZZLE_X);
56
57 inst->U.I.SrcReg[0].File = RC_FILE_SPECIAL;
58 inst->U.I.SrcReg[0].Index = RC_SPECIAL_ALU_RESULT;
59 inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_XYZW;
60 inst->U.I.SrcReg[0].Negate = 0;
61
62 return 1;
63 }
64
65 static int r500_swizzle_is_native(rc_opcode opcode, struct rc_src_register reg)
66 {
67 unsigned int relevant;
68 int i;
69
70 if (opcode == RC_OPCODE_TEX ||
71 opcode == RC_OPCODE_TXB ||
72 opcode == RC_OPCODE_TXP ||
73 opcode == RC_OPCODE_KIL) {
74 if (reg.Abs)
75 return 0;
76
77 if (opcode == RC_OPCODE_KIL && (reg.Swizzle != RC_SWIZZLE_XYZW || reg.Negate != RC_MASK_NONE))
78 return 0;
79
80 if (reg.Negate)
81 reg.Negate ^= RC_MASK_XYZW;
82
83 for(i = 0; i < 4; ++i) {
84 unsigned int swz = GET_SWZ(reg.Swizzle, i);
85 if (swz == RC_SWIZZLE_UNUSED) {
86 reg.Negate &= ~(1 << i);
87 continue;
88 }
89 if (swz >= 4)
90 return 0;
91 }
92
93 if (reg.Negate)
94 return 0;
95
96 return 1;
97 } else if (opcode == RC_OPCODE_DDX || opcode == RC_OPCODE_DDY) {
98 /* DDX/MDH and DDY/MDV explicitly ignore incoming swizzles;
99 * if it doesn't fit perfectly into a .xyzw case... */
100 if (reg.Swizzle == RC_SWIZZLE_XYZW && !reg.Abs && !reg.Negate)
101 return 1;
102
103 return 0;
104 } else {
105 /* ALU instructions support almost everything */
106 if (reg.Abs)
107 return 1;
108
109 relevant = 0;
110 for(i = 0; i < 3; ++i) {
111 unsigned int swz = GET_SWZ(reg.Swizzle, i);
112 if (swz != RC_SWIZZLE_UNUSED && swz != RC_SWIZZLE_ZERO)
113 relevant |= 1 << i;
114 }
115 if ((reg.Negate & relevant) && ((reg.Negate & relevant) != relevant))
116 return 0;
117
118 return 1;
119 }
120 }
121
122 /**
123 * Split source register access.
124 *
125 * The only thing we *cannot* do in an ALU instruction is per-component
126 * negation.
127 */
128 static void r500_swizzle_split(struct rc_src_register src, unsigned int usemask,
129 struct rc_swizzle_split * split)
130 {
131 unsigned int negatebase[2] = { 0, 0 };
132 int i;
133
134 for(i = 0; i < 4; ++i) {
135 unsigned int swz = GET_SWZ(src.Swizzle, i);
136 if (swz == RC_SWIZZLE_UNUSED || !GET_BIT(usemask, i))
137 continue;
138 negatebase[GET_BIT(src.Negate, i)] |= 1 << i;
139 }
140
141 split->NumPhases = 0;
142
143 for(i = 0; i <= 1; ++i) {
144 if (!negatebase[i])
145 continue;
146
147 split->Phase[split->NumPhases++] = negatebase[i];
148 }
149 }
150
151 struct rc_swizzle_caps r500_swizzle_caps = {
152 .IsNative = r500_swizzle_is_native,
153 .Split = r500_swizzle_split
154 };
155
156 static char *toswiz(int swiz_val) {
157 switch(swiz_val) {
158 case 0: return "R";
159 case 1: return "G";
160 case 2: return "B";
161 case 3: return "A";
162 case 4: return "0";
163 case 5: return "H";
164 case 6: return "1";
165 case 7: return "U";
166 }
167 return NULL;
168 }
169
170 static char *toop(int op_val)
171 {
172 char *str = NULL;
173 switch (op_val) {
174 case 0: str = "MAD"; break;
175 case 1: str = "DP3"; break;
176 case 2: str = "DP4"; break;
177 case 3: str = "D2A"; break;
178 case 4: str = "MIN"; break;
179 case 5: str = "MAX"; break;
180 case 6: str = "Reserved"; break;
181 case 7: str = "CND"; break;
182 case 8: str = "CMP"; break;
183 case 9: str = "FRC"; break;
184 case 10: str = "SOP"; break;
185 case 11: str = "MDH"; break;
186 case 12: str = "MDV"; break;
187 }
188 return str;
189 }
190
191 static char *to_alpha_op(int op_val)
192 {
193 char *str = NULL;
194 switch (op_val) {
195 case 0: str = "MAD"; break;
196 case 1: str = "DP"; break;
197 case 2: str = "MIN"; break;
198 case 3: str = "MAX"; break;
199 case 4: str = "Reserved"; break;
200 case 5: str = "CND"; break;
201 case 6: str = "CMP"; break;
202 case 7: str = "FRC"; break;
203 case 8: str = "EX2"; break;
204 case 9: str = "LN2"; break;
205 case 10: str = "RCP"; break;
206 case 11: str = "RSQ"; break;
207 case 12: str = "SIN"; break;
208 case 13: str = "COS"; break;
209 case 14: str = "MDH"; break;
210 case 15: str = "MDV"; break;
211 }
212 return str;
213 }
214
215 static char *to_mask(int val)
216 {
217 char *str = NULL;
218 switch(val) {
219 case 0: str = "NONE"; break;
220 case 1: str = "R"; break;
221 case 2: str = "G"; break;
222 case 3: str = "RG"; break;
223 case 4: str = "B"; break;
224 case 5: str = "RB"; break;
225 case 6: str = "GB"; break;
226 case 7: str = "RGB"; break;
227 case 8: str = "A"; break;
228 case 9: str = "AR"; break;
229 case 10: str = "AG"; break;
230 case 11: str = "ARG"; break;
231 case 12: str = "AB"; break;
232 case 13: str = "ARB"; break;
233 case 14: str = "AGB"; break;
234 case 15: str = "ARGB"; break;
235 }
236 return str;
237 }
238
239 static char *to_texop(int val)
240 {
241 switch(val) {
242 case 0: return "NOP";
243 case 1: return "LD";
244 case 2: return "TEXKILL";
245 case 3: return "PROJ";
246 case 4: return "LODBIAS";
247 case 5: return "LOD";
248 case 6: return "DXDY";
249 }
250 return NULL;
251 }
252
253 void r500FragmentProgramDump(struct radeon_compiler *c, void *user)
254 {
255 struct r300_fragment_program_compiler *compiler = (struct r300_fragment_program_compiler*)c;
256 struct r500_fragment_program_code *code = &compiler->code->code.r500;
257 int n, i;
258 uint32_t inst;
259 uint32_t inst0;
260 char *str = NULL;
261 fprintf(stderr, "R500 Fragment Program:\n--------\n");
262
263 for (n = 0; n < code->inst_end+1; n++) {
264 inst0 = inst = code->inst[n].inst0;
265 fprintf(stderr,"%d\t0:CMN_INST 0x%08x:", n, inst);
266 switch(inst & 0x3) {
267 case R500_INST_TYPE_ALU: str = "ALU"; break;
268 case R500_INST_TYPE_OUT: str = "OUT"; break;
269 case R500_INST_TYPE_FC: str = "FC"; break;
270 case R500_INST_TYPE_TEX: str = "TEX"; break;
271 };
272 fprintf(stderr,"%s %s %s %s %s ", str,
273 inst & R500_INST_TEX_SEM_WAIT ? "TEX_WAIT" : "",
274 inst & R500_INST_LAST ? "LAST" : "",
275 inst & R500_INST_NOP ? "NOP" : "",
276 inst & R500_INST_ALU_WAIT ? "ALU WAIT" : "");
277 fprintf(stderr,"wmask: %s omask: %s\n", to_mask((inst >> 11) & 0xf),
278 to_mask((inst >> 15) & 0xf));
279
280 switch(inst0 & 0x3) {
281 case R500_INST_TYPE_ALU:
282 case R500_INST_TYPE_OUT:
283 fprintf(stderr,"\t1:RGB_ADDR 0x%08x:", code->inst[n].inst1);
284 inst = code->inst[n].inst1;
285
286 fprintf(stderr,"Addr0: %d%c, Addr1: %d%c, Addr2: %d%c, srcp:%d\n",
287 inst & 0xff, (inst & (1<<8)) ? 'c' : 't',
288 (inst >> 10) & 0xff, (inst & (1<<18)) ? 'c' : 't',
289 (inst >> 20) & 0xff, (inst & (1<<28)) ? 'c' : 't',
290 (inst >> 30));
291
292 fprintf(stderr,"\t2:ALPHA_ADDR 0x%08x:", code->inst[n].inst2);
293 inst = code->inst[n].inst2;
294 fprintf(stderr,"Addr0: %d%c, Addr1: %d%c, Addr2: %d%c, srcp:%d\n",
295 inst & 0xff, (inst & (1<<8)) ? 'c' : 't',
296 (inst >> 10) & 0xff, (inst & (1<<18)) ? 'c' : 't',
297 (inst >> 20) & 0xff, (inst & (1<<28)) ? 'c' : 't',
298 (inst >> 30));
299 fprintf(stderr,"\t3 RGB_INST: 0x%08x:", code->inst[n].inst3);
300 inst = code->inst[n].inst3;
301 fprintf(stderr,"rgb_A_src:%d %s/%s/%s %d rgb_B_src:%d %s/%s/%s %d targ: %d\n",
302 (inst) & 0x3, toswiz((inst >> 2) & 0x7), toswiz((inst >> 5) & 0x7), toswiz((inst >> 8) & 0x7),
303 (inst >> 11) & 0x3,
304 (inst >> 13) & 0x3, toswiz((inst >> 15) & 0x7), toswiz((inst >> 18) & 0x7), toswiz((inst >> 21) & 0x7),
305 (inst >> 24) & 0x3, (inst >> 29) & 0x3);
306
307
308 fprintf(stderr,"\t4 ALPHA_INST:0x%08x:", code->inst[n].inst4);
309 inst = code->inst[n].inst4;
310 fprintf(stderr,"%s dest:%d%s alp_A_src:%d %s %d alp_B_src:%d %s %d targ %d w:%d\n", to_alpha_op(inst & 0xf),
311 (inst >> 4) & 0x7f, inst & (1<<11) ? "(rel)":"",
312 (inst >> 12) & 0x3, toswiz((inst >> 14) & 0x7), (inst >> 17) & 0x3,
313 (inst >> 19) & 0x3, toswiz((inst >> 21) & 0x7), (inst >> 24) & 0x3,
314 (inst >> 29) & 0x3,
315 (inst >> 31) & 0x1);
316
317 fprintf(stderr,"\t5 RGBA_INST: 0x%08x:", code->inst[n].inst5);
318 inst = code->inst[n].inst5;
319 fprintf(stderr,"%s dest:%d%s rgb_C_src:%d %s/%s/%s %d alp_C_src:%d %s %d\n", toop(inst & 0xf),
320 (inst >> 4) & 0x7f, inst & (1<<11) ? "(rel)":"",
321 (inst >> 12) & 0x3, toswiz((inst >> 14) & 0x7), toswiz((inst >> 17) & 0x7), toswiz((inst >> 20) & 0x7),
322 (inst >> 23) & 0x3,
323 (inst >> 25) & 0x3, toswiz((inst >> 27) & 0x7), (inst >> 30) & 0x3);
324 break;
325 case R500_INST_TYPE_FC:
326 fprintf(stderr, "\t2:FC_INST 0x%08x:", code->inst[n].inst2);
327 inst = code->inst[n].inst2;
328 /* JUMP_FUNC JUMP_ANY*/
329 fprintf(stderr, "0x%02x %1x ", inst >> 8 & 0xff,
330 (inst & R500_FC_JUMP_ANY) >> 5);
331
332 /* OP */
333 switch(inst & 0x7){
334 case R500_FC_OP_JUMP:
335 fprintf(stderr, "JUMP");
336 break;
337 case R500_FC_OP_LOOP:
338 fprintf(stderr, "LOOP");
339 break;
340 case R500_FC_OP_ENDLOOP:
341 fprintf(stderr, "ENDLOOP");
342 break;
343 case R500_FC_OP_REP:
344 fprintf(stderr, "REP");
345 break;
346 case R500_FC_OP_ENDREP:
347 fprintf(stderr, "ENDREP");
348 break;
349 case R500_FC_OP_BREAKLOOP:
350 fprintf(stderr, "BREAKLOOP");
351 break;
352 case R500_FC_OP_BREAKREP:
353 fprintf(stderr, "BREAKREP");
354 break;
355 case R500_FC_OP_CONTINUE:
356 fprintf(stderr, "CONTINUE");
357 break;
358 }
359 fprintf(stderr," ");
360 /* A_OP */
361 switch(inst & (0x3 << 6)){
362 case R500_FC_A_OP_NONE:
363 fprintf(stderr, "NONE");
364 break;
365 case R500_FC_A_OP_POP:
366 fprintf(stderr, "POP");
367 break;
368 case R500_FC_A_OP_PUSH:
369 fprintf(stderr, "PUSH");
370 break;
371 }
372 /* B_OP0 B_OP1 */
373 for(i=0; i<2; i++){
374 fprintf(stderr, " ");
375 switch(inst & (0x3 << (24 + (i * 2)))){
376 /* R500_FC_B_OP0_NONE
377 * R500_FC_B_OP1_NONE */
378 case 0:
379 fprintf(stderr, "NONE");
380 break;
381 case R500_FC_B_OP0_DECR:
382 case R500_FC_B_OP1_DECR:
383 fprintf(stderr, "DECR");
384 break;
385 case R500_FC_B_OP0_INCR:
386 case R500_FC_B_OP1_INCR:
387 fprintf(stderr, "INCR");
388 break;
389 }
390 }
391 /*POP_CNT B_ELSE */
392 fprintf(stderr, " %d %1x", (inst >> 16) & 0x1f, (inst & R500_FC_B_ELSE) >> 4);
393 inst = code->inst[n].inst3;
394 /* JUMP_ADDR */
395 fprintf(stderr, " %d", inst >> 16);
396
397 if(code->inst[n].inst2 & R500_FC_IGNORE_UNCOVERED){
398 fprintf(stderr, " IGN_UNC");
399 }
400 inst = code->inst[n].inst3;
401 fprintf(stderr, "\n\t3:FC_ADDR 0x%08x:", inst);
402 fprintf(stderr, "BOOL: 0x%02x, INT: 0x%02x, JUMP_ADDR: %d, JMP_GLBL: %1x\n",
403 inst & 0x1f, (inst >> 8) & 0x1f, (inst >> 16) & 0x1ff, inst >> 31);
404 break;
405 case R500_INST_TYPE_TEX:
406 inst = code->inst[n].inst1;
407 fprintf(stderr,"\t1:TEX_INST: 0x%08x: id: %d op:%s, %s, %s %s\n", inst, (inst >> 16) & 0xf,
408 to_texop((inst >> 22) & 0x7), (inst & (1<<25)) ? "ACQ" : "",
409 (inst & (1<<26)) ? "IGNUNC" : "", (inst & (1<<27)) ? "UNSCALED" : "SCALED");
410 inst = code->inst[n].inst2;
411 fprintf(stderr,"\t2:TEX_ADDR: 0x%08x: src: %d%s %s/%s/%s/%s dst: %d%s %s/%s/%s/%s\n", inst,
412 inst & 127, inst & (1<<7) ? "(rel)" : "",
413 toswiz((inst >> 8) & 0x3), toswiz((inst >> 10) & 0x3),
414 toswiz((inst >> 12) & 0x3), toswiz((inst >> 14) & 0x3),
415 (inst >> 16) & 127, inst & (1<<23) ? "(rel)" : "",
416 toswiz((inst >> 24) & 0x3), toswiz((inst >> 26) & 0x3),
417 toswiz((inst >> 28) & 0x3), toswiz((inst >> 30) & 0x3));
418
419 fprintf(stderr,"\t3:TEX_DXDY: 0x%08x\n", code->inst[n].inst3);
420 break;
421 }
422 fprintf(stderr,"\n");
423 }
424
425 }