2015-07-22 03:54:18 +01:00
|
|
|
/*
|
|
|
|
* Copyright © 2014 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:
|
|
|
|
* Connor Abbott (cwabbott0@gmail.com)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2017-03-20 16:04:16 +00:00
|
|
|
#ifndef NIR_CONTROL_FLOW_H
|
|
|
|
#define NIR_CONTROL_FLOW_H
|
2015-07-22 03:54:18 +01:00
|
|
|
|
2017-03-20 16:04:16 +00:00
|
|
|
#include "nir.h"
|
2015-07-22 03:54:18 +01:00
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** NIR Control Flow Modification
|
|
|
|
*
|
2017-02-28 01:21:42 +00:00
|
|
|
* This file contains various APIs that make modifying control flow in NIR,
|
2015-07-22 03:54:18 +01:00
|
|
|
* while maintaining the invariants checked by the validator, much easier.
|
2015-07-22 03:54:34 +01:00
|
|
|
* There are two parts to this:
|
|
|
|
*
|
2017-02-28 01:21:42 +00:00
|
|
|
* 1. Inserting control flow (ifs and loops) in various places, for creating
|
2015-07-22 03:54:34 +01:00
|
|
|
* IR either from scratch or as part of some lowering pass.
|
|
|
|
* 2. Taking existing pieces of the IR and either moving them around or
|
|
|
|
* deleting them.
|
2015-07-22 03:54:18 +01:00
|
|
|
*/
|
|
|
|
|
nir/cf: add a cursor structure
For now, it allows us to refactor the control flow insertion API's so
that there's a single entrypoint (with some wrappers). More importantly,
it will allow us to reduce the combinatorial explosion in the extract
function. There, we need to specify two points to extract, which may be
at the beginning of a block, the end of a block, or in the middle of a
block. And then there are various wrappers based off of that (before a
control flow node, before a control flow list, etc.). Rather than having
9 different functions, we can have one function and push the actual
logic of determining which variant to use down to the split function,
which will be shared with nir_cf_node_insert().
In the future, we may want to make the instruction insertion API's as
well as the builder use this, but that's a future cleanup.
Signed-off-by: Connor Abbott <connor.w.abbott@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
2015-07-22 03:54:30 +01:00
|
|
|
/** Control flow insertion. */
|
|
|
|
|
2015-07-22 03:54:33 +01:00
|
|
|
/** puts a control flow node where the cursor is */
|
|
|
|
void nir_cf_node_insert(nir_cursor cursor, nir_cf_node *node);
|
|
|
|
|
2015-07-22 03:54:18 +01:00
|
|
|
/** puts a control flow node immediately after another control flow node */
|
2015-07-22 03:54:33 +01:00
|
|
|
static inline void
|
|
|
|
nir_cf_node_insert_after(nir_cf_node *node, nir_cf_node *after)
|
|
|
|
{
|
|
|
|
nir_cf_node_insert(nir_after_cf_node(node), after);
|
|
|
|
}
|
2015-07-22 03:54:18 +01:00
|
|
|
|
|
|
|
/** puts a control flow node immediately before another control flow node */
|
2015-07-22 03:54:33 +01:00
|
|
|
static inline void
|
|
|
|
nir_cf_node_insert_before(nir_cf_node *node, nir_cf_node *before)
|
|
|
|
{
|
|
|
|
nir_cf_node_insert(nir_before_cf_node(node), before);
|
|
|
|
}
|
2015-07-22 03:54:18 +01:00
|
|
|
|
|
|
|
/** puts a control flow node at the beginning of a list from an if, loop, or function */
|
2015-07-22 03:54:33 +01:00
|
|
|
static inline void
|
|
|
|
nir_cf_node_insert_begin(struct exec_list *list, nir_cf_node *node)
|
|
|
|
{
|
|
|
|
nir_cf_node_insert(nir_before_cf_list(list), node);
|
|
|
|
}
|
2015-07-22 03:54:18 +01:00
|
|
|
|
|
|
|
/** puts a control flow node at the end of a list from an if, loop, or function */
|
2015-07-22 03:54:33 +01:00
|
|
|
static inline void
|
|
|
|
nir_cf_node_insert_end(struct exec_list *list, nir_cf_node *node)
|
|
|
|
{
|
|
|
|
nir_cf_node_insert(nir_after_cf_list(list), node);
|
|
|
|
}
|
2015-07-22 03:54:18 +01:00
|
|
|
|
|
|
|
|
2015-07-22 03:54:34 +01:00
|
|
|
/** Control flow motion.
|
|
|
|
*
|
|
|
|
* These functions let you take a part of a control flow list (basically
|
|
|
|
* equivalent to a series of statement in GLSL) and "extract" it from the IR,
|
|
|
|
* so that it's a free-floating piece of IR that can be either re-inserted
|
|
|
|
* somewhere else or deleted entirely. A few notes on using it:
|
|
|
|
*
|
|
|
|
* 1. Phi nodes are considered attached to the piece of control flow that
|
|
|
|
* their sources come from. There are three places where phi nodes can
|
|
|
|
* occur, which are the three places where a block can have multiple
|
|
|
|
* predecessors:
|
|
|
|
*
|
|
|
|
* 1) After an if statement, if neither branch ends in a jump.
|
2017-02-28 01:21:42 +00:00
|
|
|
* 2) After a loop, if there are multiple breaks.
|
2015-07-22 03:54:34 +01:00
|
|
|
* 3) At the beginning of a loop.
|
|
|
|
*
|
|
|
|
* For #1, the phi node is considered to be part of the if, and for #2 and
|
|
|
|
* #3 the phi node is considered to be part of the loop. This allows us to
|
2017-02-28 01:21:42 +00:00
|
|
|
* keep phis intact, but it means that phi nodes cannot be separated from
|
2015-07-22 03:54:34 +01:00
|
|
|
* the control flow they come from. For example, extracting an if without
|
|
|
|
* extracting all the phi nodes after it is not allowed, and neither is
|
|
|
|
* extracting only some of the phi nodes at the beginning of a block. It
|
|
|
|
* also means that extracting from the beginning of a basic block actually
|
|
|
|
* means extracting from the first non-phi instruction, since there's no
|
|
|
|
* situation where extracting phi nodes without extracting what comes
|
|
|
|
* before them makes any sense.
|
|
|
|
*
|
|
|
|
* 2. Phi node sources are guaranteed to remain valid, meaning that they still
|
|
|
|
* correspond one-to-one with the predecessors of the basic block they're
|
|
|
|
* part of. In addition, the original sources will be preserved unless they
|
|
|
|
* correspond to a break or continue that was deleted. However, no attempt
|
|
|
|
* is made to ensure that SSA form is maintained. In particular, it is
|
|
|
|
* *not* guaranteed that definitions of SSA values will dominate all their
|
|
|
|
* uses after all is said and done. Either the caller must ensure that this
|
|
|
|
* is the case, or it must insert extra phi nodes to restore SSA.
|
|
|
|
*
|
|
|
|
* 3. It is invalid to move a piece of IR with a break/continue outside of the
|
|
|
|
* loop it references. Doing this will result in invalid
|
|
|
|
* successors/predecessors and phi node sources.
|
|
|
|
*
|
|
|
|
* 4. It is invalid to move a piece of IR from one function implementation to
|
|
|
|
* another.
|
|
|
|
*
|
|
|
|
* 5. Extracting a control flow list will leave lots of dangling references to
|
|
|
|
* and from other pieces of the IR. It also leaves things in a not 100%
|
|
|
|
* consistent state. This means that some things (e.g. inserting
|
|
|
|
* instructions) might not work reliably on the extracted control flow. It
|
|
|
|
* also means that extracting control flow without re-inserting it or
|
|
|
|
* deleting it is a Bad Thing (tm).
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
struct exec_list list;
|
|
|
|
nir_function_impl *impl; /* for cleaning up if the list is deleted */
|
|
|
|
} nir_cf_list;
|
|
|
|
|
2022-04-26 14:53:31 +01:00
|
|
|
nir_cursor nir_cf_extract(nir_cf_list *extracted, nir_cursor begin,
|
|
|
|
nir_cursor end);
|
2015-07-22 03:54:34 +01:00
|
|
|
|
2022-04-19 13:05:04 +01:00
|
|
|
nir_cursor nir_cf_reinsert(nir_cf_list *cf_list, nir_cursor cursor);
|
2015-07-22 03:54:34 +01:00
|
|
|
|
|
|
|
void nir_cf_delete(nir_cf_list *cf_list);
|
|
|
|
|
2016-08-25 03:48:57 +01:00
|
|
|
void nir_cf_list_clone(nir_cf_list *dst, nir_cf_list *src, nir_cf_node *parent,
|
|
|
|
struct hash_table *remap_table);
|
|
|
|
|
2018-11-16 03:57:11 +00:00
|
|
|
static inline void
|
|
|
|
nir_cf_list_clone_and_reinsert(nir_cf_list *src_list, nir_cf_node *parent,
|
|
|
|
nir_cursor cursor,
|
|
|
|
struct hash_table *remap_table)
|
|
|
|
{
|
|
|
|
nir_cf_list list;
|
|
|
|
nir_cf_list_clone(&list, src_list, parent, remap_table);
|
|
|
|
nir_cf_reinsert(&list, cursor);
|
|
|
|
}
|
|
|
|
|
2015-07-22 03:54:34 +01:00
|
|
|
static inline void
|
|
|
|
nir_cf_list_extract(nir_cf_list *extracted, struct exec_list *cf_list)
|
|
|
|
{
|
|
|
|
nir_cf_extract(extracted, nir_before_cf_list(cf_list),
|
|
|
|
nir_after_cf_list(cf_list));
|
|
|
|
}
|
|
|
|
|
2015-07-22 03:54:35 +01:00
|
|
|
/** removes a control flow node, doing any cleanup necessary */
|
|
|
|
static inline void
|
|
|
|
nir_cf_node_remove(nir_cf_node *node)
|
|
|
|
{
|
|
|
|
nir_cf_list list;
|
|
|
|
nir_cf_extract(&list, nir_before_cf_node(node), nir_after_cf_node(node));
|
|
|
|
nir_cf_delete(&list);
|
|
|
|
}
|
|
|
|
|
2020-08-04 16:12:47 +01:00
|
|
|
/** inserts undef phi sources from predcessor into phis of the block */
|
|
|
|
void nir_insert_phi_undef(nir_block *block, nir_block *pred);
|
|
|
|
|
2015-07-22 03:54:18 +01:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
2017-03-20 16:04:16 +00:00
|
|
|
|
|
|
|
#endif /* NIR_CONTROL_FLOW_H */
|