summaryrefslogtreecommitdiffstats
path: root/src/compiler/nir/nir_control_flow.h
blob: b71382fc5977566077f14187076988f0b9e2a054 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 * 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)
 *
 */

#include "nir.h"

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

/** NIR Control Flow Modification
 *
 * This file contains various API's that make modifying control flow in NIR,
 * while maintaining the invariants checked by the validator, much easier.
 * There are two parts to this:
 *
 * 1. Inserting control flow (if's and loops) in various places, for creating
 *    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.
 */

/** Control flow insertion. */

/** puts a control flow node where the cursor is */
void nir_cf_node_insert(nir_cursor cursor, nir_cf_node *node);

/** puts a control flow node immediately after another control flow node */
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);
}

/** puts a control flow node immediately before another control flow node */
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);
}

/** puts a control flow node at the beginning of a list from an if, loop, or function */
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);
}

/** puts a control flow node at the end of a list from an if, loop, or function */
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);
}


/** 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.
 *    2) After a loop, if there are multiple break's.
 *    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
 *    keep phi's intact, but it means that phi nodes cannot be separated from
 *    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;

void nir_cf_extract(nir_cf_list *extracted, nir_cursor begin, nir_cursor end);

void nir_cf_reinsert(nir_cf_list *cf_list, nir_cursor cursor);

void nir_cf_delete(nir_cf_list *cf_list);

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));
}

/** 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);
}

#ifdef __cplusplus
}
#endif