}
static exec_node *
-link(void *mem_ctx, bblock_t *block)
+link(void *mem_ctx, bblock_t *block, enum bblock_link_kind kind)
{
- bblock_link *l = new(mem_ctx) bblock_link(block);
+ bblock_link *l = new(mem_ctx) bblock_link(block, kind);
return &l->link;
}
}
void
-bblock_t::add_successor(void *mem_ctx, bblock_t *successor)
+bblock_t::add_successor(void *mem_ctx, bblock_t *successor,
+ enum bblock_link_kind kind)
{
- successor->parents.push_tail(::link(mem_ctx, this));
- children.push_tail(::link(mem_ctx, successor));
+ successor->parents.push_tail(::link(mem_ctx, this, kind));
+ children.push_tail(::link(mem_ctx, successor, kind));
}
bool
-bblock_t::is_predecessor_of(const bblock_t *block) const
+bblock_t::is_predecessor_of(const bblock_t *block,
+ enum bblock_link_kind kind) const
{
foreach_list_typed_safe (bblock_link, parent, link, &block->parents) {
- if (parent->block == this) {
+ if (parent->block == this && parent->kind <= kind) {
return true;
}
}
}
bool
-bblock_t::is_successor_of(const bblock_t *block) const
+bblock_t::is_successor_of(const bblock_t *block,
+ enum bblock_link_kind kind) const
{
foreach_list_typed_safe (bblock_link, child, link, &block->children) {
- if (child->block == this) {
+ if (child->block == this && child->kind <= kind) {
return true;
}
}
/* Push our information onto a stack so we can recover from
* nested ifs.
*/
- if_stack.push_tail(link(mem_ctx, cur_if));
- else_stack.push_tail(link(mem_ctx, cur_else));
+ if_stack.push_tail(link(mem_ctx, cur_if, bblock_link_logical));
+ else_stack.push_tail(link(mem_ctx, cur_else, bblock_link_logical));
cur_if = cur;
cur_else = NULL;
* instructions.
*/
next = new_block();
- cur_if->add_successor(mem_ctx, next);
+ cur_if->add_successor(mem_ctx, next, bblock_link_logical);
set_next_block(&cur, next, ip);
break;
next = new_block();
assert(cur_if != NULL);
- cur_if->add_successor(mem_ctx, next);
+ cur_if->add_successor(mem_ctx, next, bblock_link_logical);
set_next_block(&cur, next, ip);
break;
} else {
cur_endif = new_block();
- cur->add_successor(mem_ctx, cur_endif);
+ cur->add_successor(mem_ctx, cur_endif, bblock_link_logical);
set_next_block(&cur, cur_endif, ip - 1);
}
cur->instructions.push_tail(inst);
if (cur_else) {
- cur_else->add_successor(mem_ctx, cur_endif);
+ cur_else->add_successor(mem_ctx, cur_endif, bblock_link_logical);
} else {
assert(cur_if != NULL);
- cur_if->add_successor(mem_ctx, cur_endif);
+ cur_if->add_successor(mem_ctx, cur_endif, bblock_link_logical);
}
assert(cur_if->end()->opcode == BRW_OPCODE_IF);
/* Push our information onto a stack so we can recover from
* nested loops.
*/
- do_stack.push_tail(link(mem_ctx, cur_do));
- while_stack.push_tail(link(mem_ctx, cur_while));
+ do_stack.push_tail(link(mem_ctx, cur_do, bblock_link_logical));
+ while_stack.push_tail(link(mem_ctx, cur_while, bblock_link_logical));
/* Set up the block just after the while. Don't know when exactly
* it will start, yet.
} else {
cur_do = new_block();
- cur->add_successor(mem_ctx, cur_do);
+ cur->add_successor(mem_ctx, cur_do, bblock_link_logical);
set_next_block(&cur, cur_do, ip - 1);
}
* corruption.
*/
next = new_block();
- cur->add_successor(mem_ctx, next);
- cur->add_successor(mem_ctx, cur_while);
+ cur->add_successor(mem_ctx, next, bblock_link_logical);
+ cur->add_successor(mem_ctx, cur_while, bblock_link_physical);
set_next_block(&cur, next, ip);
break;
* loop, the top of the loop again, into a use of the variable).
*/
assert(cur_do != NULL);
- cur->add_successor(mem_ctx, cur_do->next());
+ cur->add_successor(mem_ctx, cur_do->next(), bblock_link_logical);
next = new_block();
if (inst->predicate)
- cur->add_successor(mem_ctx, next);
+ cur->add_successor(mem_ctx, next, bblock_link_logical);
set_next_block(&cur, next, ip);
break;
* See the DO case for additional explanation.
*/
assert(cur_do != NULL);
- cur->add_successor(mem_ctx, cur_do);
+ cur->add_successor(mem_ctx, cur_do, bblock_link_physical);
next = new_block();
if (inst->predicate)
- cur->add_successor(mem_ctx, next);
+ cur->add_successor(mem_ctx, next, bblock_link_logical);
set_next_block(&cur, next, ip);
break;
* channels, so we may skip over the divergence point at the top of
* the loop to keep the CFG as unambiguous as possible.
*/
- cur->add_successor(mem_ctx, inst->predicate ? cur_do :
- cur_do->next());
+ if (inst->predicate) {
+ cur->add_successor(mem_ctx, cur_do, bblock_link_logical);
+ } else {
+ cur->add_successor(mem_ctx, cur_do->next(), bblock_link_logical);
+ }
set_next_block(&cur, cur_while, ip);
/* Add removed-block's successors to its predecessors' successor lists. */
foreach_list_typed (bblock_link, successor, link, &block->children) {
- if (!successor->block->is_successor_of(predecessor->block)) {
+ if (!successor->block->is_successor_of(predecessor->block,
+ successor->kind)) {
predecessor->block->children.push_tail(link(mem_ctx,
- successor->block));
+ successor->block,
+ successor->kind));
}
}
}
/* Add removed-block's predecessors to its successors' predecessor lists. */
foreach_list_typed (bblock_link, predecessor, link, &block->parents) {
- if (!predecessor->block->is_predecessor_of(successor->block)) {
+ if (!predecessor->block->is_predecessor_of(successor->block,
+ predecessor->kind)) {
successor->block->parents.push_tail(link(mem_ctx,
- predecessor->block));
+ predecessor->block,
+ predecessor->kind));
}
}
}
fprintf(stderr, "START B%d IDOM(none)", block->num);
foreach_list_typed(bblock_link, link, link, &block->parents) {
- fprintf(stderr, " <-B%d",
+ fprintf(stderr, " <%cB%d",
+ link->kind == bblock_link_logical ? '-' : '~',
link->block->num);
}
fprintf(stderr, "\n");
block->dump(s);
fprintf(stderr, "END B%d", block->num);
foreach_list_typed(bblock_link, link, link, &block->children) {
- fprintf(stderr, " ->B%d",
+ fprintf(stderr, " %c>B%d",
+ link->kind == bblock_link_logical ? '-' : '~',
link->block->num);
}
fprintf(stderr, "\n");
struct bblock_t;
+/**
+ * CFG edge types.
+ *
+ * A logical edge represents a potential control flow path of the original
+ * scalar program, while a physical edge represents a control flow path that
+ * may not have existed in the original program but was introduced during
+ * vectorization in order to implement divergent control flow of different
+ * shader invocations within the same SIMD thread.
+ *
+ * All logical edges in the CFG are considered to be physical edges but not
+ * the other way around -- I.e. the logical CFG is a subset of the physical
+ * one.
+ */
+enum bblock_link_kind {
+ bblock_link_logical = 0,
+ bblock_link_physical
+};
+
struct bblock_link {
#ifdef __cplusplus
DECLARE_RALLOC_CXX_OPERATORS(bblock_link)
- bblock_link(bblock_t *block)
- : block(block)
+ bblock_link(bblock_t *block, enum bblock_link_kind kind)
+ : block(block), kind(kind)
{
}
#endif
struct exec_node link;
struct bblock_t *block;
+
+ /* Type of this CFG edge. Because bblock_link_logical also implies
+ * bblock_link_physical, the proper way to test for membership of edge 'l'
+ * in CFG kind 'k' is 'l.kind <= k'.
+ */
+ enum bblock_link_kind kind;
};
struct backend_instruction;
explicit bblock_t(cfg_t *cfg);
- void add_successor(void *mem_ctx, bblock_t *successor);
- bool is_predecessor_of(const bblock_t *block) const;
- bool is_successor_of(const bblock_t *block) const;
+ void add_successor(void *mem_ctx, bblock_t *successor,
+ enum bblock_link_kind kind);
+ bool is_predecessor_of(const bblock_t *block,
+ enum bblock_link_kind kind) const;
+ bool is_successor_of(const bblock_t *block,
+ enum bblock_link_kind kind) const;
bool can_combine_with(const bblock_t *that) const;
void combine_with(bblock_t *that);
void dump(backend_shader *s) const;