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>
34 * Flatten: flatten out legs of if/else, etc
36 * TODO probably should use some heuristic to decide to not flatten
37 * if one side of the other is too large / deeply nested / whatever?
40 struct ir3_flatten_ctx
{
41 struct ir3_block
*block
;
45 static struct ir3_register
*unwrap(struct ir3_register
*reg
)
48 if (reg
->flags
& IR3_REG_SSA
) {
49 struct ir3_instruction
*instr
= reg
->instr
;
54 if (instr
->regs_count
> 1)
55 return instr
->regs
[1];
65 static void ir3_instr_flatten(struct ir3_flatten_ctx
*ctx
,
66 struct ir3_instruction
*instr
)
68 struct ir3_instruction
*src
;
70 /* if we've already visited this instruction, bail now: */
71 if (ir3_instr_check_mark(instr
))
74 instr
->block
= ctx
->block
;
76 /* TODO: maybe some threshold to decide whether to
80 if (instr
->opc
== OPC_META_PHI
) {
81 struct ir3_register
*cond
, *t
, *f
;
83 cond
= unwrap(instr
->regs
[1]);
84 t
= unwrap(instr
->regs
[2]); /* true val */
85 f
= unwrap(instr
->regs
[3]); /* false val */
87 /* must have cond, but t or f may be null if only written
88 * one one side of the if/else (in which case we can just
89 * convert the PHI to a simple move).
95 /* convert the PHI instruction to sel.{b16,b32} */
98 /* instruction type based on dst size: */
99 if (instr
->regs
[0]->flags
& IR3_REG_HALF
)
100 instr
->opc
= OPC_SEL_B16
;
102 instr
->opc
= OPC_SEL_B32
;
105 instr
->regs
[2] = cond
;
108 /* convert to simple mov: */
110 instr
->cat1
.dst_type
= TYPE_F32
;
111 instr
->cat1
.src_type
= TYPE_F32
;
112 instr
->regs_count
= 2;
113 instr
->regs
[1] = t
? t
: f
;
117 } else if ((instr
->opc
== OPC_META_INPUT
) &&
118 (instr
->regs_count
== 2)) {
121 if (instr
->regs
[0]->flags
& IR3_REG_HALF
)
126 /* convert meta:input to mov: */
128 instr
->cat1
.src_type
= ftype
;
129 instr
->cat1
.dst_type
= ftype
;
133 /* recursively visit children: */
134 foreach_ssa_src(src
, instr
)
135 ir3_instr_flatten(ctx
, src
);
138 /* return >= 0 is # of phi's flattened, < 0 is error */
139 int ir3_block_flatten(struct ir3_block
*block
)
141 struct ir3_flatten_ctx ctx
= {
146 ir3_clear_mark(block
->shader
);
147 for(i
= 0; i
< block
->noutputs
; i
++)
148 if (block
->outputs
[i
])
149 ir3_instr_flatten(&ctx
, block
->outputs
[i
]);