Merge branch 'llvm-cliptest-viewport'
[mesa.git] / src / mesa / drivers / dri / r300 / compiler / radeon_dataflow.c
1 /*
2 * Copyright (C) 2009 Nicolai Haehnle.
3 * Copyright 2010 Tom Stellard <tstellar@gmail.com>
4 *
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
23 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 */
28
29 #include "radeon_dataflow.h"
30
31 #include "radeon_compiler.h"
32 #include "radeon_compiler_util.h"
33 #include "radeon_program.h"
34
35 struct read_write_mask_data {
36 void * UserData;
37 rc_read_write_mask_fn Cb;
38 };
39
40 static void reads_normal_callback(
41 void * userdata,
42 struct rc_instruction * fullinst,
43 struct rc_src_register * src)
44 {
45 struct read_write_mask_data * cb_data = userdata;
46 unsigned int refmask = 0;
47 unsigned int chan;
48 for(chan = 0; chan < 4; chan++) {
49 refmask |= 1 << GET_SWZ(src->Swizzle, chan);
50 }
51 refmask &= RC_MASK_XYZW;
52
53 if (refmask) {
54 cb_data->Cb(cb_data->UserData, fullinst, src->File,
55 src->Index, refmask);
56 }
57
58 if (refmask && src->RelAddr) {
59 cb_data->Cb(cb_data->UserData, fullinst, RC_FILE_ADDRESS, 0,
60 RC_MASK_X);
61 }
62 }
63
64 static void pair_get_src_refmasks(unsigned int * refmasks,
65 struct rc_pair_instruction * inst,
66 unsigned int swz, unsigned int src)
67 {
68 if (swz >= 4)
69 return;
70
71 if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z) {
72 if(src == RC_PAIR_PRESUB_SRC) {
73 unsigned int i;
74 int srcp_regs =
75 rc_presubtract_src_reg_count(
76 inst->RGB.Src[src].Index);
77 for(i = 0; i < srcp_regs; i++) {
78 refmasks[i] |= 1 << swz;
79 }
80 }
81 else {
82 refmasks[src] |= 1 << swz;
83 }
84 }
85
86 if (swz == RC_SWIZZLE_W) {
87 if (src == RC_PAIR_PRESUB_SRC) {
88 unsigned int i;
89 int srcp_regs = rc_presubtract_src_reg_count(
90 inst->Alpha.Src[src].Index);
91 for(i = 0; i < srcp_regs; i++) {
92 refmasks[i] |= 1 << swz;
93 }
94 }
95 else {
96 refmasks[src] |= 1 << swz;
97 }
98 }
99 }
100
101 static void reads_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
102 {
103 struct rc_pair_instruction * inst = &fullinst->U.P;
104 unsigned int refmasks[3] = { 0, 0, 0 };
105
106 unsigned int arg;
107
108 for(arg = 0; arg < 3; ++arg) {
109 unsigned int chan;
110 for(chan = 0; chan < 3; ++chan) {
111 unsigned int swz_rgb =
112 GET_SWZ(inst->RGB.Arg[arg].Swizzle, chan);
113 unsigned int swz_alpha =
114 GET_SWZ(inst->Alpha.Arg[arg].Swizzle, chan);
115 pair_get_src_refmasks(refmasks, inst, swz_rgb,
116 inst->RGB.Arg[arg].Source);
117 pair_get_src_refmasks(refmasks, inst, swz_alpha,
118 inst->Alpha.Arg[arg].Source);
119 }
120 }
121
122 for(unsigned int src = 0; src < 3; ++src) {
123 if (inst->RGB.Src[src].Used && (refmasks[src] & RC_MASK_XYZ))
124 cb(userdata, fullinst, inst->RGB.Src[src].File, inst->RGB.Src[src].Index,
125 refmasks[src] & RC_MASK_XYZ);
126
127 if (inst->Alpha.Src[src].Used && (refmasks[src] & RC_MASK_W))
128 cb(userdata, fullinst, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, RC_MASK_W);
129 }
130 }
131
132 static void pair_sub_for_all_args(
133 struct rc_instruction * fullinst,
134 struct rc_pair_sub_instruction * sub,
135 rc_pair_read_arg_fn cb,
136 void * userdata)
137 {
138 int i;
139 const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
140
141 for(i = 0; i < info->NumSrcRegs; i++) {
142 cb(userdata, fullinst, &sub->Arg[i]);
143 }
144 }
145
146 /* This function calls the callback function (cb) for each source used by
147 * the instruction.
148 * */
149 void rc_for_all_reads_src(
150 struct rc_instruction * inst,
151 rc_read_src_fn cb,
152 void * userdata)
153 {
154 const struct rc_opcode_info * opcode =
155 rc_get_opcode_info(inst->U.I.Opcode);
156
157 /* This function only works with normal instructions. */
158 if (inst->Type != RC_INSTRUCTION_NORMAL) {
159 assert(0);
160 return;
161 }
162
163 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
164
165 if (inst->U.I.SrcReg[src].File == RC_FILE_NONE)
166 continue;
167
168 if (inst->U.I.SrcReg[src].File == RC_FILE_PRESUB) {
169 unsigned int i;
170 unsigned int srcp_regs = rc_presubtract_src_reg_count(
171 inst->U.I.PreSub.Opcode);
172 for( i = 0; i < srcp_regs; i++) {
173 cb(userdata, inst, &inst->U.I.PreSub.SrcReg[i]);
174 }
175 } else {
176 cb(userdata, inst, &inst->U.I.SrcReg[src]);
177 }
178 }
179 }
180
181 /**
182 * This function calls the callback function (cb) for each arg of the RGB and
183 * alpha components.
184 */
185 void rc_pair_for_all_reads_arg(
186 struct rc_instruction * inst,
187 rc_pair_read_arg_fn cb,
188 void * userdata)
189 {
190 /* This function only works with pair instructions. */
191 if (inst->Type != RC_INSTRUCTION_PAIR) {
192 assert(0);
193 return;
194 }
195
196 pair_sub_for_all_args(inst, &inst->U.P.RGB, cb, userdata);
197 pair_sub_for_all_args(inst, &inst->U.P.Alpha, cb, userdata);
198 }
199
200 /**
201 * Calls a callback function for all register reads.
202 *
203 * This is conservative, i.e. if the same register is referenced multiple times,
204 * the callback may also be called multiple times.
205 * Also, the writemask of the instruction is not taken into account.
206 */
207 void rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
208 {
209 if (inst->Type == RC_INSTRUCTION_NORMAL) {
210 struct read_write_mask_data cb_data;
211 cb_data.UserData = userdata;
212 cb_data.Cb = cb;
213
214 rc_for_all_reads_src(inst, reads_normal_callback, &cb_data);
215 } else {
216 reads_pair(inst, cb, userdata);
217 }
218 }
219
220
221
222 static void writes_normal(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
223 {
224 struct rc_sub_instruction * inst = &fullinst->U.I;
225 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
226
227 if (opcode->HasDstReg && inst->DstReg.WriteMask)
228 cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, inst->DstReg.WriteMask);
229
230 if (inst->WriteALUResult)
231 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
232 }
233
234 static void writes_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
235 {
236 struct rc_pair_instruction * inst = &fullinst->U.P;
237
238 if (inst->RGB.WriteMask)
239 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, inst->RGB.WriteMask);
240
241 if (inst->Alpha.WriteMask)
242 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, RC_MASK_W);
243
244 if (inst->WriteALUResult)
245 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
246 }
247
248 /**
249 * Calls a callback function for all register writes in the instruction,
250 * reporting writemasks to the callback function.
251 *
252 * \warning Does not report output registers for paired instructions!
253 */
254 void rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
255 {
256 if (inst->Type == RC_INSTRUCTION_NORMAL) {
257 writes_normal(inst, cb, userdata);
258 } else {
259 writes_pair(inst, cb, userdata);
260 }
261 }
262
263
264 struct mask_to_chan_data {
265 void * UserData;
266 rc_read_write_chan_fn Fn;
267 };
268
269 static void mask_to_chan_cb(void * data, struct rc_instruction * inst,
270 rc_register_file file, unsigned int index, unsigned int mask)
271 {
272 struct mask_to_chan_data * d = data;
273 for(unsigned int chan = 0; chan < 4; ++chan) {
274 if (GET_BIT(mask, chan))
275 d->Fn(d->UserData, inst, file, index, chan);
276 }
277 }
278
279 /**
280 * Calls a callback function for all sourced register channels.
281 *
282 * This is conservative, i.e. channels may be called multiple times,
283 * and the writemask of the instruction is not taken into account.
284 */
285 void rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
286 {
287 struct mask_to_chan_data d;
288 d.UserData = userdata;
289 d.Fn = cb;
290 rc_for_all_reads_mask(inst, &mask_to_chan_cb, &d);
291 }
292
293 /**
294 * Calls a callback function for all written register channels.
295 *
296 * \warning Does not report output registers for paired instructions!
297 */
298 void rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
299 {
300 struct mask_to_chan_data d;
301 d.UserData = userdata;
302 d.Fn = cb;
303 rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d);
304 }
305
306 static void remap_normal_instruction(struct rc_instruction * fullinst,
307 rc_remap_register_fn cb, void * userdata)
308 {
309 struct rc_sub_instruction * inst = &fullinst->U.I;
310 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
311
312 if (opcode->HasDstReg) {
313 rc_register_file file = inst->DstReg.File;
314 unsigned int index = inst->DstReg.Index;
315
316 cb(userdata, fullinst, &file, &index);
317
318 inst->DstReg.File = file;
319 inst->DstReg.Index = index;
320 }
321
322 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
323 rc_register_file file = inst->SrcReg[src].File;
324 unsigned int index = inst->SrcReg[src].Index;
325
326 if (file == RC_FILE_PRESUB) {
327 unsigned int i;
328 unsigned int srcp_srcs = rc_presubtract_src_reg_count(
329 inst->PreSub.Opcode);
330 for(i = 0; i < srcp_srcs; i++) {
331 file = inst->PreSub.SrcReg[i].File;
332 index = inst->PreSub.SrcReg[i].Index;
333 cb(userdata, fullinst, &file, &index);
334 inst->PreSub.SrcReg[i].File = file;
335 inst->PreSub.SrcReg[i].Index = index;
336 }
337
338 }
339 else {
340 cb(userdata, fullinst, &file, &index);
341
342 inst->SrcReg[src].File = file;
343 inst->SrcReg[src].Index = index;
344 }
345 }
346 }
347
348 static void remap_pair_instruction(struct rc_instruction * fullinst,
349 rc_remap_register_fn cb, void * userdata)
350 {
351 struct rc_pair_instruction * inst = &fullinst->U.P;
352
353 if (inst->RGB.WriteMask) {
354 rc_register_file file = RC_FILE_TEMPORARY;
355 unsigned int index = inst->RGB.DestIndex;
356
357 cb(userdata, fullinst, &file, &index);
358
359 inst->RGB.DestIndex = index;
360 }
361
362 if (inst->Alpha.WriteMask) {
363 rc_register_file file = RC_FILE_TEMPORARY;
364 unsigned int index = inst->Alpha.DestIndex;
365
366 cb(userdata, fullinst, &file, &index);
367
368 inst->Alpha.DestIndex = index;
369 }
370
371 for(unsigned int src = 0; src < 3; ++src) {
372 if (inst->RGB.Src[src].Used) {
373 rc_register_file file = inst->RGB.Src[src].File;
374 unsigned int index = inst->RGB.Src[src].Index;
375
376 cb(userdata, fullinst, &file, &index);
377
378 inst->RGB.Src[src].File = file;
379 inst->RGB.Src[src].Index = index;
380 }
381
382 if (inst->Alpha.Src[src].Used) {
383 rc_register_file file = inst->Alpha.Src[src].File;
384 unsigned int index = inst->Alpha.Src[src].Index;
385
386 cb(userdata, fullinst, &file, &index);
387
388 inst->Alpha.Src[src].File = file;
389 inst->Alpha.Src[src].Index = index;
390 }
391 }
392 }
393
394
395 /**
396 * Remap all register accesses according to the given function.
397 * That is, call the function \p cb for each referenced register (both read and written)
398 * and update the given instruction \p inst accordingly
399 * if it modifies its \ref pfile and \ref pindex contents.
400 */
401 void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata)
402 {
403 if (inst->Type == RC_INSTRUCTION_NORMAL)
404 remap_normal_instruction(inst, cb, userdata);
405 else
406 remap_pair_instruction(inst, cb, userdata);
407 }
408
409 /**
410 * @return RC_OPCODE_NOOP if inst is not a flow control instruction.
411 * @return The opcode of inst if it is a flow control instruction.
412 */
413 static rc_opcode get_flow_control_inst(struct rc_instruction * inst)
414 {
415 const struct rc_opcode_info * info;
416 if (inst->Type == RC_INSTRUCTION_NORMAL) {
417 info = rc_get_opcode_info(inst->U.I.Opcode);
418 } else {
419 info = rc_get_opcode_info(inst->U.P.RGB.Opcode);
420 /*A flow control instruction shouldn't have an alpha
421 * instruction.*/
422 assert(!info->IsFlowControl ||
423 inst->U.P.Alpha.Opcode == RC_OPCODE_NOP);
424 }
425
426 if (info->IsFlowControl)
427 return info->Opcode;
428 else
429 return RC_OPCODE_NOP;
430
431 }
432
433 struct get_readers_callback_data {
434 struct radeon_compiler * C;
435 struct rc_reader_data * ReaderData;
436 rc_read_src_fn ReadCB;
437 rc_read_write_mask_fn WriteCB;
438 unsigned int AliveWriteMask;
439 };
440
441 static void add_reader(
442 struct memory_pool * pool,
443 struct rc_reader_data * data,
444 struct rc_instruction * inst,
445 unsigned int mask,
446 struct rc_src_register * src)
447 {
448 struct rc_reader * new;
449 memory_pool_array_reserve(pool, struct rc_reader, data->Readers,
450 data->ReaderCount, data->ReadersReserved, 1);
451 new = &data->Readers[data->ReaderCount++];
452 new->Inst = inst;
453 new->WriteMask = mask;
454 new->Src = src;
455 }
456
457 /**
458 * This function is used by rc_get_readers_normal() to determine whether inst
459 * is a reader of userdata->ReaderData->Writer
460 */
461 static void get_readers_normal_read_callback(
462 void * userdata,
463 struct rc_instruction * inst,
464 struct rc_src_register * src)
465 {
466 struct get_readers_callback_data * d = userdata;
467 unsigned int read_mask;
468
469 if (src->RelAddr)
470 d->ReaderData->Abort = 1;
471
472 unsigned int shared_mask = rc_src_reads_dst_mask(src->File, src->Index,
473 src->Swizzle,
474 d->ReaderData->Writer->U.I.DstReg.File,
475 d->ReaderData->Writer->U.I.DstReg.Index,
476 d->AliveWriteMask);
477
478 if (shared_mask == RC_MASK_NONE)
479 return;
480
481 /* If we make it this far, it means that this source reads from the
482 * same register written to by d->ReaderData->Writer. */
483
484 if (d->ReaderData->AbortOnRead) {
485 d->ReaderData->Abort = 1;
486 return;
487 }
488
489 read_mask = rc_swizzle_to_writemask(src->Swizzle);
490 /* XXX The behavior in this case should be configurable. */
491 if ((read_mask & d->AliveWriteMask) != read_mask) {
492 d->ReaderData->Abort = 1;
493 return;
494 }
495
496 d->ReadCB(d->ReaderData, inst, src);
497 if (d->ReaderData->Abort)
498 return;
499
500 add_reader(&d->C->Pool, d->ReaderData, inst, shared_mask, src);
501 }
502
503 /**
504 * This function is used by rc_get_readers_normal() to determine when
505 * userdata->ReaderData->Writer is dead (i. e. All compontents of its
506 * destination register have been overwritten by other instructions).
507 */
508 static void get_readers_write_callback(
509 void *userdata,
510 struct rc_instruction * inst,
511 rc_register_file file,
512 unsigned int index,
513 unsigned int mask)
514 {
515 struct get_readers_callback_data * d = userdata;
516
517 if (index == d->ReaderData->Writer->U.I.DstReg.Index
518 && file == d->ReaderData->Writer->U.I.DstReg.File) {
519 unsigned int shared_mask = mask
520 & d->ReaderData->Writer->U.I.DstReg.WriteMask;
521 if (d->ReaderData->InElse) {
522 if (shared_mask & d->AliveWriteMask) {
523 /* We set AbortOnRead here because the
524 * destination register of d->ReaderData->Writer
525 * is written to in both the IF and the
526 * ELSE block of this IF/ELSE statement.
527 * This means that readers of this
528 * destination register that follow this IF/ELSE
529 * statement use the value of different
530 * instructions depending on the control flow
531 * decisions made by the program. */
532 d->ReaderData->AbortOnRead = 1;
533 }
534 } else {
535 d->AliveWriteMask &= ~shared_mask;
536 }
537 }
538
539 d->WriteCB(d->ReaderData, inst, file, index, mask);
540 }
541
542 /**
543 * This function will create a list of readers via the rc_reader_data struct.
544 * This function will abort (set the flag data->Abort) and return if it
545 * encounters an instruction that reads from @param writer and also a different
546 * instruction. Here are some examples:
547 *
548 * writer = instruction 0;
549 * 0 MOV TEMP[0].xy, TEMP[1].xy
550 * 1 MOV TEMP[0].zw, TEMP[2].xy
551 * 2 MOV TEMP[3], TEMP[0]
552 * The Abort flag will be set on instruction 2, because it reads values written
553 * by instructions 0 and 1.
554 *
555 * writer = instruction 1;
556 * 0 IF TEMP[0].x
557 * 1 MOV TEMP[1], TEMP[2]
558 * 2 ELSE
559 * 3 MOV TEMP[1], TEMP[2]
560 * 4 ENDIF
561 * 5 MOV TEMP[3], TEMP[1]
562 * The Abort flag will be set on instruction 5, because it could read from the
563 * value written by either instruction 1 or 3, depending on the jump decision
564 * made at instruction 0.
565 *
566 * writer = instruction 0;
567 * 0 MOV TEMP[0], TEMP[1]
568 * 2 BGNLOOP
569 * 3 ADD TEMP[0], TEMP[0], none.1
570 * 4 ENDLOOP
571 * The Abort flag will be set on instruction 3, because in the first iteration
572 * of the loop it reads the value written by instruction 0 and in all other
573 * iterations it reads the value written by instruction 3.
574 *
575 * @param read_cb This function will be called for for every instruction that
576 * has been determined to be a reader of writer.
577 * @param write_cb This function will be called for every instruction after
578 * writer.
579 */
580 void rc_get_readers_normal(
581 struct radeon_compiler * c,
582 struct rc_instruction * writer,
583 struct rc_reader_data * data,
584 rc_read_src_fn read_cb,
585 rc_read_write_mask_fn write_cb)
586 {
587 struct rc_instruction * tmp;
588 struct get_readers_callback_data d;
589 unsigned int branch_depth = 0;
590
591 data->Writer = writer;
592 data->Abort = 0;
593 data->AbortOnRead = 0;
594 data->InElse = 0;
595 data->ReaderCount = 0;
596 data->ReadersReserved = 0;
597 data->Readers = NULL;
598
599 d.C = c;
600 d.AliveWriteMask = writer->U.I.DstReg.WriteMask;
601 d.ReaderData = data;
602 d.ReadCB = read_cb;
603 d.WriteCB = write_cb;
604
605 if (!writer->U.I.DstReg.WriteMask)
606 return;
607
608 for(tmp = writer->Next; tmp != &c->Program.Instructions;
609 tmp = tmp->Next){
610 rc_opcode opcode = get_flow_control_inst(tmp);
611 switch(opcode) {
612 case RC_OPCODE_BGNLOOP:
613 /* XXX We can do better when we see a BGNLOOP if we
614 * add a flag called AbortOnWrite to struct
615 * rc_reader_data and leave it set until the next
616 * ENDLOOP. */
617 case RC_OPCODE_ENDLOOP:
618 /* XXX We can do better when we see an ENDLOOP by
619 * searching backwards from writer and looking for
620 * readers of writer's destination index. If we find a
621 * reader before we get to the BGNLOOP, we must abort
622 * unless there is another writer between that reader
623 * and the BGNLOOP. */
624 data->Abort = 1;
625 return;
626 case RC_OPCODE_IF:
627 branch_depth++;
628 break;
629 case RC_OPCODE_ELSE:
630 if (branch_depth == 0)
631 data->InElse = 1;
632 break;
633 case RC_OPCODE_ENDIF:
634 if (branch_depth == 0) {
635 data->AbortOnRead = 1;
636 data->InElse = 0;
637 }
638 else {
639 branch_depth--;
640 }
641 break;
642 default:
643 break;
644 }
645
646 if (!data->InElse)
647 rc_for_all_reads_src(tmp, get_readers_normal_read_callback, &d);
648 rc_for_all_writes_mask(tmp, get_readers_write_callback, &d);
649
650 if (data->Abort)
651 return;
652
653 if (!d.AliveWriteMask)
654 return;
655 }
656 }