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 * Based on test_fs_cmod_propagation.cpp
24 */
25
26#include <gtest/gtest.h>
27#include "brw_vec4.h"
28#include "brw_vec4_builder.h"
29#include "brw_cfg.h"
30#include "program/program.h"
31
32using namespace brw;
33
34class cmod_propagation_test : public ::testing::Test {
35   virtual void SetUp();
36   virtual void TearDown();
37
38public:
39   struct brw_compiler *compiler;
40   struct intel_device_info *devinfo;
41   void *ctx;
42   struct gl_shader_program *shader_prog;
43   struct brw_vue_prog_data *prog_data;
44   vec4_visitor *v;
45};
46
47class cmod_propagation_vec4_visitor : public vec4_visitor
48{
49public:
50   cmod_propagation_vec4_visitor(struct brw_compiler *compiler,
51                                 void *mem_ctx,
52                                 nir_shader *shader,
53                                 struct brw_vue_prog_data *prog_data)
54      : vec4_visitor(compiler, NULL, NULL, prog_data, shader, mem_ctx,
55                     false, -1, false)
56      {
57         prog_data->dispatch_mode = DISPATCH_MODE_4X2_DUAL_OBJECT;
58      }
59
60protected:
61   /* Dummy implementation for pure virtual methods */
62   virtual dst_reg *make_reg_for_system_value(int /* location */)
63   {
64      unreachable("Not reached");
65   }
66
67   virtual void setup_payload()
68   {
69      unreachable("Not reached");
70   }
71
72   virtual void emit_prolog()
73   {
74      unreachable("Not reached");
75   }
76
77   virtual void emit_program_code()
78   {
79      unreachable("Not reached");
80   }
81
82   virtual void emit_thread_end()
83   {
84      unreachable("Not reached");
85   }
86
87   virtual void emit_urb_write_header(int /* mrf */)
88   {
89      unreachable("Not reached");
90   }
91
92   virtual vec4_instruction *emit_urb_write_opcode(bool /* complete */)
93   {
94      unreachable("Not reached");
95   }
96};
97
98
99void cmod_propagation_test::SetUp()
100{
101   ctx = ralloc_context(NULL);
102   compiler = rzalloc(ctx, struct brw_compiler);
103   devinfo = rzalloc(ctx, struct intel_device_info);
104   compiler->devinfo = devinfo;
105
106   prog_data = ralloc(ctx, struct brw_vue_prog_data);
107   nir_shader *shader =
108      nir_shader_create(ctx, MESA_SHADER_VERTEX, NULL, NULL);
109
110   v = new cmod_propagation_vec4_visitor(compiler, ctx, shader, prog_data);
111
112   devinfo->ver = 7;
113   devinfo->verx10 = devinfo->ver * 10;
114}
115
116void cmod_propagation_test::TearDown()
117{
118   delete v;
119   v = NULL;
120
121   ralloc_free(ctx);
122   ctx = NULL;
123}
124
125static vec4_instruction *
126instruction(bblock_t *block, int num)
127{
128   vec4_instruction *inst = (vec4_instruction *)block->start();
129   for (int i = 0; i < num; i++) {
130      inst = (vec4_instruction *)inst->next;
131   }
132   return inst;
133}
134
135static bool
136cmod_propagation(vec4_visitor *v)
137{
138   const bool print = getenv("TEST_DEBUG");
139
140   if (print) {
141      fprintf(stderr, "= Before =\n");
142      v->dump_instructions();
143   }
144
145   bool ret = v->opt_cmod_propagation();
146
147   if (print) {
148      fprintf(stderr, "\n= After =\n");
149      v->dump_instructions();
150   }
151
152   return ret;
153}
154
155TEST_F(cmod_propagation_test, basic)
156{
157   const vec4_builder bld = vec4_builder(v).at_end();
158   dst_reg dest = dst_reg(v, glsl_type::float_type);
159   src_reg src0 = src_reg(v, glsl_type::float_type);
160   src_reg src1 = src_reg(v, glsl_type::float_type);
161   src_reg zero(brw_imm_f(0.0f));
162   dst_reg dest_null = bld.null_reg_f();
163   dest_null.writemask = WRITEMASK_X;
164
165   bld.ADD(dest, src0, src1);
166   bld.CMP(dest_null, src_reg(dest), zero, BRW_CONDITIONAL_GE);
167
168   /* = Before =
169    *
170    * 0: add        dest.x  src0.xxxx  src1.xxxx
171    * 1: cmp.ge.f0  null.x  dest.xxxx  0.0f
172    *
173    * = After =
174    * 0: add.ge.f0  dest.x  src0.xxxx  src1.xxxx
175    */
176
177   v->calculate_cfg();
178   bblock_t *block0 = v->cfg->blocks[0];
179
180   EXPECT_EQ(0, block0->start_ip);
181   EXPECT_EQ(1, block0->end_ip);
182
183   EXPECT_TRUE(cmod_propagation(v));
184
185   ASSERT_EQ(0, block0->start_ip);
186   ASSERT_EQ(0, block0->end_ip);
187   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
188   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 0)->conditional_mod);
189}
190
191TEST_F(cmod_propagation_test, basic_different_dst_writemask)
192{
193   const vec4_builder bld = vec4_builder(v).at_end();
194   dst_reg dest = dst_reg(v, glsl_type::float_type);
195   src_reg src0 = src_reg(v, glsl_type::float_type);
196   src_reg src1 = src_reg(v, glsl_type::float_type);
197   src_reg zero(brw_imm_f(0.0f));
198   dst_reg dest_null = bld.null_reg_f();
199
200   bld.ADD(dest, src0, src1);
201   bld.CMP(dest_null, src_reg(dest), zero, BRW_CONDITIONAL_GE);
202
203   /* = Before =
204    *
205    * 0: add        dest.x     src0  src1
206    * 1: cmp.ge.f0  null.xyzw  dest  0.0f
207    *
208    * = After =
209    * (no changes)
210    */
211
212   v->calculate_cfg();
213   bblock_t *block0 = v->cfg->blocks[0];
214
215   EXPECT_EQ(0, block0->start_ip);
216   EXPECT_EQ(1, block0->end_ip);
217
218   EXPECT_FALSE(cmod_propagation(v));
219
220   ASSERT_EQ(0, block0->start_ip);
221   ASSERT_EQ(1, block0->end_ip);
222   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
223   EXPECT_EQ(BRW_CONDITIONAL_NONE, instruction(block0, 0)->conditional_mod);
224   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
225   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 1)->conditional_mod);
226}
227
228TEST_F(cmod_propagation_test, andz_one)
229{
230   const vec4_builder bld = vec4_builder(v).at_end();
231   dst_reg dest = dst_reg(v, glsl_type::int_type);
232   src_reg src0 = src_reg(v, glsl_type::float_type);
233   src_reg zero(brw_imm_f(0.0f));
234   src_reg one(brw_imm_d(1));
235
236   bld.CMP(retype(dest, BRW_REGISTER_TYPE_F), src0, zero, BRW_CONDITIONAL_L);
237   set_condmod(BRW_CONDITIONAL_Z,
238               bld.AND(bld.null_reg_d(), src_reg(dest), one));
239
240   /* = Before =
241    * 0: cmp.l.f0     dest:F  src0:F  0F
242    * 1: and.z.f0     null:D  dest:D  1D
243    *
244    * = After =
245    * (no changes)
246    */
247
248   v->calculate_cfg();
249   bblock_t *block0 = v->cfg->blocks[0];
250
251   EXPECT_EQ(0, block0->start_ip);
252   EXPECT_EQ(1, block0->end_ip);
253
254   EXPECT_FALSE(cmod_propagation(v));
255
256   ASSERT_EQ(0, block0->start_ip);
257   ASSERT_EQ(1, block0->end_ip);
258   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 0)->opcode);
259   EXPECT_EQ(BRW_CONDITIONAL_L, instruction(block0, 0)->conditional_mod);
260   EXPECT_EQ(BRW_OPCODE_AND, instruction(block0, 1)->opcode);
261   EXPECT_EQ(BRW_CONDITIONAL_EQ, instruction(block0, 1)->conditional_mod);
262}
263
264TEST_F(cmod_propagation_test, non_cmod_instruction)
265{
266   const vec4_builder bld = vec4_builder(v).at_end();
267   dst_reg dest = dst_reg(v, glsl_type::uint_type);
268   src_reg src0 = src_reg(v, glsl_type::uint_type);
269   src_reg zero(brw_imm_ud(0u));
270   bld.FBL(dest, src0);
271   bld.CMP(bld.null_reg_ud(), src_reg(dest), zero, BRW_CONDITIONAL_GE);
272
273   /* = Before =
274    *
275    * 0: fbl        dest  src0
276    * 1: cmp.ge.f0  null  dest  0u
277    *
278    * = After =
279    * (no changes)
280    */
281
282   v->calculate_cfg();
283   bblock_t *block0 = v->cfg->blocks[0];
284
285   EXPECT_EQ(0, block0->start_ip);
286   EXPECT_EQ(1, block0->end_ip);
287
288   EXPECT_FALSE(cmod_propagation(v));
289
290   ASSERT_EQ(0, block0->start_ip);
291   ASSERT_EQ(1, block0->end_ip);
292   EXPECT_EQ(BRW_OPCODE_FBL, instruction(block0, 0)->opcode);
293   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
294   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 1)->conditional_mod);
295}
296
297TEST_F(cmod_propagation_test, intervening_flag_write)
298{
299   const vec4_builder bld = vec4_builder(v).at_end();
300   dst_reg dest = dst_reg(v, glsl_type::float_type);
301   src_reg src0 = src_reg(v, glsl_type::float_type);
302   src_reg src1 = src_reg(v, glsl_type::float_type);
303   src_reg src2 = src_reg(v, glsl_type::float_type);
304   src_reg zero(brw_imm_f(0.0f));
305   bld.ADD(dest, src0, src1);
306   bld.CMP(bld.null_reg_f(), src2, zero, BRW_CONDITIONAL_GE);
307   bld.CMP(bld.null_reg_f(), src_reg(dest), zero, BRW_CONDITIONAL_GE);
308
309   /* = Before =
310    *
311    * 0: add        dest  src0  src1
312    * 1: cmp.ge.f0  null  src2  0.0f
313    * 2: cmp.ge.f0  null  dest  0.0f
314    *
315    * = After =
316    * (no changes)
317    */
318
319   v->calculate_cfg();
320   bblock_t *block0 = v->cfg->blocks[0];
321
322   EXPECT_EQ(0, block0->start_ip);
323   EXPECT_EQ(2, block0->end_ip);
324
325   EXPECT_FALSE(cmod_propagation(v));
326
327   ASSERT_EQ(0, block0->start_ip);
328   ASSERT_EQ(2, block0->end_ip);
329   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
330   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
331   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 1)->conditional_mod);
332   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 2)->opcode);
333   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 2)->conditional_mod);
334}
335
336TEST_F(cmod_propagation_test, intervening_flag_read)
337{
338   const vec4_builder bld = vec4_builder(v).at_end();
339   dst_reg dest0 = dst_reg(v, glsl_type::float_type);
340   dst_reg dest1 = dst_reg(v, glsl_type::float_type);
341   src_reg src0 = src_reg(v, glsl_type::float_type);
342   src_reg src1 = src_reg(v, glsl_type::float_type);
343   src_reg src2 = src_reg(v, glsl_type::float_type);
344   src_reg zero(brw_imm_f(0.0f));
345   bld.ADD(dest0, src0, src1);
346   set_predicate(BRW_PREDICATE_NORMAL, bld.SEL(dest1, src2, zero));
347   bld.CMP(bld.null_reg_f(), src_reg(dest0), zero, BRW_CONDITIONAL_GE);
348
349   /* = Before =
350    *
351    * 0: add        dest0 src0  src1
352    * 1: (+f0) sel  dest1 src2  0.0f
353    * 2: cmp.ge.f0  null  dest0 0.0f
354    *
355    * = After =
356    * (no changes)
357    */
358
359   v->calculate_cfg();
360   bblock_t *block0 = v->cfg->blocks[0];
361
362   EXPECT_EQ(0, block0->start_ip);
363   EXPECT_EQ(2, block0->end_ip);
364
365   EXPECT_FALSE(cmod_propagation(v));
366
367   ASSERT_EQ(0, block0->start_ip);
368   ASSERT_EQ(2, block0->end_ip);
369   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
370   EXPECT_EQ(BRW_OPCODE_SEL, instruction(block0, 1)->opcode);
371   EXPECT_EQ(BRW_PREDICATE_NORMAL, instruction(block0, 1)->predicate);
372   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 2)->opcode);
373   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 2)->conditional_mod);
374}
375
376TEST_F(cmod_propagation_test, intervening_dest_write)
377{
378   const vec4_builder bld = vec4_builder(v).at_end();
379   dst_reg dest = dst_reg(v, glsl_type::vec4_type);
380   src_reg src0 = src_reg(v, glsl_type::float_type);
381   src_reg src1 = src_reg(v, glsl_type::float_type);
382   src_reg src2 = src_reg(v, glsl_type::vec2_type);
383   src_reg zero(brw_imm_f(0.0f));
384   bld.ADD(offset(dest, 8, 2), src0, src1);
385   bld.emit(SHADER_OPCODE_TEX, dest, src2)
386      ->size_written = 4 * REG_SIZE;
387   bld.CMP(bld.null_reg_f(), offset(src_reg(dest), 8, 2), zero, BRW_CONDITIONAL_GE);
388
389   /* = Before =
390    *
391    * 0: add        dest+2  src0    src1
392    * 1: tex rlen 4 dest+0  src2
393    * 2: cmp.ge.f0  null    dest+2  0.0f
394    *
395    * = After =
396    * (no changes)
397    */
398
399   v->calculate_cfg();
400   bblock_t *block0 = v->cfg->blocks[0];
401
402   EXPECT_EQ(0, block0->start_ip);
403   EXPECT_EQ(2, block0->end_ip);
404
405   EXPECT_FALSE(cmod_propagation(v));
406
407   ASSERT_EQ(0, block0->start_ip);
408   ASSERT_EQ(2, block0->end_ip);
409   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
410   EXPECT_EQ(BRW_CONDITIONAL_NONE, instruction(block0, 0)->conditional_mod);
411   EXPECT_EQ(SHADER_OPCODE_TEX, instruction(block0, 1)->opcode);
412   EXPECT_EQ(BRW_CONDITIONAL_NONE, instruction(block0, 0)->conditional_mod);
413   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 2)->opcode);
414   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 2)->conditional_mod);
415}
416
417TEST_F(cmod_propagation_test, intervening_flag_read_same_value)
418{
419   const vec4_builder bld = vec4_builder(v).at_end();
420   dst_reg dest0 = dst_reg(v, glsl_type::float_type);
421   dst_reg dest1 = dst_reg(v, glsl_type::float_type);
422   src_reg src0 = src_reg(v, glsl_type::float_type);
423   src_reg src1 = src_reg(v, glsl_type::float_type);
424   src_reg src2 = src_reg(v, glsl_type::float_type);
425   src_reg zero(brw_imm_f(0.0f));
426   dst_reg dest_null = bld.null_reg_f();
427   dest_null.writemask = WRITEMASK_X;
428
429   set_condmod(BRW_CONDITIONAL_GE, bld.ADD(dest0, src0, src1));
430   set_predicate(BRW_PREDICATE_NORMAL, bld.SEL(dest1, src2, zero));
431   bld.CMP(dest_null, src_reg(dest0), zero, BRW_CONDITIONAL_GE);
432
433   /* = Before =
434    *
435    * 0: add.ge.f0  dest0   src0  src1
436    * 1: (+f0) sel  dest1   src2  0.0f
437    * 2: cmp.ge.f0  null.x  dest0 0.0f
438    *
439    * = After =
440    * 0: add.ge.f0  dest0 src0  src1
441    * 1: (+f0) sel  dest1 src2  0.0f
442    */
443
444   v->calculate_cfg();
445   bblock_t *block0 = v->cfg->blocks[0];
446
447   EXPECT_EQ(0, block0->start_ip);
448   EXPECT_EQ(2, block0->end_ip);
449
450   EXPECT_TRUE(cmod_propagation(v));
451   ASSERT_EQ(0, block0->start_ip);
452   ASSERT_EQ(1, block0->end_ip);
453   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
454   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 0)->conditional_mod);
455   EXPECT_EQ(BRW_OPCODE_SEL, instruction(block0, 1)->opcode);
456   EXPECT_EQ(BRW_PREDICATE_NORMAL, instruction(block0, 1)->predicate);
457}
458
459TEST_F(cmod_propagation_test, negate)
460{
461   const vec4_builder bld = vec4_builder(v).at_end();
462   dst_reg dest = dst_reg(v, glsl_type::float_type);
463   src_reg src0 = src_reg(v, glsl_type::float_type);
464   src_reg src1 = src_reg(v, glsl_type::float_type);
465   src_reg zero(brw_imm_f(0.0f));
466   bld.ADD(dest, src0, src1);
467   src_reg tmp_src = src_reg(dest);
468   tmp_src.negate = true;
469   dst_reg dest_null = bld.null_reg_f();
470   dest_null.writemask = WRITEMASK_X;
471   bld.CMP(dest_null, tmp_src, zero, BRW_CONDITIONAL_GE);
472
473   /* = Before =
474    *
475    * 0: add        dest     src0  src1
476    * 1: cmp.ge.f0  null.x  -dest 0.0f
477    *
478    * = After =
479    * 0: add.le.f0  dest     src0  src1
480    */
481
482   v->calculate_cfg();
483   bblock_t *block0 = v->cfg->blocks[0];
484
485   EXPECT_EQ(0, block0->start_ip);
486   EXPECT_EQ(1, block0->end_ip);
487
488   EXPECT_TRUE(cmod_propagation(v));
489   EXPECT_EQ(0, block0->start_ip);
490   EXPECT_EQ(0, block0->end_ip);
491   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
492   EXPECT_EQ(BRW_CONDITIONAL_LE, instruction(block0, 0)->conditional_mod);
493}
494
495TEST_F(cmod_propagation_test, movnz)
496{
497   const vec4_builder bld = vec4_builder(v).at_end();
498   dst_reg dest = dst_reg(v, glsl_type::float_type);
499   src_reg src0 = src_reg(v, glsl_type::float_type);
500   src_reg src1 = src_reg(v, glsl_type::float_type);
501   dst_reg dest_null = bld.null_reg_f();
502   dest_null.writemask = WRITEMASK_X;
503
504   bld.CMP(dest, src0, src1, BRW_CONDITIONAL_L);
505   set_condmod(BRW_CONDITIONAL_NZ,
506               bld.MOV(dest_null, src_reg(dest)));
507
508   /* = Before =
509    *
510    * 0: cmp.l.f0  dest:F  src0:F  src1:F
511    * 1: mov.nz.f0 null.x  dest:F
512    *
513    * = After =
514    * 0: cmp.l.f0  dest  src0:F  src1:F
515    */
516
517   v->calculate_cfg();
518   bblock_t *block0 = v->cfg->blocks[0];
519
520   EXPECT_EQ(0, block0->start_ip);
521   EXPECT_EQ(1, block0->end_ip);
522
523   EXPECT_TRUE(cmod_propagation(v));
524
525   ASSERT_EQ(0, block0->start_ip);
526   ASSERT_EQ(0, block0->end_ip);
527   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 0)->opcode);
528   EXPECT_EQ(BRW_CONDITIONAL_L, instruction(block0, 0)->conditional_mod);
529}
530
531TEST_F(cmod_propagation_test, different_types_cmod_with_zero)
532{
533   const vec4_builder bld = vec4_builder(v).at_end();
534   dst_reg dest = dst_reg(v, glsl_type::int_type);
535   src_reg src0 = src_reg(v, glsl_type::int_type);
536   src_reg src1 = src_reg(v, glsl_type::int_type);
537   src_reg zero(brw_imm_f(0.0f));
538   bld.ADD(dest, src0, src1);
539   bld.CMP(bld.null_reg_f(), retype(src_reg(dest), BRW_REGISTER_TYPE_F), zero,
540           BRW_CONDITIONAL_GE);
541
542   /* = Before =
543    *
544    * 0: add        dest:D  src0:D  src1:D
545    * 1: cmp.ge.f0  null:F  dest:F  0.0f
546    *
547    * = After =
548    * (no changes)
549    */
550
551   v->calculate_cfg();
552   bblock_t *block0 = v->cfg->blocks[0];
553
554   EXPECT_EQ(0, block0->start_ip);
555   EXPECT_EQ(1, block0->end_ip);
556
557   EXPECT_FALSE(cmod_propagation(v));
558
559   ASSERT_EQ(0, block0->start_ip);
560   ASSERT_EQ(1, block0->end_ip);
561   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
562   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
563   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 1)->conditional_mod);
564}
565
566TEST_F(cmod_propagation_test, andnz_non_one)
567{
568   const vec4_builder bld = vec4_builder(v).at_end();
569   dst_reg dest = dst_reg(v, glsl_type::int_type);
570   src_reg src0 = src_reg(v, glsl_type::float_type);
571   src_reg zero(brw_imm_f(0.0f));
572   src_reg nonone(brw_imm_d(38));
573
574   bld.CMP(retype(dest, BRW_REGISTER_TYPE_F), src0, zero, BRW_CONDITIONAL_L);
575   set_condmod(BRW_CONDITIONAL_NZ,
576               bld.AND(bld.null_reg_d(), src_reg(dest), nonone));
577
578   /* = Before =
579    * 0: cmp.l.f0     dest:F  src0:F  0F
580    * 1: and.nz.f0    null:D  dest:D  38D
581    *
582    * = After =
583    * (no changes)
584    */
585
586   v->calculate_cfg();
587   bblock_t *block0 = v->cfg->blocks[0];
588
589   EXPECT_EQ(0, block0->start_ip);
590   EXPECT_EQ(1, block0->end_ip);
591
592   EXPECT_FALSE(cmod_propagation(v));
593
594   ASSERT_EQ(0, block0->start_ip);
595   ASSERT_EQ(1, block0->end_ip);
596   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 0)->opcode);
597   EXPECT_EQ(BRW_CONDITIONAL_L, instruction(block0, 0)->conditional_mod);
598   EXPECT_EQ(BRW_OPCODE_AND, instruction(block0, 1)->opcode);
599   EXPECT_EQ(BRW_CONDITIONAL_NZ, instruction(block0, 1)->conditional_mod);
600}
601
602/* Note that basic is using glsl_type:float types, while this one is using
603 * glsl_type::vec4 */
604TEST_F(cmod_propagation_test, basic_vec4)
605{
606   const vec4_builder bld = vec4_builder(v).at_end();
607   dst_reg dest = dst_reg(v, glsl_type::vec4_type);
608   src_reg src0 = src_reg(v, glsl_type::vec4_type);
609   src_reg src1 = src_reg(v, glsl_type::vec4_type);
610   src_reg zero(brw_imm_f(0.0f));
611
612   bld.MUL(dest, src0, src1);
613   bld.CMP(bld.null_reg_f(), src_reg(dest), zero, BRW_CONDITIONAL_NZ);
614
615   /* = Before =
616    * 0: mul         dest.xyzw  src0.xyzw  src1.xyzw
617    * 1: cmp.nz.f0.0 null.xyzw  dest.xyzw  0.0f
618    *
619    * = After =
620    * 0: mul.nz.f0.0 dest.xyzw  src0.xyzw  src1.xyzw
621    */
622
623   v->calculate_cfg();
624   bblock_t *block0 = v->cfg->blocks[0];
625
626   EXPECT_EQ(0, block0->start_ip);
627   EXPECT_EQ(1, block0->end_ip);
628
629   EXPECT_TRUE(cmod_propagation(v));
630
631   ASSERT_EQ(0, block0->start_ip);
632   ASSERT_EQ(0, block0->end_ip);
633   EXPECT_EQ(BRW_OPCODE_MUL, instruction(block0, 0)->opcode);
634   EXPECT_EQ(BRW_CONDITIONAL_NZ, instruction(block0, 0)->conditional_mod);
635}
636
637TEST_F(cmod_propagation_test, basic_vec4_different_dst_writemask)
638{
639   const vec4_builder bld = vec4_builder(v).at_end();
640   dst_reg dest = dst_reg(v, glsl_type::vec4_type);
641   dest.writemask = WRITEMASK_X;
642   src_reg src0 = src_reg(v, glsl_type::vec4_type);
643   src_reg src1 = src_reg(v, glsl_type::vec4_type);
644   src_reg zero(brw_imm_f(0.0f));
645   dst_reg dest_null = bld.null_reg_f();
646
647   bld.MUL(dest, src0, src1);
648   bld.CMP(dest_null, src_reg(dest), zero, BRW_CONDITIONAL_NZ);
649
650   /* = Before =
651    * 0: mul         dest.x  src0  src1
652    * 1: cmp.nz.f0.0 null    dest  0.0f
653    *
654    * = After =
655    * (no changes)
656    */
657
658   v->calculate_cfg();
659   bblock_t *block0 = v->cfg->blocks[0];
660
661   EXPECT_EQ(0, block0->start_ip);
662   EXPECT_EQ(1, block0->end_ip);
663
664   EXPECT_FALSE(cmod_propagation(v));
665
666   ASSERT_EQ(0, block0->start_ip);
667   ASSERT_EQ(1, block0->end_ip);
668   EXPECT_EQ(BRW_OPCODE_MUL, instruction(block0, 0)->opcode);
669   EXPECT_EQ(BRW_CONDITIONAL_NONE, instruction(block0, 0)->conditional_mod);
670   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
671   EXPECT_EQ(BRW_CONDITIONAL_NZ, instruction(block0, 1)->conditional_mod);
672}
673
674TEST_F(cmod_propagation_test, mad_one_component_vec4)
675{
676   const vec4_builder bld = vec4_builder(v).at_end();
677   dst_reg dest = dst_reg(v, glsl_type::vec4_type);
678   dest.writemask = WRITEMASK_X;
679   src_reg src0 = src_reg(v, glsl_type::vec4_type);
680   src_reg src1 = src_reg(v, glsl_type::vec4_type);
681   src_reg src2 = src_reg(v, glsl_type::vec4_type);
682   src0.swizzle = src1.swizzle = src2.swizzle = BRW_SWIZZLE_XXXX;
683   src2.negate = true;
684   src_reg zero(brw_imm_f(0.0f));
685   src_reg tmp(dest);
686   tmp.swizzle = BRW_SWIZZLE_XXXX;
687   dst_reg dest_null = bld.null_reg_f();
688   dest_null.writemask = WRITEMASK_X;
689
690   bld.MAD(dest, src0, src1, src2);
691   bld.CMP(dest_null, tmp, zero, BRW_CONDITIONAL_L);
692
693   /* = Before =
694    *
695    * 0: mad         dest.x:F  src0.xxxx:F  src10.xxxx:F  -src2.xxxx:F
696    * 1: cmp.l.f0.0  null.x:F  dest.xxxx:F  0.0f
697    *
698    * = After =
699    * 0: mad.l.f0    dest.x:F  src0.xxxx:F  src10.xxxx:F  -src2.xxxx:F
700    */
701
702   v->calculate_cfg();
703   bblock_t *block0 = v->cfg->blocks[0];
704
705   EXPECT_EQ(0, block0->start_ip);
706   EXPECT_EQ(1, block0->end_ip);
707
708   EXPECT_TRUE(cmod_propagation(v));
709
710   ASSERT_EQ(0, block0->start_ip);
711   ASSERT_EQ(0, block0->end_ip);
712   EXPECT_EQ(BRW_OPCODE_MAD, instruction(block0, 0)->opcode);
713   EXPECT_EQ(BRW_CONDITIONAL_L, instruction(block0, 0)->conditional_mod);
714}
715
716TEST_F(cmod_propagation_test, mad_more_one_component_vec4)
717{
718   const vec4_builder bld = vec4_builder(v).at_end();
719   dst_reg dest = dst_reg(v, glsl_type::vec4_type);
720   dest.writemask = WRITEMASK_XW;
721   src_reg src0 = src_reg(v, glsl_type::vec4_type);
722   src_reg src1 = src_reg(v, glsl_type::vec4_type);
723   src_reg src2 = src_reg(v, glsl_type::vec4_type);
724   src0.swizzle = src1.swizzle = src2.swizzle = BRW_SWIZZLE_XXXX;
725   src2.negate = true;
726   src_reg zero(brw_imm_f(0.0f));
727   src_reg tmp(dest);
728   tmp.swizzle = BRW_SWIZZLE_XXXX;
729   dst_reg dest_null = bld.null_reg_f();
730
731   bld.MAD(dest, src0, src1, src2);
732   bld.CMP(dest_null, tmp, zero, BRW_CONDITIONAL_L);
733
734   /* = Before =
735    *
736    * 0: mad         dest.xw:F  src0.xxxx:F  src10.xxxx:F  -src2.xxxx:F
737    * 1: cmp.l.f0.0  null:F  dest.xxxx:F  zeroF
738    *
739    * = After =
740    * (No changes)
741    */
742
743   v->calculate_cfg();
744   bblock_t *block0 = v->cfg->blocks[0];
745
746   EXPECT_EQ(0, block0->start_ip);
747   EXPECT_EQ(1, block0->end_ip);
748
749   EXPECT_FALSE(cmod_propagation(v));
750
751   ASSERT_EQ(0, block0->start_ip);
752   ASSERT_EQ(1, block0->end_ip);
753   EXPECT_EQ(BRW_OPCODE_MAD, instruction(block0, 0)->opcode);
754   EXPECT_EQ(BRW_CONDITIONAL_NONE, instruction(block0, 0)->conditional_mod);
755   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
756   EXPECT_EQ(BRW_CONDITIONAL_L, instruction(block0, 1)->conditional_mod);
757}
758
759TEST_F(cmod_propagation_test, cmp_mov_vec4)
760{
761   const vec4_builder bld = vec4_builder(v).at_end();
762   dst_reg dest = dst_reg(v, glsl_type::ivec4_type);
763   dest.writemask = WRITEMASK_X;
764   src_reg src0 = src_reg(v, glsl_type::ivec4_type);
765   src0.swizzle = BRW_SWIZZLE_XXXX;
766   src0.file = UNIFORM;
767   src_reg nonone = retype(brw_imm_d(16), BRW_REGISTER_TYPE_D);
768   src_reg mov_src = src_reg(dest);
769   mov_src.swizzle = BRW_SWIZZLE_XXXX;
770   dst_reg dest_null = bld.null_reg_d();
771   dest_null.writemask = WRITEMASK_X;
772
773   bld.CMP(dest, src0, nonone, BRW_CONDITIONAL_GE);
774   set_condmod(BRW_CONDITIONAL_NZ,
775               bld.MOV(dest_null, mov_src));
776
777   /* = Before =
778    *
779    * 0: cmp.ge.f0  dest.x:D  u.xxxx:D  16D
780    * 1: mov.nz.f0  null.x:D  dest.xxxx:D
781    *
782    * = After =
783    * 0: cmp.ge.f0  dest.x:D  u.xxxx:D  16D
784    */
785
786   v->calculate_cfg();
787   bblock_t *block0 = v->cfg->blocks[0];
788
789   EXPECT_EQ(0, block0->start_ip);
790   EXPECT_EQ(1, block0->end_ip);
791
792   EXPECT_TRUE(cmod_propagation(v));
793
794   ASSERT_EQ(0, block0->start_ip);
795   ASSERT_EQ(0, block0->end_ip);
796   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 0)->opcode);
797   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 0)->conditional_mod);
798}
799
800TEST_F(cmod_propagation_test, mul_cmp_different_channels_vec4)
801{
802   const vec4_builder bld = vec4_builder(v).at_end();
803   dst_reg dest = dst_reg(v, glsl_type::vec4_type);
804   src_reg src0 = src_reg(v, glsl_type::vec4_type);
805   src_reg src1 = src_reg(v, glsl_type::vec4_type);
806   src_reg zero(brw_imm_f(0.0f));
807   src_reg cmp_src = src_reg(dest);
808   cmp_src.swizzle = BRW_SWIZZLE4(0,1,3,2);
809
810   bld.MUL(dest, src0, src1);
811   bld.CMP(bld.null_reg_f(), cmp_src, zero, BRW_CONDITIONAL_NZ);
812
813   /* = Before =
814    * 0: mul         dest  src0       src1
815    * 1: cmp.nz.f0.0 null  dest.xywz  0.0f
816    *
817    * = After =
818    * (No changes)
819    */
820
821   v->calculate_cfg();
822   bblock_t *block0 = v->cfg->blocks[0];
823
824   EXPECT_EQ(0, block0->start_ip);
825   EXPECT_EQ(1, block0->end_ip);
826
827   EXPECT_FALSE(cmod_propagation(v));
828
829   ASSERT_EQ(0, block0->start_ip);
830   ASSERT_EQ(1, block0->end_ip);
831   EXPECT_EQ(BRW_OPCODE_MUL, instruction(block0, 0)->opcode);
832   EXPECT_EQ(BRW_CONDITIONAL_NONE, instruction(block0, 0)->conditional_mod);
833   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
834   EXPECT_EQ(BRW_CONDITIONAL_NZ, instruction(block0, 1)->conditional_mod);
835}
836
837TEST_F(cmod_propagation_test, add_cmp_same_dst_writemask)
838{
839   const vec4_builder bld = vec4_builder(v).at_end();
840   dst_reg dest = dst_reg(v, glsl_type::vec4_type);
841   src_reg src0 = src_reg(v, glsl_type::vec4_type);
842   src_reg src1 = src_reg(v, glsl_type::vec4_type);
843   dst_reg dest_null = bld.null_reg_f();
844
845   bld.ADD(dest, src0, src1);
846   vec4_instruction *inst = bld.CMP(dest_null, src0, src1, BRW_CONDITIONAL_GE);
847   inst->src[1].negate = true;
848
849   /* = Before =
850    *
851    * 0: add        dest.xyzw  src0  src1
852    * 1: cmp.ge.f0  null.xyzw  src0  -src1
853    *
854    * = After =
855    * 0: add.ge.f0  dest.xyzw  src0  src1
856    */
857
858   v->calculate_cfg();
859   bblock_t *block0 = v->cfg->blocks[0];
860
861   EXPECT_EQ(0, block0->start_ip);
862   EXPECT_EQ(1, block0->end_ip);
863
864   EXPECT_TRUE(cmod_propagation(v));
865
866   ASSERT_EQ(0, block0->start_ip);
867   ASSERT_EQ(0, block0->end_ip);
868   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
869   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 0)->conditional_mod);
870}
871
872TEST_F(cmod_propagation_test, add_cmp_different_dst_writemask)
873{
874   const vec4_builder bld = vec4_builder(v).at_end();
875   dst_reg dest = dst_reg(v, glsl_type::float_type);
876   src_reg src0 = src_reg(v, glsl_type::vec4_type);
877   src_reg src1 = src_reg(v, glsl_type::vec4_type);
878   dst_reg dest_null = bld.null_reg_f();
879
880   bld.ADD(dest, src0, src1);
881   vec4_instruction *inst = bld.CMP(dest_null, src0, src1, BRW_CONDITIONAL_GE);
882   inst->src[1].negate = true;
883
884   /* = Before =
885    *
886    * 0: add        dest.x     src0  src1
887    * 1: cmp.ge.f0  null.xyzw  src0  -src1
888    *
889    * = After =
890    * (no changes)
891    */
892
893   v->calculate_cfg();
894   bblock_t *block0 = v->cfg->blocks[0];
895
896   EXPECT_EQ(0, block0->start_ip);
897   EXPECT_EQ(1, block0->end_ip);
898
899   EXPECT_FALSE(cmod_propagation(v));
900
901   ASSERT_EQ(0, block0->start_ip);
902   ASSERT_EQ(1, block0->end_ip);
903   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
904   EXPECT_EQ(BRW_CONDITIONAL_NONE, instruction(block0, 0)->conditional_mod);
905   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
906   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 1)->conditional_mod);
907}
908
909TEST_F(cmod_propagation_test, prop_across_sel_gfx7)
910{
911   const vec4_builder bld = vec4_builder(v).at_end();
912   dst_reg dest1 = dst_reg(v, glsl_type::float_type);
913   dst_reg dest2 = dst_reg(v, glsl_type::float_type);
914   src_reg src0 = src_reg(v, glsl_type::float_type);
915   src_reg src1 = src_reg(v, glsl_type::float_type);
916   src_reg src2 = src_reg(v, glsl_type::float_type);
917   src_reg src3 = src_reg(v, glsl_type::float_type);
918   src_reg zero(brw_imm_f(0.0f));
919   dst_reg dest_null = bld.null_reg_f();
920   dest_null.writemask = WRITEMASK_X;
921
922   bld.ADD(dest1, src0, src1);
923   bld.SEL(dest2, src2, src3)
924      ->conditional_mod = BRW_CONDITIONAL_GE;
925   bld.CMP(dest_null, src_reg(dest1), zero, BRW_CONDITIONAL_GE);
926
927   /* = Before =
928    *
929    * 0: add        dest1.x src0.xxxx  src1.xxxx
930    * 1: sel.ge.f0  dest2.x src2.xxxx  src3.xxxx
931    * 2: cmp.ge.f0  null.x  dest.xxxx  0.0f
932    *
933    * = After =
934    * 0: add.ge.f0  dest.x  src0.xxxx  src1.xxxx
935    * 1: sel.ge.f0  dest2.x src2.xxxx  src3.xxxx
936    */
937
938   v->calculate_cfg();
939   bblock_t *block0 = v->cfg->blocks[0];
940
941   EXPECT_EQ(0, block0->start_ip);
942   EXPECT_EQ(2, block0->end_ip);
943
944   EXPECT_TRUE(cmod_propagation(v));
945
946   ASSERT_EQ(0, block0->start_ip);
947   ASSERT_EQ(1, block0->end_ip);
948   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
949   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 0)->conditional_mod);
950   EXPECT_EQ(BRW_OPCODE_SEL, instruction(block0, 1)->opcode);
951   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 1)->conditional_mod);
952}
953
954TEST_F(cmod_propagation_test, prop_across_sel_gfx5)
955{
956   devinfo->ver = 5;
957   devinfo->verx10 = devinfo->ver * 10;
958
959   const vec4_builder bld = vec4_builder(v).at_end();
960   dst_reg dest1 = dst_reg(v, glsl_type::float_type);
961   dst_reg dest2 = dst_reg(v, glsl_type::float_type);
962   src_reg src0 = src_reg(v, glsl_type::float_type);
963   src_reg src1 = src_reg(v, glsl_type::float_type);
964   src_reg src2 = src_reg(v, glsl_type::float_type);
965   src_reg src3 = src_reg(v, glsl_type::float_type);
966   src_reg zero(brw_imm_f(0.0f));
967   dst_reg dest_null = bld.null_reg_f();
968   dest_null.writemask = WRITEMASK_X;
969
970   bld.ADD(dest1, src0, src1);
971   bld.SEL(dest2, src2, src3)
972      ->conditional_mod = BRW_CONDITIONAL_GE;
973   bld.CMP(dest_null, src_reg(dest1), zero, BRW_CONDITIONAL_GE);
974
975   /* = Before =
976    *
977    * 0: add        dest1.x src0.xxxx  src1.xxxx
978    * 1: sel.ge.f0  dest2.x src2.xxxx  src3.xxxx
979    * 2: cmp.ge.f0  null.x  dest.xxxx  0.0f
980    *
981    * = After =
982    * (no changes)
983    *
984    * On Gfx4 and Gfx5, sel.l (for min) and sel.ge (for max) are implemented
985    * using a separate cmpn and sel instruction.  This lowering occurs in
986    * fs_vistor::lower_minmax which is called a long time after the first
987    * calls to cmod_propagation.
988    */
989
990   v->calculate_cfg();
991   bblock_t *block0 = v->cfg->blocks[0];
992
993   EXPECT_EQ(0, block0->start_ip);
994   EXPECT_EQ(2, block0->end_ip);
995
996   EXPECT_FALSE(cmod_propagation(v));
997
998   ASSERT_EQ(0, block0->start_ip);
999   ASSERT_EQ(2, block0->end_ip);
1000   EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
1001   EXPECT_EQ(BRW_CONDITIONAL_NONE, instruction(block0, 0)->conditional_mod);
1002   EXPECT_EQ(BRW_OPCODE_SEL, instruction(block0, 1)->opcode);
1003   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 1)->conditional_mod);
1004   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 2)->opcode);
1005   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 2)->conditional_mod);
1006}
1007
1008TEST_F(cmod_propagation_test, prop_into_sel_gfx5)
1009{
1010   devinfo->ver = 5;
1011   devinfo->verx10 = devinfo->ver * 10;
1012
1013   const vec4_builder bld = vec4_builder(v).at_end();
1014   dst_reg dest = dst_reg(v, glsl_type::float_type);
1015   src_reg src0 = src_reg(v, glsl_type::float_type);
1016   src_reg src1 = src_reg(v, glsl_type::float_type);
1017   src_reg zero(brw_imm_f(0.0f));
1018   dst_reg dest_null = bld.null_reg_f();
1019   dest_null.writemask = WRITEMASK_X;
1020
1021   bld.SEL(dest, src0, src1)
1022      ->conditional_mod = BRW_CONDITIONAL_GE;
1023   bld.CMP(dest_null, src_reg(dest), zero, BRW_CONDITIONAL_GE);
1024
1025   /* = Before =
1026    *
1027    * 0: sel.ge.f0  dest.x  src2.xxxx  src3.xxxx
1028    * 1: cmp.ge.f0  null.x  dest.xxxx  0.0f
1029    *
1030    * = After =
1031    * (no changes)
1032    *
1033    * Do not copy propagate into a sel.cond instruction.  While it does modify
1034    * the flags, the flags are not based on the result compared with zero (as
1035    * with most other instructions).  The result is based on the sources
1036    * compared with each other (like cmp.cond).
1037    */
1038
1039   v->calculate_cfg();
1040   bblock_t *block0 = v->cfg->blocks[0];
1041
1042   EXPECT_EQ(0, block0->start_ip);
1043   EXPECT_EQ(1, block0->end_ip);
1044
1045   EXPECT_FALSE(cmod_propagation(v));
1046
1047   ASSERT_EQ(0, block0->start_ip);
1048   ASSERT_EQ(1, block0->end_ip);
1049   EXPECT_EQ(BRW_OPCODE_SEL, instruction(block0, 0)->opcode);
1050   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 0)->conditional_mod);
1051   EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
1052   EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 1)->conditional_mod);
1053}
1054