Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/*
2
 * Copyright © 2014 Broadcom
3
 *
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, sublicense,
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:
10
 *
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
13
 * Software.
14
 *
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 NONINFRINGEMENT.  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 DEALINGS
21
 * IN THE SOFTWARE.
22
 */
23
 
24
/**
25
 * @file vc4_opt_algebraic.c
26
 *
27
 * This is the optimization pass for miscellaneous changes to instructions
28
 * where we can simplify the operation by some knowledge about the specific
29
 * operations.
30
 *
31
 * Mostly this will be a matter of turning things into MOVs so that they can
32
 * later be copy-propagated out.
33
 */
34
 
35
#include "vc4_qir.h"
36
#include "util/u_math.h"
37
 
38
static bool debug;
39
 
40
static void
41
dump_from(struct vc4_compile *c, struct qinst *inst)
42
{
43
        if (!debug)
44
                return;
45
 
46
        fprintf(stderr, "optimizing: ");
47
        qir_dump_inst(c, inst);
48
        fprintf(stderr, "\n");
49
}
50
 
51
static void
52
dump_to(struct vc4_compile *c, struct qinst *inst)
53
{
54
        if (!debug)
55
                return;
56
 
57
        fprintf(stderr, "to: ");
58
        qir_dump_inst(c, inst);
59
        fprintf(stderr, "\n");
60
}
61
 
62
static bool
63
is_constant_value(struct vc4_compile *c, struct qreg reg,
64
                  uint32_t val)
65
{
66
        if (reg.file == QFILE_UNIF &&
67
            c->uniform_contents[reg.index] == QUNIFORM_CONSTANT &&
68
            c->uniform_data[reg.index] == val) {
69
                return true;
70
        }
71
 
72
        if (reg.file == QFILE_SMALL_IMM && reg.index == val)
73
                return true;
74
 
75
        return false;
76
}
77
 
78
static bool
79
is_zero(struct vc4_compile *c, struct qreg reg)
80
{
81
        reg = qir_follow_movs(c, reg);
82
        return is_constant_value(c, reg, 0);
83
}
84
 
85
static bool
86
is_1f(struct vc4_compile *c, struct qreg reg)
87
{
88
        reg = qir_follow_movs(c, reg);
89
        return is_constant_value(c, reg, fui(1.0));
90
}
91
 
92
static void
93
replace_with_mov(struct vc4_compile *c, struct qinst *inst, struct qreg arg)
94
{
95
        dump_from(c, inst);
96
        inst->op = QOP_MOV;
97
        inst->src[0] = arg;
98
        inst->src[1] = c->undef;
99
        dump_to(c, inst);
100
}
101
 
102
static bool
103
replace_x_0_with_x(struct vc4_compile *c,
104
                 struct qinst *inst,
105
                 int arg)
106
{
107
        if (!is_zero(c, inst->src[arg]))
108
                return false;
109
        replace_with_mov(c, inst, inst->src[1 - arg]);
110
        return true;
111
}
112
 
113
static bool
114
replace_x_0_with_0(struct vc4_compile *c,
115
                  struct qinst *inst,
116
                  int arg)
117
{
118
        if (!is_zero(c, inst->src[arg]))
119
                return false;
120
        replace_with_mov(c, inst, inst->src[arg]);
121
        return true;
122
}
123
 
124
static bool
125
fmul_replace_one(struct vc4_compile *c,
126
                 struct qinst *inst,
127
                 int arg)
128
{
129
        if (!is_1f(c, inst->src[arg]))
130
                return false;
131
        replace_with_mov(c, inst, inst->src[1 - arg]);
132
        return true;
133
}
134
 
135
bool
136
qir_opt_algebraic(struct vc4_compile *c)
137
{
138
        bool progress = false;
139
        struct simple_node *node;
140
 
141
        foreach(node, &c->instructions) {
142
                struct qinst *inst = (struct qinst *)node;
143
 
144
                switch (inst->op) {
145
                case QOP_SEL_X_Y_ZS:
146
                case QOP_SEL_X_Y_ZC:
147
                case QOP_SEL_X_Y_NS:
148
                case QOP_SEL_X_Y_NC:
149
                        if (qir_reg_equals(inst->src[0], inst->src[1])) {
150
                                /* Turn "dst = (sf == x) ? a : a)" into
151
                                 * "dst = a"
152
                                 */
153
                                replace_with_mov(c, inst, inst->src[1]);
154
                                progress = true;
155
                                break;
156
                        }
157
 
158
                        if (is_zero(c, inst->src[1])) {
159
                                /* Replace references to a 0 uniform value
160
                                 * with the SEL_X_0 equivalent.
161
                                 */
162
                                dump_from(c, inst);
163
                                inst->op -= (QOP_SEL_X_Y_ZS - QOP_SEL_X_0_ZS);
164
                                inst->src[1] = c->undef;
165
                                progress = true;
166
                                dump_to(c, inst);
167
                                break;
168
                        }
169
 
170
                        if (is_zero(c, inst->src[0])) {
171
                                /* Replace references to a 0 uniform value
172
                                 * with the SEL_X_0 equivalent, flipping the
173
                                 * condition being evaluated since the operand
174
                                 * order is flipped.
175
                                 */
176
                                dump_from(c, inst);
177
                                inst->op -= QOP_SEL_X_Y_ZS;
178
                                inst->op ^= 1;
179
                                inst->op += QOP_SEL_X_0_ZS;
180
                                inst->src[0] = inst->src[1];
181
                                inst->src[1] = c->undef;
182
                                progress = true;
183
                                dump_to(c, inst);
184
                                break;
185
                        }
186
 
187
                        break;
188
 
189
                case QOP_FSUB:
190
                case QOP_SUB:
191
                        if (is_zero(c, inst->src[1])) {
192
                                replace_with_mov(c, inst, inst->src[0]);
193
                        }
194
                        break;
195
 
196
                case QOP_ADD:
197
                        if (replace_x_0_with_x(c, inst, 0) ||
198
                            replace_x_0_with_x(c, inst, 1)) {
199
                                progress = true;
200
                                break;
201
                        }
202
                        break;
203
 
204
                case QOP_FADD:
205
                        if (replace_x_0_with_x(c, inst, 0) ||
206
                            replace_x_0_with_x(c, inst, 1)) {
207
                                progress = true;
208
                                break;
209
                        }
210
 
211
                        /* FADD(a, FSUB(0, b)) -> FSUB(a, b) */
212
                        if (inst->src[1].file == QFILE_TEMP &&
213
                            c->defs[inst->src[1].index]->op == QOP_FSUB) {
214
                                struct qinst *fsub = c->defs[inst->src[1].index];
215
                                if (is_zero(c, fsub->src[0])) {
216
                                        dump_from(c, inst);
217
                                        inst->op = QOP_FSUB;
218
                                        inst->src[1] = fsub->src[1];
219
                                        progress = true;
220
                                        dump_to(c, inst);
221
                                        break;
222
                                }
223
                        }
224
 
225
                        /* FADD(FSUB(0, b), a) -> FSUB(a, b) */
226
                        if (inst->src[0].file == QFILE_TEMP &&
227
                            c->defs[inst->src[0].index]->op == QOP_FSUB) {
228
                                struct qinst *fsub = c->defs[inst->src[0].index];
229
                                if (is_zero(c, fsub->src[0])) {
230
                                        dump_from(c, inst);
231
                                        inst->op = QOP_FSUB;
232
                                        inst->src[0] = inst->src[1];
233
                                        inst->src[1] = fsub->src[1];
234
                                        dump_to(c, inst);
235
                                        progress = true;
236
                                        break;
237
                                }
238
                        }
239
                        break;
240
 
241
                case QOP_FMUL:
242
                        if (replace_x_0_with_0(c, inst, 0) ||
243
                            replace_x_0_with_0(c, inst, 1) ||
244
                            fmul_replace_one(c, inst, 0) ||
245
                            fmul_replace_one(c, inst, 1)) {
246
                                progress = true;
247
                                break;
248
                        }
249
                        break;
250
 
251
                case QOP_MUL24:
252
                        if (replace_x_0_with_0(c, inst, 0) ||
253
                            replace_x_0_with_0(c, inst, 1)) {
254
                                progress = true;
255
                                break;
256
                        }
257
                        break;
258
 
259
                case QOP_AND:
260
                        if (replace_x_0_with_0(c, inst, 0) ||
261
                            replace_x_0_with_0(c, inst, 1)) {
262
                                progress = true;
263
                                break;
264
                        }
265
 
266
                        if (is_constant_value(c, inst->src[0], ~0)) {
267
                                replace_with_mov(c, inst, inst->src[1]);
268
                                progress = true;
269
                                break;
270
                        }
271
                        if (is_constant_value(c, inst->src[1], ~0)) {
272
                                replace_with_mov(c, inst, inst->src[0]);
273
                                progress = true;
274
                                break;
275
                        }
276
                        break;
277
 
278
                case QOP_OR:
279
                        if (replace_x_0_with_x(c, inst, 0) ||
280
                            replace_x_0_with_x(c, inst, 1)) {
281
                                progress = true;
282
                                break;
283
                        }
284
                        break;
285
 
286
                default:
287
                        break;
288
                }
289
        }
290
 
291
        return progress;
292
}