OSDN Git Service

i965/fs: Don't propagate cmod to inst with different type.
[android-x86/external-mesa.git] / src / mesa / drivers / dri / i965 / brw_fs_cmod_propagation.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 #include "brw_fs.h"
25 #include "brw_fs_live_variables.h"
26 #include "brw_cfg.h"
27
28 /** @file brw_fs_cmod_propagation.cpp
29  *
30  * Implements a pass that propagates the conditional modifier from a CMP x 0.0
31  * instruction into the instruction that generated x. For instance, in this
32  * sequence
33  *
34  *    add(8)          g70<1>F    g69<8,8,1>F    4096F
35  *    cmp.ge.f0(8)    null       g70<8,8,1>F    0F
36  *
37  * we can do the comparison as part of the ADD instruction directly:
38  *
39  *    add.ge.f0(8)    g70<1>F    g69<8,8,1>F    4096F
40  *
41  * If there had been a use of the flag register and another CMP using g70
42  *
43  *    add.ge.f0(8)    g70<1>F    g69<8,8,1>F    4096F
44  *    (+f0) sel(8)    g71<F>     g72<8,8,1>F    g73<8,8,1>F
45  *    cmp.ge.f0(8)    null       g70<8,8,1>F    0F
46  *
47  * we can recognize that the CMP is generating the flag value that already
48  * exists and therefore remove the instruction.
49  */
50
51 static bool
52 opt_cmod_propagation_local(fs_visitor *v, bblock_t *block)
53 {
54    bool progress = false;
55    int ip = block->end_ip + 1;
56
57    foreach_inst_in_block_reverse_safe(fs_inst, inst, block) {
58       ip--;
59
60       if ((inst->opcode != BRW_OPCODE_CMP &&
61            inst->opcode != BRW_OPCODE_MOV) ||
62           inst->predicate != BRW_PREDICATE_NONE ||
63           !inst->dst.is_null() ||
64           inst->src[0].file != GRF ||
65           inst->src[0].abs)
66          continue;
67
68       if (inst->opcode == BRW_OPCODE_CMP && !inst->src[1].is_zero())
69          continue;
70
71       if (inst->opcode == BRW_OPCODE_MOV &&
72           inst->conditional_mod != BRW_CONDITIONAL_NZ)
73          continue;
74
75       bool read_flag = false;
76       foreach_inst_in_block_reverse_starting_from(fs_inst, scan_inst, inst,
77                                                   block) {
78          if (scan_inst->overwrites_reg(inst->src[0])) {
79             if (scan_inst->is_partial_write() ||
80                 scan_inst->dst.reg_offset != inst->src[0].reg_offset)
81                break;
82
83             /* Comparisons operate differently for ints and floats */
84             if (scan_inst->dst.type != inst->dst.type)
85                break;
86
87             /* If the instruction generating inst's source also wrote the
88              * flag, and inst is doing a simple .nz comparison, then inst
89              * is redundant - the appropriate value is already in the flag
90              * register.  Delete inst.
91              */
92             if (inst->conditional_mod == BRW_CONDITIONAL_NZ &&
93                 !inst->src[0].negate &&
94                 scan_inst->writes_flag()) {
95                inst->remove(block);
96                progress = true;
97                break;
98             }
99
100             /* Otherwise, try propagating the conditional. */
101             enum brw_conditional_mod cond =
102                inst->src[0].negate ? brw_swap_cmod(inst->conditional_mod)
103                                    : inst->conditional_mod;
104
105             if (scan_inst->can_do_cmod() &&
106                 ((!read_flag && scan_inst->conditional_mod == BRW_CONDITIONAL_NONE) ||
107                  scan_inst->conditional_mod == cond)) {
108                scan_inst->conditional_mod = cond;
109                inst->remove(block);
110                progress = true;
111             }
112             break;
113          }
114
115          if (scan_inst->writes_flag())
116             break;
117
118          read_flag = read_flag || scan_inst->reads_flag();
119       }
120    }
121
122    return progress;
123 }
124
125 bool
126 fs_visitor::opt_cmod_propagation()
127 {
128    bool progress = false;
129
130    foreach_block_reverse(block, cfg) {
131       progress = opt_cmod_propagation_local(this, block) || progress;
132    }
133
134    if (progress)
135       invalidate_live_intervals();
136
137    return progress;
138 }