i965: Refactor SIMD16-to-2xSIMD8 checks.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_fs_combine_constants.cpp
1 /*
2 * Copyright © 2014 Intel Corporation
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 /** @file brw_fs_combine_constants.cpp
25 *
26 * This file contains the opt_combine_constants() pass that runs after the
27 * regular optimization loop. It passes over the instruction list and
28 * selectively promotes immediate values to registers by emitting a mov(1)
29 * instruction.
30 *
31 * This is useful on Gen 7 particularly, because a few instructions can be
32 * coissued (i.e., issued in the same cycle as another thread on the same EU
33 * issues an instruction) under some circumstances, one of which is that they
34 * cannot use immediate values.
35 */
36
37 #include "brw_fs.h"
38 #include "brw_fs_live_variables.h"
39 #include "brw_cfg.h"
40
41 /* Returns whether an instruction could co-issue if its immediate source were
42 * replaced with a GRF source.
43 */
44 static bool
45 could_coissue(const struct brw_context *brw, const fs_inst *inst)
46 {
47 if (brw->gen != 7)
48 return false;
49
50 switch (inst->opcode) {
51 case BRW_OPCODE_MOV:
52 case BRW_OPCODE_CMP:
53 case BRW_OPCODE_ADD:
54 case BRW_OPCODE_MUL:
55 return true;
56 default:
57 return false;
58 }
59 }
60
61 /**
62 * Returns true for instructions that don't support immediate sources.
63 */
64 static bool
65 must_promote_imm(const fs_inst *inst)
66 {
67 switch (inst->opcode) {
68 case BRW_OPCODE_MAD:
69 case BRW_OPCODE_LRP:
70 return true;
71 default:
72 return false;
73 }
74 }
75
76 /** A box for putting fs_regs in a linked list. */
77 struct reg_link {
78 DECLARE_RALLOC_CXX_OPERATORS(reg_link)
79
80 reg_link(fs_reg *reg) : reg(reg) {}
81
82 struct exec_node link;
83 fs_reg *reg;
84 };
85
86 static struct exec_node *
87 link(void *mem_ctx, fs_reg *reg)
88 {
89 reg_link *l = new(mem_ctx) reg_link(reg);
90 return &l->link;
91 }
92
93 /**
94 * Information about an immediate value.
95 */
96 struct imm {
97 /** The common ancestor of all blocks using this immediate value. */
98 bblock_t *block;
99
100 /**
101 * The instruction generating the immediate value, if all uses are contained
102 * within a single basic block. Otherwise, NULL.
103 */
104 fs_inst *inst;
105
106 /**
107 * A list of fs_regs that refer to this immediate. If we promote it, we'll
108 * have to patch these up to refer to the new GRF.
109 */
110 exec_list *uses;
111
112 /** The immediate value. We currently only handle floats. */
113 float val;
114
115 /**
116 * The GRF register and subregister number where we've decided to store the
117 * constant value.
118 */
119 uint8_t subreg_offset;
120 uint16_t reg;
121
122 /** The number of coissuable instructions using this immediate. */
123 uint16_t uses_by_coissue;
124
125 /**
126 * Whether this constant is used by an instruction that can't handle an
127 * immediate source (and already has to be promoted to a GRF).
128 */
129 bool must_promote;
130
131 uint16_t first_use_ip;
132 uint16_t last_use_ip;
133 };
134
135 /** The working set of information about immediates. */
136 struct table {
137 struct imm *imm;
138 int size;
139 int len;
140 };
141
142 static struct imm *
143 find_imm(struct table *table, float val)
144 {
145 assert(signbit(val) == 0);
146
147 for (int i = 0; i < table->len; i++) {
148 if (table->imm[i].val == val) {
149 return &table->imm[i];
150 }
151 }
152 return NULL;
153 }
154
155 static struct imm *
156 new_imm(struct table *table, void *mem_ctx)
157 {
158 if (table->len == table->size) {
159 table->size *= 2;
160 table->imm = reralloc(mem_ctx, table->imm, struct imm, table->size);
161 }
162 return &table->imm[table->len++];
163 }
164
165 /**
166 * Comparator used for sorting an array of imm structures.
167 *
168 * We sort by basic block number, then last use IP, then first use IP (least
169 * to greatest). This sorting causes immediates live in the same area to be
170 * allocated to the same register in the hopes that all values will be dead
171 * about the same time and the register can be reused.
172 */
173 static int
174 compare(const void *_a, const void *_b)
175 {
176 const struct imm *a = (const struct imm *)_a,
177 *b = (const struct imm *)_b;
178
179 int block_diff = a->block->num - b->block->num;
180 if (block_diff)
181 return block_diff;
182
183 int end_diff = a->last_use_ip - b->last_use_ip;
184 if (end_diff)
185 return end_diff;
186
187 return a->first_use_ip - b->first_use_ip;
188 }
189
190 bool
191 fs_visitor::opt_combine_constants()
192 {
193 void *const_ctx = ralloc_context(NULL);
194
195 struct table table;
196 table.size = 8;
197 table.len = 0;
198 table.imm = ralloc_array(const_ctx, struct imm, table.size);
199
200 cfg->calculate_idom();
201 unsigned ip = -1;
202
203 /* Make a pass through all instructions and count the number of times each
204 * constant is used by coissueable instructions or instructions that cannot
205 * take immediate arguments.
206 */
207 foreach_block_and_inst(block, fs_inst, inst, cfg) {
208 ip++;
209
210 if (!could_coissue(brw, inst) && !must_promote_imm(inst))
211 continue;
212
213 for (int i = 0; i < inst->sources; i++) {
214 if (inst->src[i].file != IMM ||
215 inst->src[i].type != BRW_REGISTER_TYPE_F)
216 continue;
217
218 float val = fabsf(inst->src[i].fixed_hw_reg.dw1.f);
219 struct imm *imm = find_imm(&table, val);
220
221 if (imm) {
222 bblock_t *intersection = cfg_t::intersect(block, imm->block);
223 if (intersection != imm->block)
224 imm->inst = NULL;
225 imm->block = intersection;
226 imm->uses->push_tail(link(const_ctx, &inst->src[i]));
227 imm->uses_by_coissue += could_coissue(brw, inst);
228 imm->must_promote = imm->must_promote || must_promote_imm(inst);
229 imm->last_use_ip = ip;
230 } else {
231 imm = new_imm(&table, const_ctx);
232 imm->block = block;
233 imm->inst = inst;
234 imm->uses = new(const_ctx) exec_list();
235 imm->uses->push_tail(link(const_ctx, &inst->src[i]));
236 imm->val = val;
237 imm->uses_by_coissue = could_coissue(brw, inst);
238 imm->must_promote = must_promote_imm(inst);
239 imm->first_use_ip = ip;
240 imm->last_use_ip = ip;
241 }
242 }
243 }
244
245 /* Remove constants from the table that don't have enough uses to make them
246 * profitable to store in a register.
247 */
248 for (int i = 0; i < table.len;) {
249 struct imm *imm = &table.imm[i];
250
251 if (!imm->must_promote && imm->uses_by_coissue < 4) {
252 table.imm[i] = table.imm[table.len - 1];
253 table.len--;
254 continue;
255 }
256 i++;
257 }
258 if (table.len == 0) {
259 ralloc_free(const_ctx);
260 return false;
261 }
262 if (cfg->num_blocks != 1)
263 qsort(table.imm, table.len, sizeof(struct imm), compare);
264
265
266 /* Insert MOVs to load the constant values into GRFs. */
267 fs_reg reg(GRF, alloc.allocate(dispatch_width / 8));
268 reg.stride = 0;
269 for (int i = 0; i < table.len; i++) {
270 struct imm *imm = &table.imm[i];
271
272 fs_inst *mov = MOV(reg, fs_reg(imm->val));
273 mov->force_writemask_all = true;
274 if (imm->inst) {
275 imm->inst->insert_before(imm->block, mov);
276 } else {
277 backend_instruction *inst = imm->block->last_non_control_flow_inst();
278 inst->insert_after(imm->block, mov);
279 }
280 imm->reg = reg.reg;
281 imm->subreg_offset = reg.subreg_offset;
282
283 reg.subreg_offset += sizeof(float);
284 if ((unsigned)reg.subreg_offset == dispatch_width * sizeof(float)) {
285 reg.reg = alloc.allocate(dispatch_width / 8);
286 reg.subreg_offset = 0;
287 }
288 }
289 promoted_constants = table.len;
290
291 /* Rewrite the immediate sources to refer to the new GRFs. */
292 for (int i = 0; i < table.len; i++) {
293 foreach_list_typed(reg_link, link, link, table.imm[i].uses) {
294 fs_reg *reg = link->reg;
295 reg->file = GRF;
296 reg->reg = table.imm[i].reg;
297 reg->subreg_offset = table.imm[i].subreg_offset;
298 reg->stride = 0;
299 reg->negate = signbit(reg->fixed_hw_reg.dw1.f) !=
300 signbit(table.imm[i].val);
301 assert(fabsf(reg->fixed_hw_reg.dw1.f) == table.imm[i].val);
302 }
303 }
304
305 ralloc_free(const_ctx);
306 invalidate_live_intervals();
307
308 return true;
309 }