1/* 2 * Copyright (C) 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io> 3 * Copyright (C) 2019-2020 Collabora, Ltd. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25#include "agx_compiler.h" 26 27static void 28agx_print_sized(char prefix, unsigned value, enum agx_size size, FILE *fp) 29{ 30 switch (size) { 31 case AGX_SIZE_16: 32 fprintf(fp, "%c%u%c", prefix, value >> 1, (value & 1) ? 'h' : 'l'); 33 return; 34 case AGX_SIZE_32: 35 assert((value & 1) == 0); 36 fprintf(fp, "%c%u", prefix, value >> 1); 37 return; 38 case AGX_SIZE_64: 39 assert((value & 1) == 0); 40 fprintf(fp, "%c%u:%c%u", prefix, value >> 1, 41 prefix, (value >> 1) + 1); 42 return; 43 } 44 45 unreachable("Invalid size"); 46} 47 48static void 49agx_print_index(agx_index index, FILE *fp) 50{ 51 switch (index.type) { 52 case AGX_INDEX_NULL: 53 fprintf(fp, "_"); 54 return; 55 56 case AGX_INDEX_NORMAL: 57 if (index.cache) 58 fprintf(fp, "$"); 59 60 if (index.discard) 61 fprintf(fp, "`"); 62 63 if (index.kill) 64 fprintf(fp, "*"); 65 66 fprintf(fp, "%u", index.value); 67 break; 68 69 case AGX_INDEX_IMMEDIATE: 70 fprintf(fp, "#%u", index.value); 71 break; 72 73 case AGX_INDEX_UNIFORM: 74 agx_print_sized('u', index.value, index.size, fp); 75 break; 76 77 case AGX_INDEX_REGISTER: 78 agx_print_sized('r', index.value, index.size, fp); 79 break; 80 81 default: 82 unreachable("Invalid index type"); 83 } 84 85 /* Print length suffixes if not implied */ 86 if (index.type == AGX_INDEX_NORMAL || index.type == AGX_INDEX_IMMEDIATE) { 87 if (index.size == AGX_SIZE_16) 88 fprintf(fp, "h"); 89 else if (index.size == AGX_SIZE_64) 90 fprintf(fp, "d"); 91 } 92 93 if (index.abs) 94 fprintf(fp, ".abs"); 95 96 if (index.neg) 97 fprintf(fp, ".neg"); 98} 99 100void 101agx_print_instr(agx_instr *I, FILE *fp) 102{ 103 assert(I->op < AGX_NUM_OPCODES); 104 struct agx_opcode_info info = agx_opcodes_info[I->op]; 105 106 fprintf(fp, " %s", info.name); 107 108 if (I->saturate) 109 fprintf(fp, ".sat"); 110 111 if (I->last) 112 fprintf(fp, ".last"); 113 114 fprintf(fp, " "); 115 116 bool print_comma = false; 117 118 for (unsigned d = 0; d < info.nr_dests; ++d) { 119 if (print_comma) 120 fprintf(fp, ", "); 121 else 122 print_comma = true; 123 124 agx_print_index(I->dest[d], fp); 125 } 126 127 for (unsigned s = 0; s < I->nr_srcs; ++s) { 128 if (print_comma) 129 fprintf(fp, ", "); 130 else 131 print_comma = true; 132 133 agx_print_index(I->src[s], fp); 134 } 135 136 if (I->mask) { 137 fprintf(fp, ", "); 138 139 for (unsigned i = 0; i < 4; ++i) { 140 if (I->mask & (1 << i)) 141 fprintf(fp, "%c", "xyzw"[i]); 142 } 143 } 144 145 /* TODO: Do better for enums, truth tables, etc */ 146 if (info.immediates) { 147 if (print_comma) 148 fprintf(fp, ", "); 149 else 150 print_comma = true; 151 152 fprintf(fp, "#%X", I->imm); 153 } 154 155 if (info.immediates & AGX_IMMEDIATE_DIM) { 156 if (print_comma) 157 fprintf(fp, ", "); 158 else 159 print_comma = true; 160 161 fprintf(fp, "dim %u", I->dim); // TODO enumify 162 } 163 164 if (info.immediates & AGX_IMMEDIATE_SCOREBOARD) { 165 if (print_comma) 166 fprintf(fp, ", "); 167 else 168 print_comma = true; 169 170 fprintf(fp, "slot %u", I->scoreboard); 171 } 172 173 if (info.immediates & AGX_IMMEDIATE_NEST) { 174 if (print_comma) 175 fprintf(fp, ", "); 176 else 177 print_comma = true; 178 179 fprintf(fp, "n=%u", I->nest); 180 } 181 182 if ((info.immediates & AGX_IMMEDIATE_INVERT_COND) && I->invert_cond) { 183 if (print_comma) 184 fprintf(fp, ", "); 185 else 186 print_comma = true; 187 188 fprintf(fp, "inv"); 189 } 190 191 fprintf(fp, "\n"); 192} 193 194void 195agx_print_block(agx_block *block, FILE *fp) 196{ 197 fprintf(fp, "block%u {\n", block->index); 198 199 agx_foreach_instr_in_block(block, ins) 200 agx_print_instr(ins, fp); 201 202 fprintf(fp, "}"); 203 204 if (block->successors[0]) { 205 fprintf(fp, " -> "); 206 207 agx_foreach_successor(block, succ) 208 fprintf(fp, "block%u ", succ->index); 209 } 210 211 if (block->predecessors.size) { 212 fprintf(fp, " from"); 213 214 agx_foreach_predecessor(block, pred) 215 fprintf(fp, " block%u", (*pred)->index); 216 } 217 218 fprintf(fp, "\n\n"); 219} 220 221void 222agx_print_shader(agx_context *ctx, FILE *fp) 223{ 224 agx_foreach_block(ctx, block) 225 agx_print_block(block, fp); 226} 227