2 * Copyright 2013 Vadim Girlin <vadimgirlin@gmail.com>
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 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
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 AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include "sb_shader.h"
35 container_node
* ssa_prepare::create_phi_nodes(int count
) {
36 container_node
*p
= sh
.create_container();
37 val_set
&vars
= cur_set();
40 for (val_set::iterator I
= vars
.begin(sh
), E
= vars
.end(sh
); I
!= E
; ++I
) {
41 nn
= sh
.create_node(NT_OP
, NST_PHI
);
42 nn
->dst
.assign(1, *I
);
43 nn
->src
.assign(count
, *I
);
49 void ssa_prepare::add_defs(node
&n
) {
50 val_set
&s
= cur_set();
51 for (vvec::iterator I
= n
.dst
.begin(), E
= n
.dst
.end(); I
!= E
; ++I
) {
63 bool ssa_prepare::visit(cf_node
& n
, bool enter
) {
73 bool ssa_prepare::visit(alu_node
& n
, bool enter
) {
81 bool ssa_prepare::visit(fetch_node
& n
, bool enter
) {
89 bool ssa_prepare::visit(region_node
& n
, bool enter
) {
94 cur_set().add_set(n
.vars_defined
);
95 if (n
.dep_count() > 0)
96 n
.phi
= create_phi_nodes(n
.dep_count());
97 if (n
.rep_count() > 1) {
98 n
.loop_phi
= create_phi_nodes(n
.rep_count());
99 n
.loop_phi
->subtype
= NST_LOOP_PHI_CONTAINER
;
101 n
.vars_defined
.clear();
107 bool ssa_prepare::visit(repeat_node
& n
, bool enter
) {
112 n
.target
->vars_defined
.add_set(cur_set());
119 bool ssa_prepare::visit(depart_node
& n
, bool enter
) {
124 n
.target
->vars_defined
.add_set(cur_set());
131 // ===============================
133 int ssa_rename::init() {
134 rename_stack
.push(def_map());
138 bool ssa_rename::visit(alu_group_node
& n
, bool enter
) {
139 // taking into account parallel execution of the alu group
141 for (node_iterator I
= n
.begin(), E
= n
.end(); I
!= E
; ++I
) {
142 I
->accept(*this, true);
145 for (node_iterator I
= n
.begin(), E
= n
.end(); I
!= E
; ++I
) {
146 I
->accept(*this, false);
152 bool ssa_rename::visit(cf_node
& n
, bool enter
) {
161 bool ssa_rename::visit(alu_node
& n
, bool enter
) {
168 if (n
.pred
&& n
.dst
[0]) {
171 unsigned index
= get_index(rename_stack
.top(), d
);
172 value
*p
= sh
.get_value_version(d
, index
);
174 psi
= sh
.create_node(NT_OP
, NST_PSI
);
176 container_node
*parent
;
177 if (n
.parent
->subtype
== NST_ALU_GROUP
)
180 assert (n
.parent
->parent
->subtype
== NST_ALU_GROUP
);
181 parent
= n
.parent
->parent
;
183 parent
->insert_after(psi
);
185 assert(n
.bc
.pred_sel
);
189 psi
->src
[3] = n
.pred
;
190 psi
->src
[4] = sh
.get_pred_sel(n
.bc
.pred_sel
- PRED_SEL_0
);
192 psi
->dst
.push_back(d
);
202 if (!n
.dst
.empty() && n
.dst
[0]) {
203 // FIXME probably use separate pass for such things
204 if ((n
.bc
.op_ptr
->flags
& AF_INTERP
) || n
.bc
.op
== ALU_OP2_CUBE
)
205 n
.dst
[0]->flags
|= VLF_PIN_CHAN
;
211 bool ssa_rename::visit(alu_packed_node
& n
, bool enter
) {
213 for (node_iterator I
= n
.begin(), E
= n
.end(); I
!= E
; ++I
) {
214 I
->accept(*this, true);
217 for (node_iterator I
= n
.begin(), E
= n
.end(); I
!= E
; ++I
) {
218 I
->accept(*this, false);
221 bool repl
= (n
.op_ptr()->flags
& AF_REPL
) ||
222 (ctx
.is_cayman() && (n
.first
->alu_op_slot_flags() & AF_S
));
229 bool ssa_rename::visit(fetch_node
& n
, bool enter
) {
238 bool ssa_rename::visit(region_node
& n
, bool enter
) {
241 rename_phi_args(n
.loop_phi
, 0, true);
244 rename_phi_args(n
.phi
, ~0u, true);
249 bool ssa_rename::visit(repeat_node
& n
, bool enter
) {
251 push(n
.target
->loop_phi
);
253 if (n
.target
->loop_phi
)
254 rename_phi_args(n
.target
->loop_phi
, n
.rep_id
, false);
260 bool ssa_rename::visit(depart_node
& n
, bool enter
) {
265 rename_phi_args(n
.target
->phi
, n
.dep_id
, false);
271 bool ssa_rename::visit(if_node
& n
, bool enter
) {
274 n
.cond
= rename_use(&n
, n
.cond
);
279 void ssa_rename::push(node
* phi
) {
280 rename_stack
.push(rename_stack
.top());
283 void ssa_rename::pop() {
287 value
* ssa_rename::rename_use(node
*n
, value
* v
) {
291 unsigned index
= get_index(rename_stack
.top(), v
);
292 v
= sh
.get_value_version(v
, index
);
294 // if (alu) instruction is predicated and source arg comes from psi node
295 // (that is, from another predicated instruction through its psi node),
296 // we can try to select the corresponding source value directly
297 if (n
->pred
&& v
->def
&& v
->def
->subtype
== NST_PSI
) {
298 assert(n
->subtype
== NST_ALU_INST
);
299 alu_node
*an
= static_cast<alu_node
*>(n
);
301 // FIXME make it more generic ???
302 if (pn
->src
.size() == 6) {
303 if (pn
->src
[3] == n
->pred
) {
304 value
* ps
= sh
.get_pred_sel(an
->bc
.pred_sel
- PRED_SEL_0
);
305 if (pn
->src
[4] == ps
)
315 value
* ssa_rename::rename_def(node
*n
, value
* v
) {
316 unsigned index
= new_index(def_count
, v
);
317 set_index(rename_stack
.top(), v
, index
);
318 value
*r
= sh
.get_value_version(v
, index
);
322 void ssa_rename::rename_src_vec(node
*n
, vvec
&vv
, bool src
) {
323 for(vvec::iterator I
= vv
.begin(), E
= vv
.end(); I
!= E
; ++I
) {
325 if (!v
|| v
->is_readonly())
329 if (!v
->rel
->is_readonly())
330 v
->rel
= rename_use(n
, v
->rel
);
331 rename_src_vec(n
, v
->muse
, true);
333 v
= rename_use(n
, v
);
337 void ssa_rename::rename_src(node
* n
) {
339 n
->pred
= rename_use(n
, n
->pred
);
341 rename_src_vec(n
, n
->src
, true);
342 rename_src_vec(n
, n
->dst
, false);
346 void ssa_rename::rename_dst_vec(node
*n
, vvec
&vv
, bool set_def
) {
348 for(vvec::iterator I
= vv
.begin(), E
= vv
.end(); I
!= E
; ++I
) {
354 rename_dst_vec(n
, v
->mdef
, false);
356 v
= rename_def(n
, v
);
363 void ssa_rename::rename_dst(node
* n
) {
364 rename_dst_vec(n
, n
->dst
, true);
367 unsigned ssa_rename::get_index(def_map
& m
, value
* v
) {
368 def_map::iterator I
= m
.find(v
);
374 void ssa_rename::set_index(def_map
& m
, value
* v
, unsigned index
) {
375 std::pair
<def_map::iterator
,bool> r
= m
.insert(std::make_pair(v
, index
));
377 r
.first
->second
= index
;
380 unsigned ssa_rename::new_index(def_map
& m
, value
* v
) {
382 def_map::iterator I
= m
.find(v
);
386 m
.insert(std::make_pair(v
, index
));
390 bool ssa_rename::visit(node
& n
, bool enter
) {
392 assert(n
.subtype
== NST_PSI
);
399 bool ssa_rename::visit(container_node
& n
, bool enter
) {
402 // should be root container node
403 assert(n
.parent
== NULL
);
404 rename_src_vec(&n
, n
.src
, true);
409 void ssa_rename::rename_phi_args(container_node
* phi
, unsigned op
, bool def
) {
410 for (node_iterator I
= phi
->begin(), E
= phi
->end(); I
!= E
; ++I
) {
413 o
->src
[op
] = rename_use(o
, o
->src
[op
]);
415 o
->dst
[0] = rename_def(o
, o
->dst
[0]);
421 } // namespace r600_sb