freedreno/ir3: drop dot graph dumping
At least for now.. right now the instruction and instruction list printing should suffice, and the re-working of ir3_block would require a lot of changes in that code. Signed-off-by: Rob Clark <robclark@freedesktop.org>
This commit is contained in:
@@ -125,13 +125,13 @@ ir3_SOURCES := \
|
||||
ir3/ir3_compiler.h \
|
||||
ir3/ir3_cp.c \
|
||||
ir3/ir3_depth.c \
|
||||
ir3/ir3_dump.c \
|
||||
ir3/ir3_flatten.c \
|
||||
ir3/ir3_group.c \
|
||||
ir3/ir3.h \
|
||||
ir3/ir3_legalize.c \
|
||||
ir3/ir3_nir.h \
|
||||
ir3/ir3_nir_lower_if_else.c \
|
||||
ir3/ir3_print.c \
|
||||
ir3/ir3_ra.c \
|
||||
ir3/ir3_sched.c \
|
||||
ir3/ir3_shader.c \
|
||||
|
||||
@@ -68,7 +68,6 @@ static const struct debug_named_value debug_options[] = {
|
||||
{"fraghalf", FD_DBG_FRAGHALF, "Use half-precision in fragment shader"},
|
||||
{"nobin", FD_DBG_NOBIN, "Disable hw binning"},
|
||||
{"optmsgs", FD_DBG_OPTMSGS,"Enable optimizer debug messages"},
|
||||
{"optdump", FD_DBG_OPTDUMP,"Dump shader DAG to .dot files"},
|
||||
{"glsl120", FD_DBG_GLSL120,"Temporary flag to force GLSL 120 (rather than 130) on a3xx+"},
|
||||
{"nocp", FD_DBG_NOCP, "Disable copy-propagation"},
|
||||
{"nir", FD_DBG_NIR, "Enable experimental NIR compiler"},
|
||||
|
||||
@@ -63,7 +63,6 @@ enum adreno_stencil_op fd_stencil_op(unsigned op);
|
||||
#define FD_DBG_FRAGHALF 0x0080
|
||||
#define FD_DBG_NOBIN 0x0100
|
||||
#define FD_DBG_OPTMSGS 0x0400
|
||||
#define FD_DBG_OPTDUMP 0x0800
|
||||
#define FD_DBG_GLSL120 0x1000
|
||||
#define FD_DBG_NOCP 0x2000
|
||||
#define FD_DBG_NIR 0x4000
|
||||
|
||||
@@ -747,12 +747,8 @@ static inline struct ir3_instruction * __ssa_src_n(struct ir3_instruction *instr
|
||||
|
||||
|
||||
/* dump: */
|
||||
#include <stdio.h>
|
||||
void ir3_dump(struct ir3 *shader, const char *name,
|
||||
struct ir3_block *block /* XXX maybe 'block' ptr should move to ir3? */,
|
||||
FILE *f);
|
||||
void ir3_dump_instr_single(struct ir3_instruction *instr);
|
||||
void ir3_dump_instr_list(struct ir3_instruction *instr);
|
||||
void ir3_print(struct ir3 *ir);
|
||||
void ir3_print_instr(struct ir3_instruction *instr);
|
||||
|
||||
/* flatten if/else: */
|
||||
int ir3_block_flatten(struct ir3_block *block);
|
||||
@@ -765,7 +761,7 @@ void ir3_block_depth(struct ir3_block *block);
|
||||
/* copy-propagate: */
|
||||
void ir3_block_cp(struct ir3_block *block);
|
||||
|
||||
/* group neightbors and insert mov's to resolve conflicts: */
|
||||
/* group neighbors and insert mov's to resolve conflicts: */
|
||||
void ir3_block_group(struct ir3_block *block);
|
||||
|
||||
/* scheduling: */
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <err.h>
|
||||
|
||||
#include "tgsi/tgsi_parse.h"
|
||||
@@ -243,7 +244,7 @@ int main(int argc, char **argv)
|
||||
|
||||
while (n < argc) {
|
||||
if (!strcmp(argv[n], "--verbose")) {
|
||||
fd_mesa_debug |= FD_DBG_OPTDUMP | FD_DBG_MSGS | FD_DBG_OPTMSGS;
|
||||
fd_mesa_debug |= FD_DBG_MSGS | FD_DBG_OPTMSGS;
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3515,22 +3515,6 @@ compile_instructions(struct ir3_compile_context *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
compile_dump(struct ir3_compile_context *ctx)
|
||||
{
|
||||
const char *name = (ctx->so->type == SHADER_VERTEX) ? "vert" : "frag";
|
||||
static unsigned n = 0;
|
||||
char fname[16];
|
||||
FILE *f;
|
||||
snprintf(fname, sizeof(fname), "%s-%04u.dot", name, n++);
|
||||
f = fopen(fname, "w");
|
||||
if (!f)
|
||||
return;
|
||||
ir3_block_depth(ctx->block);
|
||||
ir3_dump(ctx->ir, name, ctx->block, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int
|
||||
ir3_compile_shader(struct ir3_shader_variant *so,
|
||||
const struct tgsi_token *tokens, struct ir3_shader_key key,
|
||||
@@ -3613,20 +3597,15 @@ ir3_compile_shader(struct ir3_shader_variant *so,
|
||||
block->outputs[block->noutputs++] = ctx.kill[i];
|
||||
}
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTDUMP)
|
||||
compile_dump(&ctx);
|
||||
|
||||
ret = ir3_block_flatten(block);
|
||||
if (ret < 0) {
|
||||
DBG("FLATTEN failed!");
|
||||
goto out;
|
||||
}
|
||||
if ((ret > 0) && (fd_mesa_debug & FD_DBG_OPTDUMP))
|
||||
compile_dump(&ctx);
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTMSGS) {
|
||||
printf("BEFORE CP:\n");
|
||||
ir3_dump_instr_list(block->head);
|
||||
ir3_print(so->ir);
|
||||
}
|
||||
|
||||
ir3_block_depth(block);
|
||||
@@ -3641,7 +3620,7 @@ ir3_compile_shader(struct ir3_shader_variant *so,
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTMSGS) {
|
||||
printf("BEFORE GROUPING:\n");
|
||||
ir3_dump_instr_list(block->head);
|
||||
ir3_print(so->ir);
|
||||
}
|
||||
|
||||
/* Group left/right neighbors, inserting mov's where needed to
|
||||
@@ -3649,14 +3628,11 @@ ir3_compile_shader(struct ir3_shader_variant *so,
|
||||
*/
|
||||
ir3_block_group(block);
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTDUMP)
|
||||
compile_dump(&ctx);
|
||||
|
||||
ir3_block_depth(block);
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTMSGS) {
|
||||
printf("AFTER DEPTH:\n");
|
||||
ir3_dump_instr_list(block->head);
|
||||
ir3_print(so->ir);
|
||||
}
|
||||
|
||||
ret = ir3_block_sched(block);
|
||||
@@ -3667,7 +3643,7 @@ ir3_compile_shader(struct ir3_shader_variant *so,
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTMSGS) {
|
||||
printf("AFTER SCHED:\n");
|
||||
ir3_dump_instr_list(block->head);
|
||||
ir3_print(so->ir);
|
||||
}
|
||||
|
||||
ret = ir3_block_ra(block, so->type, so->frag_coord, so->frag_face);
|
||||
@@ -3678,7 +3654,7 @@ ir3_compile_shader(struct ir3_shader_variant *so,
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTMSGS) {
|
||||
printf("AFTER RA:\n");
|
||||
ir3_dump_instr_list(block->head);
|
||||
ir3_print(so->ir);
|
||||
}
|
||||
|
||||
ir3_block_legalize(block, &so->has_samp, &max_bary);
|
||||
|
||||
@@ -1908,22 +1908,6 @@ fixup_frag_inputs(struct ir3_compile *ctx)
|
||||
block->inputs = inputs;
|
||||
}
|
||||
|
||||
static void
|
||||
compile_dump(struct ir3_compile *ctx)
|
||||
{
|
||||
const char *name = (ctx->so->type == SHADER_VERTEX) ? "vert" : "frag";
|
||||
static unsigned n = 0;
|
||||
char fname[16];
|
||||
FILE *f;
|
||||
snprintf(fname, sizeof(fname), "%s-%04u.dot", name, n++);
|
||||
f = fopen(fname, "w");
|
||||
if (!f)
|
||||
return;
|
||||
ir3_block_depth(ctx->block);
|
||||
ir3_dump(ctx->ir, name, ctx->block, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int
|
||||
ir3_compile_shader_nir(struct ir3_shader_variant *so,
|
||||
const struct tgsi_token *tokens, struct ir3_shader_key key)
|
||||
@@ -2008,12 +1992,9 @@ ir3_compile_shader_nir(struct ir3_shader_variant *so,
|
||||
block->outputs[block->noutputs++] = ctx->kill[i];
|
||||
}
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTDUMP)
|
||||
compile_dump(ctx);
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTMSGS) {
|
||||
printf("BEFORE CP:\n");
|
||||
ir3_dump_instr_list(block->head);
|
||||
ir3_print(so->ir);
|
||||
}
|
||||
|
||||
ir3_block_depth(block);
|
||||
@@ -2022,7 +2003,7 @@ ir3_compile_shader_nir(struct ir3_shader_variant *so,
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTMSGS) {
|
||||
printf("BEFORE GROUPING:\n");
|
||||
ir3_dump_instr_list(block->head);
|
||||
ir3_print(so->ir);
|
||||
}
|
||||
|
||||
/* Group left/right neighbors, inserting mov's where needed to
|
||||
@@ -2030,14 +2011,11 @@ ir3_compile_shader_nir(struct ir3_shader_variant *so,
|
||||
*/
|
||||
ir3_block_group(block);
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTDUMP)
|
||||
compile_dump(ctx);
|
||||
|
||||
ir3_block_depth(block);
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTMSGS) {
|
||||
printf("AFTER DEPTH:\n");
|
||||
ir3_dump_instr_list(block->head);
|
||||
ir3_print(so->ir);
|
||||
}
|
||||
|
||||
ret = ir3_block_sched(block);
|
||||
@@ -2048,7 +2026,7 @@ ir3_compile_shader_nir(struct ir3_shader_variant *so,
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTMSGS) {
|
||||
printf("AFTER SCHED:\n");
|
||||
ir3_dump_instr_list(block->head);
|
||||
ir3_print(so->ir);
|
||||
}
|
||||
|
||||
ret = ir3_block_ra(block, so->type, so->frag_coord, so->frag_face);
|
||||
@@ -2059,7 +2037,7 @@ ir3_compile_shader_nir(struct ir3_shader_variant *so,
|
||||
|
||||
if (fd_mesa_debug & FD_DBG_OPTMSGS) {
|
||||
printf("AFTER RA:\n");
|
||||
ir3_dump_instr_list(block->head);
|
||||
ir3_print(so->ir);
|
||||
}
|
||||
|
||||
ir3_block_legalize(block, &so->has_samp, &max_bary);
|
||||
|
||||
@@ -1,456 +0,0 @@
|
||||
/* -*- 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]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/* -*- 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);
|
||||
}
|
||||
}
|
||||
@@ -78,14 +78,14 @@ struct ir3_ra_ctx {
|
||||
#define ra_dump_list(msg, n) do { \
|
||||
if (ra_debug) { \
|
||||
debug_printf("-- " msg); \
|
||||
ir3_dump_instr_list(n); \
|
||||
ir3_print(n->block->shader); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ra_dump_instr(msg, n) do { \
|
||||
if (ra_debug) { \
|
||||
debug_printf(">> " msg); \
|
||||
ir3_dump_instr_single(n); \
|
||||
ir3_print_instr(n); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user