1/* 2 * Copyright (c) 2018 Lima Project 3 * 4 * Copyright (c) 2013 Codethink (http://www.codethink.co.uk) 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, sub license, 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 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the 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 NON-INFRINGEMENT. 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 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 */ 26 27#include "gpir.h" 28#include "codegen.h" 29 30typedef enum { 31 unit_acc_0, 32 unit_acc_1, 33 unit_mul_0, 34 unit_mul_1, 35 unit_pass, 36 unit_complex, 37 num_units 38} gp_unit; 39 40static const gpir_codegen_store_src gp_unit_to_store_src[num_units] = { 41 [unit_acc_0] = gpir_codegen_store_src_acc_0, 42 [unit_acc_1] = gpir_codegen_store_src_acc_1, 43 [unit_mul_0] = gpir_codegen_store_src_mul_0, 44 [unit_mul_1] = gpir_codegen_store_src_mul_1, 45 [unit_pass] = gpir_codegen_store_src_pass, 46 [unit_complex] = gpir_codegen_store_src_complex, 47}; 48 49static void 50print_dest(gpir_codegen_instr *instr, gp_unit unit, unsigned cur_dest_index) 51{ 52 printf("^%u", cur_dest_index + unit); 53 54 gpir_codegen_store_src src = gp_unit_to_store_src[unit]; 55 56 if (instr->store0_src_x == src || 57 instr->store0_src_y == src) { 58 if (instr->store0_temporary) { 59 /* Temporary stores ignore the address, and always use whatever's 60 * stored in address register 0. 61 */ 62 printf("/t[addr0]"); 63 } else { 64 if (instr->store0_varying) 65 printf("/v"); 66 else 67 printf("/$"); 68 printf("%u", instr->store0_addr); 69 } 70 71 printf("."); 72 if (instr->store0_src_x == src) 73 printf("x"); 74 if (instr->store0_src_y == src) 75 printf("y"); 76 } 77 78 if (instr->store1_src_z == src || 79 instr->store1_src_w == src) { 80 if (instr->store1_temporary) { 81 printf("/t[addr0]"); 82 } else { 83 if (instr->store1_varying) 84 printf("/v"); 85 else 86 printf("/$"); 87 printf("%u", instr->store1_addr); 88 } 89 90 printf("."); 91 if (instr->store1_src_z == src) 92 printf("z"); 93 if (instr->store1_src_w == src) 94 printf("w"); 95 } 96 97 if (unit == unit_complex) { 98 switch (instr->complex_op) { 99 case gpir_codegen_complex_op_temp_store_addr: 100 printf("/addr0"); 101 break; 102 case gpir_codegen_complex_op_temp_load_addr_0: 103 printf("/addr1"); 104 break; 105 case gpir_codegen_complex_op_temp_load_addr_1: 106 printf("/addr2"); 107 break; 108 case gpir_codegen_complex_op_temp_load_addr_2: 109 printf("/addr3"); 110 break; 111 default: 112 break; 113 } 114 } 115} 116 117static void 118print_src(gpir_codegen_src src, gp_unit unit, unsigned unit_src_num, 119 gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 120 unsigned cur_dest_index) 121{ 122 switch (src) { 123 case gpir_codegen_src_attrib_x: 124 case gpir_codegen_src_attrib_y: 125 case gpir_codegen_src_attrib_z: 126 case gpir_codegen_src_attrib_w: 127 printf("%c%d.%c", instr->register0_attribute ? 'a' : '$', 128 instr->register0_addr, "xyzw"[src - gpir_codegen_src_attrib_x]); 129 break; 130 131 case gpir_codegen_src_register_x: 132 case gpir_codegen_src_register_y: 133 case gpir_codegen_src_register_z: 134 case gpir_codegen_src_register_w: 135 printf("$%d.%c", instr->register1_addr, 136 "xyzw"[src - gpir_codegen_src_register_x]); 137 break; 138 139 case gpir_codegen_src_unknown_0: 140 case gpir_codegen_src_unknown_1: 141 case gpir_codegen_src_unknown_2: 142 case gpir_codegen_src_unknown_3: 143 printf("unknown%d", src - gpir_codegen_src_unknown_0); 144 break; 145 146 case gpir_codegen_src_load_x: 147 case gpir_codegen_src_load_y: 148 case gpir_codegen_src_load_z: 149 case gpir_codegen_src_load_w: 150 printf("t[%d", instr->load_addr); 151 switch (instr->load_offset) { 152 case gpir_codegen_load_off_ld_addr_0: 153 printf("+addr1"); 154 break; 155 case gpir_codegen_load_off_ld_addr_1: 156 printf("+addr2"); 157 break; 158 case gpir_codegen_load_off_ld_addr_2: 159 printf("+addr3"); 160 break; 161 case gpir_codegen_load_off_none: 162 break; 163 default: 164 printf("+unk%d", instr->load_offset); 165 } 166 printf("].%c", "xyzw"[src - gpir_codegen_src_load_x]); 167 break; 168 169 case gpir_codegen_src_p1_acc_0: 170 printf("^%d", cur_dest_index - 1 * num_units + unit_acc_0); 171 break; 172 173 case gpir_codegen_src_p1_acc_1: 174 printf("^%d", cur_dest_index - 1 * num_units + unit_acc_1); 175 break; 176 177 case gpir_codegen_src_p1_mul_0: 178 printf("^%d", cur_dest_index - 1 * num_units + unit_mul_0); 179 break; 180 181 case gpir_codegen_src_p1_mul_1: 182 printf("^%d", cur_dest_index - 1 * num_units + unit_mul_1); 183 break; 184 185 case gpir_codegen_src_p1_pass: 186 printf("^%d", cur_dest_index - 1 * num_units + unit_pass); 187 break; 188 189 case gpir_codegen_src_unused: 190 printf("unused"); 191 break; 192 193 case gpir_codegen_src_p1_complex: /* Also ident */ 194 switch (unit) { 195 case unit_acc_0: 196 case unit_acc_1: 197 if (unit_src_num == 1) { 198 printf("0"); 199 return; 200 } 201 break; 202 case unit_mul_0: 203 case unit_mul_1: 204 if (unit_src_num == 1) { 205 printf("1"); 206 return; 207 } 208 break; 209 default: 210 break; 211 } 212 printf("^%d", cur_dest_index - 1 * num_units + unit_complex); 213 break; 214 215 case gpir_codegen_src_p2_pass: 216 printf("^%d", cur_dest_index - 2 * num_units + unit_pass); 217 break; 218 219 case gpir_codegen_src_p2_acc_0: 220 printf("^%d", cur_dest_index - 2 * num_units + unit_acc_0); 221 break; 222 223 case gpir_codegen_src_p2_acc_1: 224 printf("^%d", cur_dest_index - 2 * num_units + unit_acc_1); 225 break; 226 227 case gpir_codegen_src_p2_mul_0: 228 printf("^%d", cur_dest_index - 2 * num_units + unit_mul_0); 229 break; 230 231 case gpir_codegen_src_p2_mul_1: 232 printf("^%d", cur_dest_index - 2 * num_units + unit_mul_1); 233 break; 234 235 case gpir_codegen_src_p1_attrib_x: 236 case gpir_codegen_src_p1_attrib_y: 237 case gpir_codegen_src_p1_attrib_z: 238 case gpir_codegen_src_p1_attrib_w: 239 printf("%c%d.%c", prev_instr->register0_attribute ? 'a' : '$', 240 prev_instr->register0_addr, 241 "xyzw"[src - gpir_codegen_src_attrib_x]); 242 break; 243 } 244} 245 246static void 247print_mul(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 248 unsigned cur_dest_index) 249{ 250 switch (instr->mul_op) { 251 case gpir_codegen_mul_op_mul: 252 case gpir_codegen_mul_op_complex2: 253 if (instr->mul0_src0 != gpir_codegen_src_unused && 254 instr->mul0_src1 != gpir_codegen_src_unused) { 255 if (instr->mul0_src1 == gpir_codegen_src_ident && 256 !instr->mul0_neg) { 257 printf("mov "); 258 print_dest(instr, unit_mul_0, cur_dest_index); 259 printf(" "); 260 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr, 261 cur_dest_index); 262 } else { 263 if (instr->mul_op == gpir_codegen_mul_op_complex2) 264 printf("complex2 "); 265 else 266 printf("mul "); 267 268 print_dest(instr, unit_mul_0, cur_dest_index); 269 printf(" "); 270 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr, 271 cur_dest_index); 272 printf(" "); 273 if (instr->mul0_neg) 274 printf("-"); 275 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr, 276 cur_dest_index); 277 } 278 279 printf(", "); 280 } 281 282 if (instr->mul1_src0 != gpir_codegen_src_unused && 283 instr->mul1_src1 != gpir_codegen_src_unused) { 284 if (instr->mul1_src1 == gpir_codegen_src_ident && 285 !instr->mul1_neg) { 286 printf("mov "); 287 print_dest(instr, unit_mul_1, cur_dest_index); 288 printf(" "); 289 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr, 290 cur_dest_index); 291 } else { 292 printf("mul "); 293 print_dest(instr, unit_mul_1, cur_dest_index); 294 printf(" "); 295 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr, 296 cur_dest_index); 297 printf(" "); 298 if (instr->mul1_neg) 299 printf("-"); 300 print_src(instr->mul1_src1, unit_mul_0, 1, instr, prev_instr, 301 cur_dest_index); 302 } 303 } 304 305 break; 306 case gpir_codegen_mul_op_complex1: 307 printf("complex1 "); 308 print_dest(instr, unit_mul_0, cur_dest_index); 309 printf(" "); 310 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr, 311 cur_dest_index); 312 printf(" "); 313 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr, 314 cur_dest_index); 315 printf(" "); 316 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr, 317 cur_dest_index); 318 printf(" "); 319 print_src(instr->mul1_src1, unit_mul_1, 1, instr, prev_instr, 320 cur_dest_index); 321 break; 322 323 case gpir_codegen_mul_op_select: 324 printf("sel "); 325 print_dest(instr, unit_mul_0, cur_dest_index); 326 printf(" "); 327 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr, 328 cur_dest_index); 329 printf(" "); 330 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr, 331 cur_dest_index); 332 printf(" "); 333 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr, 334 cur_dest_index); 335 break; 336 337 default: 338 printf("unknown%u ", instr->mul_op); 339 print_dest(instr, unit_mul_0, cur_dest_index); 340 printf(" "); 341 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr, 342 cur_dest_index); 343 printf(" "); 344 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr, 345 cur_dest_index); 346 printf(" "); 347 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr, 348 cur_dest_index); 349 printf(" "); 350 print_src(instr->mul1_src1, unit_mul_1, 1, instr, prev_instr, 351 cur_dest_index); 352 break; 353 } 354 355 printf(", "); 356} 357 358typedef struct { 359 const char *name; 360 unsigned srcs; 361} acc_op_info; 362 363#define CASE(_name, _srcs) \ 364 [gpir_codegen_acc_op_##_name] = { \ 365 .name = #_name, \ 366 .srcs = _srcs \ 367 } 368 369static const acc_op_info acc_op_infos[8] = { 370 CASE(add, 2), 371 CASE(floor, 1), 372 CASE(sign, 1), 373 CASE(ge, 2), 374 CASE(lt, 2), 375 CASE(min, 2), 376 CASE(max, 2), 377}; 378 379#undef CASE 380 381static void 382print_acc(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 383 unsigned cur_dest_index) 384{ 385 const acc_op_info op = acc_op_infos[instr->acc_op]; 386 387 if (instr->acc0_src0 != gpir_codegen_src_unused && 388 instr->acc0_src1 != gpir_codegen_src_unused) { 389 acc_op_info acc0_op = op; 390 if (instr->acc0_src1 == gpir_codegen_src_ident && 391 instr->acc0_src1_neg) { 392 /* add x, -0 -> mov x */ 393 acc0_op.name = "mov"; 394 acc0_op.srcs = 1; 395 } 396 397 if (acc0_op.name) 398 printf("%s ", acc0_op.name); 399 else 400 printf("op%u ", instr->acc_op); 401 402 print_dest(instr, unit_acc_0, cur_dest_index); 403 printf(" "); 404 if (instr->acc0_src0_neg) 405 printf("-"); 406 print_src(instr->acc0_src0, unit_acc_0, 0, instr, prev_instr, 407 cur_dest_index); 408 if (acc0_op.srcs > 1) { 409 printf(" "); 410 if (instr->acc0_src1_neg) 411 printf("-"); 412 print_src(instr->acc0_src1, unit_acc_0, 1, instr, prev_instr, 413 cur_dest_index); 414 } 415 416 printf(", "); 417 } 418 419 if (instr->acc1_src0 != gpir_codegen_src_unused && 420 instr->acc1_src1 != gpir_codegen_src_unused) { 421 acc_op_info acc1_op = op; 422 if (instr->acc1_src1 == gpir_codegen_src_ident && 423 instr->acc1_src1_neg) { 424 /* add x, -0 -> mov x */ 425 acc1_op.name = "mov"; 426 acc1_op.srcs = 1; 427 } 428 429 if (acc1_op.name) 430 printf("%s ", acc1_op.name); 431 else 432 printf("op%u ", instr->acc_op); 433 434 print_dest(instr, unit_acc_1, cur_dest_index); 435 printf(" "); 436 if (instr->acc1_src0_neg) 437 printf("-"); 438 print_src(instr->acc1_src0, unit_acc_1, 0, instr, prev_instr, 439 cur_dest_index); 440 if (acc1_op.srcs > 1) { 441 printf(" "); 442 if (instr->acc1_src1_neg) 443 printf("-"); 444 print_src(instr->acc1_src1, unit_acc_1, 1, instr, prev_instr, 445 cur_dest_index); 446 } 447 448 printf(", "); 449 } 450} 451 452static void 453print_pass(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 454 unsigned cur_dest_index) 455{ 456 if (instr->pass_src == gpir_codegen_src_unused) 457 return; 458 459 switch (instr->pass_op) { 460 case gpir_codegen_pass_op_pass: 461 printf("mov "); 462 break; 463 case gpir_codegen_pass_op_preexp2: 464 printf("preexp2 "); 465 break; 466 case gpir_codegen_pass_op_postlog2: 467 printf("postlog2 "); 468 break; 469 case gpir_codegen_pass_op_clamp: 470 printf("clamp "); 471 break; 472 default: 473 printf("unk%u ", instr->pass_op); 474 } 475 476 print_dest(instr, unit_pass, cur_dest_index); 477 printf(" "); 478 print_src(instr->pass_src, unit_pass, 0, instr, prev_instr, 479 cur_dest_index); 480 481 if (instr->pass_op == gpir_codegen_pass_op_clamp) { 482 printf(" "); 483 print_src(gpir_codegen_src_load_x, unit_pass, 1, instr, prev_instr, 484 cur_dest_index); 485 printf(" "); 486 print_src(gpir_codegen_src_load_y, unit_pass, 2, instr, prev_instr, 487 cur_dest_index); 488 } 489 490 printf(", "); 491} 492 493static void 494print_complex(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 495 unsigned cur_dest_index) 496{ 497 if (instr->complex_src == gpir_codegen_src_unused) 498 return; 499 500 switch (instr->complex_op) { 501 case gpir_codegen_complex_op_nop: 502 return; 503 504 case gpir_codegen_complex_op_exp2: 505 printf("exp2 "); 506 break; 507 case gpir_codegen_complex_op_log2: 508 printf("log2 "); 509 break; 510 case gpir_codegen_complex_op_rsqrt: 511 printf("rsqrt "); 512 break; 513 case gpir_codegen_complex_op_rcp: 514 printf("rcp "); 515 break; 516 case gpir_codegen_complex_op_pass: 517 case gpir_codegen_complex_op_temp_store_addr: 518 case gpir_codegen_complex_op_temp_load_addr_0: 519 case gpir_codegen_complex_op_temp_load_addr_1: 520 case gpir_codegen_complex_op_temp_load_addr_2: 521 printf("mov "); 522 break; 523 default: 524 printf("unk%u ", instr->complex_op); 525 } 526 527 print_dest(instr, unit_complex, cur_dest_index); 528 printf(" "); 529 print_src(instr->complex_src, unit_complex, 0, instr, prev_instr, 530 cur_dest_index); 531 printf(", "); 532} 533 534static void 535print_instr(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 536 unsigned instr_number, unsigned cur_dest_index) 537{ 538 printf("%03d: ", instr_number); 539 print_mul(instr, prev_instr, cur_dest_index); 540 print_acc(instr, prev_instr, cur_dest_index); 541 print_complex(instr, prev_instr, cur_dest_index); 542 print_pass(instr, prev_instr, cur_dest_index); 543 544 if (instr->branch) { 545 /* The branch condition is taken from the current pass unit result */ 546 printf("branch ^%d %03d, ", cur_dest_index + unit_pass, 547 instr->branch_target + (instr->branch_target_lo ? 0 : 0x100)); 548 } 549 550 if (instr->unknown_1 != 0) 551 printf("unknown_1 %u", instr->unknown_1); 552 553 printf("\n"); 554} 555 556void 557gpir_disassemble_program(gpir_codegen_instr *code, unsigned num_instr) 558{ 559 printf("=======disassembly:=======\n"); 560 561 unsigned cur_dest_index = 0; 562 unsigned cur_instr = 0; 563 for (gpir_codegen_instr *instr = code; cur_instr < num_instr; 564 instr++, cur_instr++, cur_dest_index += num_units) { 565 print_instr(instr, instr - 1, cur_instr, cur_dest_index); 566 } 567} 568 569