Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
  2.  
  3. /*
  4.  * Copyright (C) 2014 Rob Clark <robclark@freedesktop.org>
  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 <robclark@freedesktop.org>
  27.  */
  28.  
  29. #include <stdarg.h>
  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, "&#934;");
  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<a0.x + %u>", reg->num);
  134.                 else
  135.                         fprintf(ctx->f, "\x1b[0;31mr<a0.x + %u>\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:<in%u>: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:<out%u>: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:<dst0> -> %s", PTRID(instr), target);
  237.                 }
  238.         } else {
  239.                 printdef(ctx, defer, "instr%lx:<dst0> -> %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, "|<dst0>");
  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, "<src%u> ", 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:<src%u>",
  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, "|<in%u> 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, "|<out%u> 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:<out%u>: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:<in%u>: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. }
  457.