1 /*
2  * Copyright (c) 2017 Lima Project
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, sub license,
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
12  * next paragraph) shall be included in all copies or substantial portions
13  * of the 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 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
21  * DEALINGS IN THE SOFTWARE.
22  *
23  */
24 
25 #include "util/u_math.h"
26 #include "util/ralloc.h"
27 #include "util/bitscan.h"
28 
29 #include "ppir.h"
30 
31 const ppir_op_info ppir_op_infos[] = {
32    [ppir_op_mov] = {
33       .name = "mov",
34       .slots = (int []) {
35          PPIR_INSTR_SLOT_ALU_SCL_ADD, PPIR_INSTR_SLOT_ALU_SCL_MUL,
36          PPIR_INSTR_SLOT_ALU_VEC_ADD, PPIR_INSTR_SLOT_ALU_VEC_MUL,
37          PPIR_INSTR_SLOT_END
38       },
39    },
40    [ppir_op_abs] = {
41       .name = "abs",
42    },
43    [ppir_op_neg] = {
44       .name = "neg",
45    },
46    [ppir_op_sat] = {
47       .name = "sat",
48    },
49    [ppir_op_mul] = {
50       .name = "mul",
51       .slots = (int []) {
52          PPIR_INSTR_SLOT_ALU_SCL_MUL, PPIR_INSTR_SLOT_ALU_VEC_MUL,
53          PPIR_INSTR_SLOT_END
54       },
55    },
56    [ppir_op_add] = {
57       .name = "add",
58       .slots = (int []) {
59          PPIR_INSTR_SLOT_ALU_SCL_ADD, PPIR_INSTR_SLOT_ALU_VEC_ADD,
60          PPIR_INSTR_SLOT_END
61       },
62    },
63    [ppir_op_sum3] = {
64       .name = "sum3",
65       .slots = (int []) {
66          PPIR_INSTR_SLOT_ALU_VEC_ADD, PPIR_INSTR_SLOT_END
67       },
68    },
69    [ppir_op_sum4] = {
70       .name = "sum4",
71       .slots = (int []) {
72          PPIR_INSTR_SLOT_ALU_VEC_ADD, PPIR_INSTR_SLOT_END
73       },
74    },
75    [ppir_op_rsqrt] = {
76       .name = "rsqrt",
77       .slots = (int []) {
78          PPIR_INSTR_SLOT_ALU_COMBINE, PPIR_INSTR_SLOT_END
79       },
80    },
81    [ppir_op_log2] = {
82       .name = "log2",
83       .slots = (int []) {
84          PPIR_INSTR_SLOT_ALU_COMBINE, PPIR_INSTR_SLOT_END
85       },
86    },
87    [ppir_op_exp2] = {
88       .name = "exp2",
89       .slots = (int []) {
90          PPIR_INSTR_SLOT_ALU_COMBINE, PPIR_INSTR_SLOT_END
91       },
92    },
93    [ppir_op_sqrt] = {
94       .name = "sqrt",
95       .slots = (int []) {
96          PPIR_INSTR_SLOT_ALU_COMBINE, PPIR_INSTR_SLOT_END
97       },
98    },
99    [ppir_op_sin] = {
100       .name = "sin",
101       .slots = (int []) {
102          PPIR_INSTR_SLOT_ALU_COMBINE, PPIR_INSTR_SLOT_END
103       },
104    },
105    [ppir_op_cos] = {
106       .name = "cos",
107       .slots = (int []) {
108          PPIR_INSTR_SLOT_ALU_COMBINE, PPIR_INSTR_SLOT_END
109       },
110    },
111    [ppir_op_max] = {
112       .name = "max",
113       .slots = (int []) {
114          PPIR_INSTR_SLOT_ALU_SCL_ADD, PPIR_INSTR_SLOT_ALU_SCL_MUL,
115          PPIR_INSTR_SLOT_ALU_VEC_ADD, PPIR_INSTR_SLOT_ALU_VEC_MUL,
116          PPIR_INSTR_SLOT_END
117       },
118    },
119    [ppir_op_min] = {
120       .name = "min",
121       .slots = (int []) {
122          PPIR_INSTR_SLOT_ALU_SCL_ADD, PPIR_INSTR_SLOT_ALU_SCL_MUL,
123          PPIR_INSTR_SLOT_ALU_VEC_ADD, PPIR_INSTR_SLOT_ALU_VEC_MUL,
124          PPIR_INSTR_SLOT_END
125       },
126    },
127    [ppir_op_floor] = {
128       .name = "floor",
129       .slots = (int []) {
130          PPIR_INSTR_SLOT_ALU_SCL_ADD, PPIR_INSTR_SLOT_ALU_VEC_ADD,
131          PPIR_INSTR_SLOT_END
132       },
133    },
134    [ppir_op_ceil] = {
135       .name = "ceil",
136       .slots = (int []) {
137          PPIR_INSTR_SLOT_ALU_SCL_ADD, PPIR_INSTR_SLOT_ALU_VEC_ADD,
138          PPIR_INSTR_SLOT_END
139       },
140    },
141    [ppir_op_fract] = {
142       .name = "fract",
143       .slots = (int []) {
144          PPIR_INSTR_SLOT_ALU_SCL_ADD, PPIR_INSTR_SLOT_ALU_VEC_ADD,
145          PPIR_INSTR_SLOT_END
146       },
147    },
148    [ppir_op_ddx] = {
149       .name = "ddx",
150       .slots = (int []) {
151          PPIR_INSTR_SLOT_ALU_SCL_ADD, PPIR_INSTR_SLOT_ALU_VEC_ADD,
152          PPIR_INSTR_SLOT_END
153       },
154    },
155    [ppir_op_ddy] = {
156       .name = "ddy",
157       .slots = (int []) {
158          PPIR_INSTR_SLOT_ALU_SCL_ADD, PPIR_INSTR_SLOT_ALU_VEC_ADD,
159          PPIR_INSTR_SLOT_END
160       },
161    },
162    [ppir_op_and] = {
163       .name = "and",
164       .slots = (int []) {
165          PPIR_INSTR_SLOT_ALU_SCL_MUL, PPIR_INSTR_SLOT_ALU_VEC_MUL,
166          PPIR_INSTR_SLOT_END
167       },
168    },
169    [ppir_op_or] = {
170       .name = "or",
171       .slots = (int []) {
172          PPIR_INSTR_SLOT_ALU_SCL_MUL, PPIR_INSTR_SLOT_ALU_VEC_MUL,
173          PPIR_INSTR_SLOT_END
174       },
175    },
176    [ppir_op_xor] = {
177       .name = "xor",
178       .slots = (int []) {
179          PPIR_INSTR_SLOT_ALU_SCL_MUL, PPIR_INSTR_SLOT_ALU_VEC_MUL,
180          PPIR_INSTR_SLOT_END
181       },
182    },
183    [ppir_op_not] = {
184       .name = "not",
185       .slots = (int []) {
186          PPIR_INSTR_SLOT_ALU_SCL_MUL, PPIR_INSTR_SLOT_ALU_VEC_MUL,
187          PPIR_INSTR_SLOT_END
188       },
189    },
190    [ppir_op_lt] = {
191       .name = "lt",
192    },
193    [ppir_op_le] = {
194       .name = "le",
195    },
196    [ppir_op_gt] = {
197       .name = "gt",
198       .slots = (int []) {
199          PPIR_INSTR_SLOT_ALU_SCL_MUL, PPIR_INSTR_SLOT_ALU_SCL_ADD,
200          PPIR_INSTR_SLOT_ALU_VEC_MUL, PPIR_INSTR_SLOT_ALU_VEC_ADD,
201          PPIR_INSTR_SLOT_END
202       },
203    },
204    [ppir_op_ge] = {
205       .name = "ge",
206       .slots = (int []) {
207          PPIR_INSTR_SLOT_ALU_SCL_MUL, PPIR_INSTR_SLOT_ALU_SCL_ADD,
208          PPIR_INSTR_SLOT_ALU_VEC_MUL, PPIR_INSTR_SLOT_ALU_VEC_ADD,
209          PPIR_INSTR_SLOT_END
210       },
211    },
212    [ppir_op_eq] = {
213       .name = "eq",
214       .slots = (int []) {
215          PPIR_INSTR_SLOT_ALU_SCL_MUL, PPIR_INSTR_SLOT_ALU_SCL_ADD,
216          PPIR_INSTR_SLOT_ALU_VEC_MUL, PPIR_INSTR_SLOT_ALU_VEC_ADD,
217          PPIR_INSTR_SLOT_END
218       },
219    },
220    [ppir_op_ne] = {
221       .name = "ne",
222       .slots = (int []) {
223          PPIR_INSTR_SLOT_ALU_SCL_MUL, PPIR_INSTR_SLOT_ALU_SCL_ADD,
224          PPIR_INSTR_SLOT_ALU_VEC_MUL, PPIR_INSTR_SLOT_ALU_VEC_ADD,
225          PPIR_INSTR_SLOT_END
226       },
227    },
228    [ppir_op_select] = {
229       .name = "select",
230       .slots = (int []) {
231          PPIR_INSTR_SLOT_ALU_SCL_ADD, PPIR_INSTR_SLOT_ALU_VEC_ADD,
232          PPIR_INSTR_SLOT_END
233       },
234    },
235    [ppir_op_rcp] = {
236       .name = "rcp",
237       .slots = (int []) {
238          PPIR_INSTR_SLOT_ALU_COMBINE, PPIR_INSTR_SLOT_END
239       },
240    },
241    [ppir_op_load_varying] = {
242       .name = "ld_var",
243       .type = ppir_node_type_load,
244       .slots = (int []) {
245          PPIR_INSTR_SLOT_VARYING, PPIR_INSTR_SLOT_END
246       },
247    },
248    [ppir_op_load_coords] = {
249       .name = "ld_coords",
250       .type = ppir_node_type_load,
251       .slots = (int []) {
252          PPIR_INSTR_SLOT_VARYING, PPIR_INSTR_SLOT_END
253       },
254    },
255    [ppir_op_load_coords_reg] = {
256       .name = "ld_coords_reg",
257       .type = ppir_node_type_load,
258       .slots = (int []) {
259          PPIR_INSTR_SLOT_VARYING, PPIR_INSTR_SLOT_END
260       },
261    },
262    [ppir_op_load_fragcoord] = {
263       .name = "ld_fragcoord",
264       .type = ppir_node_type_load,
265       .slots = (int []) {
266          PPIR_INSTR_SLOT_VARYING, PPIR_INSTR_SLOT_END
267       },
268    },
269    [ppir_op_load_pointcoord] = {
270       .name = "ld_pointcoord",
271       .type = ppir_node_type_load,
272       .slots = (int []) {
273          PPIR_INSTR_SLOT_VARYING, PPIR_INSTR_SLOT_END
274       },
275    },
276    [ppir_op_load_frontface] = {
277       .name = "ld_frontface",
278       .type = ppir_node_type_load,
279       .slots = (int []) {
280          PPIR_INSTR_SLOT_VARYING, PPIR_INSTR_SLOT_END
281       },
282    },
283    [ppir_op_load_uniform] = {
284       .name = "ld_uni",
285       .type = ppir_node_type_load,
286       .slots = (int []) {
287          PPIR_INSTR_SLOT_UNIFORM, PPIR_INSTR_SLOT_END
288       },
289    },
290    [ppir_op_load_texture] = {
291       .name = "ld_tex",
292       .type = ppir_node_type_load_texture,
293       .slots = (int []) {
294          PPIR_INSTR_SLOT_TEXLD, PPIR_INSTR_SLOT_END
295       },
296    },
297    [ppir_op_load_temp] = {
298       .name = "ld_temp",
299       .type = ppir_node_type_load,
300       .slots = (int []) {
301          PPIR_INSTR_SLOT_UNIFORM, PPIR_INSTR_SLOT_END
302       },
303    },
304    [ppir_op_const] = {
305       .name = "const",
306       .type = ppir_node_type_const,
307    },
308    [ppir_op_store_temp] = {
309       .name = "st_temp",
310       .type = ppir_node_type_store,
311       .slots = (int []) {
312          PPIR_INSTR_SLOT_STORE_TEMP, PPIR_INSTR_SLOT_END
313       },
314    },
315    [ppir_op_discard] = {
316       .name = "discard",
317       .type = ppir_node_type_discard,
318       .slots = (int []) {
319          PPIR_INSTR_SLOT_BRANCH, PPIR_INSTR_SLOT_END
320       },
321    },
322    [ppir_op_branch] = {
323       .name = "branch",
324       .type = ppir_node_type_branch,
325       .slots = (int []) {
326          PPIR_INSTR_SLOT_BRANCH, PPIR_INSTR_SLOT_END
327       },
328    },
329    [ppir_op_undef] = {
330       .name = "undef",
331       .type = ppir_node_type_alu,
332       .slots = (int []) {
333       },
334    },
335    [ppir_op_dummy] = {
336       .name = "dummy",
337       .type = ppir_node_type_alu,
338       .slots = (int []) {
339       },
340    },
341 };
342 
ppir_node_create(ppir_block * block,ppir_op op,int index,unsigned mask)343 void *ppir_node_create(ppir_block *block, ppir_op op, int index, unsigned mask)
344 {
345    ppir_compiler *comp = block->comp;
346    static const int node_size[] = {
347       [ppir_node_type_alu] = sizeof(ppir_alu_node),
348       [ppir_node_type_const] = sizeof(ppir_const_node),
349       [ppir_node_type_load] = sizeof(ppir_load_node),
350       [ppir_node_type_store] = sizeof(ppir_store_node),
351       [ppir_node_type_load_texture] = sizeof(ppir_load_texture_node),
352       [ppir_node_type_discard] = sizeof(ppir_discard_node),
353       [ppir_node_type_branch] = sizeof(ppir_branch_node),
354    };
355 
356    ppir_node_type type = ppir_op_infos[op].type;
357    int size = node_size[type];
358    ppir_node *node = rzalloc_size(block, size);
359    if (!node)
360       return NULL;
361 
362    list_inithead(&node->succ_list);
363    list_inithead(&node->pred_list);
364 
365    if (index >= 0) {
366       if (mask) {
367          /* reg has 4 slots for each component write node */
368          while (mask)
369             comp->var_nodes[(index << 2) + comp->reg_base + u_bit_scan(&mask)] = node;
370          snprintf(node->name, sizeof(node->name), "reg%d", index);
371       } else {
372          comp->var_nodes[index] = node;
373          snprintf(node->name, sizeof(node->name), "ssa%d", index);
374       }
375    }
376    else
377       snprintf(node->name, sizeof(node->name), "new");
378 
379    node->op = op;
380    node->type = type;
381    node->index = comp->cur_index++;
382    node->block = block;
383 
384    return node;
385 }
386 
ppir_node_add_dep(ppir_node * succ,ppir_node * pred,ppir_dep_type type)387 void ppir_node_add_dep(ppir_node *succ, ppir_node *pred,
388                        ppir_dep_type type)
389 {
390    /* don't add dep for two nodes from different block */
391    if (succ->block != pred->block) {
392       pred->succ_different_block = true;
393       return;
394    }
395 
396    /* don't add duplicated dep */
397    ppir_node_foreach_pred(succ, dep) {
398       if (dep->pred == pred)
399          return;
400    }
401 
402    ppir_dep *dep = ralloc(succ, ppir_dep);
403    dep->pred = pred;
404    dep->succ = succ;
405    dep->type = type;
406    list_addtail(&dep->pred_link, &succ->pred_list);
407    list_addtail(&dep->succ_link, &pred->succ_list);
408 }
409 
ppir_node_remove_dep(ppir_dep * dep)410 void ppir_node_remove_dep(ppir_dep *dep)
411 {
412    list_del(&dep->succ_link);
413    list_del(&dep->pred_link);
414    ralloc_free(dep);
415 }
416 
_ppir_node_replace_child(ppir_src * src,ppir_node * old_child,ppir_node * new_child)417 static void _ppir_node_replace_child(ppir_src *src, ppir_node *old_child, ppir_node *new_child)
418 {
419    ppir_dest *od = ppir_node_get_dest(old_child);
420    if (ppir_node_target_equal(src, od)) {
421       ppir_node_target_assign(src, new_child);
422    }
423 }
424 
ppir_node_replace_child(ppir_node * parent,ppir_node * old_child,ppir_node * new_child)425 void ppir_node_replace_child(ppir_node *parent, ppir_node *old_child, ppir_node *new_child)
426 {
427    switch (parent->type) {
428    case ppir_node_type_alu:
429    {
430       ppir_alu_node *alu = ppir_node_to_alu(parent);
431       for (int i = 0; i < alu->num_src; i++)
432          _ppir_node_replace_child(alu->src + i, old_child, new_child);
433       break;
434    }
435    case ppir_node_type_branch:
436    {
437       ppir_branch_node *branch = ppir_node_to_branch(parent);
438       for (int i = 0; i < 2; i++)
439          _ppir_node_replace_child(branch->src + i, old_child, new_child);
440       break;
441    }
442    case ppir_node_type_load:
443    {
444       ppir_load_node *load = ppir_node_to_load(parent);
445       _ppir_node_replace_child(&load->src, old_child, new_child);
446       break;
447    }
448    case ppir_node_type_load_texture:
449    {
450       ppir_load_texture_node *load_texture = ppir_node_to_load_texture(parent);
451       for (int i = 0; i < load_texture->num_src; i++)
452          _ppir_node_replace_child(ppir_node_get_src(parent, i), old_child, new_child);
453       break;
454    }
455    case ppir_node_type_store:
456    {
457       ppir_store_node *store = ppir_node_to_store(parent);
458       _ppir_node_replace_child(&store->src, old_child, new_child);
459       break;
460    }
461    default:
462       ppir_debug("unknown node type in %s\n", __func__);
463       break;
464    }
465 }
466 
ppir_node_replace_pred(ppir_dep * dep,ppir_node * new_pred)467 void ppir_node_replace_pred(ppir_dep *dep, ppir_node *new_pred)
468 {
469    list_del(&dep->succ_link);
470    dep->pred = new_pred;
471    list_addtail(&dep->succ_link, &new_pred->succ_list);
472 }
473 
ppir_dep_for_pred(ppir_node * node,ppir_node * pred)474 ppir_dep *ppir_dep_for_pred(ppir_node *node, ppir_node *pred)
475 {
476    if (!pred)
477       return NULL;
478 
479    if (node->block != pred->block)
480       return NULL;
481 
482    ppir_node_foreach_pred(node, dep) {
483       if (dep->pred == pred)
484          return dep;
485    }
486    return NULL;
487 }
488 
ppir_node_replace_all_succ(ppir_node * dst,ppir_node * src)489 void ppir_node_replace_all_succ(ppir_node *dst, ppir_node *src)
490 {
491    ppir_node_foreach_succ_safe(src, dep) {
492       ppir_node_replace_pred(dep, dst);
493       ppir_node_replace_child(dep->succ, src, dst);
494    }
495 }
496 
ppir_node_delete(ppir_node * node)497 void ppir_node_delete(ppir_node *node)
498 {
499    ppir_node_foreach_succ_safe(node, dep)
500       ppir_node_remove_dep(dep);
501 
502    ppir_node_foreach_pred_safe(node, dep)
503       ppir_node_remove_dep(dep);
504 
505    list_del(&node->list);
506    ralloc_free(node);
507 }
508 
ppir_node_print_dest(ppir_dest * dest)509 static void ppir_node_print_dest(ppir_dest *dest)
510 {
511    switch (dest->type) {
512    case ppir_target_ssa:
513       printf("ssa%d", dest->ssa.index);
514       break;
515    case ppir_target_pipeline:
516       printf("pipeline %d", dest->pipeline);
517       break;
518    case ppir_target_register:
519       printf("reg %d", dest->reg->index);
520       break;
521    }
522 }
523 
ppir_node_print_src(ppir_src * src)524 static void ppir_node_print_src(ppir_src *src)
525 {
526    switch (src->type) {
527    case ppir_target_ssa: {
528       if (src->node)
529          printf("ssa node %d", src->node->index);
530       else
531          printf("ssa idx %d", src->ssa ? src->ssa->index : -1);
532       break;
533    }
534    case ppir_target_pipeline:
535       if (src->node)
536          printf("pipeline %d node %d", src->pipeline, src->node->index);
537       else
538          printf("pipeline %d", src->pipeline);
539       break;
540    case ppir_target_register:
541       printf("reg %d", src->reg->index);
542       break;
543    }
544 }
545 
ppir_node_print_node(ppir_node * node,int space)546 static void ppir_node_print_node(ppir_node *node, int space)
547 {
548    for (int i = 0; i < space; i++)
549       printf(" ");
550 
551    printf("%s%d: %s %s: ", node->printed && !ppir_node_is_leaf(node) ? "+" : "",
552           node->index, ppir_op_infos[node->op].name, node->name);
553 
554    ppir_dest *dest = ppir_node_get_dest(node);
555    if (dest) {
556       printf("dest: ");
557       ppir_node_print_dest(dest);
558    }
559 
560    if (ppir_node_get_src_num(node) > 0) {
561       printf(" src: ");
562    }
563    for (int i = 0; i < ppir_node_get_src_num(node); i++) {
564       ppir_node_print_src(ppir_node_get_src(node, i));
565       if (i != (ppir_node_get_src_num(node) - 1))
566          printf(", ");
567    }
568    printf("\n");
569 
570    if (!node->printed) {
571       ppir_node_foreach_pred(node, dep) {
572          ppir_node *pred = dep->pred;
573          ppir_node_print_node(pred, space + 2);
574       }
575 
576       node->printed = true;
577    }
578 }
579 
ppir_node_print_prog(ppir_compiler * comp)580 void ppir_node_print_prog(ppir_compiler *comp)
581 {
582    if (!(lima_debug & LIMA_DEBUG_PP))
583       return;
584 
585    list_for_each_entry(ppir_block, block, &comp->block_list, list) {
586       list_for_each_entry(ppir_node, node, &block->node_list, list) {
587          node->printed = false;
588       }
589    }
590 
591    printf("========prog========\n");
592    list_for_each_entry(ppir_block, block, &comp->block_list, list) {
593       printf("-------block %3d-------\n", block->index);
594       list_for_each_entry(ppir_node, node, &block->node_list, list) {
595          if (ppir_node_is_root(node))
596             ppir_node_print_node(node, 0);
597       }
598    }
599    printf("====================\n");
600 }
601 
ppir_node_insert_mov_local(ppir_node * node)602 static ppir_node *ppir_node_insert_mov_local(ppir_node *node)
603 {
604    ppir_node *move = ppir_node_create(node->block, ppir_op_mov, -1, 0);
605    if (unlikely(!move))
606       return NULL;
607 
608    ppir_dest *dest = ppir_node_get_dest(node);
609    ppir_alu_node *alu = ppir_node_to_alu(move);
610    alu->dest = *dest;
611    alu->num_src = 1;
612    ppir_node_target_assign(alu->src, node);
613 
614    for (int s = 0; s < 4; s++)
615       alu->src->swizzle[s] = s;
616 
617    ppir_node_replace_all_succ(move, node);
618    ppir_node_add_dep(move, node, ppir_dep_src);
619    list_addtail(&move->list, &node->list);
620 
621    if (node->is_end) {
622       node->is_end = false;
623       move->is_end = true;
624    }
625 
626    return move;
627 }
628 
ppir_node_insert_mov(ppir_node * old)629 ppir_node *ppir_node_insert_mov(ppir_node *old)
630 {
631    ppir_node *move = ppir_node_insert_mov_local(old);
632    ppir_compiler *comp = old->block->comp;
633 
634    list_for_each_entry(ppir_block, block, &comp->block_list, list) {
635       if (old->block == block)
636          continue;
637       list_for_each_entry_safe(ppir_node, node, &block->node_list, list) {
638          for (int i = 0; i < ppir_node_get_src_num(node); i++){
639             ppir_src *src = ppir_node_get_src(node, i);
640             if (!src)
641                continue;
642             if (src->node == old)
643                ppir_node_target_assign(src, move);
644          }
645       }
646    }
647 
648    return move;
649 }
650 
ppir_node_has_single_src_succ(ppir_node * node)651 bool ppir_node_has_single_src_succ(ppir_node *node)
652 {
653    if (ppir_node_has_single_succ(node) &&
654        list_first_entry(&node->succ_list,
655                         ppir_dep, succ_link)->type == ppir_dep_src)
656       return true;
657 
658    int cnt = 0;
659    ppir_node_foreach_succ(node, dep) {
660       if (dep->type != ppir_dep_src)
661          continue;
662       cnt++;
663    }
664 
665    return cnt == 1;
666 }
667