Path: blob/21.2-virgl/src/freedreno/ir3/ir3_print.c
4565 views
/*1* Copyright (C) 2014 Rob Clark <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Rob Clark <[email protected]>24*/2526#include <stdarg.h>27#include <stdio.h>2829#include "util/log.h"30#include "ir3.h"3132#define PTRID(x) ((unsigned long)(x))3334/* ansi escape sequences: */35#define RESET "\x1b[0m"36#define RED "\x1b[0;31m"37#define GREEN "\x1b[0;32m"38#define BLUE "\x1b[0;34m"39#define MAGENTA "\x1b[0;35m"4041/* syntax coloring, mostly to make it easier to see different sorts of42* srcs (immediate, constant, ssa, array, ...)43*/44#define SYN_REG(x) RED x RESET45#define SYN_IMMED(x) GREEN x RESET46#define SYN_CONST(x) GREEN x RESET47#define SYN_SSA(x) BLUE x RESET48#define SYN_ARRAY(x) MAGENTA x RESET4950static const char *51type_name(type_t type)52{53static const char *type_names[] = {54/* clang-format off */55[TYPE_F16] = "f16",56[TYPE_F32] = "f32",57[TYPE_U16] = "u16",58[TYPE_U32] = "u32",59[TYPE_S16] = "s16",60[TYPE_S32] = "s32",61[TYPE_U8] = "u8",62[TYPE_S8] = "s8",63/* clang-format on */64};65return type_names[type];66}6768static void69print_instr_name(struct log_stream *stream, struct ir3_instruction *instr,70bool flags)71{72if (!instr)73return;74#ifdef DEBUG75mesa_log_stream_printf(stream, "%04u:", instr->serialno);76#endif77mesa_log_stream_printf(stream, "%04u:", instr->name);78mesa_log_stream_printf(stream, "%04u:", instr->ip);79if (instr->flags & IR3_INSTR_UNUSED) {80mesa_log_stream_printf(stream, "XXX: ");81} else {82mesa_log_stream_printf(stream, "%03u: ", instr->use_count);83}8485if (flags) {86mesa_log_stream_printf(stream, "\t");87if (instr->flags & IR3_INSTR_SY)88mesa_log_stream_printf(stream, "(sy)");89if (instr->flags & IR3_INSTR_SS)90mesa_log_stream_printf(stream, "(ss)");91if (instr->flags & IR3_INSTR_JP)92mesa_log_stream_printf(stream, "(jp)");93if (instr->repeat)94mesa_log_stream_printf(stream, "(rpt%d)", instr->repeat);95if (instr->nop)96mesa_log_stream_printf(stream, "(nop%d)", instr->nop);97if (instr->flags & IR3_INSTR_UL)98mesa_log_stream_printf(stream, "(ul)");99} else {100mesa_log_stream_printf(stream, " ");101}102103if (is_meta(instr)) {104switch (instr->opc) {105case OPC_META_INPUT:106mesa_log_stream_printf(stream, "_meta:in");107break;108case OPC_META_SPLIT:109mesa_log_stream_printf(stream, "_meta:split");110break;111case OPC_META_COLLECT:112mesa_log_stream_printf(stream, "_meta:collect");113break;114case OPC_META_TEX_PREFETCH:115mesa_log_stream_printf(stream, "_meta:tex_prefetch");116break;117case OPC_META_PARALLEL_COPY:118mesa_log_stream_printf(stream, "_meta:parallel_copy");119break;120case OPC_META_PHI:121mesa_log_stream_printf(stream, "_meta:phi");122break;123124/* shouldn't hit here.. just for debugging: */125default:126mesa_log_stream_printf(stream, "_meta:%d", instr->opc);127break;128}129} else if (opc_cat(instr->opc) == 1) {130if (instr->opc == OPC_MOV) {131if (instr->cat1.src_type == instr->cat1.dst_type)132mesa_log_stream_printf(stream, "mov");133else134mesa_log_stream_printf(stream, "cov");135} else {136mesa_log_stream_printf(stream, "%s",137disasm_a3xx_instr_name(instr->opc));138}139140if (instr->opc != OPC_MOVMSK) {141mesa_log_stream_printf(stream, ".%s%s",142type_name(instr->cat1.src_type),143type_name(instr->cat1.dst_type));144}145} else if (instr->opc == OPC_B) {146const char *name[8] = {147/* clang-format off */148[BRANCH_PLAIN] = "br",149[BRANCH_OR] = "brao",150[BRANCH_AND] = "braa",151[BRANCH_CONST] = "brac",152[BRANCH_ANY] = "bany",153[BRANCH_ALL] = "ball",154[BRANCH_X] = "brax",155/* clang-format on */156};157mesa_log_stream_printf(stream, "%s", name[instr->cat0.brtype]);158} else {159mesa_log_stream_printf(stream, "%s", disasm_a3xx_instr_name(instr->opc));160if (instr->flags & IR3_INSTR_3D)161mesa_log_stream_printf(stream, ".3d");162if (instr->flags & IR3_INSTR_A)163mesa_log_stream_printf(stream, ".a");164if (instr->flags & IR3_INSTR_O)165mesa_log_stream_printf(stream, ".o");166if (instr->flags & IR3_INSTR_P)167mesa_log_stream_printf(stream, ".p");168if (instr->flags & IR3_INSTR_S)169mesa_log_stream_printf(stream, ".s");170if (instr->flags & IR3_INSTR_A1EN)171mesa_log_stream_printf(stream, ".a1en");172if (instr->opc == OPC_LDC)173mesa_log_stream_printf(stream, ".offset%d", instr->cat6.d);174if (instr->flags & IR3_INSTR_B) {175mesa_log_stream_printf(176stream, ".base%d",177is_tex(instr) ? instr->cat5.tex_base : instr->cat6.base);178}179if (instr->flags & IR3_INSTR_S2EN)180mesa_log_stream_printf(stream, ".s2en");181182static const char *cond[0x7] = {183"lt", "le", "gt", "ge", "eq", "ne",184};185186switch (instr->opc) {187case OPC_CMPS_F:188case OPC_CMPS_U:189case OPC_CMPS_S:190case OPC_CMPV_F:191case OPC_CMPV_U:192case OPC_CMPV_S:193mesa_log_stream_printf(stream, ".%s",194cond[instr->cat2.condition & 0x7]);195break;196default:197break;198}199}200}201202static void203print_ssa_def_name(struct log_stream *stream, struct ir3_register *reg)204{205mesa_log_stream_printf(stream, SYN_SSA("ssa_%u"), reg->instr->serialno);206if (reg->name != 0)207mesa_log_stream_printf(stream, ":%u", reg->name);208}209210static void211print_ssa_name(struct log_stream *stream, struct ir3_register *reg, bool dst)212{213if (!dst) {214if (!reg->def)215mesa_log_stream_printf(stream, SYN_SSA("undef"));216else217print_ssa_def_name(stream, reg->def);218} else {219print_ssa_def_name(stream, reg);220}221222if (reg->num != INVALID_REG && !(reg->flags & IR3_REG_ARRAY))223mesa_log_stream_printf(stream, "(" SYN_REG("r%u.%c") ")", reg_num(reg),224"xyzw"[reg_comp(reg)]);225}226227static void228print_reg_name(struct log_stream *stream, struct ir3_instruction *instr,229struct ir3_register *reg, bool dest)230{231if ((reg->flags & (IR3_REG_FABS | IR3_REG_SABS)) &&232(reg->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT)))233mesa_log_stream_printf(stream, "(absneg)");234else if (reg->flags & (IR3_REG_FNEG | IR3_REG_SNEG | IR3_REG_BNOT))235mesa_log_stream_printf(stream, "(neg)");236else if (reg->flags & (IR3_REG_FABS | IR3_REG_SABS))237mesa_log_stream_printf(stream, "(abs)");238239if (reg->flags & IR3_REG_FIRST_KILL)240mesa_log_stream_printf(stream, "(kill)");241if (reg->flags & IR3_REG_UNUSED)242mesa_log_stream_printf(stream, "(unused)");243244if (reg->flags & IR3_REG_R)245mesa_log_stream_printf(stream, "(r)");246247/* Right now all instructions that use tied registers only have one248* destination register, so we can just print (tied) as if it's a flag,249* although it's more convenient for RA if it's a pointer.250*/251if (reg->tied)252printf("(tied)");253254if (reg->flags & IR3_REG_SHARED)255mesa_log_stream_printf(stream, "s");256if (reg->flags & IR3_REG_HALF)257mesa_log_stream_printf(stream, "h");258259if (reg->flags & IR3_REG_IMMED) {260mesa_log_stream_printf(stream, SYN_IMMED("imm[%f,%d,0x%x]"), reg->fim_val,261reg->iim_val, reg->iim_val);262} else if (reg->flags & IR3_REG_ARRAY) {263if (reg->flags & IR3_REG_SSA) {264print_ssa_name(stream, reg, dest);265mesa_log_stream_printf(stream, ":");266}267mesa_log_stream_printf(stream,268SYN_ARRAY("arr[id=%u, offset=%d, size=%u]"),269reg->array.id, reg->array.offset, reg->size);270if (reg->array.base != INVALID_REG)271mesa_log_stream_printf(stream, "(" SYN_REG("r%u.%c") ")",272reg->array.base >> 2,273"xyzw"[reg->array.base & 0x3]);274} else if (reg->flags & IR3_REG_SSA) {275print_ssa_name(stream, reg, dest);276} else if (reg->flags & IR3_REG_RELATIV) {277if (reg->flags & IR3_REG_CONST)278mesa_log_stream_printf(stream, SYN_CONST("c<a0.x + %d>"),279reg->array.offset);280else281mesa_log_stream_printf(stream, SYN_REG("r<a0.x + %d>") " (%u)",282reg->array.offset, reg->size);283} else {284if (reg->flags & IR3_REG_CONST)285mesa_log_stream_printf(stream, SYN_CONST("c%u.%c"), reg_num(reg),286"xyzw"[reg_comp(reg)]);287else288mesa_log_stream_printf(stream, SYN_REG("r%u.%c"), reg_num(reg),289"xyzw"[reg_comp(reg)]);290}291292if (reg->wrmask > 0x1)293mesa_log_stream_printf(stream, " (wrmask=0x%x)", reg->wrmask);294}295296static void297tab(struct log_stream *stream, int lvl)298{299for (int i = 0; i < lvl; i++)300mesa_log_stream_printf(stream, "\t");301}302303static void304print_instr(struct log_stream *stream, struct ir3_instruction *instr, int lvl)305{306tab(stream, lvl);307308print_instr_name(stream, instr, true);309310if (is_tex(instr)) {311mesa_log_stream_printf(stream, " (%s)(", type_name(instr->cat5.type));312for (unsigned i = 0; i < 4; i++)313if (instr->dsts[0]->wrmask & (1 << i))314mesa_log_stream_printf(stream, "%c", "xyzw"[i]);315mesa_log_stream_printf(stream, ")");316} else if ((instr->srcs_count > 0 || instr->dsts_count > 0) &&317(instr->opc != OPC_B)) {318/* NOTE the b(ranch) instruction has a suffix, which is319* handled below320*/321mesa_log_stream_printf(stream, " ");322}323324if (!is_flow(instr) || instr->opc == OPC_END || instr->opc == OPC_CHMASK) {325bool first = true;326foreach_dst (reg, instr) {327if (reg->wrmask == 0)328continue;329if (!first)330mesa_log_stream_printf(stream, ", ");331print_reg_name(stream, instr, reg, true);332first = false;333}334foreach_src (reg, instr) {335if (!first)336mesa_log_stream_printf(stream, ", ");337print_reg_name(stream, instr, reg, false);338first = false;339}340}341342if (is_tex(instr) && !(instr->flags & IR3_INSTR_S2EN)) {343if (!!(instr->flags & IR3_INSTR_B)) {344if (!!(instr->flags & IR3_INSTR_A1EN)) {345mesa_log_stream_printf(stream, ", s#%d", instr->cat5.samp);346} else {347mesa_log_stream_printf(stream, ", s#%d, t#%d",348instr->cat5.samp & 0xf,349instr->cat5.samp >> 4);350}351} else {352mesa_log_stream_printf(stream, ", s#%d, t#%d", instr->cat5.samp,353instr->cat5.tex);354}355}356357if (instr->opc == OPC_META_SPLIT) {358mesa_log_stream_printf(stream, ", off=%d", instr->split.off);359} else if (instr->opc == OPC_META_TEX_PREFETCH) {360mesa_log_stream_printf(stream, ", tex=%d, samp=%d, input_offset=%d",361instr->prefetch.tex, instr->prefetch.samp,362instr->prefetch.input_offset);363}364365if (is_flow(instr) && instr->cat0.target) {366/* the predicate register src is implied: */367if (instr->opc == OPC_B) {368static const struct {369const char *suffix;370int nsrc;371bool idx;372} brinfo[7] = {373/* clang-format off */374[BRANCH_PLAIN] = {"r", 1, false},375[BRANCH_OR] = {"rao", 2, false},376[BRANCH_AND] = {"raa", 2, false},377[BRANCH_CONST] = {"rac", 0, true},378[BRANCH_ANY] = {"any", 1, false},379[BRANCH_ALL] = {"all", 1, false},380[BRANCH_X] = {"rax", 0, false},381/* clang-format on */382};383384mesa_log_stream_printf(stream, "%s",385brinfo[instr->cat0.brtype].suffix);386if (brinfo[instr->cat0.brtype].idx) {387mesa_log_stream_printf(stream, ".%u", instr->cat0.idx);388}389if (brinfo[instr->cat0.brtype].nsrc >= 1) {390mesa_log_stream_printf(stream, " %sp0.%c (",391instr->cat0.inv1 ? "!" : "",392"xyzw"[instr->cat0.comp1 & 0x3]);393print_reg_name(stream, instr, instr->srcs[0], false);394mesa_log_stream_printf(stream, "), ");395}396if (brinfo[instr->cat0.brtype].nsrc >= 2) {397mesa_log_stream_printf(stream, " %sp0.%c (",398instr->cat0.inv2 ? "!" : "",399"xyzw"[instr->cat0.comp2 & 0x3]);400print_reg_name(stream, instr, instr->srcs[1], false);401mesa_log_stream_printf(stream, "), ");402}403}404mesa_log_stream_printf(stream, " target=block%u",405block_id(instr->cat0.target));406}407408if (instr->deps_count) {409mesa_log_stream_printf(stream, ", false-deps:");410unsigned n = 0;411for (unsigned i = 0; i < instr->deps_count; i++) {412if (!instr->deps[i])413continue;414if (n++ > 0)415mesa_log_stream_printf(stream, ", ");416mesa_log_stream_printf(stream, SYN_SSA("ssa_%u"),417instr->deps[i]->serialno);418}419}420421mesa_log_stream_printf(stream, "\n");422}423424void425ir3_print_instr(struct ir3_instruction *instr)426{427struct log_stream *stream = mesa_log_streami();428print_instr(stream, instr, 0);429mesa_log_stream_destroy(stream);430}431432static void433print_block(struct ir3_block *block, int lvl)434{435struct log_stream *stream = mesa_log_streami();436437tab(stream, lvl);438mesa_log_stream_printf(stream, "block%u {\n", block_id(block));439440if (block->predecessors_count > 0) {441tab(stream, lvl + 1);442mesa_log_stream_printf(stream, "pred: ");443for (unsigned i = 0; i < block->predecessors_count; i++) {444struct ir3_block *pred = block->predecessors[i];445if (i != 0)446mesa_log_stream_printf(stream, ", ");447mesa_log_stream_printf(stream, "block%u", block_id(pred));448}449mesa_log_stream_printf(stream, "\n");450}451452foreach_instr (instr, &block->instr_list) {453print_instr(stream, instr, lvl + 1);454}455456tab(stream, lvl + 1);457mesa_log_stream_printf(stream, "/* keeps:\n");458for (unsigned i = 0; i < block->keeps_count; i++) {459print_instr(stream, block->keeps[i], lvl + 2);460}461tab(stream, lvl + 1);462mesa_log_stream_printf(stream, " */\n");463464if (block->successors[1]) {465/* leading into if/else: */466tab(stream, lvl + 1);467mesa_log_stream_printf(stream, "/* succs: if ");468switch (block->brtype) {469case IR3_BRANCH_COND:470break;471case IR3_BRANCH_ANY:472printf("any ");473break;474case IR3_BRANCH_ALL:475printf("all ");476break;477case IR3_BRANCH_GETONE:478printf("getone ");479break;480}481if (block->condition)482mesa_log_stream_printf(stream, SYN_SSA("ssa_%u") " ",483block->condition->serialno);484mesa_log_stream_printf(stream, "block%u; else block%u; */\n",485block_id(block->successors[0]),486block_id(block->successors[1]));487} else if (block->successors[0]) {488tab(stream, lvl + 1);489mesa_log_stream_printf(stream, "/* succs: block%u; */\n",490block_id(block->successors[0]));491}492tab(stream, lvl);493mesa_log_stream_printf(stream, "}\n");494}495496void497ir3_print(struct ir3 *ir)498{499foreach_block (block, &ir->block_list)500print_block(block, 0);501}502503504