2012-04-10 12:01:50 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2012 Intel Corporation
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
|
|
|
* IN THE SOFTWARE.
|
|
|
|
|
*
|
|
|
|
|
* Authors:
|
|
|
|
|
* Eric Anholt <eric@anholt.net>
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2012-10-03 13:03:12 -07:00
|
|
|
#include "brw_cfg.h"
|
2012-04-10 12:01:50 -07:00
|
|
|
|
2013-10-30 16:51:32 -07:00
|
|
|
/** @file brw_cfg.cpp
|
2012-04-10 12:01:50 -07:00
|
|
|
*
|
|
|
|
|
* Walks the shader instructions generated and creates a set of basic
|
|
|
|
|
* blocks with successor/predecessor edges connecting them.
|
|
|
|
|
*/
|
|
|
|
|
|
2012-10-03 13:16:09 -07:00
|
|
|
static bblock_t *
|
2012-04-10 12:01:50 -07:00
|
|
|
pop_stack(exec_list *list)
|
|
|
|
|
{
|
2012-10-03 13:16:09 -07:00
|
|
|
bblock_link *link = (bblock_link *)list->get_tail();
|
|
|
|
|
bblock_t *block = link->block;
|
2014-05-12 14:40:40 -07:00
|
|
|
link->link.remove();
|
2012-04-10 12:01:50 -07:00
|
|
|
|
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-12 14:40:40 -07:00
|
|
|
static exec_node *
|
|
|
|
|
link(void *mem_ctx, bblock_t *block)
|
|
|
|
|
{
|
|
|
|
|
bblock_link *l = new(mem_ctx) bblock_link(block);
|
|
|
|
|
return &l->link;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-13 22:17:50 -07:00
|
|
|
bblock_t::bblock_t(cfg_t *cfg) :
|
2016-11-28 13:25:01 -08:00
|
|
|
cfg(cfg), idom(NULL), start_ip(0), end_ip(0), num(0), cycle_count(0)
|
2012-04-10 12:01:50 -07:00
|
|
|
{
|
2014-09-01 15:01:23 -07:00
|
|
|
instructions.make_empty();
|
2012-04-10 12:01:50 -07:00
|
|
|
parents.make_empty();
|
|
|
|
|
children.make_empty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-10-03 13:16:09 -07:00
|
|
|
bblock_t::add_successor(void *mem_ctx, bblock_t *successor)
|
2012-04-10 12:01:50 -07:00
|
|
|
{
|
2014-07-11 16:17:47 -07:00
|
|
|
successor->parents.push_tail(::link(mem_ctx, this));
|
|
|
|
|
children.push_tail(::link(mem_ctx, successor));
|
2012-04-10 12:01:50 -07:00
|
|
|
}
|
|
|
|
|
|
2014-07-16 12:14:41 -07:00
|
|
|
bool
|
|
|
|
|
bblock_t::is_predecessor_of(const bblock_t *block) const
|
|
|
|
|
{
|
|
|
|
|
foreach_list_typed_safe (bblock_link, parent, link, &block->parents) {
|
|
|
|
|
if (parent->block == this) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
bblock_t::is_successor_of(const bblock_t *block) const
|
|
|
|
|
{
|
|
|
|
|
foreach_list_typed_safe (bblock_link, child, link, &block->children) {
|
|
|
|
|
if (child->block == this) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-15 14:51:43 -07:00
|
|
|
static bool
|
|
|
|
|
ends_block(const backend_instruction *inst)
|
|
|
|
|
{
|
|
|
|
|
enum opcode op = inst->opcode;
|
|
|
|
|
|
|
|
|
|
return op == BRW_OPCODE_IF ||
|
|
|
|
|
op == BRW_OPCODE_ELSE ||
|
|
|
|
|
op == BRW_OPCODE_CONTINUE ||
|
|
|
|
|
op == BRW_OPCODE_BREAK ||
|
|
|
|
|
op == BRW_OPCODE_WHILE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
starts_block(const backend_instruction *inst)
|
|
|
|
|
{
|
|
|
|
|
enum opcode op = inst->opcode;
|
|
|
|
|
|
|
|
|
|
return op == BRW_OPCODE_DO ||
|
|
|
|
|
op == BRW_OPCODE_ENDIF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
bblock_t::can_combine_with(const bblock_t *that) const
|
|
|
|
|
{
|
|
|
|
|
if ((const bblock_t *)this->link.next != that)
|
|
|
|
|
return false;
|
|
|
|
|
|
2014-09-01 15:01:23 -07:00
|
|
|
if (ends_block(this->end()) ||
|
|
|
|
|
starts_block(that->start()))
|
2014-07-15 14:51:43 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
bblock_t::combine_with(bblock_t *that)
|
|
|
|
|
{
|
|
|
|
|
assert(this->can_combine_with(that));
|
|
|
|
|
foreach_list_typed (bblock_link, link, link, &this->children) {
|
|
|
|
|
assert(link->block == that);
|
|
|
|
|
}
|
|
|
|
|
foreach_list_typed (bblock_link, link, link, &that->parents) {
|
|
|
|
|
assert(link->block == this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->end_ip = that->end_ip;
|
2014-09-01 15:01:23 -07:00
|
|
|
this->instructions.append_list(&that->instructions);
|
2014-07-15 14:51:43 -07:00
|
|
|
|
|
|
|
|
this->cfg->remove_block(that);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 11:03:14 -08:00
|
|
|
void
|
2015-05-20 09:44:01 -07:00
|
|
|
bblock_t::dump(backend_shader *s) const
|
2013-11-28 11:03:14 -08:00
|
|
|
{
|
|
|
|
|
int ip = this->start_ip;
|
2014-09-01 15:01:23 -07:00
|
|
|
foreach_inst_in_block(backend_instruction, inst, this) {
|
2013-12-22 23:29:31 -08:00
|
|
|
fprintf(stderr, "%5d: ", ip);
|
2015-05-20 09:44:01 -07:00
|
|
|
s->dump_instruction(inst);
|
2013-11-28 11:03:14 -08:00
|
|
|
ip++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-28 23:24:44 -08:00
|
|
|
cfg_t::cfg_t(exec_list *instructions)
|
2012-11-20 17:30:46 -08:00
|
|
|
{
|
2013-10-23 11:16:26 -07:00
|
|
|
mem_ctx = ralloc_context(NULL);
|
2012-04-10 12:01:50 -07:00
|
|
|
block_list.make_empty();
|
2013-09-20 16:29:48 -07:00
|
|
|
blocks = NULL;
|
2012-04-10 12:01:50 -07:00
|
|
|
num_blocks = 0;
|
2014-02-18 16:35:56 -08:00
|
|
|
idom_dirty = true;
|
2016-11-28 13:24:04 -08:00
|
|
|
cycle_count = 0;
|
2013-11-30 20:38:48 -08:00
|
|
|
|
|
|
|
|
bblock_t *cur = NULL;
|
|
|
|
|
int ip = 0;
|
2012-04-10 12:01:50 -07:00
|
|
|
|
2012-10-03 13:16:09 -07:00
|
|
|
bblock_t *entry = new_block();
|
2013-12-02 10:29:49 -08:00
|
|
|
bblock_t *cur_if = NULL; /**< BB ending with IF. */
|
|
|
|
|
bblock_t *cur_else = NULL; /**< BB ending with ELSE. */
|
|
|
|
|
bblock_t *cur_endif = NULL; /**< BB starting with ENDIF. */
|
2014-05-17 11:53:45 -07:00
|
|
|
bblock_t *cur_do = NULL; /**< BB starting with DO. */
|
2013-12-02 10:29:49 -08:00
|
|
|
bblock_t *cur_while = NULL; /**< BB immediately following WHILE. */
|
2013-11-28 23:39:02 -08:00
|
|
|
exec_list if_stack, else_stack, do_stack, while_stack;
|
2012-10-03 13:16:09 -07:00
|
|
|
bblock_t *next;
|
2012-04-10 12:01:50 -07:00
|
|
|
|
2013-11-30 20:38:48 -08:00
|
|
|
set_next_block(&cur, entry, ip);
|
2012-04-10 12:01:50 -07:00
|
|
|
|
2014-09-01 15:01:23 -07:00
|
|
|
foreach_in_list_safe(backend_instruction, inst, instructions) {
|
2012-04-10 12:01:50 -07:00
|
|
|
/* set_next_block wants the post-incremented ip */
|
|
|
|
|
ip++;
|
|
|
|
|
|
2016-08-17 11:40:01 -07:00
|
|
|
inst->exec_node::remove();
|
|
|
|
|
|
2012-04-10 12:01:50 -07:00
|
|
|
switch (inst->opcode) {
|
|
|
|
|
case BRW_OPCODE_IF:
|
2014-09-01 15:01:23 -07:00
|
|
|
cur->instructions.push_tail(inst);
|
|
|
|
|
|
2012-04-10 12:01:50 -07:00
|
|
|
/* Push our information onto a stack so we can recover from
|
|
|
|
|
* nested ifs.
|
|
|
|
|
*/
|
2014-05-12 14:40:40 -07:00
|
|
|
if_stack.push_tail(link(mem_ctx, cur_if));
|
|
|
|
|
else_stack.push_tail(link(mem_ctx, cur_else));
|
2012-04-10 12:01:50 -07:00
|
|
|
|
|
|
|
|
cur_if = cur;
|
|
|
|
|
cur_else = NULL;
|
i965/cfg: Rework to make IF & ELSE blocks flow into ENDIF.
Previously we made the basic block following an ENDIF instruction a
successor of the basic blocks ending with IF and ELSE. The PRM says that
IF and ELSE instructions jump *to* the ENDIF, rather than over it.
This should be immaterial to dataflow analysis, except for if, break,
endif sequences:
START B1 <-B0 <-B9
0x00000100: cmp.g.f0(8) null g15<8,8,1>F g4<0,1,0>F
0x00000110: (+f0) if(8) 0 0 null 0x00000000UD
END B1 ->B2 ->B4
START B2 <-B1
break
0x00000120: break(8) 0 0 null 0D
END B2 ->B10
START B3
0x00000130: endif(8) 2 null 0x00000002UD
END B3 ->B4
The ENDIF block would have no parents, so dataflow analysis would
generate incorrect results, preventing copy propagation from eliminating
some instructions.
This patch changes the CFG to make ENDIF start rather than end basic
blocks, so that it can be the jump target of the IF and ELSE
instructions.
It helps three programs (including two fs8/fs16 pairs).
total instructions in shared programs: 1561126 -> 1561060 (-0.00%)
instructions in affected programs: 837 -> 771 (-7.89%)
More importantly, it allows copy propagation to handle more cases.
Disabling the register_coalesce() pass before this patch hurts 58
programs, while afterward it only hurts 11 programs.
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-11-28 21:33:05 -08:00
|
|
|
cur_endif = NULL;
|
2012-04-10 12:01:50 -07:00
|
|
|
|
|
|
|
|
/* Set up our immediately following block, full of "then"
|
|
|
|
|
* instructions.
|
|
|
|
|
*/
|
|
|
|
|
next = new_block();
|
|
|
|
|
cur_if->add_successor(mem_ctx, next);
|
|
|
|
|
|
2013-11-30 20:38:48 -08:00
|
|
|
set_next_block(&cur, next, ip);
|
2012-04-10 12:01:50 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BRW_OPCODE_ELSE:
|
2014-09-01 15:01:23 -07:00
|
|
|
cur->instructions.push_tail(inst);
|
|
|
|
|
|
i965/cfg: Rework to make IF & ELSE blocks flow into ENDIF.
Previously we made the basic block following an ENDIF instruction a
successor of the basic blocks ending with IF and ELSE. The PRM says that
IF and ELSE instructions jump *to* the ENDIF, rather than over it.
This should be immaterial to dataflow analysis, except for if, break,
endif sequences:
START B1 <-B0 <-B9
0x00000100: cmp.g.f0(8) null g15<8,8,1>F g4<0,1,0>F
0x00000110: (+f0) if(8) 0 0 null 0x00000000UD
END B1 ->B2 ->B4
START B2 <-B1
break
0x00000120: break(8) 0 0 null 0D
END B2 ->B10
START B3
0x00000130: endif(8) 2 null 0x00000002UD
END B3 ->B4
The ENDIF block would have no parents, so dataflow analysis would
generate incorrect results, preventing copy propagation from eliminating
some instructions.
This patch changes the CFG to make ENDIF start rather than end basic
blocks, so that it can be the jump target of the IF and ELSE
instructions.
It helps three programs (including two fs8/fs16 pairs).
total instructions in shared programs: 1561126 -> 1561060 (-0.00%)
instructions in affected programs: 837 -> 771 (-7.89%)
More importantly, it allows copy propagation to handle more cases.
Disabling the register_coalesce() pass before this patch hurts 58
programs, while afterward it only hurts 11 programs.
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-11-28 21:33:05 -08:00
|
|
|
cur_else = cur;
|
2012-04-10 12:01:50 -07:00
|
|
|
|
|
|
|
|
next = new_block();
|
2015-07-10 19:49:49 -07:00
|
|
|
assert(cur_if != NULL);
|
2012-04-10 12:01:50 -07:00
|
|
|
cur_if->add_successor(mem_ctx, next);
|
|
|
|
|
|
2013-11-30 20:38:48 -08:00
|
|
|
set_next_block(&cur, next, ip);
|
2012-04-10 12:01:50 -07:00
|
|
|
break;
|
|
|
|
|
|
2013-10-30 16:51:32 -07:00
|
|
|
case BRW_OPCODE_ENDIF: {
|
2014-09-01 15:01:23 -07:00
|
|
|
if (cur->instructions.is_empty()) {
|
i965/cfg: Rework to make IF & ELSE blocks flow into ENDIF.
Previously we made the basic block following an ENDIF instruction a
successor of the basic blocks ending with IF and ELSE. The PRM says that
IF and ELSE instructions jump *to* the ENDIF, rather than over it.
This should be immaterial to dataflow analysis, except for if, break,
endif sequences:
START B1 <-B0 <-B9
0x00000100: cmp.g.f0(8) null g15<8,8,1>F g4<0,1,0>F
0x00000110: (+f0) if(8) 0 0 null 0x00000000UD
END B1 ->B2 ->B4
START B2 <-B1
break
0x00000120: break(8) 0 0 null 0D
END B2 ->B10
START B3
0x00000130: endif(8) 2 null 0x00000002UD
END B3 ->B4
The ENDIF block would have no parents, so dataflow analysis would
generate incorrect results, preventing copy propagation from eliminating
some instructions.
This patch changes the CFG to make ENDIF start rather than end basic
blocks, so that it can be the jump target of the IF and ELSE
instructions.
It helps three programs (including two fs8/fs16 pairs).
total instructions in shared programs: 1561126 -> 1561060 (-0.00%)
instructions in affected programs: 837 -> 771 (-7.89%)
More importantly, it allows copy propagation to handle more cases.
Disabling the register_coalesce() pass before this patch hurts 58
programs, while afterward it only hurts 11 programs.
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-11-28 21:33:05 -08:00
|
|
|
/* New block was just created; use it. */
|
|
|
|
|
cur_endif = cur;
|
|
|
|
|
} else {
|
|
|
|
|
cur_endif = new_block();
|
|
|
|
|
|
|
|
|
|
cur->add_successor(mem_ctx, cur_endif);
|
|
|
|
|
|
2013-11-30 20:38:48 -08:00
|
|
|
set_next_block(&cur, cur_endif, ip - 1);
|
i965/cfg: Rework to make IF & ELSE blocks flow into ENDIF.
Previously we made the basic block following an ENDIF instruction a
successor of the basic blocks ending with IF and ELSE. The PRM says that
IF and ELSE instructions jump *to* the ENDIF, rather than over it.
This should be immaterial to dataflow analysis, except for if, break,
endif sequences:
START B1 <-B0 <-B9
0x00000100: cmp.g.f0(8) null g15<8,8,1>F g4<0,1,0>F
0x00000110: (+f0) if(8) 0 0 null 0x00000000UD
END B1 ->B2 ->B4
START B2 <-B1
break
0x00000120: break(8) 0 0 null 0D
END B2 ->B10
START B3
0x00000130: endif(8) 2 null 0x00000002UD
END B3 ->B4
The ENDIF block would have no parents, so dataflow analysis would
generate incorrect results, preventing copy propagation from eliminating
some instructions.
This patch changes the CFG to make ENDIF start rather than end basic
blocks, so that it can be the jump target of the IF and ELSE
instructions.
It helps three programs (including two fs8/fs16 pairs).
total instructions in shared programs: 1561126 -> 1561060 (-0.00%)
instructions in affected programs: 837 -> 771 (-7.89%)
More importantly, it allows copy propagation to handle more cases.
Disabling the register_coalesce() pass before this patch hurts 58
programs, while afterward it only hurts 11 programs.
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-11-28 21:33:05 -08:00
|
|
|
}
|
|
|
|
|
|
2014-09-01 15:01:23 -07:00
|
|
|
cur->instructions.push_tail(inst);
|
|
|
|
|
|
i965/cfg: Rework to make IF & ELSE blocks flow into ENDIF.
Previously we made the basic block following an ENDIF instruction a
successor of the basic blocks ending with IF and ELSE. The PRM says that
IF and ELSE instructions jump *to* the ENDIF, rather than over it.
This should be immaterial to dataflow analysis, except for if, break,
endif sequences:
START B1 <-B0 <-B9
0x00000100: cmp.g.f0(8) null g15<8,8,1>F g4<0,1,0>F
0x00000110: (+f0) if(8) 0 0 null 0x00000000UD
END B1 ->B2 ->B4
START B2 <-B1
break
0x00000120: break(8) 0 0 null 0D
END B2 ->B10
START B3
0x00000130: endif(8) 2 null 0x00000002UD
END B3 ->B4
The ENDIF block would have no parents, so dataflow analysis would
generate incorrect results, preventing copy propagation from eliminating
some instructions.
This patch changes the CFG to make ENDIF start rather than end basic
blocks, so that it can be the jump target of the IF and ELSE
instructions.
It helps three programs (including two fs8/fs16 pairs).
total instructions in shared programs: 1561126 -> 1561060 (-0.00%)
instructions in affected programs: 837 -> 771 (-7.89%)
More importantly, it allows copy propagation to handle more cases.
Disabling the register_coalesce() pass before this patch hurts 58
programs, while afterward it only hurts 11 programs.
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-11-28 21:33:05 -08:00
|
|
|
if (cur_else) {
|
|
|
|
|
cur_else->add_successor(mem_ctx, cur_endif);
|
|
|
|
|
} else {
|
2015-06-22 11:09:49 -07:00
|
|
|
assert(cur_if != NULL);
|
i965/cfg: Rework to make IF & ELSE blocks flow into ENDIF.
Previously we made the basic block following an ENDIF instruction a
successor of the basic blocks ending with IF and ELSE. The PRM says that
IF and ELSE instructions jump *to* the ENDIF, rather than over it.
This should be immaterial to dataflow analysis, except for if, break,
endif sequences:
START B1 <-B0 <-B9
0x00000100: cmp.g.f0(8) null g15<8,8,1>F g4<0,1,0>F
0x00000110: (+f0) if(8) 0 0 null 0x00000000UD
END B1 ->B2 ->B4
START B2 <-B1
break
0x00000120: break(8) 0 0 null 0D
END B2 ->B10
START B3
0x00000130: endif(8) 2 null 0x00000002UD
END B3 ->B4
The ENDIF block would have no parents, so dataflow analysis would
generate incorrect results, preventing copy propagation from eliminating
some instructions.
This patch changes the CFG to make ENDIF start rather than end basic
blocks, so that it can be the jump target of the IF and ELSE
instructions.
It helps three programs (including two fs8/fs16 pairs).
total instructions in shared programs: 1561126 -> 1561060 (-0.00%)
instructions in affected programs: 837 -> 771 (-7.89%)
More importantly, it allows copy propagation to handle more cases.
Disabling the register_coalesce() pass before this patch hurts 58
programs, while afterward it only hurts 11 programs.
Reviewed-by: Eric Anholt <eric@anholt.net>
2013-11-28 21:33:05 -08:00
|
|
|
cur_if->add_successor(mem_ctx, cur_endif);
|
|
|
|
|
}
|
2013-10-30 16:51:32 -07:00
|
|
|
|
2014-09-01 15:01:23 -07:00
|
|
|
assert(cur_if->end()->opcode == BRW_OPCODE_IF);
|
|
|
|
|
assert(!cur_else || cur_else->end()->opcode == BRW_OPCODE_ELSE);
|
2013-10-30 16:51:32 -07:00
|
|
|
|
2012-04-10 12:01:50 -07:00
|
|
|
/* Pop the stack so we're in the previous if/else/endif */
|
|
|
|
|
cur_if = pop_stack(&if_stack);
|
|
|
|
|
cur_else = pop_stack(&else_stack);
|
|
|
|
|
break;
|
2013-10-30 16:51:32 -07:00
|
|
|
}
|
2012-04-10 12:01:50 -07:00
|
|
|
case BRW_OPCODE_DO:
|
|
|
|
|
/* Push our information onto a stack so we can recover from
|
|
|
|
|
* nested loops.
|
|
|
|
|
*/
|
2014-05-12 14:40:40 -07:00
|
|
|
do_stack.push_tail(link(mem_ctx, cur_do));
|
|
|
|
|
while_stack.push_tail(link(mem_ctx, cur_while));
|
2012-04-10 12:01:50 -07:00
|
|
|
|
|
|
|
|
/* Set up the block just after the while. Don't know when exactly
|
|
|
|
|
* it will start, yet.
|
|
|
|
|
*/
|
|
|
|
|
cur_while = new_block();
|
|
|
|
|
|
2014-09-01 15:01:23 -07:00
|
|
|
if (cur->instructions.is_empty()) {
|
2014-05-17 11:53:45 -07:00
|
|
|
/* New block was just created; use it. */
|
|
|
|
|
cur_do = cur;
|
|
|
|
|
} else {
|
|
|
|
|
cur_do = new_block();
|
2012-04-10 12:01:50 -07:00
|
|
|
|
2014-05-17 11:53:45 -07:00
|
|
|
cur->add_successor(mem_ctx, cur_do);
|
|
|
|
|
|
|
|
|
|
set_next_block(&cur, cur_do, ip - 1);
|
|
|
|
|
}
|
2014-09-01 15:01:23 -07:00
|
|
|
|
|
|
|
|
cur->instructions.push_tail(inst);
|
2012-04-10 12:01:50 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BRW_OPCODE_CONTINUE:
|
2014-09-01 15:01:23 -07:00
|
|
|
cur->instructions.push_tail(inst);
|
|
|
|
|
|
2015-07-10 19:49:49 -07:00
|
|
|
assert(cur_do != NULL);
|
2012-04-10 12:01:50 -07:00
|
|
|
cur->add_successor(mem_ctx, cur_do);
|
|
|
|
|
|
|
|
|
|
next = new_block();
|
2012-10-03 13:23:05 -07:00
|
|
|
if (inst->predicate)
|
2012-04-10 12:01:50 -07:00
|
|
|
cur->add_successor(mem_ctx, next);
|
|
|
|
|
|
2013-11-30 20:38:48 -08:00
|
|
|
set_next_block(&cur, next, ip);
|
2012-04-10 12:01:50 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BRW_OPCODE_BREAK:
|
2014-09-01 15:01:23 -07:00
|
|
|
cur->instructions.push_tail(inst);
|
|
|
|
|
|
2015-07-10 19:49:49 -07:00
|
|
|
assert(cur_while != NULL);
|
2012-04-10 12:01:50 -07:00
|
|
|
cur->add_successor(mem_ctx, cur_while);
|
|
|
|
|
|
|
|
|
|
next = new_block();
|
2012-10-03 13:23:05 -07:00
|
|
|
if (inst->predicate)
|
2012-04-10 12:01:50 -07:00
|
|
|
cur->add_successor(mem_ctx, next);
|
|
|
|
|
|
2013-11-30 20:38:48 -08:00
|
|
|
set_next_block(&cur, next, ip);
|
2012-04-10 12:01:50 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case BRW_OPCODE_WHILE:
|
2014-09-01 15:01:23 -07:00
|
|
|
cur->instructions.push_tail(inst);
|
2012-04-10 12:01:50 -07:00
|
|
|
|
2015-06-22 11:09:49 -07:00
|
|
|
assert(cur_do != NULL && cur_while != NULL);
|
2012-04-10 12:01:50 -07:00
|
|
|
cur->add_successor(mem_ctx, cur_do);
|
2015-10-05 13:50:56 +02:00
|
|
|
|
|
|
|
|
if (inst->predicate)
|
|
|
|
|
cur->add_successor(mem_ctx, cur_while);
|
|
|
|
|
|
2013-11-30 20:38:48 -08:00
|
|
|
set_next_block(&cur, cur_while, ip);
|
2012-04-10 12:01:50 -07:00
|
|
|
|
|
|
|
|
/* Pop the stack so we're in the previous loop */
|
|
|
|
|
cur_do = pop_stack(&do_stack);
|
|
|
|
|
cur_while = pop_stack(&while_stack);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2014-09-01 15:01:23 -07:00
|
|
|
cur->instructions.push_tail(inst);
|
2012-04-10 12:01:50 -07:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-04 18:04:13 -08:00
|
|
|
cur->end_ip = ip - 1;
|
2012-04-10 12:01:50 -07:00
|
|
|
|
|
|
|
|
make_block_array();
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-03 13:16:09 -07:00
|
|
|
cfg_t::~cfg_t()
|
2012-04-10 12:01:50 -07:00
|
|
|
{
|
|
|
|
|
ralloc_free(mem_ctx);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-13 22:17:50 -07:00
|
|
|
void
|
|
|
|
|
cfg_t::remove_block(bblock_t *block)
|
|
|
|
|
{
|
|
|
|
|
foreach_list_typed_safe (bblock_link, predecessor, link, &block->parents) {
|
|
|
|
|
/* Remove block from all of its predecessors' successor lists. */
|
|
|
|
|
foreach_list_typed_safe (bblock_link, successor, link,
|
|
|
|
|
&predecessor->block->children) {
|
|
|
|
|
if (block == successor->block) {
|
|
|
|
|
successor->link.remove();
|
|
|
|
|
ralloc_free(successor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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)) {
|
|
|
|
|
predecessor->block->children.push_tail(link(mem_ctx,
|
|
|
|
|
successor->block));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach_list_typed_safe (bblock_link, successor, link, &block->children) {
|
|
|
|
|
/* Remove block from all of its childrens' parents lists. */
|
|
|
|
|
foreach_list_typed_safe (bblock_link, predecessor, link,
|
|
|
|
|
&successor->block->parents) {
|
|
|
|
|
if (block == predecessor->block) {
|
|
|
|
|
predecessor->link.remove();
|
|
|
|
|
ralloc_free(predecessor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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)) {
|
|
|
|
|
successor->block->parents.push_tail(link(mem_ctx,
|
|
|
|
|
predecessor->block));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
block->link.remove();
|
|
|
|
|
|
|
|
|
|
for (int b = block->num; b < this->num_blocks - 1; b++) {
|
|
|
|
|
this->blocks[b] = this->blocks[b + 1];
|
|
|
|
|
this->blocks[b]->num = b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->blocks[this->num_blocks - 1]->num = this->num_blocks - 2;
|
|
|
|
|
this->num_blocks--;
|
2014-02-18 16:35:56 -08:00
|
|
|
idom_dirty = true;
|
2014-07-13 22:17:50 -07:00
|
|
|
}
|
|
|
|
|
|
2012-10-03 13:16:09 -07:00
|
|
|
bblock_t *
|
|
|
|
|
cfg_t::new_block()
|
2012-04-10 12:01:50 -07:00
|
|
|
{
|
2014-07-13 22:17:50 -07:00
|
|
|
bblock_t *block = new(mem_ctx) bblock_t(this);
|
2012-04-10 12:01:50 -07:00
|
|
|
|
|
|
|
|
return block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2013-11-30 20:38:48 -08:00
|
|
|
cfg_t::set_next_block(bblock_t **cur, bblock_t *block, int ip)
|
2012-04-10 12:01:50 -07:00
|
|
|
{
|
2013-11-30 20:38:48 -08:00
|
|
|
if (*cur) {
|
|
|
|
|
(*cur)->end_ip = ip - 1;
|
2012-04-10 12:01:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
block->start_ip = ip;
|
2014-07-11 22:31:39 -07:00
|
|
|
block->num = num_blocks++;
|
2014-07-11 16:17:47 -07:00
|
|
|
block_list.push_tail(&block->link);
|
2013-11-30 20:38:48 -08:00
|
|
|
*cur = block;
|
2012-04-10 12:01:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-10-03 13:16:09 -07:00
|
|
|
cfg_t::make_block_array()
|
2012-04-10 12:01:50 -07:00
|
|
|
{
|
2012-10-03 13:16:09 -07:00
|
|
|
blocks = ralloc_array(mem_ctx, bblock_t *, num_blocks);
|
2012-04-10 12:01:50 -07:00
|
|
|
|
|
|
|
|
int i = 0;
|
2014-07-11 22:31:39 -07:00
|
|
|
foreach_block (block, this) {
|
2014-07-11 16:17:47 -07:00
|
|
|
blocks[i++] = block;
|
2012-04-10 12:01:50 -07:00
|
|
|
}
|
|
|
|
|
assert(i == num_blocks);
|
|
|
|
|
}
|
2013-11-28 11:03:14 -08:00
|
|
|
|
|
|
|
|
void
|
2015-05-20 09:44:01 -07:00
|
|
|
cfg_t::dump(backend_shader *s)
|
2013-11-28 11:03:14 -08:00
|
|
|
{
|
2014-02-18 16:35:56 -08:00
|
|
|
if (idom_dirty)
|
|
|
|
|
calculate_idom();
|
|
|
|
|
|
2014-07-11 22:31:39 -07:00
|
|
|
foreach_block (block, this) {
|
2015-10-05 16:21:10 -07:00
|
|
|
if (block->idom)
|
|
|
|
|
fprintf(stderr, "START B%d IDOM(B%d)", block->num, block->idom->num);
|
|
|
|
|
else
|
|
|
|
|
fprintf(stderr, "START B%d IDOM(none)", block->num);
|
|
|
|
|
|
2014-05-12 14:40:40 -07:00
|
|
|
foreach_list_typed(bblock_link, link, link, &block->parents) {
|
2013-12-22 23:29:31 -08:00
|
|
|
fprintf(stderr, " <-B%d",
|
2014-07-11 22:31:39 -07:00
|
|
|
link->block->num);
|
2013-11-28 11:03:14 -08:00
|
|
|
}
|
2013-12-22 23:29:31 -08:00
|
|
|
fprintf(stderr, "\n");
|
2015-05-20 09:44:01 -07:00
|
|
|
if (s != NULL)
|
|
|
|
|
block->dump(s);
|
2014-07-11 22:31:39 -07:00
|
|
|
fprintf(stderr, "END B%d", block->num);
|
2014-05-12 14:40:40 -07:00
|
|
|
foreach_list_typed(bblock_link, link, link, &block->children) {
|
2013-12-22 23:29:31 -08:00
|
|
|
fprintf(stderr, " ->B%d",
|
2014-07-11 22:31:39 -07:00
|
|
|
link->block->num);
|
2013-11-28 11:03:14 -08:00
|
|
|
}
|
2013-12-22 23:29:31 -08:00
|
|
|
fprintf(stderr, "\n");
|
2013-11-28 11:03:14 -08:00
|
|
|
}
|
|
|
|
|
}
|
2014-02-18 16:35:56 -08:00
|
|
|
|
|
|
|
|
/* Calculates the immediate dominator of each block, according to "A Simple,
|
|
|
|
|
* Fast Dominance Algorithm" by Keith D. Cooper, Timothy J. Harvey, and Ken
|
|
|
|
|
* Kennedy.
|
|
|
|
|
*
|
|
|
|
|
* The authors claim that for control flow graphs of sizes normally encountered
|
|
|
|
|
* (less than 1000 nodes) that this algorithm is significantly faster than
|
|
|
|
|
* others like Lengauer-Tarjan.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
cfg_t::calculate_idom()
|
|
|
|
|
{
|
|
|
|
|
foreach_block(block, this) {
|
|
|
|
|
block->idom = NULL;
|
|
|
|
|
}
|
|
|
|
|
blocks[0]->idom = blocks[0];
|
|
|
|
|
|
|
|
|
|
bool changed;
|
|
|
|
|
do {
|
|
|
|
|
changed = false;
|
|
|
|
|
|
|
|
|
|
foreach_block(block, this) {
|
|
|
|
|
if (block->num == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
bblock_t *new_idom = NULL;
|
|
|
|
|
foreach_list_typed(bblock_link, parent, link, &block->parents) {
|
|
|
|
|
if (parent->block->idom) {
|
|
|
|
|
if (new_idom == NULL) {
|
|
|
|
|
new_idom = parent->block;
|
|
|
|
|
} else if (parent->block->idom != NULL) {
|
|
|
|
|
new_idom = intersect(parent->block, new_idom);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (block->idom != new_idom) {
|
|
|
|
|
block->idom = new_idom;
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (changed);
|
|
|
|
|
|
|
|
|
|
idom_dirty = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bblock_t *
|
|
|
|
|
cfg_t::intersect(bblock_t *b1, bblock_t *b2)
|
|
|
|
|
{
|
|
|
|
|
/* Note, the comparisons here are the opposite of what the paper says
|
|
|
|
|
* because we index blocks from beginning -> end (i.e. reverse post-order)
|
|
|
|
|
* instead of post-order like they assume.
|
|
|
|
|
*/
|
|
|
|
|
while (b1->num != b2->num) {
|
|
|
|
|
while (b1->num > b2->num)
|
|
|
|
|
b1 = b1->idom;
|
|
|
|
|
while (b2->num > b1->num)
|
|
|
|
|
b2 = b2->idom;
|
|
|
|
|
}
|
|
|
|
|
assert(b1);
|
|
|
|
|
return b1;
|
|
|
|
|
}
|
2014-02-26 16:07:52 -08:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
cfg_t::dump_cfg()
|
|
|
|
|
{
|
|
|
|
|
printf("digraph CFG {\n");
|
|
|
|
|
for (int b = 0; b < num_blocks; b++) {
|
|
|
|
|
bblock_t *block = this->blocks[b];
|
|
|
|
|
|
|
|
|
|
foreach_list_typed_safe (bblock_link, child, link, &block->children) {
|
|
|
|
|
printf("\t%d -> %d\n", b, child->block->num);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
printf("}\n");
|
|
|
|
|
}
|
2014-02-26 16:15:52 -08:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
cfg_t::dump_domtree()
|
|
|
|
|
{
|
|
|
|
|
printf("digraph DominanceTree {\n");
|
|
|
|
|
foreach_block(block, this) {
|
2015-10-28 21:11:46 -07:00
|
|
|
if (block->idom) {
|
|
|
|
|
printf("\t%d -> %d\n", block->idom->num, block->num);
|
|
|
|
|
}
|
2014-02-26 16:15:52 -08:00
|
|
|
}
|
|
|
|
|
printf("}\n");
|
|
|
|
|
}
|