OSDN Git Service

vc4: Add a helper function for the construction of qregs.
[android-x86/external-mesa.git] / src / gallium / drivers / vc4 / vc4_opt_vpm.c
1 /*
2  * Copyright © 2014 Broadcom
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 /**
25  * @file vc4_opt_vpm.c
26  *
27  * This modifies instructions that:
28  * 1. exclusively consume a value read from the VPM to directly read the VPM if
29  *    other operands allow it.
30  * 2. generate the value consumed by a VPM write to write directly into the VPM.
31  */
32
33 #include "vc4_qir.h"
34
35 bool
36 qir_opt_vpm(struct vc4_compile *c)
37 {
38         if (c->stage == QSTAGE_FRAG)
39                 return false;
40
41         bool progress = false;
42         struct qinst *vpm_writes[64] = { 0 };
43         uint32_t use_count[c->num_temps];
44         uint32_t vpm_write_count = 0;
45         memset(&use_count, 0, sizeof(use_count));
46
47         list_for_each_entry(struct qinst, inst, &c->instructions, link) {
48                 switch (inst->dst.file) {
49                 case QFILE_VPM:
50                         vpm_writes[vpm_write_count++] = inst;
51                         break;
52                 default:
53                         break;
54                 }
55
56                 for (int i = 0; i < qir_get_op_nsrc(inst->op); i++) {
57                         if (inst->src[i].file == QFILE_TEMP) {
58                                 uint32_t temp = inst->src[i].index;
59                                 use_count[temp]++;
60                         }
61                 }
62         }
63
64         /* For instructions reading from a temporary that contains a VPM read
65          * result, try to move the instruction up in place of the VPM read.
66          */
67         list_for_each_entry(struct qinst, inst, &c->instructions, link) {
68                 if (!inst)
69                         continue;
70
71                 if (qir_depends_on_flags(inst) || inst->sf)
72                         continue;
73
74                 if (qir_has_side_effects(c, inst) ||
75                     qir_has_side_effect_reads(c, inst) ||
76                     qir_is_tex(inst))
77                         continue;
78
79                 for (int j = 0; j < qir_get_op_nsrc(inst->op); j++) {
80                         if (inst->src[j].file != QFILE_TEMP ||
81                             inst->src[j].pack)
82                                 continue;
83
84                         uint32_t temp = inst->src[j].index;
85
86                         /* Since VPM reads pull from a FIFO, we only get to
87                          * read each VPM entry once (unless we reset the read
88                          * pointer).  That means we can't copy-propagate a VPM
89                          * read to multiple locations.
90                          */
91                         if (use_count[temp] != 1)
92                                 continue;
93
94                         struct qinst *mov = c->defs[temp];
95                         if (!mov ||
96                             (mov->op != QOP_MOV &&
97                              mov->op != QOP_FMOV &&
98                              mov->op != QOP_MMOV) ||
99                             mov->src[0].file != QFILE_VPM) {
100                                 continue;
101                         }
102
103                         uint32_t temps = 0;
104                         for (int k = 0; k < qir_get_op_nsrc(inst->op); k++) {
105                                 if (inst->src[k].file == QFILE_TEMP)
106                                         temps++;
107                         }
108
109                         /* The instruction is safe to reorder if its other
110                          * sources are independent of previous instructions
111                          */
112                         if (temps == 1) {
113                                 list_del(&inst->link);
114                                 inst->src[j] = mov->src[0];
115                                 list_replace(&mov->link, &inst->link);
116                                 c->defs[temp] = NULL;
117                                 free(mov);
118                                 progress = true;
119                                 break;
120                         }
121                 }
122         }
123
124         for (int i = 0; i < vpm_write_count; i++) {
125                 if (!qir_is_raw_mov(vpm_writes[i]) ||
126                     vpm_writes[i]->src[0].file != QFILE_TEMP) {
127                         continue;
128                 }
129
130                 uint32_t temp = vpm_writes[i]->src[0].index;
131                 if (use_count[temp] != 1)
132                         continue;
133
134                 struct qinst *inst = c->defs[temp];
135                 if (!inst)
136                         continue;
137
138                 if (qir_depends_on_flags(inst) || inst->sf)
139                         continue;
140
141                 if (qir_has_side_effects(c, inst) ||
142                     qir_has_side_effect_reads(c, inst)) {
143                         continue;
144                 }
145
146                 /* Move the generating instruction to the end of the program
147                  * to maintain the order of the VPM writes.
148                  */
149                 assert(!vpm_writes[i]->sf);
150                 list_del(&inst->link);
151                 list_addtail(&inst->link, &vpm_writes[i]->link);
152                 qir_remove_instruction(c, vpm_writes[i]);
153
154                 c->defs[inst->dst.index] = NULL;
155                 inst->dst.file = QFILE_VPM;
156                 inst->dst.index = 0;
157
158                 progress = true;
159         }
160
161         return progress;
162 }