8b1fab0660710f38eb3c13c73c5139fa41017692
[mesa.git] / src / mesa / drivers / dri / i965 / test_fs_saturate_propagation.cpp
1 /*
2 * Copyright © 2015 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 #include <gtest/gtest.h>
25 #include "brw_fs.h"
26 #include "brw_cfg.h"
27 #include "program/program.h"
28
29 class saturate_propagation_test : public ::testing::Test {
30 virtual void SetUp();
31
32 public:
33 struct brw_context *brw;
34 struct brw_device_info *devinfo;
35 struct gl_context *ctx;
36 struct brw_wm_prog_data *prog_data;
37 struct gl_shader_program *shader_prog;
38 struct brw_fragment_program *fp;
39 fs_visitor *v;
40 };
41
42 class saturate_propagation_fs_visitor : public fs_visitor
43 {
44 public:
45 saturate_propagation_fs_visitor(struct brw_context *brw,
46 struct brw_wm_prog_data *prog_data,
47 struct gl_shader_program *shader_prog)
48 : fs_visitor(brw, NULL, MESA_SHADER_FRAGMENT, NULL, &prog_data->base,
49 shader_prog, (struct gl_program *) NULL, 8) {}
50 };
51
52
53 void saturate_propagation_test::SetUp()
54 {
55 brw = (struct brw_context *)calloc(1, sizeof(*brw));
56 devinfo = (struct brw_device_info *)calloc(1, sizeof(*brw));
57 brw->intelScreen = (struct intel_screen *)calloc(1, sizeof(*brw->intelScreen));
58 brw->intelScreen->devinfo = devinfo;
59 ctx = &brw->ctx;
60
61 fp = ralloc(NULL, struct brw_fragment_program);
62 prog_data = ralloc(NULL, struct brw_wm_prog_data);
63 shader_prog = ralloc(NULL, struct gl_shader_program);
64
65 v = new saturate_propagation_fs_visitor(brw, prog_data, shader_prog);
66
67 _mesa_init_fragment_program(ctx, &fp->program, GL_FRAGMENT_SHADER, 0);
68
69 brw->gen = devinfo->gen = 4;
70 }
71
72 static fs_inst *
73 instruction(bblock_t *block, int num)
74 {
75 fs_inst *inst = (fs_inst *)block->start();
76 for (int i = 0; i < num; i++) {
77 inst = (fs_inst *)inst->next;
78 }
79 return inst;
80 }
81
82 static bool
83 saturate_propagation(fs_visitor *v)
84 {
85 const bool print = false;
86
87 if (print) {
88 fprintf(stderr, "= Before =\n");
89 v->cfg->dump(v);
90 }
91
92 bool ret = v->opt_saturate_propagation();
93
94 if (print) {
95 fprintf(stderr, "\n= After =\n");
96 v->cfg->dump(v);
97 }
98
99 return ret;
100 }
101
102 TEST_F(saturate_propagation_test, basic)
103 {
104 fs_reg dst0 = v->vgrf(glsl_type::float_type);
105 fs_reg dst1 = v->vgrf(glsl_type::float_type);
106 fs_reg src0 = v->vgrf(glsl_type::float_type);
107 fs_reg src1 = v->vgrf(glsl_type::float_type);
108 v->emit(BRW_OPCODE_ADD, dst0, src0, src1);
109 v->emit(BRW_OPCODE_MOV, dst1, dst0)
110 ->saturate = true;
111
112 /* = Before =
113 *
114 * 0: add(8) dst0 src0 src1
115 * 1: mov.sat(8) dst1 dst0
116 *
117 * = After =
118 * 0: add.sat(8) dst0 src0 src1
119 * 1: mov(8) dst1 dst0
120 */
121
122 v->calculate_cfg();
123 bblock_t *block0 = v->cfg->blocks[0];
124
125 EXPECT_EQ(0, block0->start_ip);
126 EXPECT_EQ(1, block0->end_ip);
127
128 EXPECT_TRUE(saturate_propagation(v));
129 EXPECT_EQ(0, block0->start_ip);
130 EXPECT_EQ(1, block0->end_ip);
131 EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
132 EXPECT_TRUE(instruction(block0, 0)->saturate);
133 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
134 EXPECT_FALSE(instruction(block0, 1)->saturate);
135 }
136
137 TEST_F(saturate_propagation_test, other_non_saturated_use)
138 {
139 fs_reg dst0 = v->vgrf(glsl_type::float_type);
140 fs_reg dst1 = v->vgrf(glsl_type::float_type);
141 fs_reg dst2 = v->vgrf(glsl_type::float_type);
142 fs_reg src0 = v->vgrf(glsl_type::float_type);
143 fs_reg src1 = v->vgrf(glsl_type::float_type);
144 v->emit(BRW_OPCODE_ADD, dst0, src0, src1);
145 v->emit(BRW_OPCODE_MOV, dst1, dst0)
146 ->saturate = true;
147 v->emit(BRW_OPCODE_ADD, dst2, dst0, src0);
148
149 /* = Before =
150 *
151 * 0: add(8) dst0 src0 src1
152 * 1: mov.sat(8) dst1 dst0
153 * 2: add(8) dst2 dst0 src0
154 *
155 * = After =
156 * (no changes)
157 */
158
159 v->calculate_cfg();
160 bblock_t *block0 = v->cfg->blocks[0];
161
162 EXPECT_EQ(0, block0->start_ip);
163 EXPECT_EQ(2, block0->end_ip);
164
165 EXPECT_FALSE(saturate_propagation(v));
166 EXPECT_EQ(0, block0->start_ip);
167 EXPECT_EQ(2, block0->end_ip);
168 EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
169 EXPECT_FALSE(instruction(block0, 0)->saturate);
170 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
171 EXPECT_TRUE(instruction(block0, 1)->saturate);
172 EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 2)->opcode);
173 }
174
175 TEST_F(saturate_propagation_test, predicated_instruction)
176 {
177 fs_reg dst0 = v->vgrf(glsl_type::float_type);
178 fs_reg dst1 = v->vgrf(glsl_type::float_type);
179 fs_reg src0 = v->vgrf(glsl_type::float_type);
180 fs_reg src1 = v->vgrf(glsl_type::float_type);
181 v->emit(BRW_OPCODE_ADD, dst0, src0, src1)
182 ->predicate = BRW_PREDICATE_NORMAL;
183 v->emit(BRW_OPCODE_MOV, dst1, dst0)
184 ->saturate = true;
185
186 /* = Before =
187 *
188 * 0: (+f0) add(8) dst0 src0 src1
189 * 1: mov.sat(8) dst1 dst0
190 *
191 * = After =
192 * (no changes)
193 */
194
195 v->calculate_cfg();
196 bblock_t *block0 = v->cfg->blocks[0];
197
198 EXPECT_EQ(0, block0->start_ip);
199 EXPECT_EQ(1, block0->end_ip);
200
201 EXPECT_FALSE(saturate_propagation(v));
202 EXPECT_EQ(0, block0->start_ip);
203 EXPECT_EQ(1, block0->end_ip);
204 EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
205 EXPECT_FALSE(instruction(block0, 0)->saturate);
206 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
207 EXPECT_TRUE(instruction(block0, 1)->saturate);
208 }
209
210 TEST_F(saturate_propagation_test, neg_mov_sat)
211 {
212 fs_reg dst0 = v->vgrf(glsl_type::float_type);
213 fs_reg dst1 = v->vgrf(glsl_type::float_type);
214 fs_reg src0 = v->vgrf(glsl_type::float_type);
215 fs_reg src1 = v->vgrf(glsl_type::float_type);
216 v->emit(BRW_OPCODE_ADD, dst0, src0, src1);
217 dst0.negate = true;
218 v->emit(BRW_OPCODE_MOV, dst1, dst0)
219 ->saturate = true;
220
221 /* = Before =
222 *
223 * 0: add(8) dst0 src0 src1
224 * 1: mov.sat(8) dst1 -dst0
225 *
226 * = After =
227 * (no changes)
228 */
229
230 v->calculate_cfg();
231 bblock_t *block0 = v->cfg->blocks[0];
232
233 EXPECT_EQ(0, block0->start_ip);
234 EXPECT_EQ(1, block0->end_ip);
235
236 EXPECT_FALSE(saturate_propagation(v));
237 EXPECT_EQ(0, block0->start_ip);
238 EXPECT_EQ(1, block0->end_ip);
239 EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
240 EXPECT_FALSE(instruction(block0, 0)->saturate);
241 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
242 EXPECT_TRUE(instruction(block0, 1)->saturate);
243 }
244
245 TEST_F(saturate_propagation_test, abs_mov_sat)
246 {
247 fs_reg dst0 = v->vgrf(glsl_type::float_type);
248 fs_reg dst1 = v->vgrf(glsl_type::float_type);
249 fs_reg src0 = v->vgrf(glsl_type::float_type);
250 fs_reg src1 = v->vgrf(glsl_type::float_type);
251 v->emit(BRW_OPCODE_ADD, dst0, src0, src1);
252 dst0.abs = true;
253 v->emit(BRW_OPCODE_MOV, dst1, dst0)
254 ->saturate = true;
255
256 /* = Before =
257 *
258 * 0: add(8) dst0 src0 src1
259 * 1: mov.sat(8) dst1 (abs)dst0
260 *
261 * = After =
262 * (no changes)
263 */
264
265 v->calculate_cfg();
266 bblock_t *block0 = v->cfg->blocks[0];
267
268 EXPECT_EQ(0, block0->start_ip);
269 EXPECT_EQ(1, block0->end_ip);
270
271 EXPECT_FALSE(saturate_propagation(v));
272 EXPECT_EQ(0, block0->start_ip);
273 EXPECT_EQ(1, block0->end_ip);
274 EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
275 EXPECT_FALSE(instruction(block0, 0)->saturate);
276 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
277 EXPECT_TRUE(instruction(block0, 1)->saturate);
278 }
279
280 TEST_F(saturate_propagation_test, producer_saturates)
281 {
282 fs_reg dst0 = v->vgrf(glsl_type::float_type);
283 fs_reg dst1 = v->vgrf(glsl_type::float_type);
284 fs_reg dst2 = v->vgrf(glsl_type::float_type);
285 fs_reg src0 = v->vgrf(glsl_type::float_type);
286 fs_reg src1 = v->vgrf(glsl_type::float_type);
287 v->emit(BRW_OPCODE_ADD, dst0, src0, src1)
288 ->saturate = true;
289 v->emit(BRW_OPCODE_MOV, dst1, dst0)
290 ->saturate = true;
291 v->emit(BRW_OPCODE_MOV, dst2, dst0);
292
293 /* = Before =
294 *
295 * 0: add.sat(8) dst0 src0 src1
296 * 1: mov.sat(8) dst1 dst0
297 * 2: mov(8) dst2 dst0
298 *
299 * = After =
300 * 0: add.sat(8) dst0 src0 src1
301 * 1: mov(8) dst1 dst0
302 * 2: mov(8) dst2 dst0
303 */
304
305 v->calculate_cfg();
306 bblock_t *block0 = v->cfg->blocks[0];
307
308 EXPECT_EQ(0, block0->start_ip);
309 EXPECT_EQ(2, block0->end_ip);
310
311 EXPECT_TRUE(saturate_propagation(v));
312 EXPECT_EQ(0, block0->start_ip);
313 EXPECT_EQ(2, block0->end_ip);
314 EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
315 EXPECT_TRUE(instruction(block0, 0)->saturate);
316 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
317 EXPECT_FALSE(instruction(block0, 1)->saturate);
318 }
319
320 TEST_F(saturate_propagation_test, intervening_saturating_copy)
321 {
322 fs_reg dst0 = v->vgrf(glsl_type::float_type);
323 fs_reg dst1 = v->vgrf(glsl_type::float_type);
324 fs_reg dst2 = v->vgrf(glsl_type::float_type);
325 fs_reg src0 = v->vgrf(glsl_type::float_type);
326 fs_reg src1 = v->vgrf(glsl_type::float_type);
327 v->emit(BRW_OPCODE_ADD, dst0, src0, src1);
328 v->emit(BRW_OPCODE_MOV, dst1, dst0)
329 ->saturate = true;
330 v->emit(BRW_OPCODE_MOV, dst2, dst0)
331 ->saturate = true;
332
333 /* = Before =
334 *
335 * 0: add(8) dst0 src0 src1
336 * 1: mov.sat(8) dst1 dst0
337 * 2: mov.sat(8) dst2 dst0
338 *
339 * = After =
340 * 0: add.sat(8) dst0 src0 src1
341 * 1: mov(8) dst1 dst0
342 * 2: mov(8) dst2 dst0
343 */
344
345 v->calculate_cfg();
346 bblock_t *block0 = v->cfg->blocks[0];
347
348 EXPECT_EQ(0, block0->start_ip);
349 EXPECT_EQ(2, block0->end_ip);
350
351 EXPECT_TRUE(saturate_propagation(v));
352 EXPECT_EQ(0, block0->start_ip);
353 EXPECT_EQ(2, block0->end_ip);
354 EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
355 EXPECT_TRUE(instruction(block0, 0)->saturate);
356 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
357 EXPECT_FALSE(instruction(block0, 1)->saturate);
358 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 2)->opcode);
359 EXPECT_FALSE(instruction(block0, 2)->saturate);
360 }
361
362 TEST_F(saturate_propagation_test, intervening_dest_write)
363 {
364 fs_reg dst0 = v->vgrf(glsl_type::vec4_type);
365 fs_reg dst1 = v->vgrf(glsl_type::float_type);
366 fs_reg src0 = v->vgrf(glsl_type::float_type);
367 fs_reg src1 = v->vgrf(glsl_type::float_type);
368 fs_reg src2 = v->vgrf(glsl_type::vec2_type);
369 v->emit(BRW_OPCODE_ADD, offset(dst0, 2), src0, src1);
370 v->emit(SHADER_OPCODE_TEX, dst0, src2)
371 ->regs_written = 4;
372 v->emit(BRW_OPCODE_MOV, dst1, offset(dst0, 2))
373 ->saturate = true;
374
375 /* = Before =
376 *
377 * 0: add(8) dst0+2 src0 src1
378 * 1: tex(8) rlen 4 dst0+0 src2
379 * 2: mov.sat(8) dst1 dst0+2
380 *
381 * = After =
382 * (no changes)
383 */
384
385 v->calculate_cfg();
386 bblock_t *block0 = v->cfg->blocks[0];
387
388 EXPECT_EQ(0, block0->start_ip);
389 EXPECT_EQ(2, block0->end_ip);
390
391 EXPECT_FALSE(saturate_propagation(v));
392 EXPECT_EQ(0, block0->start_ip);
393 EXPECT_EQ(2, block0->end_ip);
394 EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
395 EXPECT_FALSE(instruction(block0, 0)->saturate);
396 EXPECT_EQ(SHADER_OPCODE_TEX, instruction(block0, 1)->opcode);
397 EXPECT_FALSE(instruction(block0, 0)->saturate);
398 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 2)->opcode);
399 EXPECT_TRUE(instruction(block0, 2)->saturate);
400 }
401
402 TEST_F(saturate_propagation_test, mul_neg_mov_sat_mov_sat)
403 {
404 fs_reg dst0 = v->vgrf(glsl_type::float_type);
405 fs_reg dst1 = v->vgrf(glsl_type::float_type);
406 fs_reg dst2 = v->vgrf(glsl_type::float_type);
407 fs_reg src0 = v->vgrf(glsl_type::float_type);
408 fs_reg src1 = v->vgrf(glsl_type::float_type);
409 v->emit(BRW_OPCODE_MUL, dst0, src0, src1);
410 dst0.negate = true;
411 v->emit(BRW_OPCODE_MOV, dst1, dst0)
412 ->saturate = true;
413 dst0.negate = false;
414 v->emit(BRW_OPCODE_MOV, dst2, dst0)
415 ->saturate = true;
416
417 /* = Before =
418 *
419 * 0: mul(8) dst0 src0 src1
420 * 1: mov.sat(8) dst1 -dst0
421 * 2: mov.sat(8) dst2 dst0
422 *
423 * = After =
424 * (no changes)
425 */
426
427 v->calculate_cfg();
428 bblock_t *block0 = v->cfg->blocks[0];
429
430 EXPECT_EQ(0, block0->start_ip);
431 EXPECT_EQ(2, block0->end_ip);
432
433 EXPECT_FALSE(saturate_propagation(v));
434 EXPECT_EQ(0, block0->start_ip);
435 EXPECT_EQ(2, block0->end_ip);
436 EXPECT_EQ(BRW_OPCODE_MUL, instruction(block0, 0)->opcode);
437 EXPECT_FALSE(instruction(block0, 0)->saturate);
438 EXPECT_FALSE(instruction(block0, 0)->src[1].negate);
439 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
440 EXPECT_TRUE(instruction(block0, 1)->saturate);
441 EXPECT_TRUE(instruction(block0, 1)->src[0].negate);
442 EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 2)->opcode);
443 EXPECT_TRUE(instruction(block0, 2)->saturate);
444 }