1 /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
4 * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org>
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * Rob Clark <robclark@freedesktop.org>
29 #include "freedreno_util.h"
36 * We could eventually drop this, if the front-end did not insert any
37 * mov's.. For now keeping it as a separate pass since that is less
38 * painful than updating the existing frontend. It is expected that
39 * with an eventual new NIR based frontend that we won't need this.
42 static void block_cp(struct ir3_block
*block
);
43 static struct ir3_instruction
* instr_cp(struct ir3_instruction
*instr
);
45 static bool is_eligible_mov(struct ir3_instruction
*instr
)
47 if ((instr
->category
== 1) &&
48 (instr
->cat1
.src_type
== instr
->cat1
.dst_type
)) {
49 struct ir3_register
*dst
= instr
->regs
[0];
50 struct ir3_register
*src
= instr
->regs
[1];
51 struct ir3_instruction
*src_instr
= ssa(src
);
52 if (dst
->flags
& IR3_REG_ADDR
)
54 /* TODO: propagate abs/neg modifiers if possible */
55 if (src
->flags
& (IR3_REG_ABS
| IR3_REG_NEGATE
| IR3_REG_RELATIV
))
59 /* TODO: remove this hack: */
60 if (is_meta(src_instr
) && (src_instr
->opc
== OPC_META_FO
))
67 static void walk_children(struct ir3_instruction
*instr
)
71 /* walk down the graph from each src: */
72 for (i
= 1; i
< instr
->regs_count
; i
++) {
73 struct ir3_register
*src
= instr
->regs
[i
];
74 if (src
->flags
& IR3_REG_SSA
)
75 src
->instr
= instr_cp(src
->instr
);
80 static struct ir3_instruction
*
81 instr_cp(struct ir3_instruction
*instr
)
83 /* stay within the block.. don't try to operate across
84 * basic block boundaries or we'll have problems when
85 * dealing with multiple basic blocks:
87 if (is_meta(instr
) && (instr
->opc
== OPC_META_INPUT
))
90 if (is_eligible_mov(instr
)) {
91 struct ir3_instruction
*src_instr
= ssa(instr
->regs
[1]);
92 return instr_cp(src_instr
);
95 /* Check termination condition before walking children (rather
96 * than before checking eligible-mov). A mov instruction may
97 * appear as ssa-src for multiple other instructions, and we
98 * want to consider it for removal for each, rather than just
99 * the first one. (But regardless of how many places it shows
100 * up as a src, we only need to recursively walk the children
103 if (!ir3_instr_check_mark(instr
))
104 walk_children(instr
);
109 static void block_cp(struct ir3_block
*block
)
113 for (i
= 0; i
< block
->noutputs
; i
++) {
114 if (block
->outputs
[i
]) {
115 struct ir3_instruction
*out
=
116 instr_cp(block
->outputs
[i
]);
118 block
->outputs
[i
] = out
;
123 void ir3_block_cp(struct ir3_block
*block
)
125 ir3_clear_mark(block
->shader
);