r600g/sb: add MEM_RING support
[mesa.git] / src / gallium / drivers / r600 / sb / sb_bc_parser.cpp
1 /*
2 * Copyright 2013 Vadim Girlin <vadimgirlin@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 * Authors:
24 * Vadim Girlin
25 */
26
27 #define BCP_DEBUG 0
28
29 #if BCP_DEBUG
30 #define BCP_DUMP(q) do { q } while (0)
31 #else
32 #define BCP_DUMP(q)
33 #endif
34
35 extern "C" {
36 #include "r600_pipe.h"
37 #include "r600_shader.h"
38 }
39
40 #include <stack>
41
42 #include "sb_bc.h"
43 #include "sb_shader.h"
44 #include "sb_pass.h"
45
46 namespace r600_sb {
47
48 int bc_parser::decode() {
49
50 dw = bc->bytecode;
51 bc_ndw = bc->ndw;
52 max_cf = 0;
53
54 dec = new bc_decoder(ctx, dw, bc_ndw);
55
56 shader_target t = TARGET_UNKNOWN;
57
58 if (pshader) {
59 switch (bc->type) {
60 case TGSI_PROCESSOR_FRAGMENT: t = TARGET_PS; break;
61 case TGSI_PROCESSOR_VERTEX:
62 t = pshader->vs_as_es ? TARGET_ES : TARGET_VS;
63 break;
64 case TGSI_PROCESSOR_GEOMETRY: t = TARGET_GS; break;
65 case TGSI_PROCESSOR_COMPUTE: t = TARGET_COMPUTE; break;
66 default: assert(!"unknown shader target"); return -1; break;
67 }
68 } else {
69 if (bc->type == TGSI_PROCESSOR_COMPUTE)
70 t = TARGET_COMPUTE;
71 else
72 t = TARGET_FETCH;
73 }
74
75 sh = new shader(ctx, t, bc->debug_id);
76 sh->safe_math = sb_context::safe_math || (t == TARGET_COMPUTE);
77
78 int r = decode_shader();
79
80 delete dec;
81
82 sh->ngpr = bc->ngpr;
83 sh->nstack = bc->nstack;
84
85 return r;
86 }
87
88 int bc_parser::decode_shader() {
89 int r = 0;
90 unsigned i = 0;
91 bool eop = false;
92
93 sh->init();
94
95 do {
96 eop = false;
97 if ((r = decode_cf(i, eop)))
98 return r;
99
100 } while (!eop || (i >> 1) <= max_cf);
101
102 return 0;
103 }
104
105 int bc_parser::prepare() {
106 int r = 0;
107 if ((r = parse_decls()))
108 return r;
109 if ((r = prepare_ir()))
110 return r;
111 return 0;
112 }
113
114 int bc_parser::parse_decls() {
115
116 if (!pshader) {
117 if (gpr_reladdr)
118 sh->add_gpr_array(0, bc->ngpr, 0x0F);
119
120 // compute shaders have some values preloaded in R0, R1
121 sh->add_input(0 /* GPR */, true /* preloaded */, 0x0F /* mask */);
122 sh->add_input(1 /* GPR */, true /* preloaded */, 0x0F /* mask */);
123 return 0;
124 }
125
126 if (pshader->indirect_files & ~(1 << TGSI_FILE_CONSTANT)) {
127
128 assert(pshader->num_arrays);
129
130 if (pshader->num_arrays) {
131 for (unsigned i = 0; i < pshader->num_arrays; ++i) {
132 r600_shader_array &a = pshader->arrays[i];
133 sh->add_gpr_array(a.gpr_start, a.gpr_count, a.comp_mask);
134 }
135 } else {
136 sh->add_gpr_array(0, pshader->bc.ngpr, 0x0F);
137 }
138 }
139
140 if (sh->target == TARGET_VS || sh->target == TARGET_ES)
141 sh->add_input(0, 1, 0x0F);
142 else if (sh->target == TARGET_GS) {
143 sh->add_input(0, 1, 0x0F);
144 sh->add_input(1, 1, 0x0F);
145 }
146
147 bool ps_interp = ctx.hw_class >= HW_CLASS_EVERGREEN
148 && sh->target == TARGET_PS;
149
150 unsigned linear = 0, persp = 0, centroid = 1;
151
152 for (unsigned i = 0; i < pshader->ninput; ++i) {
153 r600_shader_io & in = pshader->input[i];
154 bool preloaded = sh->target == TARGET_PS && !(ps_interp && in.spi_sid);
155 sh->add_input(in.gpr, preloaded, /*in.write_mask*/ 0x0F);
156 if (ps_interp && in.spi_sid) {
157 if (in.interpolate == TGSI_INTERPOLATE_LINEAR ||
158 in.interpolate == TGSI_INTERPOLATE_COLOR)
159 linear = 1;
160 else if (in.interpolate == TGSI_INTERPOLATE_PERSPECTIVE)
161 persp = 1;
162 if (in.centroid)
163 centroid = 2;
164 }
165 }
166
167 if (ps_interp) {
168 unsigned mask = (1 << (2 * (linear + persp) * centroid)) - 1;
169 unsigned gpr = 0;
170
171 while (mask) {
172 sh->add_input(gpr, true, mask & 0x0F);
173 ++gpr;
174 mask >>= 4;
175 }
176 }
177
178 return 0;
179 }
180
181 int bc_parser::decode_cf(unsigned &i, bool &eop) {
182
183 int r;
184
185 cf_node *cf = sh->create_cf();
186 sh->root->push_back(cf);
187
188 unsigned id = i >> 1;
189
190 cf->bc.id = id;
191
192 if (cf_map.size() < id + 1)
193 cf_map.resize(id + 1);
194
195 cf_map[id] = cf;
196
197 if ((r = dec->decode_cf(i, cf->bc)))
198 return r;
199
200 cf_op_flags flags = (cf_op_flags)cf->bc.op_ptr->flags;
201
202 if (flags & CF_ALU) {
203 if ((r = decode_alu_clause(cf)))
204 return r;
205 } else if (flags & CF_FETCH) {
206 if ((r = decode_fetch_clause(cf)))
207 return r;;
208 } else if (flags & CF_EXP) {
209 if (cf->bc.rw_rel)
210 gpr_reladdr = true;
211 assert(!cf->bc.rw_rel);
212 } else if (flags & CF_MEM) {
213 if (cf->bc.rw_rel)
214 gpr_reladdr = true;
215 assert(!cf->bc.rw_rel);
216 } else if (flags & CF_BRANCH) {
217 if (cf->bc.addr > max_cf)
218 max_cf = cf->bc.addr;
219 }
220
221 eop = cf->bc.end_of_program || cf->bc.op == CF_OP_CF_END ||
222 cf->bc.op == CF_OP_RET;
223 return 0;
224 }
225
226 int bc_parser::decode_alu_clause(cf_node* cf) {
227 unsigned i = cf->bc.addr << 1, cnt = cf->bc.count + 1, gcnt;
228
229 cf->subtype = NST_ALU_CLAUSE;
230
231 cgroup = 0;
232 memset(slots[0], 0, 5*sizeof(slots[0][0]));
233
234 unsigned ng = 0;
235
236 do {
237 decode_alu_group(cf, i, gcnt);
238 assert(gcnt <= cnt);
239 cnt -= gcnt;
240 ng++;
241 } while (cnt);
242
243 return 0;
244 }
245
246 int bc_parser::decode_alu_group(cf_node* cf, unsigned &i, unsigned &gcnt) {
247 int r;
248 alu_node *n;
249 alu_group_node *g = sh->create_alu_group();
250
251 cgroup = !cgroup;
252 memset(slots[cgroup], 0, 5*sizeof(slots[0][0]));
253 gcnt = 0;
254
255 unsigned literal_mask = 0;
256
257 do {
258 n = sh->create_alu();
259 g->push_back(n);
260
261 if ((r = dec->decode_alu(i, n->bc)))
262 return r;
263
264 if (!sh->assign_slot(n, slots[cgroup])) {
265 assert(!"alu slot assignment failed");
266 return -1;
267 }
268
269 gcnt++;
270
271 } while (gcnt <= 5 && !n->bc.last);
272
273 assert(n->bc.last);
274
275 for (node_iterator I = g->begin(), E = g->end(); I != E; ++I) {
276 n = static_cast<alu_node*>(*I);
277
278 if (n->bc.dst_rel)
279 gpr_reladdr = true;
280
281 for (int k = 0; k < n->bc.op_ptr->src_count; ++k) {
282 bc_alu_src &src = n->bc.src[k];
283 if (src.rel)
284 gpr_reladdr = true;
285 if (src.sel == ALU_SRC_LITERAL) {
286 literal_mask |= (1 << src.chan);
287 src.value.u = dw[i + src.chan];
288 }
289 }
290 }
291
292 unsigned literal_ndw = 0;
293 while (literal_mask) {
294 g->literals.push_back(dw[i + literal_ndw]);
295 literal_ndw += 1;
296 literal_mask >>= 1;
297 }
298
299 literal_ndw = (literal_ndw + 1) & ~1u;
300
301 i += literal_ndw;
302 gcnt += literal_ndw >> 1;
303
304 cf->push_back(g);
305 return 0;
306 }
307
308 int bc_parser::prepare_alu_clause(cf_node* cf) {
309
310 // loop over alu groups
311 for (node_iterator I = cf->begin(), E = cf->end(); I != E; ++I) {
312 assert(I->subtype == NST_ALU_GROUP);
313 alu_group_node *g = static_cast<alu_group_node*>(*I);
314 prepare_alu_group(cf, g);
315 }
316
317 return 0;
318 }
319
320 int bc_parser::prepare_alu_group(cf_node* cf, alu_group_node *g) {
321
322 alu_node *n;
323
324 cgroup = !cgroup;
325 memset(slots[cgroup], 0, 5*sizeof(slots[0][0]));
326
327 for (node_iterator I = g->begin(), E = g->end();
328 I != E; ++I) {
329 n = static_cast<alu_node*>(*I);
330
331 if (!sh->assign_slot(n, slots[cgroup])) {
332 assert(!"alu slot assignment failed");
333 return -1;
334 }
335
336 unsigned src_count = n->bc.op_ptr->src_count;
337
338 if (ctx.alu_slots(n->bc.op) & AF_4SLOT)
339 n->flags |= NF_ALU_4SLOT;
340
341 n->src.resize(src_count);
342
343 unsigned flags = n->bc.op_ptr->flags;
344
345 if (flags & AF_PRED) {
346 n->dst.resize(3);
347 if (n->bc.update_pred)
348 n->dst[1] = sh->get_special_value(SV_ALU_PRED);
349 if (n->bc.update_exec_mask)
350 n->dst[2] = sh->get_special_value(SV_EXEC_MASK);
351
352 n->flags |= NF_DONT_HOIST;
353
354 } else if (flags & AF_KILL) {
355
356 n->dst.resize(2);
357 n->dst[1] = sh->get_special_value(SV_VALID_MASK);
358 sh->set_uses_kill();
359
360 n->flags |= NF_DONT_HOIST | NF_DONT_MOVE |
361 NF_DONT_KILL | NF_SCHEDULE_EARLY;
362
363 } else {
364 n->dst.resize(1);
365 }
366
367 if (flags & AF_MOVA) {
368
369 n->dst[0] = sh->get_special_value(SV_AR_INDEX);
370
371 n->flags |= NF_DONT_HOIST;
372
373 } else if (n->bc.op_ptr->src_count == 3 || n->bc.write_mask) {
374 assert(!n->bc.dst_rel || n->bc.index_mode == INDEX_AR_X);
375
376 value *v = sh->get_gpr_value(false, n->bc.dst_gpr, n->bc.dst_chan,
377 n->bc.dst_rel);
378
379 n->dst[0] = v;
380 }
381
382 if (n->bc.pred_sel) {
383 sh->has_alu_predication = true;
384 n->pred = sh->get_special_value(SV_ALU_PRED);
385 }
386
387 for (unsigned s = 0; s < src_count; ++s) {
388 bc_alu_src &src = n->bc.src[s];
389
390 if (src.sel == ALU_SRC_LITERAL) {
391 n->src[s] = sh->get_const_value(src.value);
392 } else if (src.sel == ALU_SRC_PS || src.sel == ALU_SRC_PV) {
393 unsigned pgroup = !cgroup, prev_slot = src.sel == ALU_SRC_PS ?
394 SLOT_TRANS : src.chan;
395
396 // XXX shouldn't happen but llvm backend uses PS on cayman
397 if (prev_slot == SLOT_TRANS && ctx.is_cayman())
398 prev_slot = SLOT_X;
399
400 alu_node *prev_alu = slots[pgroup][prev_slot];
401
402 assert(prev_alu);
403
404 if (!prev_alu->dst[0]) {
405 value * t = sh->create_temp_value();
406 prev_alu->dst[0] = t;
407 }
408
409 value *d = prev_alu->dst[0];
410
411 if (d->is_rel()) {
412 d = sh->get_gpr_value(true, prev_alu->bc.dst_gpr,
413 prev_alu->bc.dst_chan,
414 prev_alu->bc.dst_rel);
415 }
416
417 n->src[s] = d;
418 } else if (ctx.is_kcache_sel(src.sel)) {
419 unsigned sel = src.sel, kc_addr;
420 unsigned kc_set = ((sel >> 7) & 2) + ((sel >> 5) & 1);
421
422 bc_kcache &kc = cf->bc.kc[kc_set];
423 kc_addr = (kc.addr << 4) + (sel & 0x1F);
424 n->src[s] = sh->get_kcache_value(kc.bank, kc_addr, src.chan);
425 } else if (src.sel < MAX_GPR) {
426 value *v = sh->get_gpr_value(true, src.sel, src.chan, src.rel);
427
428 n->src[s] = v;
429
430 } else if (src.sel >= ALU_SRC_PARAM_OFFSET) {
431 // using slot for value channel because in fact the slot
432 // determines the channel that is loaded by INTERP_LOAD_P0
433 // (and maybe some others).
434 // otherwise GVN will consider INTERP_LOAD_P0s with the same
435 // param index as equal instructions and leave only one of them
436 n->src[s] = sh->get_special_ro_value(sel_chan(src.sel,
437 n->bc.slot));
438 } else {
439 switch (src.sel) {
440 case ALU_SRC_0:
441 n->src[s] = sh->get_const_value(0);
442 break;
443 case ALU_SRC_0_5:
444 n->src[s] = sh->get_const_value(0.5f);
445 break;
446 case ALU_SRC_1:
447 n->src[s] = sh->get_const_value(1.0f);
448 break;
449 case ALU_SRC_1_INT:
450 n->src[s] = sh->get_const_value(1);
451 break;
452 case ALU_SRC_M_1_INT:
453 n->src[s] = sh->get_const_value(-1);
454 break;
455 default:
456 n->src[s] = sh->get_special_ro_value(src.sel);
457 break;
458 }
459 }
460 }
461 }
462
463 // pack multislot instructions into alu_packed_node
464
465 alu_packed_node *p = NULL;
466 for (node_iterator N, I = g->begin(), E = g->end(); I != E; I = N) {
467 N = I + 1;
468 alu_node *a = static_cast<alu_node*>(*I);
469 unsigned sflags = a->bc.slot_flags;
470
471 if (sflags == AF_4V || (ctx.is_cayman() && sflags == AF_S)) {
472 if (!p)
473 p = sh->create_alu_packed();
474
475 a->remove();
476 p->push_back(a);
477 }
478 }
479
480 if (p) {
481 g->push_front(p);
482
483 if (p->count() == 3 && ctx.is_cayman()) {
484 // cayman's scalar instruction that can use 3 or 4 slots
485
486 // FIXME for simplicity we'll always add 4th slot,
487 // but probably we might want to always remove 4th slot and make
488 // sure that regalloc won't choose 'w' component for dst
489
490 alu_node *f = static_cast<alu_node*>(p->first);
491 alu_node *a = sh->create_alu();
492 a->src = f->src;
493 a->dst.resize(f->dst.size());
494 a->bc = f->bc;
495 a->bc.slot = SLOT_W;
496 p->push_back(a);
497 }
498 }
499
500 return 0;
501 }
502
503 int bc_parser::decode_fetch_clause(cf_node* cf) {
504 int r;
505 unsigned i = cf->bc.addr << 1, cnt = cf->bc.count + 1;
506
507 cf->subtype = NST_TEX_CLAUSE;
508
509 while (cnt--) {
510 fetch_node *n = sh->create_fetch();
511 cf->push_back(n);
512 if ((r = dec->decode_fetch(i, n->bc)))
513 return r;
514 if (n->bc.src_rel || n->bc.dst_rel)
515 gpr_reladdr = true;
516
517 }
518 return 0;
519 }
520
521 int bc_parser::prepare_fetch_clause(cf_node *cf) {
522
523 vvec grad_v, grad_h;
524
525 for (node_iterator I = cf->begin(), E = cf->end(); I != E; ++I) {
526
527 fetch_node *n = static_cast<fetch_node*>(*I);
528 assert(n->is_valid());
529
530 unsigned flags = n->bc.op_ptr->flags;
531
532 unsigned vtx = flags & FF_VTX;
533 unsigned num_src = vtx ? ctx.vtx_src_num : 4;
534
535 n->dst.resize(4);
536
537 if (flags & (FF_SETGRAD | FF_USEGRAD | FF_GETGRAD)) {
538 sh->uses_gradients = true;
539 }
540
541 if (flags & FF_SETGRAD) {
542
543 vvec *grad = NULL;
544
545 switch (n->bc.op) {
546 case FETCH_OP_SET_GRADIENTS_V:
547 grad = &grad_v;
548 break;
549 case FETCH_OP_SET_GRADIENTS_H:
550 grad = &grad_h;
551 break;
552 default:
553 assert(!"unexpected SET_GRAD instruction");
554 return -1;
555 }
556
557 if (grad->empty())
558 grad->resize(4);
559
560 for(unsigned s = 0; s < 4; ++s) {
561 unsigned sw = n->bc.src_sel[s];
562 if (sw <= SEL_W)
563 (*grad)[s] = sh->get_gpr_value(true, n->bc.src_gpr,
564 sw, false);
565 else if (sw == SEL_0)
566 (*grad)[s] = sh->get_const_value(0.0f);
567 else if (sw == SEL_1)
568 (*grad)[s] = sh->get_const_value(1.0f);
569 }
570 } else {
571
572 if (flags & FF_USEGRAD) {
573 n->src.resize(12);
574 std::copy(grad_v.begin(), grad_v.end(), n->src.begin() + 4);
575 std::copy(grad_h.begin(), grad_h.end(), n->src.begin() + 8);
576 } else {
577 n->src.resize(4);
578 }
579
580 for(int s = 0; s < 4; ++s) {
581 if (n->bc.dst_sel[s] != SEL_MASK)
582 n->dst[s] = sh->get_gpr_value(false, n->bc.dst_gpr, s, false);
583 // NOTE: it doesn't matter here which components of the result we
584 // are using, but original n->bc.dst_sel should be taken into
585 // account when building the bytecode
586 }
587 for(unsigned s = 0; s < num_src; ++s) {
588 if (n->bc.src_sel[s] <= SEL_W)
589 n->src[s] = sh->get_gpr_value(true, n->bc.src_gpr,
590 n->bc.src_sel[s], false);
591 }
592
593 }
594 }
595
596 return 0;
597 }
598
599 int bc_parser::prepare_ir() {
600
601 for(id_cf_map::iterator I = cf_map.begin(), E = cf_map.end(); I != E; ++I) {
602 cf_node *c = *I;
603
604 if (!c)
605 continue;
606
607 unsigned flags = c->bc.op_ptr->flags;
608
609 if (flags & CF_ALU) {
610 prepare_alu_clause(c);
611 } else if (flags & CF_FETCH) {
612 prepare_fetch_clause(c);
613 } else if (c->bc.op == CF_OP_CALL_FS) {
614 sh->init_call_fs(c);
615 c->flags |= NF_SCHEDULE_EARLY | NF_DONT_MOVE;
616 } else if (flags & CF_LOOP_START) {
617 prepare_loop(c);
618 } else if (c->bc.op == CF_OP_JUMP) {
619 prepare_if(c);
620 } else if (c->bc.op == CF_OP_LOOP_END) {
621 loop_stack.pop();
622 } else if (c->bc.op == CF_OP_LOOP_CONTINUE) {
623 assert(!loop_stack.empty());
624 repeat_node *rep = sh->create_repeat(loop_stack.top());
625 if (c->parent->first != c)
626 rep->move(c->parent->first, c);
627 c->replace_with(rep);
628 sh->simplify_dep_rep(rep);
629 } else if (c->bc.op == CF_OP_LOOP_BREAK) {
630 assert(!loop_stack.empty());
631 depart_node *dep = sh->create_depart(loop_stack.top());
632 if (c->parent->first != c)
633 dep->move(c->parent->first, c);
634 c->replace_with(dep);
635 sh->simplify_dep_rep(dep);
636 } else if (flags & CF_EXP) {
637
638 // unroll burst exports
639
640 assert(c->bc.op == CF_OP_EXPORT || c->bc.op == CF_OP_EXPORT_DONE);
641
642 c->bc.set_op(CF_OP_EXPORT);
643
644 unsigned burst_count = c->bc.burst_count;
645 unsigned eop = c->bc.end_of_program;
646
647 c->bc.end_of_program = 0;
648 c->bc.burst_count = 0;
649
650 do {
651 c->src.resize(4);
652
653 for(int s = 0; s < 4; ++s) {
654 switch (c->bc.sel[s]) {
655 case SEL_0:
656 c->src[s] = sh->get_const_value(0.0f);
657 break;
658 case SEL_1:
659 c->src[s] = sh->get_const_value(1.0f);
660 break;
661 case SEL_MASK:
662 break;
663 default:
664 if (c->bc.sel[s] <= SEL_W)
665 c->src[s] = sh->get_gpr_value(true, c->bc.rw_gpr,
666 c->bc.sel[s], false);
667 else
668 assert(!"invalid src_sel for export");
669 }
670 }
671
672 if (!burst_count--)
673 break;
674
675 cf_node *cf_next = sh->create_cf();
676 cf_next->bc = c->bc;
677 ++cf_next->bc.rw_gpr;
678 ++cf_next->bc.array_base;
679
680 c->insert_after(cf_next);
681 c = cf_next;
682
683 } while (1);
684
685 c->bc.end_of_program = eop;
686 } else if (flags & CF_MEM) {
687
688 unsigned burst_count = c->bc.burst_count;
689 unsigned eop = c->bc.end_of_program;
690
691 c->bc.end_of_program = 0;
692 c->bc.burst_count = 0;
693
694 do {
695
696 c->src.resize(4);
697
698 for(int s = 0; s < 4; ++s) {
699 if (c->bc.comp_mask & (1 << s))
700 c->src[s] =
701 sh->get_gpr_value(true, c->bc.rw_gpr, s, false);
702 }
703
704 if (((flags & CF_RAT) || (!(flags & CF_STRM))) && (c->bc.type & 1)) { // indexed write
705 c->src.resize(8);
706 for(int s = 0; s < 3; ++s) {
707 c->src[4 + s] =
708 sh->get_gpr_value(true, c->bc.index_gpr, s, false);
709 }
710
711 // FIXME probably we can relax it a bit
712 c->flags |= NF_DONT_HOIST | NF_DONT_MOVE;
713 }
714
715 if (!burst_count--)
716 break;
717
718 cf_node *cf_next = sh->create_cf();
719 cf_next->bc = c->bc;
720 ++cf_next->bc.rw_gpr;
721
722 // FIXME is it correct?
723 cf_next->bc.array_base += cf_next->bc.elem_size + 1;
724
725 c->insert_after(cf_next);
726 c = cf_next;
727 } while (1);
728
729 c->bc.end_of_program = eop;
730
731 }
732 }
733
734 assert(loop_stack.empty());
735 return 0;
736 }
737
738 int bc_parser::prepare_loop(cf_node* c) {
739
740 cf_node *end = cf_map[c->bc.addr - 1];
741 assert(end->bc.op == CF_OP_LOOP_END);
742 assert(c->parent == end->parent);
743
744 region_node *reg = sh->create_region();
745 repeat_node *rep = sh->create_repeat(reg);
746
747 reg->push_back(rep);
748 c->insert_before(reg);
749 rep->move(c, end->next);
750
751 loop_stack.push(reg);
752 return 0;
753 }
754
755 int bc_parser::prepare_if(cf_node* c) {
756 cf_node *c_else = NULL, *end = cf_map[c->bc.addr];
757
758 BCP_DUMP(
759 sblog << "parsing JUMP @" << c->bc.id;
760 sblog << "\n";
761 );
762
763 if (end->bc.op == CF_OP_ELSE) {
764 BCP_DUMP(
765 sblog << " found ELSE : ";
766 dump::dump_op(end);
767 sblog << "\n";
768 );
769
770 c_else = end;
771 end = cf_map[c_else->bc.addr];
772 } else {
773 BCP_DUMP(
774 sblog << " no else\n";
775 );
776
777 c_else = end;
778 }
779
780 if (c_else->parent != c->parent)
781 c_else = NULL;
782
783 if (end->parent != c->parent)
784 end = NULL;
785
786 region_node *reg = sh->create_region();
787
788 depart_node *dep2 = sh->create_depart(reg);
789 depart_node *dep = sh->create_depart(reg);
790 if_node *n_if = sh->create_if();
791
792 c->insert_before(reg);
793
794 if (c_else != end)
795 dep->move(c_else, end);
796 dep2->move(c, end);
797
798 reg->push_back(dep);
799 dep->push_front(n_if);
800 n_if->push_back(dep2);
801
802 n_if->cond = sh->get_special_value(SV_EXEC_MASK);
803
804 return 0;
805 }
806
807
808 } // namespace r600_sb