+++ /dev/null
-/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
-
-/*
- * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Authors:
- * Rob Clark <robclark@freedesktop.org>
- */
-
-#include <stdarg.h>
-
-#include "ir3.h"
-
-#define PTRID(x) ((unsigned long)(x))
-
-struct ir3_dump_ctx {
- FILE *f;
- bool verbose;
-};
-
-static void dump_instr_name(struct ir3_dump_ctx *ctx,
- struct ir3_instruction *instr)
-{
- /* for debugging: */
- if (ctx->verbose) {
-#ifdef DEBUG
- fprintf(ctx->f, "%04u:", instr->serialno);
-#endif
- fprintf(ctx->f, "%03u: ", instr->depth);
- }
-
- if (instr->flags & IR3_INSTR_SY)
- fprintf(ctx->f, "(sy)");
- if (instr->flags & IR3_INSTR_SS)
- fprintf(ctx->f, "(ss)");
-
- if (is_meta(instr)) {
- switch(instr->opc) {
- case OPC_META_PHI:
- fprintf(ctx->f, "Φ");
- break;
- default:
- /* shouldn't hit here.. just for debugging: */
- switch (instr->opc) {
- case OPC_META_INPUT: fprintf(ctx->f, "_meta:in"); break;
- case OPC_META_OUTPUT: fprintf(ctx->f, "_meta:out"); break;
- case OPC_META_FO: fprintf(ctx->f, "_meta:fo"); break;
- case OPC_META_FI: fprintf(ctx->f, "_meta:fi"); break;
- case OPC_META_FLOW: fprintf(ctx->f, "_meta:flow"); break;
-
- default: fprintf(ctx->f, "_meta:%d", instr->opc); break;
- }
- break;
- }
- } else if (instr->category == 1) {
- static const char *type[] = {
- [TYPE_F16] = "f16",
- [TYPE_F32] = "f32",
- [TYPE_U16] = "u16",
- [TYPE_U32] = "u32",
- [TYPE_S16] = "s16",
- [TYPE_S32] = "s32",
- [TYPE_U8] = "u8",
- [TYPE_S8] = "s8",
- };
- if (instr->cat1.src_type == instr->cat1.dst_type)
- fprintf(ctx->f, "mov");
- else
- fprintf(ctx->f, "cov");
- fprintf(ctx->f, ".%s%s", type[instr->cat1.src_type], type[instr->cat1.dst_type]);
- } else {
- fprintf(ctx->f, "%s", ir3_instr_name(instr));
- if (instr->flags & IR3_INSTR_3D)
- fprintf(ctx->f, ".3d");
- if (instr->flags & IR3_INSTR_A)
- fprintf(ctx->f, ".a");
- if (instr->flags & IR3_INSTR_O)
- fprintf(ctx->f, ".o");
- if (instr->flags & IR3_INSTR_P)
- fprintf(ctx->f, ".p");
- if (instr->flags & IR3_INSTR_S)
- fprintf(ctx->f, ".s");
- if (instr->flags & IR3_INSTR_S2EN)
- fprintf(ctx->f, ".s2en");
- }
-}
-
-static void dump_reg_name(struct ir3_dump_ctx *ctx,
- struct ir3_register *reg, bool followssa)
-{
- if ((reg->flags & (IR3_REG_FABS | IR3_REG_SABS)) &&
- (reg->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT)))
- fprintf(ctx->f, "(absneg)");
- else if (reg->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT))
- fprintf(ctx->f, "(neg)");
- else if (reg->flags & (IR3_REG_FABS | IR3_REG_SABS))
- fprintf(ctx->f, "(abs)");
-
- if (reg->flags & IR3_REG_IMMED) {
- fprintf(ctx->f, "imm[%f,%d,0x%x]", reg->fim_val, reg->iim_val, reg->iim_val);
- } else if (reg->flags & IR3_REG_SSA) {
- if (ctx->verbose) {
- fprintf(ctx->f, "_");
- if (followssa) {
- fprintf(ctx->f, "[");
- dump_instr_name(ctx, reg->instr);
- fprintf(ctx->f, "]");
- }
- }
- } else if (reg->flags & IR3_REG_RELATIV) {
- if (reg->flags & IR3_REG_HALF)
- fprintf(ctx->f, "h");
- if (reg->flags & IR3_REG_CONST)
- fprintf(ctx->f, "c<a0.x + %u>", reg->num);
- else
- fprintf(ctx->f, "\x1b[0;31mr<a0.x + %u>\x1b[0m (%u)", reg->num, reg->size);
- } else {
- if (reg->flags & IR3_REG_HALF)
- fprintf(ctx->f, "h");
- if (reg->flags & IR3_REG_CONST)
- fprintf(ctx->f, "c%u.%c", reg_num(reg), "xyzw"[reg_comp(reg)]);
- else
- fprintf(ctx->f, "\x1b[0;31mr%u.%c\x1b[0m", reg_num(reg), "xyzw"[reg_comp(reg)]);
- }
-}
-
-static void ir3_instr_dump(struct ir3_dump_ctx *ctx,
- struct ir3_instruction *instr);
-static void ir3_block_dump(struct ir3_dump_ctx *ctx,
- struct ir3_block *block, const char *name);
-
-static void dump_instr(struct ir3_dump_ctx *ctx,
- struct ir3_instruction *instr)
-{
- /* if we've already visited this instruction, bail now: */
- if (ir3_instr_check_mark(instr))
- return;
-
- /* some meta-instructions need to be handled specially: */
- if (is_meta(instr)) {
- if ((instr->opc == OPC_META_FO) ||
- (instr->opc == OPC_META_FI)) {
- struct ir3_instruction *src;
- foreach_ssa_src(src, instr)
- dump_instr(ctx, src);
- } else if (instr->opc == OPC_META_FLOW) {
- struct ir3_register *reg = instr->regs[1];
- ir3_block_dump(ctx, instr->flow.if_block, "if");
- if (instr->flow.else_block)
- ir3_block_dump(ctx, instr->flow.else_block, "else");
- if (reg->flags & IR3_REG_SSA)
- dump_instr(ctx, reg->instr);
- } else if (instr->opc == OPC_META_PHI) {
- /* treat like a normal instruction: */
- ir3_instr_dump(ctx, instr);
- }
- } else {
- ir3_instr_dump(ctx, instr);
- }
-}
-
-/* arrarraggh! if link is to something outside of the current block, we
- * need to defer emitting the link until the end of the block, since the
- * edge triggers pre-creation of the node it links to inside the cluster,
- * even though it is meant to be outside..
- */
-static struct {
- char buf[40960];
- unsigned n;
-} edge_buf;
-
-/* helper to print or defer: */
-static void printdef(struct ir3_dump_ctx *ctx,
- bool defer, const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- if (defer) {
- unsigned n = edge_buf.n;
- n += vsnprintf(&edge_buf.buf[n], sizeof(edge_buf.buf) - n,
- fmt, ap);
- edge_buf.n = n;
- } else {
- vfprintf(ctx->f, fmt, ap);
- }
- va_end(ap);
-}
-
-static void dump_link2(struct ir3_dump_ctx *ctx,
- struct ir3_instruction *instr, const char *target, bool defer)
-{
- /* some meta-instructions need to be handled specially: */
- if (is_meta(instr)) {
- if (instr->opc == OPC_META_INPUT) {
- printdef(ctx, defer, "input%lx:<in%u>:w -> %s",
- PTRID(instr->inout.block),
- instr->regs[0]->num, target);
- } else if (instr->opc == OPC_META_FO) {
- struct ir3_register *reg = instr->regs[1];
- dump_link2(ctx, reg->instr, target, defer);
- printdef(ctx, defer, "[label=\".%c\"]",
- "xyzw"[instr->fo.off & 0x3]);
- } else if (instr->opc == OPC_META_FI) {
- struct ir3_instruction *src;
-
- foreach_ssa_src_n(src, i, instr) {
- dump_link2(ctx, src, target, defer);
- printdef(ctx, defer, "[label=\".%c\"]",
- "xyzw"[i & 0x3]);
- }
- } else if (instr->opc == OPC_META_OUTPUT) {
- printdef(ctx, defer, "output%lx:<out%u>:w -> %s",
- PTRID(instr->inout.block),
- instr->regs[0]->num, target);
- } else if (instr->opc == OPC_META_PHI) {
- /* treat like a normal instruction: */
- printdef(ctx, defer, "instr%lx:<dst0> -> %s", PTRID(instr), target);
- }
- } else {
- printdef(ctx, defer, "instr%lx:<dst0> -> %s", PTRID(instr), target);
- }
-}
-
-static void dump_link(struct ir3_dump_ctx *ctx,
- struct ir3_instruction *instr,
- struct ir3_block *block, const char *target)
-{
- bool defer = instr->block != block;
- dump_link2(ctx, instr, target, defer);
- printdef(ctx, defer, "\n");
-}
-
-static struct ir3_register *follow_flow(struct ir3_register *reg)
-{
- if (reg->flags & IR3_REG_SSA) {
- struct ir3_instruction *instr = reg->instr;
- /* go with the flow.. */
- if (is_meta(instr) && (instr->opc == OPC_META_FLOW))
- return instr->regs[1];
- }
- return reg;
-}
-
-static void ir3_instr_dump(struct ir3_dump_ctx *ctx,
- struct ir3_instruction *instr)
-{
- struct ir3_register *src;
-
- fprintf(ctx->f, "instr%lx [shape=record,style=filled,fillcolor=lightgrey,label=\"{",
- PTRID(instr));
- dump_instr_name(ctx, instr);
-
- /* destination register: */
- fprintf(ctx->f, "|<dst0>");
-
- /* source register(s): */
- foreach_src_n(src, i, instr) {
- struct ir3_register *reg = follow_flow(src);
-
- fprintf(ctx->f, "|");
-
- if (reg->flags & IR3_REG_SSA)
- fprintf(ctx->f, "<src%u> ", i);
-
- dump_reg_name(ctx, reg, true);
- }
-
- fprintf(ctx->f, "}\"];\n");
-
- /* and recursively dump dependent instructions: */
- foreach_src_n(src, i, instr) {
- struct ir3_register *reg = follow_flow(src);
- char target[32]; /* link target */
-
- if (!(reg->flags & IR3_REG_SSA))
- continue;
-
- snprintf(target, sizeof(target), "instr%lx:<src%u>",
- PTRID(instr), i);
-
- dump_instr(ctx, reg->instr);
- dump_link(ctx, reg->instr, instr->block, target);
- }
-}
-
-static void ir3_block_dump(struct ir3_dump_ctx *ctx,
- struct ir3_block *block, const char *name)
-{
- unsigned i, n;
-
- n = edge_buf.n;
-
- fprintf(ctx->f, "subgraph cluster%lx {\n", PTRID(block));
- fprintf(ctx->f, "label=\"%s\";\n", name);
-
- /* draw inputs: */
- fprintf(ctx->f, "input%lx [shape=record,label=\"inputs", PTRID(block));
- for (i = 0; i < block->ninputs; i++)
- if (block->inputs[i])
- fprintf(ctx->f, "|<in%u> i%u.%c", i, (i >> 2), "xyzw"[i & 0x3]);
- fprintf(ctx->f, "\"];\n");
-
- /* draw instruction graph: */
- for (i = 0; i < block->noutputs; i++)
- if (block->outputs[i])
- dump_instr(ctx, block->outputs[i]);
-
- /* draw outputs: */
- fprintf(ctx->f, "output%lx [shape=record,label=\"outputs", PTRID(block));
- for (i = 0; i < block->noutputs; i++)
- fprintf(ctx->f, "|<out%u> o%u.%c", i, (i >> 2), "xyzw"[i & 0x3]);
- fprintf(ctx->f, "\"];\n");
-
- /* and links to outputs: */
- for (i = 0; i < block->noutputs; i++) {
- char target[32]; /* link target */
-
- /* NOTE: there could be outputs that are never assigned,
- * so skip them
- */
- if (!block->outputs[i])
- continue;
-
- snprintf(target, sizeof(target), "output%lx:<out%u>:e",
- PTRID(block), i);
-
- dump_link(ctx, block->outputs[i], block, target);
- }
-
- fprintf(ctx->f, "}\n");
-
- /* and links to inputs: */
- if (block->parent) {
- for (i = 0; i < block->ninputs; i++) {
- char target[32]; /* link target */
-
- if (!block->inputs[i])
- continue;
-
- dump_instr(ctx, block->inputs[i]);
-
- snprintf(target, sizeof(target), "input%lx:<in%u>:e",
- PTRID(block), i);
-
- dump_link(ctx, block->inputs[i], block, target);
- }
- }
-
- /* dump deferred edges: */
- if (edge_buf.n > n) {
- fprintf(ctx->f, "%*s", edge_buf.n - n, &edge_buf.buf[n]);
- edge_buf.n = n;
- }
-}
-
-void ir3_dump(struct ir3 *shader, const char *name,
- struct ir3_block *block /* XXX maybe 'block' ptr should move to ir3? */,
- FILE *f)
-{
- struct ir3_dump_ctx ctx = {
- .f = f,
- };
- ir3_clear_mark(shader);
- fprintf(ctx.f, "digraph G {\n");
- fprintf(ctx.f, "rankdir=RL;\n");
- fprintf(ctx.f, "nodesep=0.25;\n");
- fprintf(ctx.f, "ranksep=1.5;\n");
- ir3_block_dump(&ctx, block, name);
- fprintf(ctx.f, "}\n");
-}
-
-/*
- * For Debugging:
- */
-
-void
-ir3_dump_instr_single(struct ir3_instruction *instr)
-{
- struct ir3_dump_ctx ctx = {
- .f = stdout,
- .verbose = true,
- };
- unsigned i;
-
- dump_instr_name(&ctx, instr);
- for (i = 0; i < instr->regs_count; i++) {
- struct ir3_register *reg = instr->regs[i];
- printf(i ? ", " : " ");
- dump_reg_name(&ctx, reg, !!i);
- }
-
- if (instr->address) {
- fprintf(ctx.f, ", address=_");
- fprintf(ctx.f, "[");
- dump_instr_name(&ctx, instr->address);
- fprintf(ctx.f, "]");
- }
-
- if (instr->fanin) {
- fprintf(ctx.f, ", fanin=_");
- fprintf(ctx.f, "[");
- dump_instr_name(&ctx, instr->fanin);
- fprintf(ctx.f, "]");
- }
-
- if (is_meta(instr)) {
- if (instr->opc == OPC_META_FO) {
- printf(", off=%d", instr->fo.off);
- } else if ((instr->opc == OPC_META_FI) && instr->fi.aid) {
- printf(", aid=%d", instr->fi.aid);
- }
- }
-
- printf("\n");
-}
-
-void
-ir3_dump_instr_list(struct ir3_instruction *instr)
-{
- struct ir3_block *block = instr->block;
- unsigned n = 0;
-
- while (instr) {
- ir3_dump_instr_single(instr);
- if (!is_meta(instr))
- n++;
- instr = instr->next;
- }
- printf("%u instructions\n", n);
-
- for (n = 0; n < block->noutputs; n++) {
- if (!block->outputs[n])
- continue;
- printf("out%d: ", n);
- ir3_dump_instr_single(block->outputs[n]);
- }
-}
--- /dev/null
+/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
+
+/*
+ * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ * Rob Clark <robclark@freedesktop.org>
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "ir3.h"
+
+#define PTRID(x) ((unsigned long)(x))
+
+static void print_instr_name(struct ir3_instruction *instr)
+{
+#ifdef DEBUG
+ printf("%04u:", instr->serialno);
+#endif
+ printf("%03u: ", instr->depth);
+
+ if (instr->flags & IR3_INSTR_SY)
+ printf("(sy)");
+ if (instr->flags & IR3_INSTR_SS)
+ printf("(ss)");
+
+ if (is_meta(instr)) {
+ switch(instr->opc) {
+ case OPC_META_PHI:
+ printf("Φ");
+ break;
+ default:
+ /* shouldn't hit here.. just for debugging: */
+ switch (instr->opc) {
+ case OPC_META_INPUT: printf("_meta:in"); break;
+ case OPC_META_OUTPUT: printf("_meta:out"); break;
+ case OPC_META_FO: printf("_meta:fo"); break;
+ case OPC_META_FI: printf("_meta:fi"); break;
+ case OPC_META_FLOW: printf("_meta:flow"); break;
+
+ default: printf("_meta:%d", instr->opc); break;
+ }
+ break;
+ }
+ } else if (instr->category == 1) {
+ static const char *type[] = {
+ [TYPE_F16] = "f16",
+ [TYPE_F32] = "f32",
+ [TYPE_U16] = "u16",
+ [TYPE_U32] = "u32",
+ [TYPE_S16] = "s16",
+ [TYPE_S32] = "s32",
+ [TYPE_U8] = "u8",
+ [TYPE_S8] = "s8",
+ };
+ if (instr->cat1.src_type == instr->cat1.dst_type)
+ printf("mov");
+ else
+ printf("cov");
+ printf(".%s%s", type[instr->cat1.src_type], type[instr->cat1.dst_type]);
+ } else {
+ printf("%s", ir3_instr_name(instr));
+ if (instr->flags & IR3_INSTR_3D)
+ printf(".3d");
+ if (instr->flags & IR3_INSTR_A)
+ printf(".a");
+ if (instr->flags & IR3_INSTR_O)
+ printf(".o");
+ if (instr->flags & IR3_INSTR_P)
+ printf(".p");
+ if (instr->flags & IR3_INSTR_S)
+ printf(".s");
+ if (instr->flags & IR3_INSTR_S2EN)
+ printf(".s2en");
+ }
+}
+
+static void print_reg_name(struct ir3_register *reg, bool followssa)
+{
+ if ((reg->flags & (IR3_REG_FABS | IR3_REG_SABS)) &&
+ (reg->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT)))
+ printf("(absneg)");
+ else if (reg->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT))
+ printf("(neg)");
+ else if (reg->flags & (IR3_REG_FABS | IR3_REG_SABS))
+ printf("(abs)");
+
+ if (reg->flags & IR3_REG_IMMED) {
+ printf("imm[%f,%d,0x%x]", reg->fim_val, reg->iim_val, reg->iim_val);
+ } else if (reg->flags & IR3_REG_SSA) {
+ printf("_");
+ if (followssa) {
+ printf("[");
+ print_instr_name(reg->instr);
+ printf("]");
+ }
+ } else if (reg->flags & IR3_REG_RELATIV) {
+ if (reg->flags & IR3_REG_HALF)
+ printf("h");
+ if (reg->flags & IR3_REG_CONST)
+ printf("c<a0.x + %u>", reg->num);
+ else
+ printf("\x1b[0;31mr<a0.x + %u>\x1b[0m (%u)", reg->num, reg->size);
+ } else {
+ if (reg->flags & IR3_REG_HALF)
+ printf("h");
+ if (reg->flags & IR3_REG_CONST)
+ printf("c%u.%c", reg_num(reg), "xyzw"[reg_comp(reg)]);
+ else
+ printf("\x1b[0;31mr%u.%c\x1b[0m", reg_num(reg), "xyzw"[reg_comp(reg)]);
+ }
+}
+
+static void
+tab(int lvl)
+{
+ for (int i = 0; i < lvl; i++)
+ printf("\t");
+}
+
+static void
+print_instr(struct ir3_instruction *instr, int lvl)
+{
+ unsigned i;
+
+ tab(lvl);
+
+ print_instr_name(instr);
+ for (i = 0; i < instr->regs_count; i++) {
+ struct ir3_register *reg = instr->regs[i];
+ printf(i ? ", " : " ");
+ print_reg_name(reg, !!i);
+ }
+
+ if (instr->address) {
+ printf(", address=_");
+ printf("[");
+ print_instr_name(instr->address);
+ printf("]");
+ }
+
+ if (instr->fanin) {
+ printf(", fanin=_");
+ printf("[");
+ print_instr_name(instr->fanin);
+ printf("]");
+ }
+
+ if (is_meta(instr)) {
+ if (instr->opc == OPC_META_FO) {
+ printf(", off=%d", instr->fo.off);
+ } else if ((instr->opc == OPC_META_FI) && instr->fi.aid) {
+ printf(", aid=%d", instr->fi.aid);
+ }
+ }
+
+ printf("\n");
+}
+
+void ir3_print_instr(struct ir3_instruction *instr)
+{
+ print_instr(instr, 0);
+}
+
+static void
+print_block(struct ir3_block *block, int lvl)
+{
+ struct ir3_instruction *instr;
+ tab(lvl); printf("block {\n");
+ for (instr = block->head; instr; instr = instr->next) {
+ print_instr(instr, lvl+1);
+ }
+ tab(lvl); printf("}\n");
+}
+
+void
+ir3_print(struct ir3 *ir)
+{
+ struct ir3_block *block = ir->block;
+
+ print_block(block, 0);
+
+ for (unsigned i = 0; i < block->noutputs; i++) {
+ if (!block->outputs[i])
+ continue;
+ printf("out%d: ", i);
+ print_instr(block->outputs[i], 0);
+ }
+}