Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/compiler/nir/nir_control_flow.c
4546 views
1
/*
2
* Copyright © 2014 Intel Corporation
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
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
* IN THE SOFTWARE.
22
*
23
* Authors:
24
* Connor Abbott ([email protected])
25
*
26
*/
27
28
#include "nir_control_flow_private.h"
29
30
/**
31
* \name Control flow modification
32
*
33
* These functions modify the control flow tree while keeping the control flow
34
* graph up-to-date. The invariants respected are:
35
* 1. Each then statement, else statement, or loop body must have at least one
36
* control flow node.
37
* 2. Each if-statement and loop must have one basic block before it and one
38
* after.
39
* 3. Two basic blocks cannot be directly next to each other.
40
* 4. If a basic block has a jump instruction, there must be only one and it
41
* must be at the end of the block.
42
*
43
* The purpose of the second one is so that we have places to insert code during
44
* GCM, as well as eliminating the possibility of critical edges.
45
*/
46
/*@{*/
47
48
static inline void
49
block_add_pred(nir_block *block, nir_block *pred)
50
{
51
_mesa_set_add(block->predecessors, pred);
52
}
53
54
static inline void
55
block_remove_pred(nir_block *block, nir_block *pred)
56
{
57
struct set_entry *entry = _mesa_set_search(block->predecessors, pred);
58
59
assert(entry);
60
61
_mesa_set_remove(block->predecessors, entry);
62
}
63
64
static void
65
link_blocks(nir_block *pred, nir_block *succ1, nir_block *succ2)
66
{
67
pred->successors[0] = succ1;
68
if (succ1 != NULL)
69
block_add_pred(succ1, pred);
70
71
pred->successors[1] = succ2;
72
if (succ2 != NULL)
73
block_add_pred(succ2, pred);
74
}
75
76
static void
77
unlink_blocks(nir_block *pred, nir_block *succ)
78
{
79
if (pred->successors[0] == succ) {
80
pred->successors[0] = pred->successors[1];
81
pred->successors[1] = NULL;
82
} else {
83
assert(pred->successors[1] == succ);
84
pred->successors[1] = NULL;
85
}
86
87
block_remove_pred(succ, pred);
88
}
89
90
static void
91
unlink_block_successors(nir_block *block)
92
{
93
if (block->successors[1] != NULL)
94
unlink_blocks(block, block->successors[1]);
95
if (block->successors[0] != NULL)
96
unlink_blocks(block, block->successors[0]);
97
}
98
99
static void
100
link_non_block_to_block(nir_cf_node *node, nir_block *block)
101
{
102
if (node->type == nir_cf_node_if) {
103
/*
104
* We're trying to link an if to a block after it; this just means linking
105
* the last block of the then and else branches.
106
*/
107
108
nir_if *if_stmt = nir_cf_node_as_if(node);
109
110
nir_block *last_then_block = nir_if_last_then_block(if_stmt);
111
nir_block *last_else_block = nir_if_last_else_block(if_stmt);
112
113
if (!nir_block_ends_in_jump(last_then_block)) {
114
unlink_block_successors(last_then_block);
115
link_blocks(last_then_block, block, NULL);
116
}
117
118
if (!nir_block_ends_in_jump(last_else_block)) {
119
unlink_block_successors(last_else_block);
120
link_blocks(last_else_block, block, NULL);
121
}
122
} else {
123
assert(node->type == nir_cf_node_loop);
124
}
125
}
126
127
static void
128
link_block_to_non_block(nir_block *block, nir_cf_node *node)
129
{
130
if (node->type == nir_cf_node_if) {
131
/*
132
* We're trying to link a block to an if after it; this just means linking
133
* the block to the first block of the then and else branches.
134
*/
135
136
nir_if *if_stmt = nir_cf_node_as_if(node);
137
138
nir_block *first_then_block = nir_if_first_then_block(if_stmt);
139
nir_block *first_else_block = nir_if_first_else_block(if_stmt);
140
141
unlink_block_successors(block);
142
link_blocks(block, first_then_block, first_else_block);
143
} else if (node->type == nir_cf_node_loop) {
144
/*
145
* For similar reasons as the corresponding case in
146
* link_non_block_to_block(), don't worry about if the loop header has
147
* any predecessors that need to be unlinked.
148
*/
149
150
nir_loop *loop = nir_cf_node_as_loop(node);
151
152
nir_block *loop_header_block = nir_loop_first_block(loop);
153
154
unlink_block_successors(block);
155
link_blocks(block, loop_header_block, NULL);
156
}
157
158
}
159
160
/**
161
* Replace a block's successor with a different one.
162
*/
163
static void
164
replace_successor(nir_block *block, nir_block *old_succ, nir_block *new_succ)
165
{
166
if (block->successors[0] == old_succ) {
167
block->successors[0] = new_succ;
168
} else {
169
assert(block->successors[1] == old_succ);
170
block->successors[1] = new_succ;
171
}
172
173
block_remove_pred(old_succ, block);
174
block_add_pred(new_succ, block);
175
}
176
177
/**
178
* Takes a basic block and inserts a new empty basic block before it, making its
179
* predecessors point to the new block. This essentially splits the block into
180
* an empty header and a body so that another non-block CF node can be inserted
181
* between the two. Note that this does *not* link the two basic blocks, so
182
* some kind of cleanup *must* be performed after this call.
183
*/
184
185
static nir_block *
186
split_block_beginning(nir_block *block)
187
{
188
nir_block *new_block = nir_block_create(ralloc_parent(block));
189
new_block->cf_node.parent = block->cf_node.parent;
190
exec_node_insert_node_before(&block->cf_node.node, &new_block->cf_node.node);
191
192
set_foreach(block->predecessors, entry) {
193
nir_block *pred = (nir_block *) entry->key;
194
replace_successor(pred, block, new_block);
195
}
196
197
/* Any phi nodes must stay part of the new block, or else their
198
* sources will be messed up.
199
*/
200
nir_foreach_instr_safe(instr, block) {
201
if (instr->type != nir_instr_type_phi)
202
break;
203
204
exec_node_remove(&instr->node);
205
instr->block = new_block;
206
exec_list_push_tail(&new_block->instr_list, &instr->node);
207
}
208
209
return new_block;
210
}
211
212
static void
213
rewrite_phi_preds(nir_block *block, nir_block *old_pred, nir_block *new_pred)
214
{
215
nir_foreach_instr_safe(instr, block) {
216
if (instr->type != nir_instr_type_phi)
217
break;
218
219
nir_phi_instr *phi = nir_instr_as_phi(instr);
220
nir_foreach_phi_src(src, phi) {
221
if (src->pred == old_pred) {
222
src->pred = new_pred;
223
break;
224
}
225
}
226
}
227
}
228
229
void
230
nir_insert_phi_undef(nir_block *block, nir_block *pred)
231
{
232
nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node);
233
nir_foreach_instr(instr, block) {
234
if (instr->type != nir_instr_type_phi)
235
break;
236
237
nir_phi_instr *phi = nir_instr_as_phi(instr);
238
nir_ssa_undef_instr *undef =
239
nir_ssa_undef_instr_create(ralloc_parent(phi),
240
phi->dest.ssa.num_components,
241
phi->dest.ssa.bit_size);
242
nir_instr_insert_before_cf_list(&impl->body, &undef->instr);
243
nir_phi_src *src = ralloc(phi, nir_phi_src);
244
src->pred = pred;
245
src->src.parent_instr = &phi->instr;
246
src->src.is_ssa = true;
247
src->src.ssa = &undef->def;
248
249
list_addtail(&src->src.use_link, &undef->def.uses);
250
251
exec_list_push_tail(&phi->srcs, &src->node);
252
}
253
}
254
255
/**
256
* Moves the successors of source to the successors of dest, leaving both
257
* successors of source NULL.
258
*/
259
260
static void
261
move_successors(nir_block *source, nir_block *dest)
262
{
263
nir_block *succ1 = source->successors[0];
264
nir_block *succ2 = source->successors[1];
265
266
if (succ1) {
267
unlink_blocks(source, succ1);
268
rewrite_phi_preds(succ1, source, dest);
269
}
270
271
if (succ2) {
272
unlink_blocks(source, succ2);
273
rewrite_phi_preds(succ2, source, dest);
274
}
275
276
unlink_block_successors(dest);
277
link_blocks(dest, succ1, succ2);
278
}
279
280
/* Given a basic block with no successors that has been inserted into the
281
* control flow tree, gives it the successors it would normally have assuming
282
* it doesn't end in a jump instruction. Also inserts phi sources with undefs
283
* if necessary.
284
*/
285
static void
286
block_add_normal_succs(nir_block *block)
287
{
288
if (exec_node_is_tail_sentinel(block->cf_node.node.next)) {
289
nir_cf_node *parent = block->cf_node.parent;
290
if (parent->type == nir_cf_node_if) {
291
nir_cf_node *next = nir_cf_node_next(parent);
292
nir_block *next_block = nir_cf_node_as_block(next);
293
294
link_blocks(block, next_block, NULL);
295
} else if (parent->type == nir_cf_node_loop) {
296
nir_loop *loop = nir_cf_node_as_loop(parent);
297
298
nir_block *head_block = nir_loop_first_block(loop);
299
300
link_blocks(block, head_block, NULL);
301
nir_insert_phi_undef(head_block, block);
302
} else {
303
nir_function_impl *impl = nir_cf_node_as_function(parent);
304
link_blocks(block, impl->end_block, NULL);
305
}
306
} else {
307
nir_cf_node *next = nir_cf_node_next(&block->cf_node);
308
if (next->type == nir_cf_node_if) {
309
nir_if *next_if = nir_cf_node_as_if(next);
310
311
nir_block *first_then_block = nir_if_first_then_block(next_if);
312
nir_block *first_else_block = nir_if_first_else_block(next_if);
313
314
link_blocks(block, first_then_block, first_else_block);
315
} else if (next->type == nir_cf_node_loop) {
316
nir_loop *next_loop = nir_cf_node_as_loop(next);
317
318
nir_block *first_block = nir_loop_first_block(next_loop);
319
320
link_blocks(block, first_block, NULL);
321
nir_insert_phi_undef(first_block, block);
322
}
323
}
324
}
325
326
static nir_block *
327
split_block_end(nir_block *block)
328
{
329
nir_block *new_block = nir_block_create(ralloc_parent(block));
330
new_block->cf_node.parent = block->cf_node.parent;
331
exec_node_insert_after(&block->cf_node.node, &new_block->cf_node.node);
332
333
if (nir_block_ends_in_jump(block)) {
334
/* Figure out what successor block would've had if it didn't have a jump
335
* instruction, and make new_block have that successor.
336
*/
337
block_add_normal_succs(new_block);
338
} else {
339
move_successors(block, new_block);
340
}
341
342
return new_block;
343
}
344
345
static nir_block *
346
split_block_before_instr(nir_instr *instr)
347
{
348
assert(instr->type != nir_instr_type_phi);
349
nir_block *new_block = split_block_beginning(instr->block);
350
351
nir_foreach_instr_safe(cur_instr, instr->block) {
352
if (cur_instr == instr)
353
break;
354
355
exec_node_remove(&cur_instr->node);
356
cur_instr->block = new_block;
357
exec_list_push_tail(&new_block->instr_list, &cur_instr->node);
358
}
359
360
return new_block;
361
}
362
363
/* Splits a basic block at the point specified by the cursor. The "before" and
364
* "after" arguments are filled out with the blocks resulting from the split
365
* if non-NULL. Note that the "beginning" of the block is actually interpreted
366
* as before the first non-phi instruction, and it's illegal to split a block
367
* before a phi instruction.
368
*/
369
370
static void
371
split_block_cursor(nir_cursor cursor,
372
nir_block **_before, nir_block **_after)
373
{
374
nir_block *before, *after;
375
switch (cursor.option) {
376
case nir_cursor_before_block:
377
after = cursor.block;
378
before = split_block_beginning(cursor.block);
379
break;
380
381
case nir_cursor_after_block:
382
before = cursor.block;
383
after = split_block_end(cursor.block);
384
break;
385
386
case nir_cursor_before_instr:
387
after = cursor.instr->block;
388
before = split_block_before_instr(cursor.instr);
389
break;
390
391
case nir_cursor_after_instr:
392
/* We lower this to split_block_before_instr() so that we can keep the
393
* after-a-jump-instr case contained to split_block_end().
394
*/
395
if (nir_instr_is_last(cursor.instr)) {
396
before = cursor.instr->block;
397
after = split_block_end(cursor.instr->block);
398
} else {
399
after = cursor.instr->block;
400
before = split_block_before_instr(nir_instr_next(cursor.instr));
401
}
402
break;
403
404
default:
405
unreachable("not reached");
406
}
407
408
if (_before)
409
*_before = before;
410
if (_after)
411
*_after = after;
412
}
413
414
/**
415
* Inserts a non-basic block between two basic blocks and links them together.
416
*/
417
418
static void
419
insert_non_block(nir_block *before, nir_cf_node *node, nir_block *after)
420
{
421
node->parent = before->cf_node.parent;
422
exec_node_insert_after(&before->cf_node.node, &node->node);
423
link_block_to_non_block(before, node);
424
link_non_block_to_block(node, after);
425
}
426
427
/* walk up the control flow tree to find the innermost enclosed loop */
428
static nir_loop *
429
nearest_loop(nir_cf_node *node)
430
{
431
while (node->type != nir_cf_node_loop) {
432
node = node->parent;
433
}
434
435
return nir_cf_node_as_loop(node);
436
}
437
438
static void
439
remove_phi_src(nir_block *block, nir_block *pred)
440
{
441
nir_foreach_instr(instr, block) {
442
if (instr->type != nir_instr_type_phi)
443
break;
444
445
nir_phi_instr *phi = nir_instr_as_phi(instr);
446
nir_foreach_phi_src_safe(src, phi) {
447
if (src->pred == pred) {
448
list_del(&src->src.use_link);
449
exec_node_remove(&src->node);
450
}
451
}
452
}
453
}
454
455
/*
456
* update the CFG after a jump instruction has been added to the end of a block
457
*/
458
459
void
460
nir_handle_add_jump(nir_block *block)
461
{
462
nir_instr *instr = nir_block_last_instr(block);
463
nir_jump_instr *jump_instr = nir_instr_as_jump(instr);
464
465
if (block->successors[0])
466
remove_phi_src(block->successors[0], block);
467
if (block->successors[1])
468
remove_phi_src(block->successors[1], block);
469
unlink_block_successors(block);
470
471
nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node);
472
nir_metadata_preserve(impl, nir_metadata_none);
473
474
switch (jump_instr->type) {
475
case nir_jump_return:
476
case nir_jump_halt:
477
link_blocks(block, impl->end_block, NULL);
478
break;
479
480
case nir_jump_break: {
481
nir_loop *loop = nearest_loop(&block->cf_node);
482
nir_cf_node *after = nir_cf_node_next(&loop->cf_node);
483
nir_block *after_block = nir_cf_node_as_block(after);
484
link_blocks(block, after_block, NULL);
485
break;
486
}
487
488
case nir_jump_continue: {
489
nir_loop *loop = nearest_loop(&block->cf_node);
490
nir_block *first_block = nir_loop_first_block(loop);
491
link_blocks(block, first_block, NULL);
492
break;
493
}
494
495
case nir_jump_goto:
496
link_blocks(block, jump_instr->target, NULL);
497
break;
498
499
case nir_jump_goto_if:
500
link_blocks(block, jump_instr->else_target, jump_instr->target);
501
break;
502
503
default:
504
unreachable("Invalid jump type");
505
}
506
}
507
508
/* Removes the successor of a block with a jump. Note that the jump to be
509
* eliminated may be free-floating.
510
*/
511
512
static void
513
unlink_jump(nir_block *block, nir_jump_type type, bool add_normal_successors)
514
{
515
if (block->successors[0])
516
remove_phi_src(block->successors[0], block);
517
if (block->successors[1])
518
remove_phi_src(block->successors[1], block);
519
520
unlink_block_successors(block);
521
if (add_normal_successors)
522
block_add_normal_succs(block);
523
}
524
525
void
526
nir_handle_remove_jump(nir_block *block, nir_jump_type type)
527
{
528
unlink_jump(block, type, true);
529
530
nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node);
531
nir_metadata_preserve(impl, nir_metadata_none);
532
}
533
534
static void
535
update_if_uses(nir_cf_node *node)
536
{
537
if (node->type != nir_cf_node_if)
538
return;
539
540
nir_if *if_stmt = nir_cf_node_as_if(node);
541
542
if_stmt->condition.parent_if = if_stmt;
543
if (if_stmt->condition.is_ssa) {
544
list_addtail(&if_stmt->condition.use_link,
545
&if_stmt->condition.ssa->if_uses);
546
} else {
547
list_addtail(&if_stmt->condition.use_link,
548
&if_stmt->condition.reg.reg->if_uses);
549
}
550
}
551
552
/**
553
* Stitch two basic blocks together into one. The aggregate must have the same
554
* predecessors as the first and the same successors as the second.
555
*/
556
557
static void
558
stitch_blocks(nir_block *before, nir_block *after)
559
{
560
/*
561
* We move after into before, so we have to deal with up to 2 successors vs.
562
* possibly a large number of predecessors.
563
*
564
* TODO: special case when before is empty and after isn't?
565
*/
566
567
if (nir_block_ends_in_jump(before)) {
568
assert(exec_list_is_empty(&after->instr_list));
569
if (after->successors[0])
570
remove_phi_src(after->successors[0], after);
571
if (after->successors[1])
572
remove_phi_src(after->successors[1], after);
573
unlink_block_successors(after);
574
exec_node_remove(&after->cf_node.node);
575
} else {
576
move_successors(after, before);
577
578
foreach_list_typed(nir_instr, instr, node, &after->instr_list) {
579
instr->block = before;
580
}
581
582
exec_list_append(&before->instr_list, &after->instr_list);
583
exec_node_remove(&after->cf_node.node);
584
}
585
}
586
587
void
588
nir_cf_node_insert(nir_cursor cursor, nir_cf_node *node)
589
{
590
nir_block *before, *after;
591
592
split_block_cursor(cursor, &before, &after);
593
594
if (node->type == nir_cf_node_block) {
595
nir_block *block = nir_cf_node_as_block(node);
596
exec_node_insert_after(&before->cf_node.node, &block->cf_node.node);
597
block->cf_node.parent = before->cf_node.parent;
598
/* stitch_blocks() assumes that any block that ends with a jump has
599
* already been setup with the correct successors, so we need to set
600
* up jumps here as the block is being inserted.
601
*/
602
if (nir_block_ends_in_jump(block))
603
nir_handle_add_jump(block);
604
605
stitch_blocks(block, after);
606
stitch_blocks(before, block);
607
} else {
608
update_if_uses(node);
609
insert_non_block(before, node, after);
610
}
611
}
612
613
static bool
614
replace_ssa_def_uses(nir_ssa_def *def, void *void_impl)
615
{
616
nir_function_impl *impl = void_impl;
617
void *mem_ctx = ralloc_parent(impl);
618
619
nir_ssa_undef_instr *undef =
620
nir_ssa_undef_instr_create(mem_ctx, def->num_components,
621
def->bit_size);
622
nir_instr_insert_before_cf_list(&impl->body, &undef->instr);
623
nir_ssa_def_rewrite_uses(def, &undef->def);
624
return true;
625
}
626
627
static void
628
cleanup_cf_node(nir_cf_node *node, nir_function_impl *impl)
629
{
630
switch (node->type) {
631
case nir_cf_node_block: {
632
nir_block *block = nir_cf_node_as_block(node);
633
/* We need to walk the instructions and clean up defs/uses */
634
nir_foreach_instr_safe(instr, block) {
635
if (instr->type == nir_instr_type_jump) {
636
nir_jump_instr *jump = nir_instr_as_jump(instr);
637
unlink_jump(block, jump->type, false);
638
if (jump->type == nir_jump_goto_if)
639
nir_instr_rewrite_src(instr, &jump->condition, NIR_SRC_INIT);
640
} else {
641
nir_foreach_ssa_def(instr, replace_ssa_def_uses, impl);
642
nir_instr_remove(instr);
643
}
644
}
645
break;
646
}
647
648
case nir_cf_node_if: {
649
nir_if *if_stmt = nir_cf_node_as_if(node);
650
foreach_list_typed(nir_cf_node, child, node, &if_stmt->then_list)
651
cleanup_cf_node(child, impl);
652
foreach_list_typed(nir_cf_node, child, node, &if_stmt->else_list)
653
cleanup_cf_node(child, impl);
654
655
list_del(&if_stmt->condition.use_link);
656
break;
657
}
658
659
case nir_cf_node_loop: {
660
nir_loop *loop = nir_cf_node_as_loop(node);
661
foreach_list_typed(nir_cf_node, child, node, &loop->body)
662
cleanup_cf_node(child, impl);
663
break;
664
}
665
case nir_cf_node_function: {
666
nir_function_impl *impl = nir_cf_node_as_function(node);
667
foreach_list_typed(nir_cf_node, child, node, &impl->body)
668
cleanup_cf_node(child, impl);
669
break;
670
}
671
default:
672
unreachable("Invalid CF node type");
673
}
674
}
675
676
void
677
nir_cf_extract(nir_cf_list *extracted, nir_cursor begin, nir_cursor end)
678
{
679
nir_block *block_begin, *block_end, *block_before, *block_after;
680
681
if (nir_cursors_equal(begin, end)) {
682
exec_list_make_empty(&extracted->list);
683
extracted->impl = NULL; /* we shouldn't need this */
684
return;
685
}
686
687
split_block_cursor(begin, &block_before, &block_begin);
688
689
/* Splitting a block twice with two cursors created before either split is
690
* tricky and there are a couple of places it can go wrong if both cursors
691
* point to the same block. One is if the second cursor is an block-based
692
* cursor and, thanks to the split above, it ends up pointing to the wrong
693
* block. If it's a before_block cursor and it's in the same block as
694
* begin, then begin must also be a before_block cursor and it should be
695
* caught by the nir_cursors_equal check above and we won't get here. If
696
* it's an after_block cursor, we need to re-adjust to ensure that it
697
* points to the second one of the split blocks, regardless of which it is.
698
*/
699
if (end.option == nir_cursor_after_block && end.block == block_before)
700
end.block = block_begin;
701
702
split_block_cursor(end, &block_end, &block_after);
703
704
/* The second place this can all go wrong is that it could be that the
705
* second split places the original block after the new block in which case
706
* the block_begin pointer that we saved off above is pointing to the block
707
* at the end rather than the block in the middle like it's supposed to be.
708
* In this case, we have to re-adjust begin_block to point to the middle
709
* one.
710
*/
711
if (block_begin == block_after)
712
block_begin = block_end;
713
714
extracted->impl = nir_cf_node_get_function(&block_begin->cf_node);
715
exec_list_make_empty(&extracted->list);
716
717
/* Dominance and other block-related information is toast. */
718
nir_metadata_preserve(extracted->impl, nir_metadata_none);
719
720
nir_cf_node *cf_node = &block_begin->cf_node;
721
nir_cf_node *cf_node_end = &block_end->cf_node;
722
while (true) {
723
nir_cf_node *next = nir_cf_node_next(cf_node);
724
725
exec_node_remove(&cf_node->node);
726
cf_node->parent = NULL;
727
exec_list_push_tail(&extracted->list, &cf_node->node);
728
729
if (cf_node == cf_node_end)
730
break;
731
732
cf_node = next;
733
}
734
735
stitch_blocks(block_before, block_after);
736
}
737
738
static void
739
relink_jump_halt_cf_node(nir_cf_node *node, nir_block *end_block)
740
{
741
switch (node->type) {
742
case nir_cf_node_block: {
743
nir_block *block = nir_cf_node_as_block(node);
744
nir_instr *last_instr = nir_block_last_instr(block);
745
if (last_instr == NULL || last_instr->type != nir_instr_type_jump)
746
break;
747
748
nir_jump_instr *jump = nir_instr_as_jump(last_instr);
749
/* We can't move a CF list from one function to another while we still
750
* have returns.
751
*/
752
assert(jump->type != nir_jump_return);
753
754
if (jump->type == nir_jump_halt) {
755
unlink_block_successors(block);
756
link_blocks(block, end_block, NULL);
757
}
758
break;
759
}
760
761
case nir_cf_node_if: {
762
nir_if *if_stmt = nir_cf_node_as_if(node);
763
foreach_list_typed(nir_cf_node, child, node, &if_stmt->then_list)
764
relink_jump_halt_cf_node(child, end_block);
765
foreach_list_typed(nir_cf_node, child, node, &if_stmt->else_list)
766
relink_jump_halt_cf_node(child, end_block);
767
break;
768
}
769
770
case nir_cf_node_loop: {
771
nir_loop *loop = nir_cf_node_as_loop(node);
772
foreach_list_typed(nir_cf_node, child, node, &loop->body)
773
relink_jump_halt_cf_node(child, end_block);
774
break;
775
}
776
777
case nir_cf_node_function:
778
unreachable("Cannot insert a function in a function");
779
780
default:
781
unreachable("Invalid CF node type");
782
}
783
}
784
785
void
786
nir_cf_reinsert(nir_cf_list *cf_list, nir_cursor cursor)
787
{
788
nir_block *before, *after;
789
790
if (exec_list_is_empty(&cf_list->list))
791
return;
792
793
nir_function_impl *cursor_impl =
794
nir_cf_node_get_function(&nir_cursor_current_block(cursor)->cf_node);
795
if (cf_list->impl != cursor_impl) {
796
foreach_list_typed(nir_cf_node, node, node, &cf_list->list)
797
relink_jump_halt_cf_node(node, cursor_impl->end_block);
798
}
799
800
split_block_cursor(cursor, &before, &after);
801
802
foreach_list_typed_safe(nir_cf_node, node, node, &cf_list->list) {
803
exec_node_remove(&node->node);
804
node->parent = before->cf_node.parent;
805
exec_node_insert_node_before(&after->cf_node.node, &node->node);
806
}
807
808
stitch_blocks(before,
809
nir_cf_node_as_block(nir_cf_node_next(&before->cf_node)));
810
stitch_blocks(nir_cf_node_as_block(nir_cf_node_prev(&after->cf_node)),
811
after);
812
}
813
814
void
815
nir_cf_delete(nir_cf_list *cf_list)
816
{
817
foreach_list_typed(nir_cf_node, node, node, &cf_list->list) {
818
cleanup_cf_node(node, cf_list->impl);
819
}
820
}
821
822