2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
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:
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
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.
28 #include "r600_compiler.h"
30 struct c_vector
*c_vector_new(void)
32 struct c_vector
*v
= calloc(1, sizeof(struct c_vector
));
41 static unsigned c_opcode_is_alu(unsigned opcode
)
140 case C_OPCODE_VFETCH
:
148 case C_OPCODE_BGNFOR
:
152 case C_OPCODE_ENDFOR
:
153 case C_OPCODE_ENDREP
:
160 case C_OPCODE_ENDPRIM
:
161 case C_OPCODE_BGNLOOP
:
162 case C_OPCODE_BGNSUB
:
163 case C_OPCODE_ENDLOOP
:
164 case C_OPCODE_ENDSUB
:
166 case C_OPCODE_CALLNZ
:
168 case C_OPCODE_BREAKC
:
173 case C_OPCODE_SWITCH
:
175 case C_OPCODE_DEFAULT
:
176 case C_OPCODE_ENDSWITCH
:
184 void c_node_init(struct c_node
*node
)
186 memset(node
, 0, sizeof(struct c_node
));
187 c_list_init(&node
->predecessors
);
188 c_list_init(&node
->successors
);
189 c_list_init(&node
->childs
);
190 c_list_init(&node
->insts
);
194 static struct c_node_link
*c_node_link_new(struct c_node
*node
)
196 struct c_node_link
*link
;
198 link
= calloc(1, sizeof(struct c_node_link
));
206 int c_node_cfg_link(struct c_node
*predecessor
, struct c_node
*successor
)
208 struct c_node_link
*pedge
, *sedge
;
210 pedge
= c_node_link_new(successor
);
211 sedge
= c_node_link_new(predecessor
);
212 if (sedge
== NULL
|| pedge
== NULL
) {
217 c_list_add_tail(pedge
, &predecessor
->successors
);
218 c_list_add_tail(sedge
, &successor
->predecessors
);
222 int c_node_add_new_instruction_head(struct c_node
*node
, struct c_instruction
*instruction
)
224 struct c_instruction
*inst
= calloc(1, sizeof(struct c_instruction
));
228 memcpy(inst
, instruction
, sizeof(struct c_instruction
));
229 c_list_add(inst
, &node
->insts
);
233 int c_node_add_new_instruction(struct c_node
*node
, struct c_instruction
*instruction
)
235 struct c_instruction
*inst
= calloc(1, sizeof(struct c_instruction
));
239 memcpy(inst
, instruction
, sizeof(struct c_instruction
));
240 c_list_add_tail(inst
, &node
->insts
);
244 struct c_node
*c_shader_cfg_new_node_after(struct c_shader
*shader
, struct c_node
*predecessor
)
246 struct c_node
*node
= calloc(1, sizeof(struct c_node
));
251 if (c_node_cfg_link(predecessor
, node
)) {
255 c_list_add_tail(node
, &shader
->nodes
);
259 int c_shader_init(struct c_shader
*shader
, unsigned type
)
265 for (i
= 0; i
< C_FILE_COUNT
; i
++) {
266 shader
->files
[i
].nvectors
= 0;
267 c_list_init(&shader
->files
[i
].vectors
);
269 c_list_init(&shader
->nodes
);
270 c_node_init(&shader
->entry
);
271 c_node_init(&shader
->end
);
272 shader
->entry
.opcode
= C_OPCODE_ENTRY
;
273 shader
->end
.opcode
= C_OPCODE_END
;
274 r
= c_node_cfg_link(&shader
->entry
, &shader
->end
);
280 struct c_vector
*c_shader_vector_new(struct c_shader
*shader
, unsigned file
, unsigned name
, int sid
)
282 struct c_vector
*v
= calloc(1, sizeof(struct c_vector
));
288 for (i
= 0; i
< 4; i
++) {
289 v
->channel
[i
] = calloc(1, sizeof(struct c_channel
));
290 if (v
->channel
[i
] == NULL
)
292 v
->channel
[i
]->vindex
= i
;
293 v
->channel
[i
]->vector
= v
;
298 shader
->files
[v
->file
].nvectors
++;
299 v
->id
= shader
->nvectors
++;
300 c_list_add_tail(v
, &shader
->files
[v
->file
].vectors
);
303 for (i
= 0; i
< 4; i
++) {
310 static void c_node_remove_link(struct c_node_link
*head
, struct c_node
*node
)
312 struct c_node_link
*link
, *tmp
;
314 c_list_for_each_safe(link
, tmp
, head
) {
315 if (link
->node
== node
) {
322 static void c_node_destroy(struct c_node
*node
)
324 struct c_instruction
*i
, *ni
;
325 struct c_node_link
*link
, *tmp
;
327 c_list_for_each_safe(i
, ni
, &node
->insts
) {
332 c_node_remove_link(&node
->parent
->childs
, node
);
334 c_list_for_each_safe(link
, tmp
, &node
->predecessors
) {
335 c_node_remove_link(&link
->node
->successors
, node
);
339 c_list_for_each_safe(link
, tmp
, &node
->successors
) {
340 c_node_remove_link(&link
->node
->predecessors
, node
);
344 c_list_for_each_safe(link
, tmp
, &node
->childs
) {
345 link
->node
->parent
= NULL
;
351 void c_shader_destroy(struct c_shader
*shader
)
353 struct c_node
*n
, *nn
;
354 struct c_vector
*v
, *nv
;
357 for (i
= 0; i
< C_FILE_COUNT
; i
++) {
358 shader
->files
[i
].nvectors
= 0;
359 c_list_for_each_safe(v
, nv
, &shader
->files
[i
].vectors
) {
368 c_list_for_each_safe(n
, nn
, &shader
->nodes
) {
372 memset(shader
, 0, sizeof(struct c_shader
));
375 static void c_shader_dfs_without_rec(struct c_node
*entry
, struct c_node
*node
)
377 struct c_node_link
*link
;
379 if (entry
== node
|| entry
->visited
)
382 c_list_for_each(link
, &entry
->successors
) {
383 c_shader_dfs_without_rec(link
->node
, node
);
387 static void c_shader_dfs_without(struct c_shader
*shader
, struct c_node
*node
)
391 shader
->entry
.visited
= 0;
392 shader
->end
.visited
= 0;
393 c_list_for_each(n
, &shader
->nodes
) {
396 c_shader_dfs_without_rec(&shader
->entry
, node
);
399 static int c_shader_build_dominator_tree_rec(struct c_shader
*shader
, struct c_node
*node
)
401 struct c_node_link
*link
, *nlink
;
408 c_list_for_each(link
, &node
->predecessors
) {
409 /* if we remove this predecessor can we reach the current node ? */
410 c_shader_dfs_without(shader
, link
->node
);
411 if (node
->visited
== 0) {
412 /* we were unable to visit current node thus current
413 * predecessor is the immediate dominator of node, as
414 * their can be only one immediate dominator we break
416 node
->parent
= link
->node
;
417 nlink
= c_node_link_new(node
);
420 c_list_add_tail(nlink
, &link
->node
->childs
);
425 /* this shouldn't happen there should at least be 1 denominator for each node */
426 if (!found
&& node
->opcode
!= C_OPCODE_ENTRY
) {
427 fprintf(stderr
, "invalid flow control graph node %p (%d) has no immediate dominator\n",
431 c_list_for_each(link
, &node
->predecessors
) {
432 r
= c_shader_build_dominator_tree_rec(shader
, link
->node
);
439 int c_shader_build_dominator_tree(struct c_shader
*shader
)
442 c_list_for_each(node
, &shader
->nodes
) {
445 return c_shader_build_dominator_tree_rec(shader
, &shader
->end
);