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
))
40 static bool insert_to_load_tex(ppir_block
*block
, ppir_node
*load_coords
, ppir_node
*ldtex
)
42 ppir_dest
*dest
= ppir_node_get_dest(ldtex
);
43 ppir_node
*move
= NULL
;
45 ppir_load_node
*load
= ppir_node_to_load(load_coords
);
46 load
->dest
.type
= ppir_target_pipeline
;
47 load
->dest
.pipeline
= ppir_pipeline_reg_discard
;
49 ppir_load_texture_node
*load_texture
= ppir_node_to_load_texture(ldtex
);
50 load_texture
->src_coords
.type
= ppir_target_pipeline
;
51 load_texture
->src_coords
.pipeline
= ppir_pipeline_reg_discard
;
53 /* Insert load_coords to ldtex instruction */
54 if (!ppir_instr_insert_node(ldtex
->instr
, load_coords
))
57 /* Create move node */
58 move
= ppir_node_create(block
, ppir_op_mov
, -1 , 0);
62 ppir_debug("insert_load_tex: create move %d for %d\n",
63 move
->index
, ldtex
->index
);
65 ppir_alu_node
*alu
= ppir_node_to_alu(move
);
68 ppir_node_replace_all_succ(move
, ldtex
);
70 dest
->type
= ppir_target_pipeline
;
71 dest
->pipeline
= ppir_pipeline_reg_sampler
;
74 ppir_node_target_assign(&alu
->src
[0], dest
);
75 for (int i
= 0; i
< 4; i
++)
76 alu
->src
->swizzle
[i
] = i
;
78 ppir_node_add_dep(move
, ldtex
);
79 list_addtail(&move
->list
, &ldtex
->list
);
81 if (!ppir_instr_insert_node(ldtex
->instr
, move
))
87 static bool insert_to_each_succ_instr(ppir_block
*block
, ppir_node
*node
)
89 ppir_dest
*dest
= ppir_node_get_dest(node
);
90 assert(dest
->type
== ppir_target_ssa
);
92 ppir_node
*move
= NULL
;
94 ppir_node_foreach_succ_safe(node
, dep
) {
95 ppir_node
*succ
= dep
->succ
;
96 assert(succ
->type
== ppir_node_type_alu
||
97 succ
->type
== ppir_node_type_branch
);
99 if (!ppir_instr_insert_node(succ
->instr
, node
)) {
100 /* create a move node to insert for failed node */
102 move
= ppir_node_create(block
, ppir_op_mov
, -1, 0);
106 ppir_debug("node_to_instr create move %d for %d\n",
107 move
->index
, node
->index
);
109 ppir_alu_node
*alu
= ppir_node_to_alu(move
);
112 ppir_node_target_assign(alu
->src
, dest
);
113 for (int i
= 0; i
< 4; i
++)
114 alu
->src
->swizzle
[i
] = i
;
117 ppir_node_replace_pred(dep
, move
);
118 ppir_node_replace_child(succ
, node
, move
);
123 if (!create_new_instr(block
, move
))
126 MAYBE_UNUSED
bool insert_result
=
127 ppir_instr_insert_node(move
->instr
, node
);
128 assert(insert_result
);
130 ppir_node_add_dep(move
, node
);
131 list_addtail(&move
->list
, &node
->list
);
134 /* dupliacte node for each successor */
137 struct list_head dup_list
;
138 list_inithead(&dup_list
);
140 ppir_node_foreach_succ_safe(node
, dep
) {
141 ppir_node
*succ
= dep
->succ
;
145 node
->instr
= succ
->instr
;
149 if (succ
->instr
== node
->instr
)
152 list_for_each_entry(ppir_node
, dup
, &dup_list
, list
) {
153 if (succ
->instr
== dup
->instr
) {
154 ppir_node_replace_pred(dep
, dup
);
159 ppir_node
*dup
= ppir_node_create(block
, node
->op
, -1, 0);
162 list_addtail(&dup
->list
, &dup_list
);
164 ppir_debug("node_to_instr duplicate %s %d from %d\n",
165 ppir_op_infos
[dup
->op
].name
, dup
->index
, node
->index
);
167 ppir_instr
*instr
= succ
->instr
;
169 dup
->instr_pos
= node
->instr_pos
;
170 ppir_node_replace_pred(dep
, dup
);
172 if ((node
->op
== ppir_op_load_uniform
) || (node
->op
== ppir_op_load_temp
)) {
173 ppir_load_node
*load
= ppir_node_to_load(node
);
174 ppir_load_node
*dup_load
= ppir_node_to_load(dup
);
175 dup_load
->dest
= load
->dest
;
176 dup_load
->index
= load
->index
;
177 dup_load
->num_components
= load
->num_components
;
178 instr
->slots
[node
->instr_pos
] = dup
;
182 list_splicetail(&dup_list
, &node
->list
);
187 static bool ppir_do_node_to_instr(ppir_block
*block
, ppir_node
*node
)
189 switch (node
->type
) {
190 case ppir_node_type_alu
:
192 /* merge pred mul and succ add in the same instr can save a reg
193 * by using pipeline reg ^vmul/^fmul */
194 ppir_alu_node
*alu
= ppir_node_to_alu(node
);
195 if (alu
->dest
.type
== ppir_target_ssa
&&
196 ppir_node_has_single_succ(node
)) {
197 ppir_node
*succ
= ppir_node_first_succ(node
);
198 if (succ
->instr_pos
== PPIR_INSTR_SLOT_ALU_VEC_ADD
) {
199 node
->instr_pos
= PPIR_INSTR_SLOT_ALU_VEC_MUL
;
200 /* select instr's condition must be inserted to fmul slot */
201 if (succ
->op
== ppir_op_select
&&
202 ppir_node_first_pred(succ
) == node
) {
203 assert(alu
->dest
.ssa
.num_components
== 1);
204 node
->instr_pos
= PPIR_INSTR_SLOT_ALU_SCL_MUL
;
206 ppir_instr_insert_mul_node(succ
, node
);
208 else if (succ
->instr_pos
== PPIR_INSTR_SLOT_ALU_SCL_ADD
&&
209 alu
->dest
.ssa
.num_components
== 1) {
210 node
->instr_pos
= PPIR_INSTR_SLOT_ALU_SCL_MUL
;
211 ppir_instr_insert_mul_node(succ
, node
);
215 /* can't inserted to any existing instr, create one */
216 if (!node
->instr
&& !create_new_instr(block
, node
))
221 case ppir_node_type_load
:
222 if ((node
->op
== ppir_op_load_uniform
) || (node
->op
== ppir_op_load_temp
)) {
223 /* merge pred load_uniform into succ instr can save a reg
224 * by using pipeline reg */
225 if (!insert_to_each_succ_instr(block
, node
))
228 ppir_load_node
*load
= ppir_node_to_load(node
);
229 load
->dest
.type
= ppir_target_pipeline
;
230 load
->dest
.pipeline
= ppir_pipeline_reg_uniform
;
232 else if (node
->op
== ppir_op_load_temp
) {
233 /* merge pred load_temp into succ instr can save a reg
234 * by using pipeline reg */
235 if (!insert_to_each_succ_instr(block
, node
))
238 ppir_load_node
*load
= ppir_node_to_load(node
);
239 load
->dest
.type
= ppir_target_pipeline
;
240 load
->dest
.pipeline
= ppir_pipeline_reg_uniform
;
242 else if (node
->op
== ppir_op_load_varying
||
243 node
->op
== ppir_op_load_fragcoord
||
244 node
->op
== ppir_op_load_pointcoord
) {
245 /* delay the load varying dup to scheduler */
246 if (!create_new_instr(block
, node
))
249 else if (node
->op
== ppir_op_load_coords
) {
250 ppir_node
*ldtex
= ppir_node_first_succ(node
);
251 if (!insert_to_load_tex(block
, node
, ldtex
))
255 /* not supported yet */
260 case ppir_node_type_load_texture
:
261 if (!create_new_instr(block
, node
))
264 case ppir_node_type_const
:
265 if (!insert_to_each_succ_instr(block
, node
))
268 case ppir_node_type_store
:
270 if (node
->op
== ppir_op_store_temp
) {
271 if (!create_new_instr(block
, node
))
276 /* Only the store color node should appear here.
277 * Currently we always insert a move node as the end instr.
278 * But it should only be done when:
279 * 1. store a const node
280 * 2. store a load node
281 * 3. store a reg assigned in another block like loop/if
284 assert(node
->op
== ppir_op_store_color
);
286 ppir_node
*move
= ppir_node_create(block
, ppir_op_mov
, -1, 0);
290 ppir_debug("node_to_instr create move %d from store %d\n",
291 move
->index
, node
->index
);
293 ppir_node_foreach_pred_safe(node
, dep
) {
294 ppir_node
*pred
= dep
->pred
;
295 /* we can't do this in this function except here as this
296 * store is the root of this recursion */
297 ppir_node_remove_dep(dep
);
298 ppir_node_add_dep(move
, pred
);
301 ppir_node_add_dep(node
, move
);
302 list_addtail(&move
->list
, &node
->list
);
304 ppir_alu_node
*alu
= ppir_node_to_alu(move
);
305 ppir_store_node
*store
= ppir_node_to_store(node
);
306 alu
->src
[0] = store
->src
;
309 alu
->dest
.type
= ppir_target_ssa
;
310 alu
->dest
.ssa
.num_components
= 4;
311 alu
->dest
.ssa
.live_in
= INT_MAX
;
312 alu
->dest
.ssa
.live_out
= 0;
313 alu
->dest
.write_mask
= 0xf;
315 store
->src
.type
= ppir_target_ssa
;
316 store
->src
.ssa
= &alu
->dest
.ssa
;
318 if (!create_new_instr(block
, move
))
321 move
->instr
->is_end
= true;
322 node
->instr
= move
->instr
;
324 /* use move for the following recursion */
328 case ppir_node_type_discard
:
329 if (!create_new_instr(block
, node
))
331 node
->instr
->is_end
= true;
333 case ppir_node_type_branch
:
334 if (!create_new_instr(block
, node
))
341 /* we have to make sure the dep not be destroyed (due to
342 * succ change) in ppir_do_node_to_instr, otherwise we can't
343 * do recursion like this */
344 ppir_node_foreach_pred(node
, dep
) {
345 ppir_node
*pred
= dep
->pred
;
348 /* pred may already be processed by the previous pred
349 * (this pred may be both node and previous pred's child) */
353 /* insert pred only when all its successors have been inserted */
354 ppir_node_foreach_succ(pred
, dep
) {
355 ppir_node
*succ
= dep
->succ
;
363 if (!ppir_do_node_to_instr(block
, pred
))
371 static bool ppir_create_instr_from_node(ppir_compiler
*comp
)
373 list_for_each_entry(ppir_block
, block
, &comp
->block_list
, list
) {
374 list_for_each_entry(ppir_node
, node
, &block
->node_list
, list
) {
375 if (ppir_node_is_root(node
)) {
376 if (!ppir_do_node_to_instr(block
, node
))
385 static void ppir_build_instr_dependency(ppir_compiler
*comp
)
387 list_for_each_entry(ppir_block
, block
, &comp
->block_list
, list
) {
388 list_for_each_entry(ppir_instr
, instr
, &block
->instr_list
, list
) {
389 for (int i
= 0; i
< PPIR_INSTR_SLOT_NUM
; i
++) {
390 ppir_node
*node
= instr
->slots
[i
];
392 ppir_node_foreach_pred(node
, dep
) {
393 ppir_node
*pred
= dep
->pred
;
394 if (pred
->instr
&& pred
->instr
!= instr
)
395 ppir_instr_add_dep(instr
, pred
->instr
);
403 bool ppir_node_to_instr(ppir_compiler
*comp
)
405 if (!ppir_create_instr_from_node(comp
))
407 ppir_instr_print_list(comp
);
409 ppir_build_instr_dependency(comp
);
410 ppir_instr_print_dep(comp
);