r300/compiler: Refactor to allow different instruction types
[mesa.git] / src / mesa / drivers / dri / r300 / compiler / radeon_dataflow_deadcode.c
1 /*
2 * Copyright (C) 2009 Nicolai Haehnle.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28 #include "radeon_dataflow.h"
29
30 #include "radeon_compiler.h"
31
32
33 struct updatemask_state {
34 unsigned char Output[RC_REGISTER_MAX_INDEX];
35 unsigned char Temporary[RC_REGISTER_MAX_INDEX];
36 unsigned char Address;
37 unsigned char Special[RC_NUM_SPECIAL_REGISTERS];
38 };
39
40 struct instruction_state {
41 unsigned char WriteMask:4;
42 unsigned char WriteALUResult:1;
43 unsigned char SrcReg[3];
44 };
45
46 struct branchinfo {
47 unsigned int HaveElse:1;
48
49 struct updatemask_state StoreEndif;
50 struct updatemask_state StoreElse;
51 };
52
53 struct deadcode_state {
54 struct radeon_compiler * C;
55 struct instruction_state * Instructions;
56
57 struct updatemask_state R;
58
59 struct branchinfo * BranchStack;
60 unsigned int BranchStackSize;
61 unsigned int BranchStackReserved;
62 };
63
64
65 static void or_updatemasks(
66 struct updatemask_state * dst,
67 struct updatemask_state * a,
68 struct updatemask_state * b)
69 {
70 for(unsigned int i = 0; i < RC_REGISTER_MAX_INDEX; ++i) {
71 dst->Output[i] = a->Output[i] | b->Output[i];
72 dst->Temporary[i] = a->Temporary[i] | b->Temporary[i];
73 }
74
75 for(unsigned int i = 0; i < RC_NUM_SPECIAL_REGISTERS; ++i)
76 dst->Special[i] = a->Special[i] | b->Special[i];
77
78 dst->Address = a->Address | b->Address;
79 }
80
81 static void push_branch(struct deadcode_state * s)
82 {
83 if (s->BranchStackSize >= s->BranchStackReserved) {
84 unsigned int new_reserve = 2 * s->BranchStackReserved;
85 struct branchinfo * new_stack;
86
87 if (!new_reserve)
88 new_reserve = 4;
89
90 new_stack = memory_pool_malloc(&s->C->Pool, new_reserve * sizeof(struct branchinfo));
91 memcpy(new_stack, s->BranchStack, s->BranchStackSize * sizeof(struct branchinfo));
92
93 s->BranchStack = new_stack;
94 s->BranchStackReserved = new_reserve;
95 }
96
97 struct branchinfo * branch = &s->BranchStack[s->BranchStackSize++];
98 branch->HaveElse = 0;
99 memcpy(&branch->StoreEndif, &s->R, sizeof(s->R));
100 }
101
102 static unsigned char * get_used_ptr(struct deadcode_state *s, rc_register_file file, unsigned int index)
103 {
104 if (file == RC_FILE_OUTPUT || file == RC_FILE_TEMPORARY) {
105 if (index >= RC_REGISTER_MAX_INDEX) {
106 rc_error(s->C, "%s: index %i is out of bounds for file %i\n", __FUNCTION__, index, file);
107 return 0;
108 }
109
110 if (file == RC_FILE_OUTPUT)
111 return &s->R.Output[index];
112 else
113 return &s->R.Temporary[index];
114 } else if (file == RC_FILE_ADDRESS) {
115 return &s->R.Address;
116 } else if (file == RC_FILE_SPECIAL) {
117 if (index >= RC_NUM_SPECIAL_REGISTERS) {
118 rc_error(s->C, "%s: special file index %i out of bounds\n", __FUNCTION__, index);
119 return 0;
120 }
121
122 return &s->R.Special[index];
123 }
124
125 return 0;
126 }
127
128 static void mark_used(struct deadcode_state * s, rc_register_file file, unsigned int index, unsigned int mask)
129 {
130 unsigned char * pused = get_used_ptr(s, file, index);
131 if (pused)
132 *pused |= mask;
133 }
134
135 static void update_instruction(struct deadcode_state * s, struct rc_instruction * inst)
136 {
137 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
138 struct instruction_state * insts = &s->Instructions[inst->IP];
139 unsigned int usedmask = 0;
140
141 if (opcode->HasDstReg) {
142 unsigned char * pused = get_used_ptr(s, inst->U.I.DstReg.File, inst->U.I.DstReg.Index);
143 if (pused) {
144 usedmask = *pused & inst->U.I.DstReg.WriteMask;
145 *pused &= ~usedmask;
146 }
147 }
148
149 insts->WriteMask |= usedmask;
150
151 if (inst->U.I.WriteALUResult) {
152 unsigned char * pused = get_used_ptr(s, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT);
153 if (pused && *pused) {
154 if (inst->U.I.WriteALUResult == RC_ALURESULT_X)
155 usedmask |= RC_MASK_X;
156 else if (inst->U.I.WriteALUResult == RC_ALURESULT_W)
157 usedmask |= RC_MASK_W;
158
159 *pused = 0;
160 insts->WriteALUResult = 1;
161 }
162 }
163
164 unsigned int srcmasks[3];
165 rc_compute_sources_for_writemask(opcode, usedmask, srcmasks);
166
167 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
168 unsigned int refmask = 0;
169 unsigned int newsrcmask = srcmasks[src] & ~insts->SrcReg[src];
170 insts->SrcReg[src] |= newsrcmask;
171
172 for(unsigned int chan = 0; chan < 4; ++chan) {
173 if (GET_BIT(newsrcmask, chan))
174 refmask |= 1 << GET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan);
175 }
176
177 /* get rid of spurious bits from ZERO, ONE, etc. swizzles */
178 refmask &= RC_MASK_XYZW;
179
180 if (!refmask)
181 continue;
182
183 mark_used(s, inst->U.I.SrcReg[src].File, inst->U.I.SrcReg[src].Index, refmask);
184
185 if (inst->U.I.SrcReg[src].RelAddr)
186 mark_used(s, RC_FILE_ADDRESS, 0, RC_MASK_X);
187 }
188 }
189
190 static void mark_output_use(void * data, unsigned int index, unsigned int mask)
191 {
192 struct deadcode_state * s = data;
193
194 mark_used(s, RC_FILE_OUTPUT, index, mask);
195 }
196
197 void rc_dataflow_deadcode(struct radeon_compiler * c, rc_dataflow_mark_outputs_fn dce, void * userdata)
198 {
199 struct deadcode_state s;
200 unsigned int nr_instructions;
201
202 memset(&s, 0, sizeof(s));
203 s.C = c;
204
205 nr_instructions = rc_recompute_ips(c);
206 s.Instructions = memory_pool_malloc(&c->Pool, sizeof(struct instruction_state)*nr_instructions);
207 memset(s.Instructions, 0, sizeof(struct instruction_state)*nr_instructions);
208
209 dce(userdata, &s, &mark_output_use);
210
211 for(struct rc_instruction * inst = c->Program.Instructions.Prev;
212 inst != &c->Program.Instructions;
213 inst = inst->Prev) {
214 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
215
216 if (opcode->IsControlFlow) {
217 if (opcode->Opcode == RC_OPCODE_ENDIF) {
218 push_branch(&s);
219 } else {
220 if (s.BranchStackSize) {
221 struct branchinfo * branch = &s.BranchStack[s.BranchStackSize-1];
222
223 if (opcode->Opcode == RC_OPCODE_IF) {
224 or_updatemasks(&s.R,
225 &s.R,
226 branch->HaveElse ? &branch->StoreElse : &branch->StoreEndif);
227
228 s.BranchStackSize--;
229 } else if (opcode->Opcode == RC_OPCODE_ELSE) {
230 if (branch->HaveElse) {
231 rc_error(c, "%s: Multiple ELSE for one IF/ENDIF\n", __FUNCTION__);
232 } else {
233 memcpy(&branch->StoreElse, &s.R, sizeof(s.R));
234 memcpy(&s.R, &branch->StoreEndif, sizeof(s.R));
235 branch->HaveElse = 1;
236 }
237 } else {
238 rc_error(c, "%s: Unhandled control flow instruction %s\n", __FUNCTION__, opcode->Name);
239 }
240 } else {
241 rc_error(c, "%s: Unexpected control flow instruction\n", __FUNCTION__);
242 }
243 }
244 }
245
246 update_instruction(&s, inst);
247 }
248
249 unsigned int ip = 0;
250 for(struct rc_instruction * inst = c->Program.Instructions.Next;
251 inst != &c->Program.Instructions;
252 inst = inst->Next, ++ip) {
253 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);\
254 int dead = 1;
255
256 if (!opcode->HasDstReg) {
257 dead = 0;
258 } else {
259 inst->U.I.DstReg.WriteMask = s.Instructions[ip].WriteMask;
260 if (s.Instructions[ip].WriteMask)
261 dead = 0;
262
263 if (s.Instructions[ip].WriteALUResult)
264 dead = 0;
265 else
266 inst->U.I.WriteALUResult = RC_ALURESULT_NONE;
267 }
268
269 if (dead) {
270 struct rc_instruction * todelete = inst;
271 inst = inst->Prev;
272 rc_remove_instruction(todelete);
273 continue;
274 }
275
276 unsigned int srcmasks[3];
277 unsigned int usemask = s.Instructions[ip].WriteMask;
278
279 if (inst->U.I.WriteALUResult == RC_ALURESULT_X)
280 usemask |= RC_MASK_X;
281 else if (inst->U.I.WriteALUResult == RC_ALURESULT_W)
282 usemask |= RC_MASK_W;
283
284 rc_compute_sources_for_writemask(opcode, usemask, srcmasks);
285
286 for(unsigned int src = 0; src < 3; ++src) {
287 for(unsigned int chan = 0; chan < 4; ++chan) {
288 if (!GET_BIT(srcmasks[src], chan))
289 SET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan, RC_SWIZZLE_UNUSED);
290 }
291 }
292 }
293
294 rc_calculate_inputs_outputs(c);
295 }