1/* 2 * Copyright (c) 2017 Lima Project 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sub license, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the 12 * next paragraph) shall be included in all copies or substantial portions 13 * of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 */ 24 25#include "util/ralloc.h" 26 27#include "ppir.h" 28 29ppir_instr *ppir_instr_create(ppir_block *block) 30{ 31 ppir_instr *instr = rzalloc(block, ppir_instr); 32 if (!instr) 33 return NULL; 34 35 list_inithead(&instr->succ_list); 36 list_inithead(&instr->pred_list); 37 38 instr->index = block->comp->cur_instr_index++; 39 instr->reg_pressure = -1; 40 41 list_addtail(&instr->list, &block->instr_list); 42 return instr; 43} 44 45void ppir_instr_add_dep(ppir_instr *succ, ppir_instr *pred) 46{ 47 /* don't add duplicated instr */ 48 ppir_instr_foreach_pred(succ, dep) { 49 if (pred == dep->pred) 50 return; 51 } 52 53 ppir_dep *dep = ralloc(succ, ppir_dep); 54 dep->pred = pred; 55 dep->succ = succ; 56 list_addtail(&dep->pred_link, &succ->pred_list); 57 list_addtail(&dep->succ_link, &pred->succ_list); 58} 59 60void ppir_instr_insert_mul_node(ppir_node *add, ppir_node *mul) 61{ 62 ppir_instr *instr = add->instr; 63 int pos = mul->instr_pos; 64 int *slots = ppir_op_infos[mul->op].slots; 65 66 for (int i = 0; slots[i] != PPIR_INSTR_SLOT_END; i++) { 67 /* possible to insert at required place */ 68 if (slots[i] == pos) { 69 if (!instr->slots[pos]) { 70 ppir_alu_node *add_alu = ppir_node_to_alu(add); 71 ppir_alu_node *mul_alu = ppir_node_to_alu(mul); 72 ppir_dest *dest = &mul_alu->dest; 73 int pipeline = pos == PPIR_INSTR_SLOT_ALU_VEC_MUL ? 74 ppir_pipeline_reg_vmul : ppir_pipeline_reg_fmul; 75 76 /* ^vmul/^fmul can't be used as last arg */ 77 if (add_alu->num_src > 1) { 78 ppir_src *last_src = add_alu->src + add_alu->num_src - 1; 79 if (ppir_node_target_equal(last_src, dest)) 80 return; 81 } 82 83 /* update add node src to use pipeline reg */ 84 ppir_src *src = add_alu->src; 85 if (add_alu->num_src == 3) { 86 if (ppir_node_target_equal(src, dest)) { 87 src->type = ppir_target_pipeline; 88 src->pipeline = pipeline; 89 } 90 91 if (ppir_node_target_equal(++src, dest)) { 92 src->type = ppir_target_pipeline; 93 src->pipeline = pipeline; 94 } 95 } 96 else { 97 assert(ppir_node_target_equal(src, dest)); 98 src->type = ppir_target_pipeline; 99 src->pipeline = pipeline; 100 } 101 102 /* update mul node dest to output to pipeline reg */ 103 dest->type = ppir_target_pipeline; 104 dest->pipeline = pipeline; 105 106 instr->slots[pos] = mul; 107 mul->instr = instr; 108 } 109 return; 110 } 111 } 112} 113 114/* check whether a const slot fix into another const slot */ 115static bool ppir_instr_insert_const(ppir_const *dst, const ppir_const *src, 116 uint8_t *swizzle) 117{ 118 int i, j; 119 120 for (i = 0; i < src->num; i++) { 121 for (j = 0; j < dst->num; j++) { 122 if (src->value[i].ui == dst->value[j].ui) 123 break; 124 } 125 126 if (j == dst->num) { 127 if (dst->num == 4) 128 return false; 129 dst->value[dst->num++] = src->value[i]; 130 } 131 132 swizzle[i] = j; 133 } 134 135 return true; 136} 137 138static void ppir_update_src_pipeline(ppir_pipeline pipeline, ppir_src *src, 139 ppir_dest *dest, uint8_t *swizzle) 140{ 141 if (ppir_node_target_equal(src, dest)) { 142 src->type = ppir_target_pipeline; 143 src->pipeline = pipeline; 144 145 if (swizzle) { 146 for (int k = 0; k < 4; k++) 147 src->swizzle[k] = swizzle[src->swizzle[k]]; 148 } 149 } 150} 151 152/* make alu node src reflact the pipeline reg */ 153static void ppir_instr_update_src_pipeline(ppir_instr *instr, ppir_pipeline pipeline, 154 ppir_dest *dest, uint8_t *swizzle) 155{ 156 for (int i = PPIR_INSTR_SLOT_ALU_START; i <= PPIR_INSTR_SLOT_ALU_END; i++) { 157 if (!instr->slots[i]) 158 continue; 159 160 ppir_alu_node *alu = ppir_node_to_alu(instr->slots[i]); 161 for (int j = 0; j < alu->num_src; j++) { 162 ppir_src *src = alu->src + j; 163 ppir_update_src_pipeline(pipeline, src, dest, swizzle); 164 } 165 } 166 167 ppir_node *branch_node = instr->slots[PPIR_INSTR_SLOT_BRANCH]; 168 if (branch_node && (branch_node->type == ppir_node_type_branch)) { 169 ppir_branch_node *branch = ppir_node_to_branch(branch_node); 170 for (int j = 0; j < 2; j++) { 171 ppir_src *src = branch->src + j; 172 ppir_update_src_pipeline(pipeline, src, dest, swizzle); 173 } 174 } 175} 176 177bool ppir_instr_insert_node(ppir_instr *instr, ppir_node *node) 178{ 179 if (node->op == ppir_op_const) { 180 int i; 181 ppir_const_node *c = ppir_node_to_const(node); 182 const ppir_const *nc = &c->constant; 183 184 for (i = 0; i < 2; i++) { 185 ppir_const ic = instr->constant[i]; 186 uint8_t swizzle[4] = {0}; 187 188 if (ppir_instr_insert_const(&ic, nc, swizzle)) { 189 ppir_node *succ = ppir_node_first_succ(node); 190 ppir_src *src = NULL; 191 for (int s = 0; s < ppir_node_get_src_num(succ); s++) { 192 src = ppir_node_get_src(succ, s); 193 if (src->node == node) 194 break; 195 } 196 assert(src->node == node); 197 198 instr->constant[i] = ic; 199 ppir_update_src_pipeline(ppir_pipeline_reg_const0 + i, src, 200 &c->dest, swizzle); 201 break; 202 } 203 } 204 205 /* no const slot can insert */ 206 if (i == 2) 207 return false; 208 209 return true; 210 } 211 else { 212 int *slots = ppir_op_infos[node->op].slots; 213 for (int i = 0; slots[i] != PPIR_INSTR_SLOT_END; i++) { 214 int pos = slots[i]; 215 216 if (instr->slots[pos]) { 217 /* node already in this instr, i.e. load_uniform */ 218 if (instr->slots[pos] == node) 219 return true; 220 else 221 continue; 222 } 223 224 /* ^fmul dests (e.g. condition for select) can only be 225 * scheduled to ALU_SCL_MUL */ 226 if (pos == PPIR_INSTR_SLOT_ALU_SCL_ADD) { 227 ppir_dest *dest = ppir_node_get_dest(node); 228 if (dest && dest->type == ppir_target_pipeline && 229 dest->pipeline == ppir_pipeline_reg_fmul) 230 continue; 231 } 232 233 if (pos == PPIR_INSTR_SLOT_ALU_SCL_MUL || 234 pos == PPIR_INSTR_SLOT_ALU_SCL_ADD) { 235 ppir_dest *dest = ppir_node_get_dest(node); 236 if (!ppir_target_is_scalar(dest)) 237 continue; 238 } 239 240 instr->slots[pos] = node; 241 node->instr = instr; 242 node->instr_pos = pos; 243 244 if ((node->op == ppir_op_load_uniform) || (node->op == ppir_op_load_temp)) { 245 ppir_load_node *l = ppir_node_to_load(node); 246 ppir_instr_update_src_pipeline( 247 instr, ppir_pipeline_reg_uniform, &l->dest, NULL); 248 } 249 250 return true; 251 } 252 253 return false; 254 } 255} 256 257static struct { 258 int len; 259 char *name; 260} ppir_instr_fields[] = { 261 [PPIR_INSTR_SLOT_VARYING] = { 4, "vary" }, 262 [PPIR_INSTR_SLOT_TEXLD] = { 4, "texl"}, 263 [PPIR_INSTR_SLOT_UNIFORM] = { 4, "unif" }, 264 [PPIR_INSTR_SLOT_ALU_VEC_MUL] = { 4, "vmul" }, 265 [PPIR_INSTR_SLOT_ALU_SCL_MUL] = { 4, "smul" }, 266 [PPIR_INSTR_SLOT_ALU_VEC_ADD] = { 4, "vadd" }, 267 [PPIR_INSTR_SLOT_ALU_SCL_ADD] = { 4, "sadd" }, 268 [PPIR_INSTR_SLOT_ALU_COMBINE] = { 4, "comb" }, 269 [PPIR_INSTR_SLOT_STORE_TEMP] = { 4, "stor" }, 270 [PPIR_INSTR_SLOT_BRANCH] = { 4, "brch" }, 271}; 272 273void ppir_instr_print_list(ppir_compiler *comp) 274{ 275 if (!(lima_debug & LIMA_DEBUG_PP)) 276 return; 277 278 printf("======ppir instr list======\n"); 279 printf(" "); 280 for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++) 281 printf("%-*s ", ppir_instr_fields[i].len, ppir_instr_fields[i].name); 282 printf("const0|1\n"); 283 284 list_for_each_entry(ppir_block, block, &comp->block_list, list) { 285 printf("-------block %3d-------\n", block->index); 286 list_for_each_entry(ppir_instr, instr, &block->instr_list, list) { 287 printf("%c%03d: ", instr->is_end ? '*' : ' ', instr->index); 288 for (int i = 0; i < PPIR_INSTR_SLOT_NUM; i++) { 289 ppir_node *node = instr->slots[i]; 290 if (node) 291 printf("%-*d ", ppir_instr_fields[i].len, node->index); 292 else 293 printf("%-*s ", ppir_instr_fields[i].len, "null"); 294 } 295 for (int i = 0; i < 2; i++) { 296 if (i) 297 printf("| "); 298 299 for (int j = 0; j < instr->constant[i].num; j++) 300 printf("%f ", instr->constant[i].value[j].f); 301 } 302 printf("\n"); 303 } 304 } 305 printf("===========================\n"); 306} 307 308static void ppir_instr_print_sub(ppir_instr *instr) 309{ 310 printf("[%s%d", 311 instr->printed && !ppir_instr_is_leaf(instr) ? "+" : "", 312 instr->index); 313 314 if (!instr->printed) { 315 ppir_instr_foreach_pred(instr, dep) { 316 ppir_instr_print_sub(dep->pred); 317 } 318 319 instr->printed = true; 320 } 321 322 printf("]"); 323} 324 325void ppir_instr_print_dep(ppir_compiler *comp) 326{ 327 if (!(lima_debug & LIMA_DEBUG_PP)) 328 return; 329 330 list_for_each_entry(ppir_block, block, &comp->block_list, list) { 331 list_for_each_entry(ppir_instr, instr, &block->instr_list, list) { 332 instr->printed = false; 333 } 334 } 335 336 printf("======ppir instr depend======\n"); 337 list_for_each_entry(ppir_block, block, &comp->block_list, list) { 338 printf("-------block %3d-------\n", block->index); 339 list_for_each_entry(ppir_instr, instr, &block->instr_list, list) { 340 if (ppir_instr_is_root(instr)) { 341 ppir_instr_print_sub(instr); 342 printf("\n"); 343 } 344 } 345 } 346 printf("=============================\n"); 347} 348