pco: commonize and improve iteration helpers

Signed-off-by: Simon Perretta <simon.perretta@imgtec.com>
Acked-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36412>
This commit is contained in:
Simon Perretta 2024-12-29 09:20:42 +00:00 committed by Marge Bot
parent 9047c30e50
commit 160f206d7c
4 changed files with 415 additions and 287 deletions

View file

@ -241,26 +241,42 @@ ForEachMacros: [
'pco_foreach_cf_node_in_loop',
'pco_foreach_func_in_shader',
'pco_foreach_func_in_shader_rev',
'pco_foreach_if_in_func',
'pco_foreach_if_in_func_from',
'pco_foreach_if_in_func_from_rev',
'pco_foreach_if_in_func_rev',
'pco_foreach_ssa_bool_if_in_func',
'pco_foreach_ssa_if_in_func',
'pco_foreach_igrp_in_block',
'pco_foreach_igrp_in_func',
'pco_foreach_instr_dest',
'pco_foreach_instr_dest_from',
'pco_foreach_instr_dest_ssa',
'pco_foreach_instr_dest_ssa_from',
'pco_foreach_instr_src',
'pco_foreach_instr_src_from',
'pco_foreach_instr_src_ssa',
'pco_foreach_instr_src_ssa_from',
'pco_foreach_instr_in_block',
'pco_foreach_instr_in_block_from',
'pco_foreach_instr_in_block_from_rev',
'pco_foreach_instr_in_block_rev',
'pco_foreach_instr_in_block_safe',
'pco_foreach_instr_in_block_safe_rev',
'pco_foreach_instr_in_func',
'pco_foreach_instr_in_func_after',
'pco_foreach_instr_in_func_from',
'pco_foreach_instr_in_func_from_rev',
'pco_foreach_instr_in_func_safe',
'pco_foreach_instr_in_func_rev',
'pco_foreach_instr_in_func_safe',
'pco_foreach_instr_in_func_safe_rev',
'pco_foreach_instr_in_igrp',
'pco_foreach_instr_in_igrp_rev',
'pco_foreach_instr_src',
'pco_foreach_instr_src_from',
'pco_foreach_instr_src_ssa',
'pco_foreach_instr_src_ssa_after',
'pco_foreach_instr_src_ssa_from',
'pco_foreach_loop_in_func',
'pco_foreach_loop_in_func_from',
'pco_foreach_loop_in_func_from_rev',
'pco_foreach_loop_in_func_rev',
'pco_foreach_phi_src_in_instr',
'rogue_foreach_block',
'rogue_foreach_block_safe',

View file

@ -259,12 +259,20 @@ enum pco_cf_node_type {
PCO_CF_NODE_TYPE_FUNC,
};
/** PCO control-flow flag. */
enum pco_cf_node_flag {
PCO_CF_NODE_FLAG_NONE = 0,
PCO_CF_NODE_FLAG_IF_THEN,
PCO_CF_NODE_FLAG_IF_ELSE,
};
/** PCO control-flow node. */
typedef struct _pco_cf_node {
struct list_head link; /** Link in lists of pco_cf_nodes. */
enum pco_cf_node_type type; /** CF node type. */
struct _pco_cf_node *parent; /** Parent cf node. */
bool flag; /** Implementation-defined flag. */
enum pco_cf_node_flag flag; /** Implementation-defined flag. */
} pco_cf_node;
/** PCO basic block. */
@ -446,6 +454,8 @@ PCO_DEFINE_CAST(pco_cf_node_as_func,
type,
PCO_CF_NODE_TYPE_FUNC)
#undef PCO_DEFINE_CAST
/* Iterators. */
#define pco_foreach_func_in_shader(func, shader) \
list_for_each_entry (pco_func, func, &(shader)->funcs, link)
@ -479,65 +489,107 @@ PCO_DEFINE_CAST(pco_cf_node_as_func,
for (pco_block *block = pco_func_last_block(func); block != NULL; \
block = pco_prev_block(block))
#define pco_foreach_instr_in_block(instr, block) \
assert(!block->parent_func->parent_shader->is_grouped); \
#define pco_foreach_if_in_func(pif, func) \
for (pco_if *pif = pco_func_first_if(func); pif != NULL; \
pif = pco_next_if(pif))
#define pco_foreach_ssa_if_in_func(pif, func) \
for (pco_if *pif = pco_func_first_if(func); pif != NULL; \
pif = pco_next_if(pif)) \
if (pco_ref_is_ssa(pif->cond))
#define pco_foreach_ssa_bool_if_in_func(pif, func) \
for (pco_if *pif = pco_func_first_if(func); pif != NULL; \
pif = pco_next_if(pif)) \
if (pco_ref_is_ssa(pif->cond) && pco_ref_get_bits(pif->cond) == 1)
#define pco_foreach_if_in_func_from(pif, from) \
for (pco_if *pif = from; pif != NULL; pif = pco_next_if(pif))
#define pco_foreach_if_in_func_from_rev(pif, from) \
for (pco_if *pif = from; pif != NULL; pif = pco_prev_if(pif))
#define pco_foreach_if_in_func_rev(pif, func) \
for (pco_if *pif = pco_func_last_if(func); pif != NULL; \
pif = pco_prev_if(pif))
#define pco_foreach_loop_in_func(loop, func) \
for (pco_loop *loop = pco_func_first_loop(func); loop != NULL; \
loop = pco_next_loop(loop))
#define pco_foreach_loop_in_func_from(loop, from) \
for (pco_loop *loop = from; loop != NULL; loop = pco_next_loop(loop))
#define pco_foreach_loop_in_func_from_rev(loop, from) \
for (pco_loop *loop = from; loop != NULL; loop = pco_prev_loop(loop))
#define pco_foreach_loop_in_func_rev(loop, func) \
for (pco_loop *loop = pco_func_last_loop(func); loop != NULL; \
loop = pco_prev_loop(loop))
#define pco_foreach_instr_in_block(instr, block) \
list_for_each_entry (pco_instr, instr, &(block)->instrs, link)
#define pco_foreach_instr_in_block_safe(instr, block) \
assert(!block->parent_func->parent_shader->is_grouped); \
#define pco_foreach_instr_in_block_from(instr, block, from) \
list_for_each_entry_from ( \
pco_instr, \
instr, \
block == from->parent_block ? &from->link : (block)->instrs.next, \
&(block)->instrs, \
link)
#define pco_foreach_instr_in_block_from_rev(instr, block, from) \
list_for_each_entry_from_rev ( \
pco_instr, \
instr, \
block == from->parent_block ? &from->link : (block)->instrs.prev, \
&(block)->instrs, \
link)
#define pco_foreach_instr_in_block_safe(instr, block) \
list_for_each_entry_safe (pco_instr, instr, &(block)->instrs, link)
#define pco_foreach_instr_in_block_rev(instr, block) \
assert(!block->parent_func->parent_shader->is_grouped); \
#define pco_foreach_instr_in_block_rev(instr, block) \
list_for_each_entry_rev (pco_instr, instr, &(block)->instrs, link)
#define pco_foreach_instr_in_block_safe_rev(instr, block) \
assert(!block->parent_func->parent_shader->is_grouped); \
#define pco_foreach_instr_in_block_safe_rev(instr, block) \
list_for_each_entry_safe_rev (pco_instr, instr, &(block)->instrs, link)
#define pco_foreach_igrp_in_block(igrp, block) \
assert(block->parent_func->parent_shader->is_grouped); \
#define pco_foreach_igrp_in_block(igrp, block) \
list_for_each_entry (pco_igrp, igrp, &(block)->instrs, link)
#define pco_foreach_phi_src_in_instr(phi_src, instr) \
list_for_each_entry (pco_phi_src, phi_src, &(instr)->phi_srcs, link)
#define pco_foreach_instr_in_func(instr, func) \
assert(!func->parent_shader->is_grouped); \
pco_foreach_block_in_func (block, func) \
list_for_each_entry (pco_instr, instr, &(block)->instrs, link)
pco_foreach_instr_in_block (instr, block)
#define pco_foreach_instr_in_func_from(instr, from) \
assert(!from->parent_func->parent_shader->is_grouped); \
pco_foreach_block_in_func_from (block, from->parent_block) \
list_for_each_entry_from (pco_instr, instr, from, &(block)->instrs, link)
pco_foreach_instr_in_block_from (instr, block, from)
#define pco_foreach_instr_in_func_after(instr, after) \
if (pco_next_instr(after)) \
pco_foreach_instr_in_func_from (instr, pco_next_instr(after))
#define pco_foreach_instr_in_func_from_rev(instr, from) \
assert(!from->parent_func->parent_shader->is_grouped); \
pco_foreach_block_in_func_from_rev (block, from->parent_block) \
list_for_each_entry_from_rev (pco_instr, \
instr, \
from, \
&(block)->instrs, \
link)
pco_foreach_instr_in_block_from_rev (instr, block, from)
#define pco_foreach_instr_in_func_safe(instr, func) \
assert(!func->parent_shader->is_grouped); \
pco_foreach_block_in_func (block, func) \
list_for_each_entry_safe (pco_instr, instr, &(block)->instrs, link)
pco_foreach_instr_in_block_safe (instr, block)
#define pco_foreach_instr_in_func_rev(instr, func) \
assert(!func->parent_shader->is_grouped); \
pco_foreach_block_in_func_rev (block, func) \
list_for_each_entry_rev (pco_instr, instr, &(block)->instrs, link)
pco_foreach_instr_in_block_rev (instr, block)
#define pco_foreach_instr_in_func_safe_rev(instr, func) \
assert(!func->parent_shader->is_grouped); \
pco_foreach_block_in_func_rev (block, func) \
list_for_each_entry_safe_rev (pco_instr, instr, &(block)->instrs, link)
pco_foreach_instr_in_block_safe_rev (instr, block)
#define pco_foreach_igrp_in_func(igrp, func) \
assert(func->parent_shader->is_grouped); \
pco_foreach_block_in_func (block, func) \
list_for_each_entry (pco_igrp, igrp, &(block)->instrs, link)
@ -558,13 +610,6 @@ PCO_DEFINE_CAST(pco_cf_node_as_func,
for (pco_ref *pdest = pdest_from; pdest < &instr->dest[instr->num_dests]; \
++pdest)
#define pco_foreach_instr_src(psrc, instr) \
for (pco_ref *psrc = &instr->src[0]; psrc < &instr->src[instr->num_srcs]; \
++psrc)
#define pco_foreach_instr_src_from(psrc, instr, psrc_from) \
for (pco_ref *psrc = psrc_from; psrc < &instr->src[instr->num_srcs]; ++psrc)
#define pco_foreach_instr_dest_ssa(pdest, instr) \
pco_foreach_instr_dest (pdest, instr) \
if (pco_ref_is_ssa(*pdest))
@ -573,6 +618,13 @@ PCO_DEFINE_CAST(pco_cf_node_as_func,
pco_foreach_instr_dest_from (pdest, instr, pdest_from) \
if (pco_ref_is_ssa(*pdest))
#define pco_foreach_instr_src(psrc, instr) \
for (pco_ref *psrc = &instr->src[0]; psrc < &instr->src[instr->num_srcs]; \
++psrc)
#define pco_foreach_instr_src_from(psrc, instr, psrc_from) \
for (pco_ref *psrc = psrc_from; psrc < &instr->src[instr->num_srcs]; ++psrc)
#define pco_foreach_instr_src_ssa(psrc, instr) \
pco_foreach_instr_src (psrc, instr) \
if (pco_ref_is_ssa(*psrc))
@ -581,24 +633,15 @@ PCO_DEFINE_CAST(pco_cf_node_as_func,
pco_foreach_instr_src_from (psrc, instr, psrc_from) \
if (pco_ref_is_ssa(*psrc))
#define pco_first_cf_node(body) list_first_entry(body, pco_cf_node, link)
#define pco_last_cf_node(body) list_last_entry(body, pco_cf_node, link)
#define pco_next_cf_node(cf_node) \
list_entry((cf_node)->link.next, pco_cf_node, link)
#define pco_prev_cf_node(cf_node) \
list_entry((cf_node)->link.prev, pco_cf_node, link)
#define pco_foreach_instr_src_ssa_after(psrc, instr, psrc_after) \
pco_foreach_instr_src_ssa_from (psrc, instr, psrc_after + 1)
/**
* \brief Returns whether the current cf node is (directly) in an else body.
*
* \param[in] cf_node The cf node.
* \return True if in the else body, else false if in the then body.
*/
static inline bool pco_cf_node_in_if_else(pco_cf_node *cf_node)
{
assert(cf_node->parent->type == PCO_CF_NODE_TYPE_IF);
return cf_node->flag;
}
#define pco_first_cf_node_list(body) list_first_entry(body, pco_cf_node, link)
#define pco_last_cf_node_list(body) list_last_entry(body, pco_cf_node, link)
#define pco_next_cf_node_list(cf_node) \
list_entry((cf_node)->link.next, pco_cf_node, link)
#define pco_prev_cf_node_list(cf_node) \
list_entry((cf_node)->link.prev, pco_cf_node, link)
/**
* \brief Returns the preamble function of a PCO shader.
@ -671,189 +714,34 @@ static inline unsigned pco_igrp_variant(const pco_igrp *igrp,
}
/* Motions. */
/**
* \brief Returns the first block in an if then body.
*
* \param[in] pif The if.
* \return The first block.
*/
static inline pco_block *pco_if_then_first_block(pco_if *pif)
{
assert(!list_is_empty(&pif->then_body));
pco_cf_node *cf_node = pco_first_cf_node(&pif->then_body);
return pco_cf_node_as_block(cf_node);
}
/**
* \brief Returns the last block in an if then body.
* \brief Returns the first CF node from the body containing the current CF
* node.
*
* \param[in] pif The if.
* \return The last block.
* \param[in] cf_node The current CF node.
* \return The first CF node.
*/
static inline pco_block *pco_if_then_last_block(pco_if *pif)
{
assert(!list_is_empty(&pif->then_body));
pco_cf_node *cf_node = pco_last_cf_node(&pif->then_body);
return pco_cf_node_as_block(cf_node);
}
/**
* \brief Returns the first block in an else body.
*
* \param[in] pif The if.
* \return The first block.
*/
static inline pco_block *pco_if_else_first_block(pco_if *pif)
{
assert(!list_is_empty(&pif->else_body));
pco_cf_node *cf_node = pco_first_cf_node(&pif->else_body);
return pco_cf_node_as_block(cf_node);
}
/**
* \brief Returns the last block in an else body.
*
* \param[in] pif The if.
* \return The last block.
*/
static inline pco_block *pco_if_else_last_block(pco_if *pif)
{
assert(!list_is_empty(&pif->else_body));
pco_cf_node *cf_node = pco_last_cf_node(&pif->else_body);
return pco_cf_node_as_block(cf_node);
}
/**
* \brief Returns the first block in a loop.
*
* \param[in] loop The loop.
* \return The first block.
*/
static inline pco_block *pco_loop_first_block(pco_loop *loop)
{
assert(!list_is_empty(&loop->body));
pco_cf_node *cf_node = pco_first_cf_node(&loop->body);
return pco_cf_node_as_block(cf_node);
}
/**
* \brief Returns the last block in a loop.
*
* \param[in] loop The loop.
* \return The last block.
*/
static inline pco_block *pco_loop_last_block(pco_loop *loop)
{
assert(!list_is_empty(&loop->body));
pco_cf_node *cf_node = pco_last_cf_node(&loop->body);
return pco_cf_node_as_block(cf_node);
}
/**
* \brief Returns the first block in a function.
*
* \param[in] func The function.
* \return The first block.
*/
static inline pco_block *pco_func_first_block(pco_func *func)
{
assert(!list_is_empty(&func->body));
pco_cf_node *cf_node = pco_first_cf_node(&func->body);
return pco_cf_node_as_block(cf_node);
}
/**
* \brief Returns the last block in a function.
*
* \param[in] func The function.
* \return The last block.
*/
static inline pco_block *pco_func_last_block(pco_func *func)
{
assert(!list_is_empty(&func->body));
pco_cf_node *cf_node = pco_last_cf_node(&func->body);
return pco_cf_node_as_block(cf_node);
}
/**
* \brief Returns the first block in a control-flow node.
*
* \param[in] cf_node The control-flow node.
* \return The first block in the control-flow node.
*/
static inline pco_block *pco_cf_node_first_block(pco_cf_node *cf_node)
{
switch (cf_node->type) {
case PCO_CF_NODE_TYPE_BLOCK:
return pco_cf_node_as_block(cf_node);
case PCO_CF_NODE_TYPE_IF:
return pco_if_then_first_block(pco_cf_node_as_if(cf_node));
case PCO_CF_NODE_TYPE_LOOP:
return pco_loop_first_block(pco_cf_node_as_loop(cf_node));
case PCO_CF_NODE_TYPE_FUNC:
return pco_func_first_block(pco_cf_node_as_func(cf_node));
default:
break;
}
UNREACHABLE("");
}
/**
* \brief Returns the last block in a control-flow node.
*
* \param[in] cf_node The control-flow node.
* \return The last block in the control-flow node.
*/
static inline pco_block *pco_cf_node_last_block(pco_cf_node *cf_node)
{
switch (cf_node->type) {
case PCO_CF_NODE_TYPE_BLOCK:
return pco_cf_node_as_block(cf_node);
case PCO_CF_NODE_TYPE_IF:
return pco_if_else_last_block(pco_cf_node_as_if(cf_node));
case PCO_CF_NODE_TYPE_LOOP:
return pco_loop_last_block(pco_cf_node_as_loop(cf_node));
case PCO_CF_NODE_TYPE_FUNC:
return pco_func_last_block(pco_cf_node_as_func(cf_node));
default:
break;
}
UNREACHABLE("");
}
static inline struct list_head *pco_parent_cf_node_body(pco_cf_node *cf_node)
static inline pco_cf_node *pco_first_cf_node(pco_cf_node *cf_node)
{
pco_cf_node *parent_cf_node = cf_node->parent;
switch (parent_cf_node->type) {
case PCO_CF_NODE_TYPE_IF:
return pco_cf_node_in_if_else(cf_node)
? &pco_cf_node_as_if(parent_cf_node)->else_body
: &pco_cf_node_as_if(parent_cf_node)->then_body;
case PCO_CF_NODE_TYPE_IF: {
pco_if *pif = pco_cf_node_as_if(parent_cf_node);
if (!list_is_empty(&pif->then_body))
return pco_first_cf_node_list(&pif->then_body);
assert(!list_is_empty(&pif->else_body));
return pco_first_cf_node_list(&pif->else_body);
}
case PCO_CF_NODE_TYPE_LOOP:
return &pco_cf_node_as_loop(parent_cf_node)->body;
return pco_first_cf_node_list(&pco_cf_node_as_loop(parent_cf_node)->body);
case PCO_CF_NODE_TYPE_FUNC:
return &pco_cf_node_as_func(parent_cf_node)->body;
return pco_first_cf_node_list(&pco_cf_node_as_func(parent_cf_node)->body);
default:
break;
@ -863,37 +751,95 @@ static inline struct list_head *pco_parent_cf_node_body(pco_cf_node *cf_node)
}
/**
* \brief Returns the next block in the function.
* \brief Returns the last CF node from the body containing the current CF node.
*
* \param[in] block The current block.
* \return The next block, or NULL if we've reached the end of the function.
* \param[in] cf_node The current CF node.
* \return The last CF node.
*/
static inline pco_block *pco_next_block(pco_block *block)
static inline pco_cf_node *pco_last_cf_node(pco_cf_node *cf_node)
{
if (!block)
pco_cf_node *parent_cf_node = cf_node->parent;
switch (parent_cf_node->type) {
case PCO_CF_NODE_TYPE_IF: {
pco_if *pif = pco_cf_node_as_if(parent_cf_node);
if (!list_is_empty(&pif->else_body))
return pco_last_cf_node_list(&pif->else_body);
assert(!list_is_empty(&pif->then_body));
return pco_last_cf_node_list(&pif->then_body);
}
case PCO_CF_NODE_TYPE_LOOP:
return pco_last_cf_node_list(&pco_cf_node_as_loop(parent_cf_node)->body);
case PCO_CF_NODE_TYPE_FUNC:
return pco_last_cf_node_list(&pco_cf_node_as_func(parent_cf_node)->body);
default:
break;
}
UNREACHABLE("");
}
/**
* \brief Returns the next CF node.
*
* \param[in] cf_node The current CF node.
* \return The next CF node.
*/
static inline pco_cf_node *pco_next_cf_node(pco_cf_node *cf_node)
{
if (!cf_node)
return NULL;
pco_cf_node *cf_node = &block->cf_node;
pco_cf_node *last_cf_node =
pco_last_cf_node(pco_parent_cf_node_body(cf_node));
switch (cf_node->type) {
case PCO_CF_NODE_TYPE_BLOCK:
/* Not yet reached the end of the body, return the next cf node. */
if (cf_node != pco_last_cf_node(cf_node))
return pco_next_cf_node_list(cf_node);
break;
/* Not yet reached the end of the body, return the next cf node. */
if (cf_node != last_cf_node)
return pco_cf_node_first_block(pco_next_cf_node(cf_node));
case PCO_CF_NODE_TYPE_IF: {
/* Return first cf node in if then body if it exists. */
pco_if *pif = pco_cf_node_as_if(cf_node);
/* Reached the end; go to the next block from the parent cf node. */
if (!list_is_empty(&pif->then_body))
return pco_first_cf_node_list(&pif->then_body);
assert(!list_is_empty(&pif->else_body));
return pco_first_cf_node_list(&pif->else_body);
}
case PCO_CF_NODE_TYPE_LOOP: {
/* Return first cf node in loop body. */
pco_loop *loop = pco_cf_node_as_loop(cf_node);
return pco_first_cf_node_list(&loop->body);
}
default:
UNREACHABLE("");
}
/* Reached the end; go to the next cf node from the parent cf node. */
pco_cf_node *parent_cf_node = cf_node->parent;
switch (parent_cf_node->type) {
case PCO_CF_NODE_TYPE_IF:
/* If we're in the then body, go to the else body. */
if (!pco_cf_node_in_if_else(cf_node))
return pco_if_else_first_block(pco_cf_node_as_if(parent_cf_node));
case PCO_CF_NODE_TYPE_IF: {
/* If we're in the then body, go to the else body if it exists. */
pco_if *pif = pco_cf_node_as_if(parent_cf_node);
if (cf_node->flag == PCO_CF_NODE_FLAG_IF_THEN &&
!list_is_empty(&pif->else_body)) {
return pco_first_cf_node_list(&pif->else_body);
}
/* Otherwise go to the next block from the parent's parent cf node. */
/* Otherwise go to the next cf_node from the parent's parent cf node. */
FALLTHROUGH;
}
case PCO_CF_NODE_TYPE_LOOP:
return pco_cf_node_first_block(pco_next_cf_node(parent_cf_node));
return pco_next_cf_node_list(parent_cf_node);
/* End of the function; return NULL. */
case PCO_CF_NODE_TYPE_FUNC:
@ -907,38 +853,62 @@ static inline pco_block *pco_next_block(pco_block *block)
}
/**
* \brief Returns the previous block in the function.
* \brief Returns the previous CF node.
*
* \param[in] block The current block.
* \return The previous block, or NULL if we've reached the start of the
* function.
* \param[in] cf_node The current CF node.
* \return The previous CF node.
*/
static inline pco_block *pco_prev_block(pco_block *block)
static inline pco_cf_node *pco_prev_cf_node(pco_cf_node *cf_node)
{
if (!block)
if (!cf_node)
return NULL;
pco_cf_node *cf_node = &block->cf_node;
pco_cf_node *first_cf_node =
pco_first_cf_node(pco_parent_cf_node_body(cf_node));
switch (cf_node->type) {
case PCO_CF_NODE_TYPE_BLOCK:
/* Not yet reached the start of the body, return the previous cf node. */
if (cf_node != pco_first_cf_node(cf_node))
return pco_prev_cf_node_list(cf_node);
break;
/* Not yet reached the start of the body, return the previous cf node. */
if (cf_node != first_cf_node)
return pco_cf_node_last_block(pco_prev_cf_node(cf_node));
case PCO_CF_NODE_TYPE_IF: {
/* Return last cf node in if else body if it's not empty. */
pco_if *pif = pco_cf_node_as_if(cf_node);
/* Reached the start; go to the previous block from the parent cf node. */
if (!list_is_empty(&pif->else_body))
return pco_last_cf_node_list(&pif->else_body);
assert(!list_is_empty(&pif->then_body));
return pco_last_cf_node_list(&pif->then_body);
}
case PCO_CF_NODE_TYPE_LOOP: {
/* Return last cf node in loop body. */
pco_loop *loop = pco_cf_node_as_loop(cf_node);
return pco_last_cf_node_list(&loop->body);
}
default:
UNREACHABLE("");
}
/* Reached the start; go to the previous cf node from the parent cf node. */
pco_cf_node *parent_cf_node = cf_node->parent;
switch (parent_cf_node->type) {
case PCO_CF_NODE_TYPE_IF:
/* If we're in the else body, go to the then body. */
if (pco_cf_node_in_if_else(cf_node))
return pco_if_then_last_block(pco_cf_node_as_if(parent_cf_node));
case PCO_CF_NODE_TYPE_IF: {
/* If we're in the else body, go to the then body if it exists. */
pco_if *pif = pco_cf_node_as_if(parent_cf_node);
if (cf_node->flag == PCO_CF_NODE_FLAG_IF_ELSE &&
!list_is_empty(&pif->then_body)) {
return pco_last_cf_node_list(&pif->then_body);
}
/* Otherwise go to the previous block from the parent's parent cf node. */
/* Otherwise go to the previous cf_node from the parent's parent cf node.
*/
FALLTHROUGH;
}
case PCO_CF_NODE_TYPE_LOOP:
return pco_cf_node_last_block(pco_prev_cf_node(parent_cf_node));
return pco_prev_cf_node_list(parent_cf_node);
/* Start of the function; return NULL. */
case PCO_CF_NODE_TYPE_FUNC:
@ -951,6 +921,112 @@ static inline pco_block *pco_prev_block(pco_block *block)
UNREACHABLE("");
}
/**
* \brief Returns the next CF node of the given type, if one exists.
*
* \param[in] cf_node The current CF node.
* \param[in] type The type of the next CF node.
* \return The next CF node if one exists, else NULL.
*/
static inline pco_cf_node *pco_next_cf_node_type(pco_cf_node *cf_node,
enum pco_cf_node_type type)
{
do {
cf_node = pco_next_cf_node(cf_node);
} while (cf_node != NULL && cf_node->type != type);
return cf_node;
}
/**
* \brief Returns the first CF node of the given type, if one exists.
*
* \param[in] func PCO function.
* \param[in] type The type of the first CF node.
* \return The first CF node if one exists, else NULL.
*/
static inline pco_cf_node *
pco_func_first_cf_node_type(pco_func *func, enum pco_cf_node_type type)
{
assert(!list_is_empty(&func->body));
pco_cf_node *cf_node = pco_first_cf_node_list(&func->body);
if (cf_node->type == type)
return cf_node;
return pco_next_cf_node_type(cf_node, type);
}
/**
* \brief Returns the previous CF node of the given type, if one exists.
*
* \param[in] cf_node The current CF node.
* \param[in] type The type of the previous CF node.
* \return The previous CF node if one exists, else NULL.
*/
static inline pco_cf_node *pco_prev_cf_node_type(pco_cf_node *cf_node,
enum pco_cf_node_type type)
{
do {
cf_node = pco_prev_cf_node(cf_node);
} while (cf_node != NULL && cf_node->type != type);
return cf_node;
}
/**
* \brief Returns the last CF node of the given type, if one exists.
*
* \param[in] func PCO function.
* \param[in] type The type of the last CF node.
* \return The last CF node if one exists, else NULL.
*/
static inline pco_cf_node *
pco_func_last_cf_node_type(pco_func *func, enum pco_cf_node_type type)
{
assert(!list_is_empty(&func->body));
pco_cf_node *cf_node = pco_last_cf_node_list(&func->body);
if (cf_node->type == type)
return cf_node;
return pco_prev_cf_node_type(cf_node, type);
}
/* CF helper iterators. */
#define PCO_DEFINE_CF_ITER(type, cf_node_type) \
static inline pco_##type *pco_next_##type(pco_##type *current_##type) \
{ \
pco_cf_node *cf_node = \
pco_next_cf_node_type(&current_##type->cf_node, cf_node_type); \
return cf_node == NULL ? NULL : pco_cf_node_as_##type(cf_node); \
} \
\
static inline pco_##type *pco_func_first_##type(pco_func *func) \
{ \
pco_cf_node *cf_node = pco_func_first_cf_node_type(func, cf_node_type); \
return cf_node == NULL ? NULL : pco_cf_node_as_##type(cf_node); \
} \
\
static inline pco_##type *pco_prev_##type(pco_##type *current_##type) \
{ \
pco_cf_node *cf_node = \
pco_prev_cf_node_type(&current_##type->cf_node, cf_node_type); \
return cf_node == NULL ? NULL : pco_cf_node_as_##type(cf_node); \
} \
\
static inline pco_##type *pco_func_last_##type(pco_func *func) \
{ \
pco_cf_node *cf_node = pco_func_last_cf_node_type(func, cf_node_type); \
return cf_node == NULL ? NULL : pco_cf_node_as_##type(cf_node); \
}
PCO_DEFINE_CF_ITER(block, PCO_CF_NODE_TYPE_BLOCK)
PCO_DEFINE_CF_ITER(if, PCO_CF_NODE_TYPE_IF)
PCO_DEFINE_CF_ITER(loop, PCO_CF_NODE_TYPE_LOOP)
#undef PCO_DEFINE_CF_ITER
/**
* \brief Returns the first instruction in a block.
*
@ -985,32 +1061,50 @@ static inline pco_instr *pco_last_instr(pco_block *block)
* \brief Returns the next instruction.
*
* \param[in] instr The current instruction.
* \return The next instruction, or NULL if the end of the block has been
* \return The next instruction, or NULL if the end of the function has been
* reached.
*/
static inline pco_instr *pco_next_instr(pco_instr *instr)
{
assert(!instr->parent_func->parent_shader->is_grouped);
if (!instr || instr == pco_last_instr(instr->parent_block))
if (!instr)
return NULL;
return list_entry(instr->link.next, pco_instr, link);
if (instr != pco_last_instr(instr->parent_block))
return list_entry(instr->link.next, pco_instr, link);
pco_block *block = pco_next_block(instr->parent_block);
/* End of the function. */
if (!block)
return NULL;
return pco_first_instr(block);
}
/**
* \brief Returns the previous instruction.
*
* \param[in] instr The current instruction.
* \return The previous instruction, or NULL if the start of the block has been
* reached.
* \return The previous instruction, or NULL if the start of the function has
* been reached.
*/
static inline pco_instr *pco_prev_instr(pco_instr *instr)
{
assert(!instr->parent_func->parent_shader->is_grouped);
if (!instr || instr == pco_first_instr(instr->parent_block))
if (!instr)
return NULL;
return list_entry(instr->link.prev, pco_instr, link);
if (instr != pco_first_instr(instr->parent_block))
return list_entry(instr->link.prev, pco_instr, link);
pco_block *block = pco_prev_block(instr->parent_block);
/* Start of the function. */
if (!block)
return NULL;
return pco_last_instr(block);
}
/**
@ -1047,39 +1141,57 @@ static inline pco_igrp *pco_last_igrp(pco_block *block)
* \brief Returns the next instruction group.
*
* \param[in] igrp The current instruction group.
* \return The next instruction group, or NULL if the end of the block has been
* reached.
* \return The next instruction group, or NULL if the end of the function has
* been reached.
*/
static inline pco_igrp *pco_next_igrp(pco_igrp *igrp)
{
assert(igrp->parent_func->parent_shader->is_grouped);
if (!igrp || igrp == pco_last_igrp(igrp->parent_block))
if (!igrp)
return NULL;
return list_entry(igrp->link.next, pco_igrp, link);
if (igrp != pco_last_igrp(igrp->parent_block))
return list_entry(igrp->link.next, pco_igrp, link);
pco_block *block = pco_next_block(igrp->parent_block);
/* End of the function. */
if (!block)
return NULL;
return pco_first_igrp(block);
}
/**
* \brief Returns the previous instruction group.
*
* \param[in] igrp The current instruction group.
* \return The previous instruction group, or NULL if the start of the block has
* been reached.
* \return The previous instruction group, or NULL if the start of the function
* has been reached.
*/
static inline pco_igrp *pco_prev_igrp(pco_igrp *igrp)
{
assert(igrp->parent_func->parent_shader->is_grouped);
if (!igrp || igrp == pco_first_igrp(igrp->parent_block))
if (!igrp)
return NULL;
return list_entry(igrp->link.prev, pco_igrp, link);
if (igrp == pco_first_igrp(igrp->parent_block))
return list_entry(igrp->link.prev, pco_igrp, link);
pco_block *block = pco_prev_block(igrp->parent_block);
/* Start of the function. */
if (!block)
return NULL;
return pco_last_igrp(block);
}
/**
* \brief Returns the first instruction in an igrp.
*
* \param[in] igrp The igrp.
* \return The first instruction.
* \return The first instruction, or NULL if the igrp is empty.
*/
static inline pco_instr *pco_igrp_first_instr(pco_igrp *igrp)
{
@ -1087,14 +1199,14 @@ static inline pco_instr *pco_igrp_first_instr(pco_igrp *igrp)
if (igrp->instrs[p])
return igrp->instrs[p];
UNREACHABLE("");
return NULL;
}
/**
* \brief Returns the last instruction in an igrp.
*
* \param[in] igrp The igrp.
* \return The last instruction.
* \return The last instruction, or NULL if the igrp is empty.
*/
static inline pco_instr *pco_igrp_last_instr(pco_igrp *igrp)
{
@ -1102,7 +1214,7 @@ static inline pco_instr *pco_igrp_last_instr(pco_igrp *igrp)
if (igrp->instrs[p])
return igrp->instrs[p];
UNREACHABLE("");
return NULL;
}
/**

View file

@ -61,7 +61,7 @@ static inline bool pco_opt_prep_mods(pco_shader *shader,
mod->op != PCO_OP_FLR)
continue;
pco_foreach_instr_in_func_from (instr, mod) {
pco_foreach_instr_in_func_after (instr, mod) {
if (instr->op != PCO_OP_FADD && instr->op != PCO_OP_FMUL)
continue;
@ -436,7 +436,7 @@ static inline bool try_prop_hw_comp(pco_ref src, pco_ref repl, pco_instr *from)
{
bool progress = false;
pco_foreach_instr_in_func_from (instr, from) {
pco_foreach_instr_in_func_after (instr, from) {
pco_foreach_instr_src_ssa (psrc, instr) {
if (psrc->val != src.val)
continue;

View file

@ -49,7 +49,7 @@ static bool vec_has_repeated_ssas(pco_instr *vec)
assert(vec->op == PCO_OP_VEC);
pco_foreach_instr_src_ssa (psrc, vec) {
pco_foreach_instr_src_ssa_from (psrc_inner, vec, psrc + 1) {
pco_foreach_instr_src_ssa_after (psrc_inner, vec, psrc) {
if (psrc_inner->val == psrc->val)
return true;
}