2
* Copyright (c) 2017 Lima Project
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sub license,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
11
* The above copyright notice and this permission notice (including the
12
* next paragraph) shall be included in all copies or substantial portions
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
* DEALINGS IN THE SOFTWARE.
28
static bool create_new_instr(ppir_block *block, ppir_node *node)
30
ppir_instr *instr = ppir_instr_create(block);
34
if (!ppir_instr_insert_node(instr, node))
41
* If a node has a pipeline dest, schedule it in the same instruction as its
43
* Since it has a pipeline dest, it must have only one successor and since we
44
* schedule nodes backwards, its successor must have already been scheduled.
45
* Load varyings can't output to a pipeline register but are also potentially
46
* trivial to insert and save an instruction if they have a single successor.
48
static bool ppir_do_node_to_instr_try_insert(ppir_block *block, ppir_node *node)
50
ppir_dest *dest = ppir_node_get_dest(node);
52
if (dest && dest->type == ppir_target_pipeline) {
53
assert(ppir_node_has_single_src_succ(node));
54
ppir_node *succ = ppir_node_first_succ(node);
58
return ppir_instr_insert_node(succ->instr, node);
62
case ppir_node_type_load:
68
if (!ppir_node_has_single_src_succ(node))
71
ppir_node *succ = ppir_node_first_succ(node);
75
return ppir_instr_insert_node(succ->instr, node);
78
static bool ppir_do_one_node_to_instr(ppir_block *block, ppir_node *node)
81
case ppir_node_type_alu:
83
/* don't create an instr for undef node */
84
if (node->op == ppir_op_undef)
87
/* merge pred mul and succ add in the same instr can save a reg
88
* by using pipeline reg ^vmul/^fmul */
89
ppir_alu_node *alu = ppir_node_to_alu(node);
90
if (alu->dest.type == ppir_target_ssa &&
91
ppir_node_has_single_succ(node) &&
92
ppir_node_has_single_src_succ(node)) {
93
ppir_node *succ = ppir_node_first_succ(node);
94
if (succ->instr_pos == PPIR_INSTR_SLOT_ALU_VEC_ADD) {
95
node->instr_pos = PPIR_INSTR_SLOT_ALU_VEC_MUL;
96
ppir_instr_insert_mul_node(succ, node);
98
else if (succ->instr_pos == PPIR_INSTR_SLOT_ALU_SCL_ADD &&
99
alu->dest.ssa.num_components == 1) {
100
node->instr_pos = PPIR_INSTR_SLOT_ALU_SCL_MUL;
101
ppir_instr_insert_mul_node(succ, node);
105
/* can't inserted to any existing instr, create one */
106
if (!node->instr && !create_new_instr(block, node))
111
case ppir_node_type_load:
112
case ppir_node_type_load_texture:
114
if (!create_new_instr(block, node))
117
/* load varying output can be a register, it doesn't need a mov */
119
case ppir_op_load_varying:
120
case ppir_op_load_coords:
121
case ppir_op_load_coords_reg:
122
case ppir_op_load_fragcoord:
123
case ppir_op_load_pointcoord:
124
case ppir_op_load_frontface:
130
/* Load cannot be pipelined, likely slot is already taken. Create a mov */
131
assert(ppir_node_has_single_src_succ(node));
132
ppir_dest *dest = ppir_node_get_dest(node);
133
assert(dest->type == ppir_target_pipeline);
134
ppir_pipeline pipeline_reg = dest->pipeline;
136
/* Turn dest back to SSA, so we can update predecessors */
137
ppir_node *succ = ppir_node_first_succ(node);
139
/* Single succ can still have multiple references to this node */
140
for (int i = 0; i < ppir_node_get_src_num(succ); i++) {
141
ppir_src *src = ppir_node_get_src(succ, i);
142
if (src && src->node == node) {
143
/* Can consume uniforms directly */
144
dest->type = ppir_target_ssa;
145
dest->ssa.index = -1;
146
ppir_node_target_assign(src, node);
150
ppir_node *move = ppir_node_insert_mov(node);
154
ppir_src *mov_src = ppir_node_get_src(move, 0);
155
mov_src->type = dest->type = ppir_target_pipeline;
156
mov_src->pipeline = dest->pipeline = pipeline_reg;
158
ppir_debug("node_to_instr create move %d for load %d\n",
159
move->index, node->index);
161
if (!ppir_instr_insert_node(node->instr, move))
166
case ppir_node_type_const: {
167
/* Const cannot be pipelined, too many consts in the instruction.
170
ppir_node *move = ppir_node_insert_mov(node);
171
if (!create_new_instr(block, move))
174
ppir_debug("node_to_instr create move %d for const %d\n",
175
move->index, node->index);
177
ppir_dest *dest = ppir_node_get_dest(node);
178
ppir_src *mov_src = ppir_node_get_src(move, 0);
180
/* update succ from ^const to ssa mov output */
181
ppir_dest *move_dest = ppir_node_get_dest(move);
182
move_dest->type = ppir_target_ssa;
183
ppir_node *succ = ppir_node_first_succ(move);
184
ppir_node_replace_child(succ, node, move);
186
mov_src->type = dest->type = ppir_target_pipeline;
187
mov_src->pipeline = dest->pipeline = ppir_pipeline_reg_const0;
189
if (!ppir_instr_insert_node(move->instr, node))
194
case ppir_node_type_store:
196
if (node->op == ppir_op_store_temp) {
197
if (!create_new_instr(block, node))
203
case ppir_node_type_discard:
204
if (!create_new_instr(block, node))
208
case ppir_node_type_branch:
209
if (!create_new_instr(block, node))
219
static unsigned int ppir_node_score(ppir_node *node)
221
/* preferentially expand nodes in later instruction slots first, so
222
* nodes for earlier slots (which are more likely pipelineable) get
223
* added to the ready list. */
224
unsigned int late_slot = 0;
225
int *slots = ppir_op_infos[node->op].slots;
227
for (int i = 0; slots[i] != PPIR_INSTR_SLOT_END; i++)
228
late_slot = MAX2(late_slot, slots[i]);
230
/* to untie, favour nodes with pipelines for earlier expansion.
231
* increase that for nodes with chained pipelines */
232
unsigned int pipeline = 0;
234
ppir_dest *dest = ppir_node_get_dest(n);
235
while (dest && dest->type == ppir_target_pipeline) {
237
assert(ppir_node_has_single_src_succ(n));
238
n = ppir_node_first_succ(n);
239
dest = ppir_node_get_dest(n);
241
assert(pipeline < 4);
243
return (late_slot << 2 | pipeline);
246
static ppir_node *ppir_ready_list_pick_best(ppir_block *block,
247
struct list_head *ready_list)
249
unsigned int best_score = 0;
250
ppir_node *best = NULL;
252
list_for_each_entry(ppir_node, node, ready_list, sched_list) {
253
unsigned int score = ppir_node_score(node);
254
if (!best || score > best_score) {
264
static bool ppir_do_node_to_instr(ppir_block *block, ppir_node *root)
266
struct list_head ready_list;
267
list_inithead(&ready_list);
268
list_addtail(&root->sched_list, &ready_list);
270
while (!list_is_empty(&ready_list)) {
271
ppir_node *node = ppir_ready_list_pick_best(block, &ready_list);
272
list_del(&node->sched_list);
274
/* first try pipeline sched, if that didn't succeed try normal sched */
275
if (!ppir_do_node_to_instr_try_insert(block, node))
276
if (!ppir_do_one_node_to_instr(block, node))
279
/* The node writes output register. We can't stop at this exact
280
* instruction because there may be another node that writes another
281
* output, so set stop flag for the block. We will set stop flag on
282
* the last instruction of the block during codegen
287
ppir_node_foreach_pred(node, dep) {
288
ppir_node *pred = dep->pred;
291
/* pred may already have been processed by a previous node */
295
/* insert pred only when all its successors have been inserted */
296
ppir_node_foreach_succ(pred, dep) {
297
ppir_node *succ = dep->succ;
305
list_addtail(&pred->sched_list, &ready_list);
312
static bool ppir_create_instr_from_node(ppir_compiler *comp)
314
list_for_each_entry(ppir_block, block, &comp->block_list, list) {
315
list_for_each_entry(ppir_node, node, &block->node_list, list) {
316
if (ppir_node_is_root(node)) {
317
if (!ppir_do_node_to_instr(block, node))
326
static void ppir_build_instr_dependency(ppir_compiler *comp)
328
list_for_each_entry(ppir_block, block, &comp->block_list, list) {
329
list_for_each_entry(ppir_instr, instr, &block->instr_list, list) {
330
for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++) {
331
ppir_node *node = instr->slots[i];
333
ppir_node_foreach_pred(node, dep) {
334
ppir_node *pred = dep->pred;
335
if (pred->instr && pred->instr != instr)
336
ppir_instr_add_dep(instr, pred->instr);
344
bool ppir_node_to_instr(ppir_compiler *comp)
346
if (!ppir_create_instr_from_node(comp))
348
ppir_instr_print_list(comp);
350
ppir_build_instr_dependency(comp);
351
ppir_instr_print_dep(comp);