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
29using namespace brw;
30
31class saturate_propagation_test : public ::testing::Test {
32   virtual void SetUp();
33
34public:
35   struct brw_compiler *compiler;
36   struct gen_device_info *devinfo;
37   struct gl_context *ctx;
38   struct brw_wm_prog_data *prog_data;
39   struct gl_shader_program *shader_prog;
40   fs_visitor *v;
41};
42
43class saturate_propagation_fs_visitor : public fs_visitor
44{
45public:
46   saturate_propagation_fs_visitor(struct brw_compiler *compiler,
47                                   struct brw_wm_prog_data *prog_data,
48                                   nir_shader *shader)
49      : fs_visitor(compiler, NULL, NULL, NULL,
50                   &prog_data->base, (struct gl_program *) NULL,
51                   shader, 16, -1) {}
52};
53
54
55void saturate_propagation_test::SetUp()
56{
57   ctx = (struct gl_context *)calloc(1, sizeof(*ctx));
58   compiler = (struct brw_compiler *)calloc(1, sizeof(*compiler));
59   devinfo = (struct gen_device_info *)calloc(1, sizeof(*devinfo));
60   compiler->devinfo = devinfo;
61
62   prog_data = ralloc(NULL, struct brw_wm_prog_data);
63   nir_shader *shader =
64      nir_shader_create(NULL, MESA_SHADER_FRAGMENT, NULL, NULL);
65
66   v = new saturate_propagation_fs_visitor(compiler, prog_data, shader);
67
68   devinfo->gen = 6;
69}
70
71static fs_inst *
72instruction(bblock_t *block, int num)
73{
74   fs_inst *inst = (fs_inst *)block->start();
75   for (int i = 0; i < num; i++) {
76      inst = (fs_inst *)inst->next;
77   }
78   return inst;
79}
80
81static bool
82saturate_propagation(fs_visitor *v)
83{
84   const bool print = false;
85
86   if (print) {
87      fprintf(stderr, "= Before =\n");
88      v->cfg->dump(v);
89   }
90
91   bool ret = v->opt_saturate_propagation();
92
93   if (print) {
94      fprintf(stderr, "\n= After =\n");
95      v->cfg->dump(v);
96   }
97
98   return ret;
99}
100
101TEST_F(saturate_propagation_test, basic)
102{
103   const fs_builder &bld = v->bld;
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   bld.ADD(dst0, src0, src1);
109   set_saturate(true, bld.MOV(dst1, dst0));
110
111   /* = Before =
112    *
113    * 0: add(16)       dst0  src0  src1
114    * 1: mov.sat(16)   dst1  dst0
115    *
116    * = After =
117    * 0: add.sat(16)   dst0  src0  src1
118    * 1: mov(16)       dst1  dst0
119    */
120
121   v->calculate_cfg();
122   bblock_t *block0 = v->cfg->blocks[0];
123
124   EXPECT_EQ(0, block0->start_ip);
125   EXPECT_EQ(1, block0->end_ip);
126
127   EXPECT_TRUE(saturate_propagation(v));
128   EXPECT_EQ(0, block0->start_ip);
129   EXPECT_EQ(1, block0->end_ip);
130   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
131   EXPECT_TRUE(instruction(block0, 0)->saturate);
132   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
133   EXPECT_FALSE(instruction(block0, 1)->saturate);
134}
135
136TEST_F(saturate_propagation_test, other_non_saturated_use)
137{
138   const fs_builder &bld = v->bld;
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   bld.ADD(dst0, src0, src1);
145   set_saturate(true, bld.MOV(dst1, dst0));
146   bld.ADD(dst2, dst0, src0);
147
148   /* = Before =
149    *
150    * 0: add(16)       dst0  src0  src1
151    * 1: mov.sat(16)   dst1  dst0
152    * 2: add(16)       dst2  dst0  src0
153    *
154    * = After =
155    * (no changes)
156    */
157
158   v->calculate_cfg();
159   bblock_t *block0 = v->cfg->blocks[0];
160
161   EXPECT_EQ(0, block0->start_ip);
162   EXPECT_EQ(2, block0->end_ip);
163
164   EXPECT_FALSE(saturate_propagation(v));
165   EXPECT_EQ(0, block0->start_ip);
166   EXPECT_EQ(2, block0->end_ip);
167   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
168   EXPECT_FALSE(instruction(block0, 0)->saturate);
169   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
170   EXPECT_TRUE(instruction(block0, 1)->saturate);
171   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 2)->opcode);
172}
173
174TEST_F(saturate_propagation_test, predicated_instruction)
175{
176   const fs_builder &bld = v->bld;
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   bld.ADD(dst0, src0, src1)
182      ->predicate = BRW_PREDICATE_NORMAL;
183   set_saturate(true, bld.MOV(dst1, dst0));
184
185   /* = Before =
186    *
187    * 0: (+f0) add(16) dst0  src0  src1
188    * 1: mov.sat(16)   dst1  dst0
189    *
190    * = After =
191    * (no changes)
192    */
193
194   v->calculate_cfg();
195   bblock_t *block0 = v->cfg->blocks[0];
196
197   EXPECT_EQ(0, block0->start_ip);
198   EXPECT_EQ(1, block0->end_ip);
199
200   EXPECT_FALSE(saturate_propagation(v));
201   EXPECT_EQ(0, block0->start_ip);
202   EXPECT_EQ(1, block0->end_ip);
203   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
204   EXPECT_FALSE(instruction(block0, 0)->saturate);
205   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
206   EXPECT_TRUE(instruction(block0, 1)->saturate);
207}
208
209TEST_F(saturate_propagation_test, neg_mov_sat)
210{
211   const fs_builder &bld = v->bld;
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   bld.RNDU(dst0, src0);
216   dst0.negate = true;
217   set_saturate(true, bld.MOV(dst1, dst0));
218
219   /* = Before =
220    *
221    * 0: rndu(16)      dst0  src0
222    * 1: mov.sat(16)   dst1  -dst0
223    *
224    * = After =
225    * (no changes)
226    */
227
228   v->calculate_cfg();
229   bblock_t *block0 = v->cfg->blocks[0];
230
231   EXPECT_EQ(0, block0->start_ip);
232   EXPECT_EQ(1, block0->end_ip);
233
234   EXPECT_FALSE(saturate_propagation(v));
235   EXPECT_EQ(0, block0->start_ip);
236   EXPECT_EQ(1, block0->end_ip);
237   EXPECT_EQ(BRW_OPCODE_RNDU, instruction(block0, 0)->opcode);
238   EXPECT_FALSE(instruction(block0, 0)->saturate);
239   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
240   EXPECT_TRUE(instruction(block0, 1)->saturate);
241}
242
243TEST_F(saturate_propagation_test, add_neg_mov_sat)
244{
245   const fs_builder &bld = v->bld;
246   fs_reg dst0 = v->vgrf(glsl_type::float_type);
247   fs_reg dst1 = v->vgrf(glsl_type::float_type);
248   fs_reg src0 = v->vgrf(glsl_type::float_type);
249   fs_reg src1 = v->vgrf(glsl_type::float_type);
250   bld.ADD(dst0, src0, src1);
251   dst0.negate = true;
252   set_saturate(true, bld.MOV(dst1, dst0));
253
254   /* = Before =
255    *
256    * 0: add(16)       dst0  src0  src1
257    * 1: mov.sat(16)   dst1  -dst0
258    *
259    * = After =
260    * 0: add.sat(16)   dst0  -src0 -src1
261    * 1: mov(16)       dst1  dst0
262    */
263
264   v->calculate_cfg();
265   bblock_t *block0 = v->cfg->blocks[0];
266
267   EXPECT_EQ(0, block0->start_ip);
268   EXPECT_EQ(1, block0->end_ip);
269
270   EXPECT_TRUE(saturate_propagation(v));
271   EXPECT_EQ(0, block0->start_ip);
272   EXPECT_EQ(1, block0->end_ip);
273   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
274   EXPECT_TRUE(instruction(block0, 0)->saturate);
275   EXPECT_TRUE(instruction(block0, 0)->src[0].negate);
276   EXPECT_TRUE(instruction(block0, 0)->src[1].negate);
277   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
278   EXPECT_FALSE(instruction(block0, 1)->saturate);
279}
280
281TEST_F(saturate_propagation_test, add_imm_float_neg_mov_sat)
282{
283   const fs_builder &bld = v->bld;
284   fs_reg dst0 = v->vgrf(glsl_type::float_type);
285   fs_reg dst1 = v->vgrf(glsl_type::float_type);
286   fs_reg src0 = v->vgrf(glsl_type::float_type);
287   fs_reg src1 = brw_imm_f(1.0f);
288   bld.ADD(dst0, src0, src1);
289   dst0.negate = true;
290   set_saturate(true, bld.MOV(dst1, dst0));
291
292   /* = Before =
293    *
294    * 0: add(16)       dst0  src0  1.0f
295    * 1: mov.sat(16)   dst1  -dst0
296    *
297    * = After =
298    * 0: add.sat(16)   dst0  -src0 -1.0f
299    * 1: mov(16)       dst1  dst0
300    */
301
302   v->calculate_cfg();
303   bblock_t *block0 = v->cfg->blocks[0];
304
305   EXPECT_EQ(0, block0->start_ip);
306   EXPECT_EQ(1, block0->end_ip);
307
308   EXPECT_TRUE(saturate_propagation(v));
309   EXPECT_EQ(0, block0->start_ip);
310   EXPECT_EQ(1, block0->end_ip);
311   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
312   EXPECT_TRUE(instruction(block0, 0)->saturate);
313   EXPECT_TRUE(instruction(block0, 0)->src[0].negate);
314   EXPECT_EQ(instruction(block0, 0)->src[1].f, -1.0f);
315   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
316   EXPECT_FALSE(instruction(block0, 1)->saturate);
317}
318
319TEST_F(saturate_propagation_test, mul_neg_mov_sat)
320{
321   const fs_builder &bld = v->bld;
322   fs_reg dst0 = v->vgrf(glsl_type::float_type);
323   fs_reg dst1 = v->vgrf(glsl_type::float_type);
324   fs_reg src0 = v->vgrf(glsl_type::float_type);
325   fs_reg src1 = v->vgrf(glsl_type::float_type);
326   bld.MUL(dst0, src0, src1);
327   dst0.negate = true;
328   set_saturate(true, bld.MOV(dst1, dst0));
329
330   /* = Before =
331    *
332    * 0: mul(16)       dst0  src0  src1
333    * 1: mov.sat(16)   dst1  -dst0
334    *
335    * = After =
336    * 0: mul.sat(16)   dst0  src0 -src1
337    * 1: mov(16)       dst1  dst0
338    */
339
340   v->calculate_cfg();
341   bblock_t *block0 = v->cfg->blocks[0];
342
343   EXPECT_EQ(0, block0->start_ip);
344   EXPECT_EQ(1, block0->end_ip);
345
346   EXPECT_TRUE(saturate_propagation(v));
347   EXPECT_EQ(0, block0->start_ip);
348   EXPECT_EQ(1, block0->end_ip);
349   EXPECT_EQ(BRW_OPCODE_MUL, instruction(block0, 0)->opcode);
350   EXPECT_TRUE(instruction(block0, 0)->saturate);
351   EXPECT_TRUE(instruction(block0, 0)->src[0].negate);
352   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
353   EXPECT_FALSE(instruction(block0, 1)->saturate);
354   EXPECT_FALSE(instruction(block0, 1)->src[0].negate);
355}
356
357TEST_F(saturate_propagation_test, mad_neg_mov_sat)
358{
359   const fs_builder &bld = v->bld;
360   fs_reg dst0 = v->vgrf(glsl_type::float_type);
361   fs_reg dst1 = v->vgrf(glsl_type::float_type);
362   fs_reg src0 = v->vgrf(glsl_type::float_type);
363   fs_reg src1 = v->vgrf(glsl_type::float_type);
364   fs_reg src2 = v->vgrf(glsl_type::float_type);
365   bld.MAD(dst0, src0, src1, src2);
366   dst0.negate = true;
367   set_saturate(true, bld.MOV(dst1, dst0));
368
369   /* = Before =
370    *
371    * 0: mad(16)       dst0  src0  src1 src2
372    * 1: mov.sat(16)   dst1  -dst0
373    *
374    * = After =
375    * 0: mad.sat(16)   dst0  -src0 -src1 src2
376    * 1: mov(16)       dst1  dst0
377    */
378
379   v->calculate_cfg();
380   bblock_t *block0 = v->cfg->blocks[0];
381
382   EXPECT_EQ(0, block0->start_ip);
383   EXPECT_EQ(1, block0->end_ip);
384
385   EXPECT_TRUE(saturate_propagation(v));
386   EXPECT_EQ(0, block0->start_ip);
387   EXPECT_EQ(1, block0->end_ip);
388   EXPECT_EQ(BRW_OPCODE_MAD, instruction(block0, 0)->opcode);
389   EXPECT_TRUE(instruction(block0, 0)->saturate);
390   EXPECT_TRUE(instruction(block0, 0)->src[0].negate);
391   EXPECT_TRUE(instruction(block0, 0)->src[1].negate);
392   EXPECT_FALSE(instruction(block0, 0)->src[2].negate);
393   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
394   EXPECT_FALSE(instruction(block0, 1)->saturate);
395   EXPECT_FALSE(instruction(block0, 1)->src[0].negate);
396}
397
398TEST_F(saturate_propagation_test, mad_imm_float_neg_mov_sat)
399{
400   const fs_builder &bld = v->bld;
401   fs_reg dst0 = v->vgrf(glsl_type::float_type);
402   fs_reg dst1 = v->vgrf(glsl_type::float_type);
403   fs_reg src0 = brw_imm_f(1.0f);
404   fs_reg src1 = brw_imm_f(-2.0f);
405   fs_reg src2 = v->vgrf(glsl_type::float_type);
406   /* The builder for MAD tries to be helpful and not put immediates as direct
407    * sources. We want to test specifically that case.
408    */
409   fs_inst *mad = bld.MAD(dst0, src2, src2, src2);
410   mad->src[0]= src0;
411   mad->src[1] = src1;
412   dst0.negate = true;
413   set_saturate(true, bld.MOV(dst1, dst0));
414
415   /* = Before =
416    *
417    * 0: mad(16)       dst0  1.0f -2.0f src2
418    * 1: mov.sat(16)   dst1  -dst0
419    *
420    * = After =
421    * 0: mad.sat(16)   dst0  -1.0f 2.0f src2
422    * 1: mov(16)       dst1  dst0
423    */
424
425   v->calculate_cfg();
426   bblock_t *block0 = v->cfg->blocks[0];
427
428   EXPECT_EQ(0, block0->start_ip);
429   EXPECT_EQ(1, block0->end_ip);
430
431   EXPECT_TRUE(saturate_propagation(v));
432   EXPECT_EQ(0, block0->start_ip);
433   EXPECT_EQ(1, block0->end_ip);
434   EXPECT_EQ(BRW_OPCODE_MAD, instruction(block0, 0)->opcode);
435   EXPECT_TRUE(instruction(block0, 0)->saturate);
436   EXPECT_EQ(instruction(block0, 0)->src[0].f, -1.0f);
437   EXPECT_EQ(instruction(block0, 0)->src[1].f, 2.0f);
438   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
439   EXPECT_FALSE(instruction(block0, 1)->saturate);
440   EXPECT_FALSE(instruction(block0, 1)->src[0].negate);
441}
442
443TEST_F(saturate_propagation_test, mul_mov_sat_neg_mov_sat)
444{
445   const fs_builder &bld = v->bld;
446   fs_reg dst0 = v->vgrf(glsl_type::float_type);
447   fs_reg dst1 = v->vgrf(glsl_type::float_type);
448   fs_reg dst2 = v->vgrf(glsl_type::float_type);
449   fs_reg src0 = v->vgrf(glsl_type::float_type);
450   fs_reg src1 = v->vgrf(glsl_type::float_type);
451   bld.MUL(dst0, src0, src1);
452   set_saturate(true, bld.MOV(dst1, dst0));
453   dst0.negate = true;
454   set_saturate(true, bld.MOV(dst2, dst0));
455
456   /* = Before =
457    *
458    * 0: mul(16)       dst0  src0  src1
459    * 1: mov.sat(16)   dst1  dst0
460    * 2: mov.sat(16)   dst2  -dst0
461    *
462    * = After =
463    * (no changes)
464    */
465
466   v->calculate_cfg();
467   bblock_t *block0 = v->cfg->blocks[0];
468
469   EXPECT_EQ(0, block0->start_ip);
470   EXPECT_EQ(2, block0->end_ip);
471
472   EXPECT_FALSE(saturate_propagation(v));
473   EXPECT_EQ(0, block0->start_ip);
474   EXPECT_EQ(2, block0->end_ip);
475   EXPECT_EQ(BRW_OPCODE_MUL, instruction(block0, 0)->opcode);
476   EXPECT_FALSE(instruction(block0, 0)->saturate);
477   EXPECT_FALSE(instruction(block0, 0)->src[1].negate);
478   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
479   EXPECT_TRUE(instruction(block0, 1)->saturate);
480   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 2)->opcode);
481   EXPECT_TRUE(instruction(block0, 2)->src[0].negate);
482   EXPECT_TRUE(instruction(block0, 2)->saturate);
483}
484
485TEST_F(saturate_propagation_test, mul_neg_mov_sat_neg_mov_sat)
486{
487   const fs_builder &bld = v->bld;
488   fs_reg dst0 = v->vgrf(glsl_type::float_type);
489   fs_reg dst1 = v->vgrf(glsl_type::float_type);
490   fs_reg dst2 = v->vgrf(glsl_type::float_type);
491   fs_reg src0 = v->vgrf(glsl_type::float_type);
492   fs_reg src1 = v->vgrf(glsl_type::float_type);
493   bld.MUL(dst0, src0, src1);
494   dst0.negate = true;
495   set_saturate(true, bld.MOV(dst1, dst0));
496   set_saturate(true, bld.MOV(dst2, dst0));
497
498   /* = Before =
499    *
500    * 0: mul(16)       dst0  src0  src1
501    * 1: mov.sat(16)   dst1  -dst0
502    * 2: mov.sat(16)   dst2  -dst0
503    *
504    * = After =
505    * (no changes)
506    */
507
508   v->calculate_cfg();
509   bblock_t *block0 = v->cfg->blocks[0];
510
511   EXPECT_EQ(0, block0->start_ip);
512   EXPECT_EQ(2, block0->end_ip);
513
514   EXPECT_FALSE(saturate_propagation(v));
515   EXPECT_EQ(0, block0->start_ip);
516   EXPECT_EQ(2, block0->end_ip);
517   EXPECT_EQ(BRW_OPCODE_MUL, instruction(block0, 0)->opcode);
518   EXPECT_FALSE(instruction(block0, 0)->saturate);
519   EXPECT_FALSE(instruction(block0, 0)->src[1].negate);
520   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
521   EXPECT_TRUE(instruction(block0, 1)->src[0].negate);
522   EXPECT_TRUE(instruction(block0, 1)->saturate);
523   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 2)->opcode);
524   EXPECT_TRUE(instruction(block0, 2)->src[0].negate);
525   EXPECT_TRUE(instruction(block0, 2)->saturate);
526}
527
528TEST_F(saturate_propagation_test, abs_mov_sat)
529{
530   const fs_builder &bld = v->bld;
531   fs_reg dst0 = v->vgrf(glsl_type::float_type);
532   fs_reg dst1 = v->vgrf(glsl_type::float_type);
533   fs_reg src0 = v->vgrf(glsl_type::float_type);
534   fs_reg src1 = v->vgrf(glsl_type::float_type);
535   bld.ADD(dst0, src0, src1);
536   dst0.abs = true;
537   set_saturate(true, bld.MOV(dst1, dst0));
538
539   /* = Before =
540    *
541    * 0: add(16)       dst0  src0  src1
542    * 1: mov.sat(16)   dst1  (abs)dst0
543    *
544    * = After =
545    * (no changes)
546    */
547
548   v->calculate_cfg();
549   bblock_t *block0 = v->cfg->blocks[0];
550
551   EXPECT_EQ(0, block0->start_ip);
552   EXPECT_EQ(1, block0->end_ip);
553
554   EXPECT_FALSE(saturate_propagation(v));
555   EXPECT_EQ(0, block0->start_ip);
556   EXPECT_EQ(1, block0->end_ip);
557   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
558   EXPECT_FALSE(instruction(block0, 0)->saturate);
559   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
560   EXPECT_TRUE(instruction(block0, 1)->saturate);
561}
562
563TEST_F(saturate_propagation_test, producer_saturates)
564{
565   const fs_builder &bld = v->bld;
566   fs_reg dst0 = v->vgrf(glsl_type::float_type);
567   fs_reg dst1 = v->vgrf(glsl_type::float_type);
568   fs_reg dst2 = v->vgrf(glsl_type::float_type);
569   fs_reg src0 = v->vgrf(glsl_type::float_type);
570   fs_reg src1 = v->vgrf(glsl_type::float_type);
571   set_saturate(true, bld.ADD(dst0, src0, src1));
572   set_saturate(true, bld.MOV(dst1, dst0));
573   bld.MOV(dst2, dst0);
574
575   /* = Before =
576    *
577    * 0: add.sat(16)   dst0  src0  src1
578    * 1: mov.sat(16)   dst1  dst0
579    * 2: mov(16)       dst2  dst0
580    *
581    * = After =
582    * 0: add.sat(16)   dst0  src0  src1
583    * 1: mov(16)       dst1  dst0
584    * 2: mov(16)       dst2  dst0
585    */
586
587   v->calculate_cfg();
588   bblock_t *block0 = v->cfg->blocks[0];
589
590   EXPECT_EQ(0, block0->start_ip);
591   EXPECT_EQ(2, block0->end_ip);
592
593   EXPECT_TRUE(saturate_propagation(v));
594   EXPECT_EQ(0, block0->start_ip);
595   EXPECT_EQ(2, block0->end_ip);
596   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
597   EXPECT_TRUE(instruction(block0, 0)->saturate);
598   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
599   EXPECT_FALSE(instruction(block0, 1)->saturate);
600}
601
602TEST_F(saturate_propagation_test, intervening_saturating_copy)
603{
604   const fs_builder &bld = v->bld;
605   fs_reg dst0 = v->vgrf(glsl_type::float_type);
606   fs_reg dst1 = v->vgrf(glsl_type::float_type);
607   fs_reg dst2 = v->vgrf(glsl_type::float_type);
608   fs_reg src0 = v->vgrf(glsl_type::float_type);
609   fs_reg src1 = v->vgrf(glsl_type::float_type);
610   bld.ADD(dst0, src0, src1);
611   set_saturate(true, bld.MOV(dst1, dst0));
612   set_saturate(true, bld.MOV(dst2, dst0));
613
614   /* = Before =
615    *
616    * 0: add(16)       dst0  src0  src1
617    * 1: mov.sat(16)   dst1  dst0
618    * 2: mov.sat(16)   dst2  dst0
619    *
620    * = After =
621    * 0: add.sat(16)   dst0  src0  src1
622    * 1: mov(16)       dst1  dst0
623    * 2: mov(16)       dst2  dst0
624    */
625
626   v->calculate_cfg();
627   bblock_t *block0 = v->cfg->blocks[0];
628
629   EXPECT_EQ(0, block0->start_ip);
630   EXPECT_EQ(2, block0->end_ip);
631
632   EXPECT_TRUE(saturate_propagation(v));
633   EXPECT_EQ(0, block0->start_ip);
634   EXPECT_EQ(2, block0->end_ip);
635   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
636   EXPECT_TRUE(instruction(block0, 0)->saturate);
637   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
638   EXPECT_FALSE(instruction(block0, 1)->saturate);
639   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 2)->opcode);
640   EXPECT_FALSE(instruction(block0, 2)->saturate);
641}
642
643TEST_F(saturate_propagation_test, intervening_dest_write)
644{
645   const fs_builder &bld = v->bld;
646   fs_reg dst0 = v->vgrf(glsl_type::vec4_type);
647   fs_reg dst1 = v->vgrf(glsl_type::float_type);
648   fs_reg src0 = v->vgrf(glsl_type::float_type);
649   fs_reg src1 = v->vgrf(glsl_type::float_type);
650   fs_reg src2 = v->vgrf(glsl_type::vec2_type);
651   bld.ADD(offset(dst0, bld, 2), src0, src1);
652   bld.emit(SHADER_OPCODE_TEX, dst0, src2)
653      ->size_written = 8 * REG_SIZE;
654   set_saturate(true, bld.MOV(dst1, offset(dst0, bld, 2)));
655
656   /* = Before =
657    *
658    * 0: add(16)        dst0+2  src0    src1
659    * 1: tex(16) rlen 4 dst0+0  src2
660    * 2: mov.sat(16)    dst1    dst0+2
661    *
662    * = After =
663    * (no changes)
664    */
665
666   v->calculate_cfg();
667   bblock_t *block0 = v->cfg->blocks[0];
668
669   EXPECT_EQ(0, block0->start_ip);
670   EXPECT_EQ(2, block0->end_ip);
671
672   EXPECT_FALSE(saturate_propagation(v));
673   EXPECT_EQ(0, block0->start_ip);
674   EXPECT_EQ(2, block0->end_ip);
675   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
676   EXPECT_FALSE(instruction(block0, 0)->saturate);
677   EXPECT_EQ(SHADER_OPCODE_TEX, instruction(block0, 1)->opcode);
678   EXPECT_FALSE(instruction(block0, 0)->saturate);
679   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 2)->opcode);
680   EXPECT_TRUE(instruction(block0, 2)->saturate);
681}
682
683TEST_F(saturate_propagation_test, mul_neg_mov_sat_mov_sat)
684{
685   const fs_builder &bld = v->bld;
686   fs_reg dst0 = v->vgrf(glsl_type::float_type);
687   fs_reg dst1 = v->vgrf(glsl_type::float_type);
688   fs_reg dst2 = v->vgrf(glsl_type::float_type);
689   fs_reg src0 = v->vgrf(glsl_type::float_type);
690   fs_reg src1 = v->vgrf(glsl_type::float_type);
691   bld.MUL(dst0, src0, src1);
692   dst0.negate = true;
693   set_saturate(true, bld.MOV(dst1, dst0));
694   dst0.negate = false;
695   set_saturate(true, bld.MOV(dst2, dst0));
696
697   /* = Before =
698    *
699    * 0: mul(16)       dst0  src0  src1
700    * 1: mov.sat(16)   dst1  -dst0
701    * 2: mov.sat(16)   dst2  dst0
702    *
703    * = After =
704    * (no changes)
705    */
706
707   v->calculate_cfg();
708   bblock_t *block0 = v->cfg->blocks[0];
709
710   EXPECT_EQ(0, block0->start_ip);
711   EXPECT_EQ(2, block0->end_ip);
712
713   EXPECT_FALSE(saturate_propagation(v));
714   EXPECT_EQ(0, block0->start_ip);
715   EXPECT_EQ(2, block0->end_ip);
716   EXPECT_EQ(BRW_OPCODE_MUL, instruction(block0, 0)->opcode);
717   EXPECT_FALSE(instruction(block0, 0)->saturate);
718   EXPECT_FALSE(instruction(block0, 0)->src[1].negate);
719   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
720   EXPECT_TRUE(instruction(block0, 1)->saturate);
721   EXPECT_TRUE(instruction(block0, 1)->src[0].negate);
722   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 2)->opcode);
723   EXPECT_TRUE(instruction(block0, 2)->saturate);
724}
725
726TEST_F(saturate_propagation_test, smaller_exec_size_consumer)
727{
728   const fs_builder &bld = v->bld;
729   fs_reg dst0 = v->vgrf(glsl_type::float_type);
730   fs_reg dst1 = v->vgrf(glsl_type::float_type);
731   fs_reg src0 = v->vgrf(glsl_type::float_type);
732   fs_reg src1 = v->vgrf(glsl_type::float_type);
733   bld.ADD(dst0, src0, src1);
734   set_saturate(true, bld.group(8, 0).MOV(dst1, dst0));
735
736   /* = Before =
737    *
738    * 0: add(16)       dst0  src0  src1
739    * 1: mov.sat(8)    dst1  dst0
740    *
741    * = After =
742    * (no changes)
743    */
744
745   v->calculate_cfg();
746   bblock_t *block0 = v->cfg->blocks[0];
747
748   EXPECT_EQ(0, block0->start_ip);
749   EXPECT_EQ(1, block0->end_ip);
750
751   EXPECT_FALSE(saturate_propagation(v));
752   EXPECT_EQ(0, block0->start_ip);
753   EXPECT_EQ(1, block0->end_ip);
754   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
755   EXPECT_FALSE(instruction(block0, 0)->saturate);
756   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
757   EXPECT_TRUE(instruction(block0, 1)->saturate);
758}
759
760TEST_F(saturate_propagation_test, larger_exec_size_consumer)
761{
762   const fs_builder &bld = v->bld;
763   fs_reg dst0 = v->vgrf(glsl_type::float_type);
764   fs_reg dst1 = v->vgrf(glsl_type::float_type);
765   fs_reg src0 = v->vgrf(glsl_type::float_type);
766   fs_reg src1 = v->vgrf(glsl_type::float_type);
767   bld.group(8, 0).ADD(dst0, src0, src1);
768   set_saturate(true, bld.MOV(dst1, dst0));
769
770   /* = Before =
771    *
772    * 0: add(8)        dst0  src0  src1
773    * 1: mov.sat(16)   dst1  dst0
774    *
775    * = After =
776    * (no changes)
777    */
778
779   v->calculate_cfg();
780   bblock_t *block0 = v->cfg->blocks[0];
781
782   EXPECT_EQ(0, block0->start_ip);
783   EXPECT_EQ(1, block0->end_ip);
784
785   EXPECT_FALSE(saturate_propagation(v));
786   EXPECT_EQ(0, block0->start_ip);
787   EXPECT_EQ(1, block0->end_ip);
788   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
789   EXPECT_FALSE(instruction(block0, 0)->saturate);
790   EXPECT_EQ(BRW_OPCODE_MOV, instruction(block0, 1)->opcode);
791   EXPECT_TRUE(instruction(block0, 1)->saturate);
792}
793