Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 1
/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
2
 
3
/*
4
 * Copyright (C) 2014 Rob Clark 
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the "Software"),
8
 * to deal in the Software without restriction, including without limitation
9
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
 * and/or sell copies of the Software, and to permit persons to whom the
11
 * Software is furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice (including the next
14
 * paragraph) shall be included in all copies or substantial portions of the
15
 * Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE.
24
 *
25
 * Authors:
26
 *    Rob Clark 
27
 */
28
 
29
#include 
30
 
31
#include "ir3.h"
32
 
33
#define PTRID(x) ((unsigned long)(x))
34
 
35
struct ir3_dump_ctx {
36
	FILE *f;
37
	bool verbose;
38
};
39
 
40
static void dump_instr_name(struct ir3_dump_ctx *ctx,
41
		struct ir3_instruction *instr)
42
{
43
	/* for debugging: */
44
	if (ctx->verbose) {
45
#ifdef DEBUG
46
		fprintf(ctx->f, "%04u:", instr->serialno);
47
#endif
48
		fprintf(ctx->f, "%03u: ", instr->depth);
49
	}
50
 
51
	if (instr->flags & IR3_INSTR_SY)
52
		fprintf(ctx->f, "(sy)");
53
	if (instr->flags & IR3_INSTR_SS)
54
		fprintf(ctx->f, "(ss)");
55
 
56
	if (is_meta(instr)) {
57
		switch(instr->opc) {
58
		case OPC_META_PHI:
59
			fprintf(ctx->f, "Φ");
60
			break;
61
		default:
62
			/* shouldn't hit here.. just for debugging: */
63
			switch (instr->opc) {
64
			case OPC_META_INPUT:  fprintf(ctx->f, "_meta:in");   break;
65
			case OPC_META_OUTPUT: fprintf(ctx->f, "_meta:out");  break;
66
			case OPC_META_FO:     fprintf(ctx->f, "_meta:fo");   break;
67
			case OPC_META_FI:     fprintf(ctx->f, "_meta:fi");   break;
68
			case OPC_META_FLOW:   fprintf(ctx->f, "_meta:flow"); break;
69
 
70
			default: fprintf(ctx->f, "_meta:%d", instr->opc); break;
71
			}
72
			break;
73
		}
74
	} else if (instr->category == 1) {
75
		static const char *type[] = {
76
				[TYPE_F16] = "f16",
77
				[TYPE_F32] = "f32",
78
				[TYPE_U16] = "u16",
79
				[TYPE_U32] = "u32",
80
				[TYPE_S16] = "s16",
81
				[TYPE_S32] = "s32",
82
				[TYPE_U8]  = "u8",
83
				[TYPE_S8]  = "s8",
84
		};
85
		if (instr->cat1.src_type == instr->cat1.dst_type)
86
			fprintf(ctx->f, "mov");
87
		else
88
			fprintf(ctx->f, "cov");
89
		fprintf(ctx->f, ".%s%s", type[instr->cat1.src_type], type[instr->cat1.dst_type]);
90
	} else {
91
		fprintf(ctx->f, "%s", ir3_instr_name(instr));
92
		if (instr->flags & IR3_INSTR_3D)
93
			fprintf(ctx->f, ".3d");
94
		if (instr->flags & IR3_INSTR_A)
95
			fprintf(ctx->f, ".a");
96
		if (instr->flags & IR3_INSTR_O)
97
			fprintf(ctx->f, ".o");
98
		if (instr->flags & IR3_INSTR_P)
99
			fprintf(ctx->f, ".p");
100
		if (instr->flags & IR3_INSTR_S)
101
			fprintf(ctx->f, ".s");
102
		if (instr->flags & IR3_INSTR_S2EN)
103
			fprintf(ctx->f, ".s2en");
104
	}
105
}
106
 
107
static void dump_reg_name(struct ir3_dump_ctx *ctx,
108
		struct ir3_register *reg, bool followssa)
109
{
110
	if ((reg->flags & (IR3_REG_FABS | IR3_REG_SABS)) &&
111
			(reg->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT)))
112
		fprintf(ctx->f, "(absneg)");
113
	else if (reg->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT))
114
		fprintf(ctx->f, "(neg)");
115
	else if (reg->flags & (IR3_REG_FABS | IR3_REG_SABS))
116
		fprintf(ctx->f, "(abs)");
117
 
118
	if (reg->flags & IR3_REG_IMMED) {
119
		fprintf(ctx->f, "imm[%f,%d,0x%x]", reg->fim_val, reg->iim_val, reg->iim_val);
120
	} else if (reg->flags & IR3_REG_SSA) {
121
		if (ctx->verbose) {
122
			fprintf(ctx->f, "_");
123
			if (followssa) {
124
				fprintf(ctx->f, "[");
125
				dump_instr_name(ctx, reg->instr);
126
				fprintf(ctx->f, "]");
127
			}
128
		}
129
	} else if (reg->flags & IR3_REG_RELATIV) {
130
		if (reg->flags & IR3_REG_HALF)
131
			fprintf(ctx->f, "h");
132
		if (reg->flags & IR3_REG_CONST)
133
			fprintf(ctx->f, "c", reg->num);
134
		else
135
			fprintf(ctx->f, "\x1b[0;31mr\x1b[0m (%u)", reg->num, reg->size);
136
	} else {
137
		if (reg->flags & IR3_REG_HALF)
138
			fprintf(ctx->f, "h");
139
		if (reg->flags & IR3_REG_CONST)
140
			fprintf(ctx->f, "c%u.%c", reg_num(reg), "xyzw"[reg_comp(reg)]);
141
		else
142
			fprintf(ctx->f, "\x1b[0;31mr%u.%c\x1b[0m", reg_num(reg), "xyzw"[reg_comp(reg)]);
143
	}
144
}
145
 
146
static void ir3_instr_dump(struct ir3_dump_ctx *ctx,
147
		struct ir3_instruction *instr);
148
static void ir3_block_dump(struct ir3_dump_ctx *ctx,
149
		struct ir3_block *block, const char *name);
150
 
151
static void dump_instr(struct ir3_dump_ctx *ctx,
152
		struct ir3_instruction *instr)
153
{
154
	/* if we've already visited this instruction, bail now: */
155
	if (ir3_instr_check_mark(instr))
156
		return;
157
 
158
	/* some meta-instructions need to be handled specially: */
159
	if (is_meta(instr)) {
160
		if ((instr->opc == OPC_META_FO) ||
161
				(instr->opc == OPC_META_FI)) {
162
			struct ir3_instruction *src;
163
			foreach_ssa_src(src, instr)
164
				dump_instr(ctx, src);
165
		} else if (instr->opc == OPC_META_FLOW) {
166
			struct ir3_register *reg = instr->regs[1];
167
			ir3_block_dump(ctx, instr->flow.if_block, "if");
168
			if (instr->flow.else_block)
169
				ir3_block_dump(ctx, instr->flow.else_block, "else");
170
			if (reg->flags & IR3_REG_SSA)
171
				dump_instr(ctx, reg->instr);
172
		} else if (instr->opc == OPC_META_PHI) {
173
			/* treat like a normal instruction: */
174
			ir3_instr_dump(ctx, instr);
175
		}
176
	} else {
177
		ir3_instr_dump(ctx, instr);
178
	}
179
}
180
 
181
/* arrarraggh!  if link is to something outside of the current block, we
182
 * need to defer emitting the link until the end of the block, since the
183
 * edge triggers pre-creation of the node it links to inside the cluster,
184
 * even though it is meant to be outside..
185
 */
186
static struct {
187
	char buf[40960];
188
	unsigned n;
189
} edge_buf;
190
 
191
/* helper to print or defer: */
192
static void printdef(struct ir3_dump_ctx *ctx,
193
		bool defer, const char *fmt, ...)
194
{
195
	va_list ap;
196
	va_start(ap, fmt);
197
	if (defer) {
198
		unsigned n = edge_buf.n;
199
		n += vsnprintf(&edge_buf.buf[n], sizeof(edge_buf.buf) - n,
200
				fmt, ap);
201
		edge_buf.n = n;
202
	} else {
203
		vfprintf(ctx->f, fmt, ap);
204
	}
205
	va_end(ap);
206
}
207
 
208
static void dump_link2(struct ir3_dump_ctx *ctx,
209
		struct ir3_instruction *instr, const char *target, bool defer)
210
{
211
	/* some meta-instructions need to be handled specially: */
212
	if (is_meta(instr)) {
213
		if (instr->opc == OPC_META_INPUT) {
214
			printdef(ctx, defer, "input%lx::w -> %s",
215
					PTRID(instr->inout.block),
216
					instr->regs[0]->num, target);
217
		} else if (instr->opc == OPC_META_FO) {
218
			struct ir3_register *reg = instr->regs[1];
219
			dump_link2(ctx, reg->instr, target, defer);
220
			printdef(ctx, defer, "[label=\".%c\"]",
221
					"xyzw"[instr->fo.off & 0x3]);
222
		} else if (instr->opc == OPC_META_FI) {
223
			struct ir3_instruction *src;
224
 
225
			foreach_ssa_src_n(src, i, instr) {
226
				dump_link2(ctx, src, target, defer);
227
				printdef(ctx, defer, "[label=\".%c\"]",
228
						"xyzw"[i & 0x3]);
229
			}
230
		} else if (instr->opc == OPC_META_OUTPUT) {
231
			printdef(ctx, defer, "output%lx::w -> %s",
232
					PTRID(instr->inout.block),
233
					instr->regs[0]->num, target);
234
		} else if (instr->opc == OPC_META_PHI) {
235
			/* treat like a normal instruction: */
236
			printdef(ctx, defer, "instr%lx: -> %s", PTRID(instr), target);
237
		}
238
	} else {
239
		printdef(ctx, defer, "instr%lx: -> %s", PTRID(instr), target);
240
	}
241
}
242
 
243
static void dump_link(struct ir3_dump_ctx *ctx,
244
		struct ir3_instruction *instr,
245
		struct ir3_block *block, const char *target)
246
{
247
	bool defer = instr->block != block;
248
	dump_link2(ctx, instr, target, defer);
249
	printdef(ctx, defer, "\n");
250
}
251
 
252
static struct ir3_register *follow_flow(struct ir3_register *reg)
253
{
254
	if (reg->flags & IR3_REG_SSA) {
255
		struct ir3_instruction *instr = reg->instr;
256
		/* go with the flow.. */
257
		if (is_meta(instr) && (instr->opc == OPC_META_FLOW))
258
			return instr->regs[1];
259
	}
260
	return reg;
261
}
262
 
263
static void ir3_instr_dump(struct ir3_dump_ctx *ctx,
264
		struct ir3_instruction *instr)
265
{
266
	struct ir3_register *src;
267
 
268
	fprintf(ctx->f, "instr%lx [shape=record,style=filled,fillcolor=lightgrey,label=\"{",
269
			PTRID(instr));
270
	dump_instr_name(ctx, instr);
271
 
272
	/* destination register: */
273
	fprintf(ctx->f, "|");
274
 
275
	/* source register(s): */
276
	foreach_src_n(src, i, instr) {
277
		struct ir3_register *reg = follow_flow(src);
278
 
279
		fprintf(ctx->f, "|");
280
 
281
		if (reg->flags & IR3_REG_SSA)
282
			fprintf(ctx->f, " ", i);
283
 
284
		dump_reg_name(ctx, reg, true);
285
	}
286
 
287
	fprintf(ctx->f, "}\"];\n");
288
 
289
	/* and recursively dump dependent instructions: */
290
	foreach_src_n(src, i, instr) {
291
		struct ir3_register *reg = follow_flow(src);
292
		char target[32];  /* link target */
293
 
294
		if (!(reg->flags & IR3_REG_SSA))
295
			continue;
296
 
297
		snprintf(target, sizeof(target), "instr%lx:",
298
				PTRID(instr), i);
299
 
300
		dump_instr(ctx, reg->instr);
301
		dump_link(ctx, reg->instr, instr->block, target);
302
	}
303
}
304
 
305
static void ir3_block_dump(struct ir3_dump_ctx *ctx,
306
		struct ir3_block *block, const char *name)
307
{
308
	unsigned i, n;
309
 
310
	n = edge_buf.n;
311
 
312
	fprintf(ctx->f, "subgraph cluster%lx {\n", PTRID(block));
313
	fprintf(ctx->f, "label=\"%s\";\n", name);
314
 
315
	/* draw inputs: */
316
	fprintf(ctx->f, "input%lx [shape=record,label=\"inputs", PTRID(block));
317
	for (i = 0; i < block->ninputs; i++)
318
		if (block->inputs[i])
319
			fprintf(ctx->f, "| i%u.%c", i, (i >> 2), "xyzw"[i & 0x3]);
320
	fprintf(ctx->f, "\"];\n");
321
 
322
	/* draw instruction graph: */
323
	for (i = 0; i < block->noutputs; i++)
324
		if (block->outputs[i])
325
			dump_instr(ctx, block->outputs[i]);
326
 
327
	/* draw outputs: */
328
	fprintf(ctx->f, "output%lx [shape=record,label=\"outputs", PTRID(block));
329
	for (i = 0; i < block->noutputs; i++)
330
		fprintf(ctx->f, "| o%u.%c", i, (i >> 2), "xyzw"[i & 0x3]);
331
	fprintf(ctx->f, "\"];\n");
332
 
333
	/* and links to outputs: */
334
	for (i = 0; i < block->noutputs; i++) {
335
		char target[32];  /* link target */
336
 
337
		/* NOTE: there could be outputs that are never assigned,
338
		 * so skip them
339
		 */
340
		if (!block->outputs[i])
341
			continue;
342
 
343
		snprintf(target, sizeof(target), "output%lx::e",
344
				PTRID(block), i);
345
 
346
		dump_link(ctx, block->outputs[i], block, target);
347
	}
348
 
349
	fprintf(ctx->f, "}\n");
350
 
351
	/* and links to inputs: */
352
	if (block->parent) {
353
		for (i = 0; i < block->ninputs; i++) {
354
			char target[32];  /* link target */
355
 
356
			if (!block->inputs[i])
357
				continue;
358
 
359
			dump_instr(ctx, block->inputs[i]);
360
 
361
			snprintf(target, sizeof(target), "input%lx::e",
362
					PTRID(block), i);
363
 
364
			dump_link(ctx, block->inputs[i], block, target);
365
		}
366
	}
367
 
368
	/* dump deferred edges: */
369
	if (edge_buf.n > n) {
370
		fprintf(ctx->f, "%*s", edge_buf.n - n, &edge_buf.buf[n]);
371
		edge_buf.n = n;
372
	}
373
}
374
 
375
void ir3_dump(struct ir3 *shader, const char *name,
376
		struct ir3_block *block /* XXX maybe 'block' ptr should move to ir3? */,
377
		FILE *f)
378
{
379
	struct ir3_dump_ctx ctx = {
380
			.f = f,
381
	};
382
	ir3_clear_mark(shader);
383
	fprintf(ctx.f, "digraph G {\n");
384
	fprintf(ctx.f, "rankdir=RL;\n");
385
	fprintf(ctx.f, "nodesep=0.25;\n");
386
	fprintf(ctx.f, "ranksep=1.5;\n");
387
	ir3_block_dump(&ctx, block, name);
388
	fprintf(ctx.f, "}\n");
389
}
390
 
391
/*
392
 * For Debugging:
393
 */
394
 
395
void
396
ir3_dump_instr_single(struct ir3_instruction *instr)
397
{
398
	struct ir3_dump_ctx ctx = {
399
			.f = stdout,
400
			.verbose = true,
401
	};
402
	unsigned i;
403
 
404
	dump_instr_name(&ctx, instr);
405
	for (i = 0; i < instr->regs_count; i++) {
406
		struct ir3_register *reg = instr->regs[i];
407
		printf(i ? ", " : " ");
408
		dump_reg_name(&ctx, reg, !!i);
409
	}
410
 
411
	if (instr->address) {
412
		fprintf(ctx.f, ", address=_");
413
		fprintf(ctx.f, "[");
414
		dump_instr_name(&ctx, instr->address);
415
		fprintf(ctx.f, "]");
416
	}
417
 
418
	if (instr->fanin) {
419
		fprintf(ctx.f, ", fanin=_");
420
		fprintf(ctx.f, "[");
421
		dump_instr_name(&ctx, instr->fanin);
422
		fprintf(ctx.f, "]");
423
	}
424
 
425
	if (is_meta(instr)) {
426
		if (instr->opc == OPC_META_FO) {
427
			printf(", off=%d", instr->fo.off);
428
		} else if ((instr->opc == OPC_META_FI) && instr->fi.aid) {
429
			printf(", aid=%d", instr->fi.aid);
430
		}
431
	}
432
 
433
	printf("\n");
434
}
435
 
436
void
437
ir3_dump_instr_list(struct ir3_instruction *instr)
438
{
439
	struct ir3_block *block = instr->block;
440
	unsigned n = 0;
441
 
442
	while (instr) {
443
		ir3_dump_instr_single(instr);
444
		if (!is_meta(instr))
445
			n++;
446
		instr = instr->next;
447
	}
448
	printf("%u instructions\n", n);
449
 
450
	for (n = 0; n < block->noutputs; n++) {
451
		if (!block->outputs[n])
452
			continue;
453
		printf("out%d: ", n);
454
		ir3_dump_instr_single(block->outputs[n]);
455
	}
456
}