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