Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/*
2
 * Copyright 2013 Vadim Girlin 
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
 * on the rights to use, copy, modify, merge, publish, distribute, sub
8
 * license, and/or sell copies of the Software, and to permit persons to whom
9
 * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18
 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22
 *
23
 * Authors:
24
 *      Vadim Girlin
25
 */
26
 
27
#include "sb_shader.h"
28
#include "sb_pass.h"
29
 
30
#define LIV_DEBUG 0
31
 
32
#if LIV_DEBUG
33
#define LIV_DUMP(a) do { a } while (0)
34
#else
35
#define LIV_DUMP(a)
36
#endif
37
 
38
namespace r600_sb {
39
 
40
bool liveness::visit(container_node& n, bool enter) {
41
	if (enter) {
42
		n.live_after = live;
43
		process_ins(n);
44
	} else {
45
		process_outs(n);
46
		n.live_before = live;
47
	}
48
	return true;
49
}
50
 
51
bool liveness::visit(bb_node& n, bool enter) {
52
	if (enter) {
53
		n.live_after = live;
54
	} else {
55
		n.live_before = live;
56
	}
57
	return true;
58
}
59
 
60
bool liveness::visit(alu_group_node& n, bool enter) {
61
	if (enter) {
62
	} else {
63
	}
64
	return true;
65
}
66
 
67
bool liveness::visit(cf_node& n, bool enter) {
68
	if (enter) {
69
		if (n.bc.op == CF_OP_CF_END) {
70
			n.flags |= NF_DEAD;
71
			return false;
72
		}
73
		n.live_after = live;
74
		update_interferences();
75
		process_op(n);
76
	} else {
77
		n.live_before = live;
78
	}
79
	return true;
80
}
81
 
82
bool liveness::visit(alu_node& n, bool enter) {
83
	if (enter) {
84
		update_interferences();
85
		process_op(n);
86
	} else {
87
	}
88
	return false;
89
}
90
 
91
bool liveness::visit(alu_packed_node& n, bool enter) {
92
	if (enter) {
93
		update_interferences();
94
		process_op(n);
95
 
96
	} else {
97
	}
98
	return false;
99
}
100
 
101
bool liveness::visit(fetch_node& n, bool enter) {
102
	if (enter) {
103
		update_interferences();
104
		process_op(n);
105
	} else {
106
	}
107
	return true;
108
}
109
 
110
bool liveness::visit(region_node& n, bool enter) {
111
	if (enter) {
112
		val_set s = live;
113
 
114
		update_interferences();
115
 
116
		if (n.phi)
117
			process_phi_outs(n.phi);
118
 
119
		n.live_after = live;
120
 
121
		live.clear();
122
 
123
		if (n.loop_phi) {
124
			n.live_before.clear();
125
		}
126
 
127
		assert(n.count() == 1);
128
		run_on(*static_cast(*n.begin()));
129
 
130
		// second pass for loops
131
		if (n.loop_phi) {
132
			process_phi_outs(n.loop_phi);
133
			n.live_before = live;
134
 
135
			run_on(*static_cast(*n.begin()));
136
 
137
			update_interferences(); // FIXME is it required
138
 
139
			process_phi_outs(n.loop_phi);
140
			process_phi_branch(n.loop_phi, 0);
141
		}
142
 
143
		update_interferences(); // FIXME is it required
144
 
145
		n.live_after = s;
146
		n.live_before = live;
147
	}
148
	return false;
149
}
150
 
151
bool liveness::visit(repeat_node& n, bool enter) {
152
	if (enter) {
153
		live = n.target->live_before;
154
		process_phi_branch(n.target->loop_phi, n.rep_id);
155
	} else {
156
	}
157
	return true;
158
}
159
 
160
bool liveness::visit(depart_node& n, bool enter) {
161
	if (enter) {
162
		live = n.target->live_after;
163
		if(n.target->phi)
164
			process_phi_branch(n.target->phi, n.dep_id);
165
	} else {
166
	}
167
	return true;
168
}
169
 
170
bool liveness::visit(if_node& n, bool enter) {
171
	if (enter) {
172
		assert(n.count() == 1);
173
		n.live_after = live;
174
 
175
		run_on(*static_cast(*n.begin()));
176
 
177
		process_op(n);
178
		live.add_set(n.live_after);
179
	}
180
	return false;
181
}
182
 
183
void liveness::update_interferences() {
184
	if (!sh.compute_interferences)
185
		return;
186
 
187
	if (!live_changed)
188
		return;
189
 
190
	LIV_DUMP(
191
		sblog << "interf ";
192
		dump::dump_set(sh, live);
193
		sblog << "\n";
194
	);
195
 
196
	val_set& s = live;
197
	for(val_set::iterator I = s.begin(sh), E = s.end(sh); I != E; ++I) {
198
		value *v = *I;
199
		assert(v);
200
 
201
		if (v->array) {
202
			v->array->interferences.add_set(s);
203
		}
204
 
205
		v->interferences.add_set(s);
206
		v->interferences.remove_val(v);
207
 
208
		LIV_DUMP(
209
			sblog << "interferences updated for ";
210
			dump::dump_val(v);
211
			sblog << " : ";
212
			dump::dump_set(sh, v->interferences);
213
			sblog << "\n";
214
		);
215
	}
216
	live_changed = false;
217
}
218
 
219
bool liveness::remove_val(value *v) {
220
	if (live.remove_val(v)) {
221
		v->flags &= ~VLF_DEAD;
222
		return true;
223
	}
224
	v->flags |= VLF_DEAD;
225
	return false;
226
}
227
 
228
bool liveness::process_maydef(value *v) {
229
	bool r = false;
230
	vvec::iterator S(v->muse.begin());
231
 
232
	for (vvec::iterator I = v->mdef.begin(), E = v->mdef.end(); I != E;
233
			++I, ++S) {
234
		value *&d = *I, *&u = *S;
235
		if (!d) {
236
			assert(!u);
237
			continue;
238
		}
239
 
240
		bool alive = remove_val(d);
241
		if (alive) {
242
			r = true;
243
		} else {
244
			d = NULL;
245
			u = NULL;
246
		}
247
	}
248
	return r;
249
}
250
 
251
bool liveness::remove_vec(vvec &vv) {
252
	bool r = false;
253
	for (vvec::reverse_iterator I = vv.rbegin(), E = vv.rend(); I != E; ++I) {
254
		value* &v = *I;
255
		if (!v)
256
			continue;
257
 
258
		if (v->is_rel()) {
259
			r |= process_maydef(v);
260
		} else
261
			r |= remove_val(v);
262
	}
263
	return r;
264
}
265
 
266
bool r600_sb::liveness::visit(node& n, bool enter) {
267
	if (enter) {
268
		update_interferences();
269
		process_op(n);
270
	}
271
	return false;
272
}
273
 
274
bool liveness::process_outs(node& n) {
275
	bool alive = remove_vec(n.dst);
276
	if (alive)
277
		live_changed = true;
278
	return alive;
279
}
280
 
281
bool liveness::add_vec(vvec &vv, bool src) {
282
	bool r = false;
283
	for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
284
		value *v = *I;
285
		if (!v || v->is_readonly())
286
			continue;
287
 
288
		if (v->is_rel()) {
289
			r |= add_vec(v->muse, true);
290
			if (v->rel->is_any_reg())
291
				r |= live.add_val(v->rel);
292
 
293
		} else if (src) {
294
			r |= live.add_val(v);
295
		}
296
	}
297
 
298
	return r;
299
}
300
 
301
void liveness::process_ins(node& n) {
302
	if (!(n.flags & NF_DEAD)) {
303
 
304
		live_changed |= add_vec(n.src, true);
305
		live_changed |= add_vec(n.dst, false);
306
 
307
		if (n.type == NT_IF) {
308
			if_node &in = (if_node&)n;
309
			if (in.cond)
310
				live_changed |= live.add_val(in.cond);
311
		}
312
		if (n.pred)
313
			live_changed |= live.add_val(n.pred);
314
	}
315
}
316
 
317
void liveness::process_op(node& n) {
318
 
319
	LIV_DUMP(
320
		sblog << "process_op: ";
321
		dump::dump_op(&n);
322
		sblog << "\n";
323
		sblog << "process_op: live_after:";
324
		dump::dump_set(sh, live);
325
		sblog << "\n";
326
	);
327
 
328
	if(!n.dst.empty() || n.is_cf_op(CF_OP_CALL_FS)) {
329
		if (!process_outs(n)) {
330
			if (!(n.flags & NF_DONT_KILL))
331
				n.flags |= NF_DEAD;
332
		} else {
333
			n.flags &= ~NF_DEAD;
334
		}
335
	}
336
	process_ins(n);
337
 
338
	LIV_DUMP(
339
		sblog << "process_op: live_before:";
340
		dump::dump_set(sh, live);
341
		sblog << "\n";
342
	);
343
}
344
 
345
int liveness::init() {
346
 
347
	if (sh.compute_interferences) {
348
		gpr_array_vec &vv = sh.arrays();
349
		for (gpr_array_vec::iterator I = vv.begin(), E = vv.end(); I != E;
350
				++I) {
351
			gpr_array *a = *I;
352
			a->interferences.clear();
353
		}
354
	}
355
 
356
	return 0;
357
}
358
 
359
void liveness::update_src_vec(vvec &vv, bool src) {
360
	for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
361
		value *v = *I;
362
 
363
		if (!v || !v->is_sgpr())
364
			continue;
365
 
366
		if (v->rel && v->rel->is_dead())
367
			v->rel->flags &= ~VLF_DEAD;
368
 
369
		if (src && v->is_dead()) {
370
			v->flags &= ~VLF_DEAD;
371
		}
372
	}
373
}
374
 
375
void liveness::process_phi_outs(container_node *phi) {
376
	for (node_iterator I = phi->begin(), E = phi->end(); I != E; ++I) {
377
		node *n = *I;
378
		if (!process_outs(*n)) {
379
			n->flags |= NF_DEAD;
380
		} else {
381
			n->flags &= ~NF_DEAD;
382
			update_src_vec(n->src, true);
383
			update_src_vec(n->dst, false);
384
		}
385
	}
386
}
387
 
388
void liveness::process_phi_branch(container_node* phi, unsigned id) {
389
	val_set &s = live;
390
	for (node_iterator I = phi->begin(), E = phi->end(); I != E; ++I) {
391
		node *n = *I;
392
		if (n->is_dead())
393
			continue;
394
 
395
		value *v = n->src[id];
396
 
397
		if (!v->is_readonly()) {
398
			live_changed |= s.add_val(v);
399
			v->flags &= ~VLF_DEAD;
400
		}
401
	}
402
}
403
 
404
} //namespace r600_sb