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, FILE *fp) 51{ 52 fprintf(fp, "^%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 fprintf(fp, "/t[addr0]"); 63 } else { 64 if (instr->store0_varying) 65 fprintf(fp, "/v"); 66 else 67 fprintf(fp, "/$"); 68 fprintf(fp, "%u", instr->store0_addr); 69 } 70 71 fprintf(fp, "."); 72 if (instr->store0_src_x == src) 73 fprintf(fp, "x"); 74 if (instr->store0_src_y == src) 75 fprintf(fp, "y"); 76 } 77 78 if (instr->store1_src_z == src || 79 instr->store1_src_w == src) { 80 if (instr->store1_temporary) { 81 fprintf(fp, "/t[addr0]"); 82 } else { 83 if (instr->store1_varying) 84 fprintf(fp, "/v"); 85 else 86 fprintf(fp, "/$"); 87 fprintf(fp, "%u", instr->store1_addr); 88 } 89 90 fprintf(fp, "."); 91 if (instr->store1_src_z == src) 92 fprintf(fp, "z"); 93 if (instr->store1_src_w == src) 94 fprintf(fp, "w"); 95 } 96 97 if (unit == unit_complex) { 98 switch (instr->complex_op) { 99 case gpir_codegen_complex_op_temp_store_addr: 100 fprintf(fp, "/addr0"); 101 break; 102 case gpir_codegen_complex_op_temp_load_addr_0: 103 fprintf(fp, "/addr1"); 104 break; 105 case gpir_codegen_complex_op_temp_load_addr_1: 106 fprintf(fp, "/addr2"); 107 break; 108 case gpir_codegen_complex_op_temp_load_addr_2: 109 fprintf(fp, "/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, FILE *fp) 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 fprintf(fp, "%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 fprintf(fp, "$%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 fprintf(fp, "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 fprintf(fp, "t[%d", instr->load_addr); 151 switch (instr->load_offset) { 152 case gpir_codegen_load_off_ld_addr_0: 153 fprintf(fp, "+addr1"); 154 break; 155 case gpir_codegen_load_off_ld_addr_1: 156 fprintf(fp, "+addr2"); 157 break; 158 case gpir_codegen_load_off_ld_addr_2: 159 fprintf(fp, "+addr3"); 160 break; 161 case gpir_codegen_load_off_none: 162 break; 163 default: 164 fprintf(fp, "+unk%d", instr->load_offset); 165 } 166 fprintf(fp, "].%c", "xyzw"[src - gpir_codegen_src_load_x]); 167 break; 168 169 case gpir_codegen_src_p1_acc_0: 170 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_acc_0); 171 break; 172 173 case gpir_codegen_src_p1_acc_1: 174 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_acc_1); 175 break; 176 177 case gpir_codegen_src_p1_mul_0: 178 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_mul_0); 179 break; 180 181 case gpir_codegen_src_p1_mul_1: 182 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_mul_1); 183 break; 184 185 case gpir_codegen_src_p1_pass: 186 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_pass); 187 break; 188 189 case gpir_codegen_src_unused: 190 fprintf(fp, "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 fprintf(fp, "0"); 199 return; 200 } 201 break; 202 case unit_mul_0: 203 case unit_mul_1: 204 if (unit_src_num == 1) { 205 fprintf(fp, "1"); 206 return; 207 } 208 break; 209 default: 210 break; 211 } 212 fprintf(fp, "^%d", cur_dest_index - 1 * num_units + unit_complex); 213 break; 214 215 case gpir_codegen_src_p2_pass: 216 fprintf(fp, "^%d", cur_dest_index - 2 * num_units + unit_pass); 217 break; 218 219 case gpir_codegen_src_p2_acc_0: 220 fprintf(fp, "^%d", cur_dest_index - 2 * num_units + unit_acc_0); 221 break; 222 223 case gpir_codegen_src_p2_acc_1: 224 fprintf(fp, "^%d", cur_dest_index - 2 * num_units + unit_acc_1); 225 break; 226 227 case gpir_codegen_src_p2_mul_0: 228 fprintf(fp, "^%d", cur_dest_index - 2 * num_units + unit_mul_0); 229 break; 230 231 case gpir_codegen_src_p2_mul_1: 232 fprintf(fp, "^%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 fprintf(fp, "%c%d.%c", prev_instr->register0_attribute ? 'a' : '$', 240 prev_instr->register0_addr, 241 "xyzw"[src - gpir_codegen_src_p1_attrib_x]); 242 break; 243 } 244} 245 246static bool 247print_mul(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 248 unsigned cur_dest_index, FILE *fp) 249{ 250 bool printed = false; 251 252 switch (instr->mul_op) { 253 case gpir_codegen_mul_op_mul: 254 case gpir_codegen_mul_op_complex2: 255 if (instr->mul0_src0 != gpir_codegen_src_unused && 256 instr->mul0_src1 != gpir_codegen_src_unused) { 257 printed = true; 258 fprintf(fp, "\t"); 259 if (instr->mul0_src1 == gpir_codegen_src_ident && 260 !instr->mul0_neg) { 261 fprintf(fp, "mov.m0 "); 262 print_dest(instr, unit_mul_0, cur_dest_index, fp); 263 fprintf(fp, " "); 264 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr, 265 cur_dest_index, fp); 266 } else { 267 if (instr->mul_op == gpir_codegen_mul_op_complex2) 268 fprintf(fp, "complex2.m0 "); 269 else 270 fprintf(fp, "mul.m0 "); 271 272 print_dest(instr, unit_mul_0, cur_dest_index, fp); 273 fprintf(fp, " "); 274 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr, 275 cur_dest_index, fp); 276 fprintf(fp, " "); 277 if (instr->mul0_neg) 278 fprintf(fp, "-"); 279 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr, 280 cur_dest_index, fp); 281 } 282 283 fprintf(fp, "\n"); 284 } 285 286 if (instr->mul1_src0 != gpir_codegen_src_unused && 287 instr->mul1_src1 != gpir_codegen_src_unused) { 288 printed = true; 289 fprintf(fp, "\t"); 290 if (instr->mul1_src1 == gpir_codegen_src_ident && 291 !instr->mul1_neg) { 292 fprintf(fp, "mov.m1 "); 293 print_dest(instr, unit_mul_1, cur_dest_index, fp); 294 fprintf(fp, " "); 295 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr, 296 cur_dest_index, fp); 297 } else { 298 fprintf(fp, "mul.m1 "); 299 print_dest(instr, unit_mul_1, cur_dest_index, fp); 300 fprintf(fp, " "); 301 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr, 302 cur_dest_index, fp); 303 fprintf(fp, " "); 304 if (instr->mul1_neg) 305 fprintf(fp, "-"); 306 print_src(instr->mul1_src1, unit_mul_0, 1, instr, prev_instr, 307 cur_dest_index, fp); 308 } 309 fprintf(fp, "\n"); 310 } 311 312 break; 313 case gpir_codegen_mul_op_complex1: 314 printed = true; 315 fprintf(fp, "\tcomplex1.m01 "); 316 print_dest(instr, unit_mul_0, cur_dest_index, fp); 317 fprintf(fp, " "); 318 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr, 319 cur_dest_index, fp); 320 fprintf(fp, " "); 321 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr, 322 cur_dest_index, fp); 323 fprintf(fp, " "); 324 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr, 325 cur_dest_index, fp); 326 fprintf(fp, " "); 327 print_src(instr->mul1_src1, unit_mul_1, 1, instr, prev_instr, 328 cur_dest_index, fp); 329 fprintf(fp, "\n"); 330 break; 331 332 case gpir_codegen_mul_op_select: 333 printed = true; 334 fprintf(fp, "\tsel.m01 "); 335 print_dest(instr, unit_mul_0, cur_dest_index, fp); 336 fprintf(fp, " "); 337 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr, 338 cur_dest_index, fp); 339 fprintf(fp, " "); 340 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr, 341 cur_dest_index, fp); 342 fprintf(fp, " "); 343 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr, 344 cur_dest_index, fp); 345 fprintf(fp, "\n"); 346 break; 347 348 default: 349 printed = true; 350 fprintf(fp, "\tunknown%u.m01 ", instr->mul_op); 351 print_dest(instr, unit_mul_0, cur_dest_index, fp); 352 fprintf(fp, " "); 353 print_src(instr->mul0_src0, unit_mul_0, 0, instr, prev_instr, 354 cur_dest_index, fp); 355 fprintf(fp, " "); 356 print_src(instr->mul0_src1, unit_mul_0, 1, instr, prev_instr, 357 cur_dest_index, fp); 358 fprintf(fp, " "); 359 print_src(instr->mul1_src0, unit_mul_1, 0, instr, prev_instr, 360 cur_dest_index, fp); 361 fprintf(fp, " "); 362 print_src(instr->mul1_src1, unit_mul_1, 1, instr, prev_instr, 363 cur_dest_index, fp); 364 fprintf(fp, "\n"); 365 break; 366 } 367 368 return printed; 369} 370 371typedef struct { 372 const char *name; 373 unsigned srcs; 374} acc_op_info; 375 376#define CASE(_name, _srcs) \ 377 [gpir_codegen_acc_op_##_name] = { \ 378 .name = #_name, \ 379 .srcs = _srcs \ 380 } 381 382static const acc_op_info acc_op_infos[8] = { 383 CASE(add, 2), 384 CASE(floor, 1), 385 CASE(sign, 1), 386 CASE(ge, 2), 387 CASE(lt, 2), 388 CASE(min, 2), 389 CASE(max, 2), 390}; 391 392#undef CASE 393 394static bool 395print_acc(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 396 unsigned cur_dest_index, FILE *fp) 397{ 398 bool printed = false; 399 const acc_op_info op = acc_op_infos[instr->acc_op]; 400 401 if (instr->acc0_src0 != gpir_codegen_src_unused) { 402 printed = true; 403 fprintf(fp, "\t"); 404 acc_op_info acc0_op = op; 405 if (instr->acc0_src1 == gpir_codegen_src_ident && 406 instr->acc0_src1_neg) { 407 /* add x, -0 -> mov x */ 408 acc0_op.name = "mov"; 409 acc0_op.srcs = 1; 410 } 411 412 if (acc0_op.name) 413 fprintf(fp, "%s.a0 ", acc0_op.name); 414 else 415 fprintf(fp, "op%u.a0 ", instr->acc_op); 416 417 print_dest(instr, unit_acc_0, cur_dest_index, fp); 418 fprintf(fp, " "); 419 if (instr->acc0_src0_neg) 420 fprintf(fp, "-"); 421 print_src(instr->acc0_src0, unit_acc_0, 0, instr, prev_instr, 422 cur_dest_index, fp); 423 if (acc0_op.srcs > 1) { 424 fprintf(fp, " "); 425 if (instr->acc0_src1_neg) 426 fprintf(fp, "-"); 427 print_src(instr->acc0_src1, unit_acc_0, 1, instr, prev_instr, 428 cur_dest_index, fp); 429 } 430 431 fprintf(fp, "\n"); 432 } 433 434 if (instr->acc1_src0 != gpir_codegen_src_unused) { 435 printed = true; 436 fprintf(fp, "\t"); 437 acc_op_info acc1_op = op; 438 if (instr->acc1_src1 == gpir_codegen_src_ident && 439 instr->acc1_src1_neg) { 440 /* add x, -0 -> mov x */ 441 acc1_op.name = "mov"; 442 acc1_op.srcs = 1; 443 } 444 445 if (acc1_op.name) 446 fprintf(fp, "%s.a1 ", acc1_op.name); 447 else 448 fprintf(fp, "op%u.a1 ", instr->acc_op); 449 450 print_dest(instr, unit_acc_1, cur_dest_index, fp); 451 fprintf(fp, " "); 452 if (instr->acc1_src0_neg) 453 fprintf(fp, "-"); 454 print_src(instr->acc1_src0, unit_acc_1, 0, instr, prev_instr, 455 cur_dest_index, fp); 456 if (acc1_op.srcs > 1) { 457 fprintf(fp, " "); 458 if (instr->acc1_src1_neg) 459 fprintf(fp, "-"); 460 print_src(instr->acc1_src1, unit_acc_1, 1, instr, prev_instr, 461 cur_dest_index, fp); 462 } 463 464 fprintf(fp, "\n"); 465 } 466 467 return printed; 468} 469 470static bool 471print_pass(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 472 unsigned cur_dest_index, FILE *fp) 473{ 474 if (instr->pass_src == gpir_codegen_src_unused) 475 return false; 476 477 fprintf(fp, "\t"); 478 479 switch (instr->pass_op) { 480 case gpir_codegen_pass_op_pass: 481 fprintf(fp, "mov.p "); 482 break; 483 case gpir_codegen_pass_op_preexp2: 484 fprintf(fp, "preexp2.p "); 485 break; 486 case gpir_codegen_pass_op_postlog2: 487 fprintf(fp, "postlog2.p "); 488 break; 489 case gpir_codegen_pass_op_clamp: 490 fprintf(fp, "clamp.p "); 491 break; 492 default: 493 fprintf(fp, "unk%u.p ", instr->pass_op); 494 } 495 496 print_dest(instr, unit_pass, cur_dest_index, fp); 497 fprintf(fp, " "); 498 print_src(instr->pass_src, unit_pass, 0, instr, prev_instr, 499 cur_dest_index, fp); 500 501 if (instr->pass_op == gpir_codegen_pass_op_clamp) { 502 fprintf(fp, " "); 503 print_src(gpir_codegen_src_load_x, unit_pass, 1, instr, prev_instr, 504 cur_dest_index, fp); 505 fprintf(fp, " "); 506 print_src(gpir_codegen_src_load_y, unit_pass, 2, instr, prev_instr, 507 cur_dest_index, fp); 508 } 509 510 fprintf(fp, "\n"); 511 512 return true; 513} 514 515static bool 516print_complex(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 517 unsigned cur_dest_index, FILE *fp) 518{ 519 if (instr->complex_src == gpir_codegen_src_unused) 520 return false; 521 522 fprintf(fp, "\t"); 523 524 switch (instr->complex_op) { 525 case gpir_codegen_complex_op_nop: 526 return false; 527 528 case gpir_codegen_complex_op_exp2: 529 fprintf(fp, "exp2.c "); 530 break; 531 case gpir_codegen_complex_op_log2: 532 fprintf(fp, "log2.c "); 533 break; 534 case gpir_codegen_complex_op_rsqrt: 535 fprintf(fp, "rsqrt.c "); 536 break; 537 case gpir_codegen_complex_op_rcp: 538 fprintf(fp, "rcp.c "); 539 break; 540 case gpir_codegen_complex_op_pass: 541 case gpir_codegen_complex_op_temp_store_addr: 542 case gpir_codegen_complex_op_temp_load_addr_0: 543 case gpir_codegen_complex_op_temp_load_addr_1: 544 case gpir_codegen_complex_op_temp_load_addr_2: 545 fprintf(fp, "mov.c "); 546 break; 547 default: 548 fprintf(fp, "unk%u.c ", instr->complex_op); 549 } 550 551 print_dest(instr, unit_complex, cur_dest_index, fp); 552 fprintf(fp, " "); 553 print_src(instr->complex_src, unit_complex, 0, instr, prev_instr, 554 cur_dest_index, fp); 555 fprintf(fp, "\n"); 556 557 return true; 558} 559 560static void 561print_instr(gpir_codegen_instr *instr, gpir_codegen_instr *prev_instr, 562 unsigned instr_number, unsigned cur_dest_index, FILE *fp) 563{ 564 bool printed = false; 565 fprintf(fp, "%03d:", instr_number); 566 printed |= print_acc(instr, prev_instr, cur_dest_index, fp); 567 printed |= print_mul(instr, prev_instr, cur_dest_index, fp); 568 printed |= print_complex(instr, prev_instr, cur_dest_index, fp); 569 printed |= print_pass(instr, prev_instr, cur_dest_index, fp); 570 571 if (instr->branch) { 572 printed = true; 573 /* The branch condition is taken from the current pass unit result */ 574 fprintf(fp, "\tbranch ^%d %03d\n", cur_dest_index + unit_pass, 575 instr->branch_target + (instr->branch_target_lo ? 0 : 0x100)); 576 } 577 578 if (instr->unknown_1 != 0) { 579 printed = true; 580 fprintf(fp, "\tunknown_1 %u\n", instr->unknown_1); 581 } 582 583 if (!printed) 584 fprintf(fp, "\tnop\n"); 585} 586 587void 588gpir_disassemble_program(gpir_codegen_instr *code, unsigned num_instr, FILE *fp) 589{ 590 unsigned cur_dest_index = 0; 591 unsigned cur_instr = 0; 592 for (gpir_codegen_instr *instr = code; cur_instr < num_instr; 593 instr++, cur_instr++, cur_dest_index += num_units) { 594 print_instr(instr, instr - 1, cur_instr, cur_dest_index, fp); 595 } 596} 597 598