2 * Copyright (c) 2017 Lima Project
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:
11 * The above copyright notice and this permission notice (including the
12 * next paragraph) shall be included in all copies or substantial portions
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.
28 static bool create_new_instr(ppir_block
*block
, ppir_node
*node
)
30 ppir_instr
*instr
= ppir_instr_create(block
);
34 if (!ppir_instr_insert_node(instr
, node
))
41 * If a node has a pipeline dest, schedule it in the same instruction as its
43 * Since it has a pipeline dest, it must have only one successor and since we
44 * schedule nodes backwards, its successor must have already been scheduled.
46 static bool ppir_do_node_to_instr_pipeline(ppir_block
*block
, ppir_node
*node
)
48 ppir_dest
*dest
= ppir_node_get_dest(node
);
50 if (!dest
|| dest
->type
!= ppir_target_pipeline
)
53 assert(ppir_node_has_single_src_succ(node
));
54 ppir_node
*succ
= ppir_node_first_succ(node
);
58 if (!ppir_instr_insert_node(succ
->instr
, node
))
64 static bool ppir_do_one_node_to_instr(ppir_block
*block
, ppir_node
*node
, ppir_node
**next
)
67 case ppir_node_type_alu
:
69 /* don't create an instr for undef node */
70 if (node
->op
== ppir_op_undef
)
73 /* merge pred mul and succ add in the same instr can save a reg
74 * by using pipeline reg ^vmul/^fmul */
75 ppir_alu_node
*alu
= ppir_node_to_alu(node
);
76 if (alu
->dest
.type
== ppir_target_ssa
&&
77 ppir_node_has_single_src_succ(node
)) {
78 ppir_node
*succ
= ppir_node_first_succ(node
);
79 if (succ
->instr_pos
== PPIR_INSTR_SLOT_ALU_VEC_ADD
) {
80 node
->instr_pos
= PPIR_INSTR_SLOT_ALU_VEC_MUL
;
81 ppir_instr_insert_mul_node(succ
, node
);
83 else if (succ
->instr_pos
== PPIR_INSTR_SLOT_ALU_SCL_ADD
&&
84 alu
->dest
.ssa
.num_components
== 1) {
85 node
->instr_pos
= PPIR_INSTR_SLOT_ALU_SCL_MUL
;
86 ppir_instr_insert_mul_node(succ
, node
);
90 /* can't inserted to any existing instr, create one */
91 if (!node
->instr
&& !create_new_instr(block
, node
))
94 if (node
->op
== ppir_op_store_color
)
95 node
->instr
->is_end
= true;
99 case ppir_node_type_load
:
100 case ppir_node_type_load_texture
:
102 if (!create_new_instr(block
, node
))
105 /* load varying output can be a register, it doesn't need a mov */
107 case ppir_op_load_varying
:
108 case ppir_op_load_coords
:
109 case ppir_op_load_coords_reg
:
110 case ppir_op_load_fragcoord
:
111 case ppir_op_load_pointcoord
:
112 case ppir_op_load_frontface
:
118 /* Load cannot be pipelined, likely slot is already taken. Create a mov */
119 assert(ppir_node_has_single_src_succ(node
));
120 ppir_dest
*dest
= ppir_node_get_dest(node
);
121 assert(dest
->type
== ppir_target_pipeline
);
122 ppir_pipeline pipeline_reg
= dest
->pipeline
;
124 /* Turn dest back to SSA, so we can update predecessors */
125 ppir_node
*succ
= ppir_node_first_succ(node
);
126 ppir_src
*succ_src
= ppir_node_get_src_for_pred(succ
, node
);
127 dest
->type
= ppir_target_ssa
;
128 dest
->ssa
.index
= -1;
129 ppir_node_target_assign(succ_src
, node
);
131 ppir_node
*move
= ppir_node_insert_mov(node
);
135 ppir_src
*mov_src
= ppir_node_get_src(move
, 0);
136 mov_src
->type
= dest
->type
= ppir_target_pipeline
;
137 mov_src
->pipeline
= dest
->pipeline
= pipeline_reg
;
139 ppir_debug("node_to_instr create move %d for load %d\n",
140 move
->index
, node
->index
);
142 if (!ppir_instr_insert_node(node
->instr
, move
))
147 case ppir_node_type_const
:
148 /* Const nodes are supposed to go through do_node_to_instr_pipeline() */
151 case ppir_node_type_store
:
153 if (node
->op
== ppir_op_store_temp
) {
154 if (!create_new_instr(block
, node
))
159 case ppir_node_type_discard
:
160 if (!create_new_instr(block
, node
))
162 node
->instr
->is_end
= true;
164 case ppir_node_type_branch
:
165 if (!create_new_instr(block
, node
))
175 static bool ppir_do_node_to_instr(ppir_block
*block
, ppir_node
*node
)
177 ppir_node
*next
= node
;
179 /* first try pipeline sched, if that didn't succeed try normal scheduling */
180 if (!ppir_do_node_to_instr_pipeline(block
, node
))
181 if (!ppir_do_one_node_to_instr(block
, node
, &next
))
184 /* next may have been updated in ppir_do_one_node_to_instr */
187 /* we have to make sure the dep not be destroyed (due to
188 * succ change) in ppir_do_node_to_instr, otherwise we can't
189 * do recursion like this */
190 ppir_node_foreach_pred(node
, dep
) {
191 ppir_node
*pred
= dep
->pred
;
194 /* pred may already be processed by the previous pred
195 * (this pred may be both node and previous pred's child) */
199 /* insert pred only when all its successors have been inserted */
200 ppir_node_foreach_succ(pred
, dep
) {
201 ppir_node
*succ
= dep
->succ
;
209 if (!ppir_do_node_to_instr(block
, pred
))
217 static bool ppir_create_instr_from_node(ppir_compiler
*comp
)
219 list_for_each_entry(ppir_block
, block
, &comp
->block_list
, list
) {
220 list_for_each_entry(ppir_node
, node
, &block
->node_list
, list
) {
221 if (ppir_node_is_root(node
)) {
222 if (!ppir_do_node_to_instr(block
, node
))
231 static void ppir_build_instr_dependency(ppir_compiler
*comp
)
233 list_for_each_entry(ppir_block
, block
, &comp
->block_list
, list
) {
234 list_for_each_entry(ppir_instr
, instr
, &block
->instr_list
, list
) {
235 for (int i
= 0; i
< PPIR_INSTR_SLOT_NUM
; i
++) {
236 ppir_node
*node
= instr
->slots
[i
];
238 ppir_node_foreach_pred(node
, dep
) {
239 ppir_node
*pred
= dep
->pred
;
240 if (pred
->instr
&& pred
->instr
!= instr
)
241 ppir_instr_add_dep(instr
, pred
->instr
);
249 bool ppir_node_to_instr(ppir_compiler
*comp
)
251 if (!ppir_create_instr_from_node(comp
))
253 ppir_instr_print_list(comp
);
255 ppir_build_instr_dependency(comp
);
256 ppir_instr_print_dep(comp
);