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