ir.om (41430B)
1 enum { 2 // Places 3 IOP_VAR, 4 IOP_VARREF, 5 IOP_FUNC, 6 IOP_CONST, 7 IOP_STR, 8 9 // Memory operations 10 IOP_LOAD, 11 IOP_STORE, 12 13 // Calling convention 14 IOP_RETVAL, 15 IOP_ARG, 16 17 // Unary arithmetic 18 IOP_NEG, 19 IOP_NOT, 20 21 // Binary arithmetic 22 IOP_ADD, 23 IOP_AND, 24 IOP_OR, 25 IOP_XOR, 26 IOP_DIV, 27 IOP_MOD, 28 IOP_LSH, 29 IOP_RSH, 30 IOP_MUL, 31 IOP_SUB, 32 33 // Comparison 34 IOP_EQ, 35 IOP_NE, 36 IOP_GT, 37 IOP_GE, 38 IOP_LT, 39 IOP_LE, 40 41 // End of block 42 IOP_CALL, 43 IOP_JUMP, 44 IOP_BRANCH, 45 IOP_RETURN, 46 } 47 48 struct irop { 49 kind: int; 50 a: *irop; 51 b: *irop; 52 n: int; 53 s: *byte; 54 slen: int; 55 t: *type; 56 mark: int; 57 filename: *byte; 58 lineno: int; 59 colno: int; 60 } 61 62 // A basic block is a sequence of expressions that end with a branch 63 struct irblock { 64 n: int; 65 ops: **irop; 66 ops_len: int; 67 ops_cap: int; 68 done: int; 69 back: **irblock; // WARNING: if the flow graph changes, this is stale. 70 back_len: int; 71 out: *irblock; 72 alt: *irblock; 73 label: *label; 74 mark: int; 75 } 76 77 struct irloopctx { 78 up: *irloopctx; 79 top: *irblock; 80 out: *irblock; 81 } 82 83 struct irlabel { 84 name: *byte; 85 left: *irlabel; 86 right: *irlabel; 87 block: *irblock; 88 } 89 90 struct irvar { 91 name: *byte; 92 left: *irvar; 93 right: *irvar; 94 t: *type; 95 n: int; 96 offset: int; 97 dead: int; 98 used_ref: int; 99 mark: int; 100 } 101 102 struct irfunc { 103 c: *compiler; 104 s: *assembler; 105 a: *alloc; 106 name: *byte; 107 filename: *byte; 108 lineno: int; 109 colno: int; 110 loopctx: *irloopctx; 111 blocks: **irblock; 112 blocks_len: int; 113 blocks_cap: int; 114 returns: **irblock; // WARNING: if the flow graph changes, this is stale. 115 returns_len: int; 116 cur: *irblock; 117 labels_tree: *irlabel; 118 vars_tree: *irvar; 119 vars: **irvar; 120 vars_len: int; 121 vars_cap: int; 122 arg_count: int; 123 frame_size: int; 124 } 125 126 func mkirblock(ic: *irfunc): *irblock { 127 var b: *irblock; 128 var tmp: **irblock; 129 var i: int; 130 131 if ic.blocks_len == ic.blocks_cap { 132 ic.blocks_cap = ic.blocks_cap * 2 + 16; 133 134 tmp = alloc(ic.a, sizeof(*tmp) * ic.blocks_cap) as **irblock; 135 136 i = 0; 137 loop { 138 if i == ic.blocks_len { 139 break; 140 } 141 142 tmp[i] = ic.blocks[i]; 143 144 i = i + 1; 145 } 146 147 ic.blocks = tmp; 148 } 149 150 b = alloc(ic.a, sizeof(*b)) as *irblock; 151 152 b.n = ic.blocks_len; 153 b.label = mklabel(ic.s); 154 b.ops = nil; 155 b.ops_len = 0; 156 b.ops_cap = 0; 157 b.done = 0; 158 b.out = nil; 159 b.alt = nil; 160 161 ic.blocks[ic.blocks_len] = b; 162 ic.blocks_len = ic.blocks_len + 1; 163 164 return b; 165 } 166 167 func ircopyloc(dst: *irop, src: *irop) { 168 dst.filename = src.filename; 169 dst.lineno = src.lineno; 170 dst.colno = src.colno; 171 } 172 173 func mkirop(ic: *irfunc, kind: int, a: *irop, b: *irop): *irop { 174 var o: *irop; 175 176 o = alloc(ic.a, sizeof(*o)) as *irop; 177 178 o.kind = kind; 179 o.a = a; 180 o.b = b; 181 182 o.filename = ic.c.filename; 183 o.lineno = ic.c.lineno; 184 o.colno = ic.c.colno; 185 186 return o; 187 } 188 189 func mkirconst(ic: *irfunc, n: int): *irop { 190 var o: *irop; 191 192 o = mkirop(ic, IOP_CONST, nil, nil); 193 194 o.n = n; 195 196 return o; 197 } 198 199 func mkirarg(ic: *irfunc, n: int, a: *irop): *irop { 200 var o: *irop; 201 202 o = mkirop(ic, IOP_ARG, a, nil); 203 204 o.n = n; 205 206 return o; 207 } 208 209 func mkirvarop(ic: *irfunc, name: *byte): *irop { 210 var iv: *irvar; 211 var o: *irop; 212 213 iv = *irfind_var(ic, name); 214 if !iv { 215 fputs(nil, name); 216 cdie(ic.c, "no such variable"); 217 } 218 219 o = mkirop(ic, IOP_VAR, nil, nil); 220 221 o.n = iv.n; 222 223 return o; 224 } 225 226 func mkirretval(ic: *irfunc, a: *irop, t: *type): *irop { 227 var o: *irop; 228 229 o = mkirop(ic, IOP_RETVAL, a, nil); 230 231 o.t = t; 232 233 return o; 234 } 235 236 func mkirstr(ic: *irfunc, s: *byte, slen: int): *irop { 237 var o: *irop; 238 239 o = mkirop(ic, IOP_STR, nil, nil); 240 241 o.s = s; 242 o.slen = slen; 243 244 return o; 245 } 246 247 func mkirfuncref(ic: *irfunc, name: *byte): *irop { 248 var o: *irop; 249 250 o = mkirop(ic, IOP_FUNC, nil, nil); 251 252 o.s = name; 253 o.slen = strlen(name); 254 255 return o; 256 } 257 258 func mkirvar(ic: *irfunc, name: *byte, t: *type): *irvar { 259 var v: *irvar; 260 var tmp: **irvar; 261 var i: int; 262 263 if ic.vars_len == ic.vars_cap { 264 ic.vars_cap = ic.vars_cap * 2 + 16; 265 266 tmp = alloc(ic.a, sizeof(*tmp) * ic.vars_cap) as **irvar; 267 268 i = 0; 269 loop { 270 if i == ic.vars_len { 271 break; 272 } 273 274 tmp[i] = ic.vars[i]; 275 276 i = i + 1; 277 } 278 279 ic.vars = tmp; 280 } 281 282 i = ic.vars_len; 283 284 v = alloc(ic.a, sizeof(*v)) as *irvar; 285 286 v.n = i; 287 v.name = name; 288 v.t = t; 289 290 ic.vars[i] = v; 291 ic.vars_len = ic.vars_len + 1; 292 293 return v; 294 } 295 296 func mkirtmp(ic: *irfunc, t: *type): *irop { 297 var o: *irop; 298 var v: *irvar; 299 300 v = mkirvar(ic, nil, t); 301 302 o = mkirop(ic, IOP_VAR, nil, nil); 303 o.n = v.n; 304 305 return o; 306 } 307 308 func irfind_var(ic: *irfunc, name: *byte): **irvar { 309 var link: **irvar; 310 var v: *irvar; 311 var dir: int; 312 313 link = &ic.vars_tree; 314 loop { 315 v = *link; 316 if !v { 317 return link; 318 } 319 320 dir = strcmp(name, v.name); 321 322 if dir == 0 { 323 return link; 324 } else if dir < 0 { 325 link = &v.left; 326 } else { // dir > 0 327 link = &v.right; 328 } 329 } 330 } 331 332 func iraddarg(ic: *irfunc, name: *byte, t: *type): *irvar { 333 var iv: **irvar; 334 335 iv = irfind_var(ic, name); 336 337 if *iv { 338 cdie(ic.c, "duplicate var"); 339 } 340 341 *iv = mkirvar(ic, name, t); 342 343 ic.arg_count = ic.arg_count + 1; 344 345 return *iv; 346 } 347 348 func iraddvar(ic: *irfunc, name: *byte, t: *type) { 349 var iv: **irvar; 350 351 iv = irfind_var(ic, name); 352 353 if *iv { 354 cdie(ic.c, "duplicate var"); 355 } 356 357 *iv = mkirvar(ic, name, t); 358 } 359 360 func ircall(ic: *irfunc, fp: *irop, nargs: int) { 361 var o: *irop; 362 var cur: *irblock; 363 var next: *irblock; 364 365 // Emit the call 366 o = mkirop(ic, IOP_CALL, fp, nil); 367 o.n = nargs; 368 iraddop(ic, o); 369 370 // Link the return path 371 next = mkirblock(ic); 372 373 cur = ic.cur; 374 if cur { 375 if cur.done { 376 cdie(ic.c, "block already done"); 377 } 378 379 cur.done = 1; 380 cur.out = next; 381 } 382 383 ic.cur = next; 384 } 385 386 func call_to_ir(ic: *irfunc, n: *node): *irop { 387 var o: *irop; 388 var a: *irop; 389 var b: *irop; 390 var ret: *irop; 391 var next: *irblock; 392 var cur: *irblock; 393 var arg: *node; 394 var tmp: **irop; 395 var fp: *irop; 396 var i: int; 397 var count: int; 398 var slen: int; 399 var blob: *byte; 400 401 if n.a.kind == N_IDENT && strcmp(n.a.s, "_include") == 0 { 402 if n.b.a.kind != N_STR { 403 cdie(ic.c, "non literal include"); 404 } 405 406 blob = gather_include(ic.c, n.b.a.s, &slen); 407 408 a = expr_to_ir(ic, n.b.b.a); 409 b = mkirconst(ic, slen); 410 o = mkirop(ic, IOP_STORE, a, b); 411 o.t = n.b.b.a.t.val; 412 iraddop(ic, o); 413 414 o = mkirstr(ic, blob, slen); 415 return o; 416 } 417 418 // Evaluate the expression left to right starting with the function 419 fp = mkirtmp(ic, n.a.t); 420 b = expr_to_ir(ic, n.a); 421 o = mkirop(ic, IOP_STORE, fp, b); 422 o.t = n.a.t; 423 iraddop(ic, o); 424 425 // Count the number of arguments 426 arg = n.b; 427 count = 0; 428 loop { 429 if !arg { 430 break; 431 } 432 433 count = count + 1; 434 435 arg = arg.b; 436 } 437 438 tmp = alloc(ic.a, sizeof(*tmp) * count) as **irop; 439 440 // Evaluate the arguments left to right 441 arg = n.b; 442 i = 0; 443 loop { 444 if !arg { 445 break; 446 } 447 448 // Create a temporary for this argument 449 tmp[i] = mkirtmp(ic, arg.a.t); 450 451 // Compute the argument value 452 b = expr_to_ir(ic, arg.a); 453 454 // Save the value 455 o = mkirop(ic, IOP_STORE, tmp[i], b); 456 o.t = arg.a.t; 457 iraddop(ic, o); 458 459 arg = arg.b; 460 i = i + 1; 461 } 462 463 // Emit arg nodes just before the call left to right 464 arg = n.b; 465 i = 0; 466 loop { 467 if i == count { 468 break; 469 } 470 471 o = mkirarg(ic, i, tmp[i]); 472 iraddop(ic, o); 473 474 arg = arg.b; 475 i = i + 1; 476 } 477 478 free(ic.a, tmp as *byte); 479 480 // Add a temporary for the return value 481 ret = mkirtmp(ic, n.t); 482 o = mkirretval(ic, ret, n.t); 483 iraddop(ic, o); 484 485 ircall(ic, fp, count); 486 487 // Return an expression that contains the return value 488 return ret; 489 } 490 491 func expr_to_ir(ic: *irfunc, n: *node): *irop { 492 var a: *irop; 493 var b: *irop; 494 var c: *irop; 495 var d: *irop; 496 var e: *irop; 497 var o: *irop; 498 var bool_body: *irblock; 499 var bool_next: *irblock; 500 var bool_final: *irblock; 501 var bool_out: *irblock; 502 var v: *decl; 503 var iv: *irvar; 504 var kind: int; 505 var size: int; 506 507 assert(!!n, "expected node"); 508 509 ic.c.filename = n.filename; 510 ic.c.lineno = n.lineno; 511 ic.c.colno = n.colno; 512 513 kind = n.kind; 514 if kind == N_NIL { 515 o = mkirconst(ic, 0); 516 return o; 517 } else if kind == N_NUM { 518 o = mkirconst(ic, n.n); 519 return o; 520 } else if kind == N_CHAR { 521 o = mkirconst(ic, n.n); 522 return o; 523 } else if kind == N_SIZEOF { 524 if n.a.t.kind == TY_BYTE { 525 size = 1; 526 } else { 527 size = type_sizeof(ic.c, n.a.t); 528 } 529 530 o = mkirconst(ic, size); 531 return o; 532 } else if kind == N_STR { 533 o = mkirstr(ic, n.s, strlen(n.s)); 534 return o; 535 } else if kind == N_CALL { 536 o = call_to_ir(ic, n); 537 return o; 538 } else if kind == N_IDENT { 539 v = find(ic.c, n.s, nil, 0); 540 541 // enum constant 542 if v && v.enum_defined { 543 o = mkirconst(ic, v.enum_value); 544 return o; 545 } 546 547 // variable 548 iv = *irfind_var(ic, n.s); 549 if iv { 550 o = mkirop(ic, IOP_VAR, nil, nil); 551 o.n = iv.n; 552 return o; 553 } 554 555 // function 556 if v && v.func_defined { 557 o = mkirfuncref(ic, n.s); 558 return o; 559 } 560 561 cdie(ic.c, "no such symbol"); 562 return nil; 563 } else if kind == N_DOT { 564 if n.a.t.kind == TY_PTR { 565 b = expr_to_ir(ic, n.a); 566 v = find(ic.c, n.a.t.val.st.name, n.b.s, 0); 567 } else { 568 a = expr_to_ir(ic, n.a); 569 if a.kind == IOP_VAR { 570 b = mkirop(ic, IOP_VARREF, nil, nil); 571 b.n = a.n; 572 ic.vars[a.n].used_ref = 1; 573 } else if a.kind == IOP_LOAD { 574 b = a.a; 575 } else { 576 die("invalid ref"); 577 } 578 v = find(ic.c, n.a.t.st.name, n.b.s, 0); 579 } 580 c = mkirconst(ic, v.member_offset); 581 d = mkirop(ic, IOP_ADD, b, c); 582 o = mkirop(ic, IOP_LOAD, d, nil); 583 o.t = n.t; 584 return o; 585 } else if kind == N_REF { 586 a = expr_to_ir(ic, n.a); 587 if a.kind == IOP_VAR { 588 o = mkirop(ic, IOP_VARREF, nil, nil); 589 o.n = a.n; 590 ic.vars[a.n].used_ref = 1; 591 return o; 592 } else if a.kind == IOP_LOAD { 593 return a.a; 594 } else { 595 die("invalid ref"); 596 return nil; 597 } 598 } else if kind == N_DEREF { 599 a = expr_to_ir(ic, n.a); 600 o = mkirop(ic, IOP_LOAD, a, nil); 601 o.t = n.t; 602 return o; 603 } else if kind == N_INDEX { 604 a = expr_to_ir(ic, n.a); 605 b = expr_to_ir(ic, n.b); 606 if n.t.kind == TY_BYTE { 607 size = 1; 608 } else { 609 size = type_sizeof(ic.c, n.t); 610 } 611 c = mkirconst(ic, size); 612 d = mkirop(ic, IOP_MUL, b, c); 613 e = mkirop(ic, IOP_ADD, a, d); 614 o = mkirop(ic, IOP_LOAD, e, nil); 615 o.t = n.t; 616 return o; 617 } else if kind == N_ASSIGN { 618 a = expr_to_ir(ic, n.a); 619 b = expr_to_ir(ic, n.b); 620 o = mkirop(ic, IOP_STORE, a, b); 621 o.t = n.t; 622 return o; 623 } else if kind == N_POS { 624 o = expr_to_ir(ic, n.a); 625 return o; 626 } else if kind == N_CAST { 627 o = expr_to_ir(ic, n.a); 628 return o; 629 } else if kind == N_NEG { 630 a = expr_to_ir(ic, n.a); 631 o = mkirop(ic, IOP_NEG, a, nil); 632 return o; 633 } else if kind == N_NOT { 634 a = expr_to_ir(ic, n.a); 635 o = mkirop(ic, IOP_NOT, a, nil); 636 return o; 637 } else if kind == N_BNOT { 638 bool_body = mkirblock(ic); 639 bool_next = mkirblock(ic); 640 bool_out = mkirblock(ic); 641 e = mkirtmp(ic, n.t); 642 643 a = expr_to_ir(ic, n.a); 644 irbranch(ic, a, bool_next, bool_body); 645 646 b = mkirconst(ic, 0); 647 o = mkirop(ic, IOP_STORE, e, b); 648 o.t = n.t; 649 iraddop(ic, o); 650 irjump(ic, bool_out, bool_next); 651 652 b = mkirconst(ic, 1); 653 o = mkirop(ic, IOP_STORE, e, b); 654 o.t = n.t; 655 iraddop(ic, o); 656 irjump(ic, bool_out, bool_out); 657 658 return e; 659 } else if kind == N_BOR { 660 bool_body = mkirblock(ic); 661 bool_next = mkirblock(ic); 662 bool_final = mkirblock(ic); 663 bool_out = mkirblock(ic); 664 e = mkirtmp(ic, n.t); 665 666 a = expr_to_ir(ic, n.a); 667 irbranch(ic, a, bool_next, bool_body); 668 669 b = mkirconst(ic, 1); 670 o = mkirop(ic, IOP_STORE, e, b); 671 o.t = n.t; 672 iraddop(ic, o); 673 irjump(ic, bool_out, bool_next); 674 675 bool_next = mkirblock(ic); 676 677 a = expr_to_ir(ic, n.b); 678 irbranch(ic, a, bool_next, bool_final); 679 680 b = mkirconst(ic, 1); 681 o = mkirop(ic, IOP_STORE, e, b); 682 o.t = n.t; 683 iraddop(ic, o); 684 irjump(ic, bool_out, bool_next); 685 686 b = mkirconst(ic, 0); 687 o = mkirop(ic, IOP_STORE, e, b); 688 o.t = n.t; 689 iraddop(ic, o); 690 irjump(ic, bool_out, bool_out); 691 692 return e; 693 } else if kind == N_BAND { 694 bool_body = mkirblock(ic); 695 bool_next = mkirblock(ic); 696 bool_final = mkirblock(ic); 697 bool_out = mkirblock(ic); 698 e = mkirtmp(ic, n.t); 699 700 a = expr_to_ir(ic, n.a); 701 irbranch(ic, a, bool_next, bool_body); 702 703 a = expr_to_ir(ic, n.b); 704 irbranch(ic, a, bool_next, bool_final); 705 706 b = mkirconst(ic, 1); 707 o = mkirop(ic, IOP_STORE, e, b); 708 o.t = n.t; 709 iraddop(ic, o); 710 irjump(ic, bool_out, bool_next); 711 712 b = mkirconst(ic, 0); 713 o = mkirop(ic, IOP_STORE, e, b); 714 o.t = n.t; 715 iraddop(ic, o); 716 irjump(ic, bool_out, bool_out); 717 718 return e; 719 } else if kind == N_LT { 720 a = expr_to_ir(ic, n.a); 721 b = expr_to_ir(ic, n.b); 722 o = mkirop(ic, IOP_LT, a, b); 723 return o; 724 } else if kind == N_GT { 725 a = expr_to_ir(ic, n.a); 726 b = expr_to_ir(ic, n.b); 727 o = mkirop(ic, IOP_GT, a, b); 728 return o; 729 } else if kind == N_LE { 730 a = expr_to_ir(ic, n.a); 731 b = expr_to_ir(ic, n.b); 732 o = mkirop(ic, IOP_LE, a, b); 733 return o; 734 } else if kind == N_GE { 735 a = expr_to_ir(ic, n.a); 736 b = expr_to_ir(ic, n.b); 737 o = mkirop(ic, IOP_GE, a, b); 738 return o; 739 } else if kind == N_EQ { 740 a = expr_to_ir(ic, n.a); 741 b = expr_to_ir(ic, n.b); 742 o = mkirop(ic, IOP_EQ, a, b); 743 return o; 744 } else if kind == N_NE { 745 a = expr_to_ir(ic, n.a); 746 b = expr_to_ir(ic, n.b); 747 o = mkirop(ic, IOP_NE, a, b); 748 return o; 749 } else if kind == N_ADD { 750 a = expr_to_ir(ic, n.a); 751 b = expr_to_ir(ic, n.b); 752 o = mkirop(ic, IOP_ADD, a, b); 753 return o; 754 } else if kind == N_SUB { 755 a = expr_to_ir(ic, n.a); 756 b = expr_to_ir(ic, n.b); 757 o = mkirop(ic, IOP_SUB, a, b); 758 return o; 759 } else if kind == N_MUL { 760 a = expr_to_ir(ic, n.a); 761 b = expr_to_ir(ic, n.b); 762 o = mkirop(ic, IOP_MUL, a, b); 763 return o; 764 } else if kind == N_DIV { 765 a = expr_to_ir(ic, n.a); 766 b = expr_to_ir(ic, n.b); 767 o = mkirop(ic, IOP_DIV, a, b); 768 return o; 769 } else if kind == N_MOD { 770 a = expr_to_ir(ic, n.a); 771 b = expr_to_ir(ic, n.b); 772 o = mkirop(ic, IOP_MOD, a, b); 773 return o; 774 } else if kind == N_LSH { 775 a = expr_to_ir(ic, n.a); 776 b = expr_to_ir(ic, n.b); 777 o = mkirop(ic, IOP_LSH, a, b); 778 return o; 779 } else if kind == N_RSH { 780 a = expr_to_ir(ic, n.a); 781 b = expr_to_ir(ic, n.b); 782 o = mkirop(ic, IOP_RSH, a, b); 783 return o; 784 } else if kind == N_AND { 785 a = expr_to_ir(ic, n.a); 786 b = expr_to_ir(ic, n.b); 787 o = mkirop(ic, IOP_AND, a, b); 788 return o; 789 } else if kind == N_OR { 790 a = expr_to_ir(ic, n.a); 791 b = expr_to_ir(ic, n.b); 792 o = mkirop(ic, IOP_OR, a, b); 793 return o; 794 } else if kind == N_XOR { 795 a = expr_to_ir(ic, n.a); 796 b = expr_to_ir(ic, n.b); 797 o = mkirop(ic, IOP_XOR, a, b); 798 return o; 799 } else { 800 cdie(ic.c, "unknown expression"); 801 return nil; 802 } 803 } 804 805 func iraddop(ic: *irfunc, o: *irop) { 806 var cur: *irblock; 807 var ops: **irop; 808 var i: int; 809 810 cur = ic.cur; 811 if !cur { 812 return; 813 } 814 815 assert(!!o, "expected op to add"); 816 assert(!cur.done, "block already closed"); 817 818 if cur.ops_len == cur.ops_cap { 819 cur.ops_cap = cur.ops_cap * 2 + 16; 820 821 ops = alloc(ic.a, cur.ops_cap * sizeof(*ops)) as **irop; 822 823 i = 0; 824 loop { 825 if i == cur.ops_len { 826 break; 827 } 828 829 ops[i] = cur.ops[i]; 830 831 i = i + 1; 832 } 833 834 cur.ops = ops; 835 } 836 837 cur.ops[cur.ops_len] = o; 838 cur.ops_len = cur.ops_len + 1; 839 } 840 841 func irjump(ic: *irfunc, to: *irblock, next: *irblock) { 842 var cur: *irblock; 843 var o: *irop; 844 845 o = mkirop(ic, IOP_JUMP, nil, nil); 846 iraddop(ic, o); 847 848 cur = ic.cur; 849 if cur { 850 if cur.done { 851 cdie(ic.c, "block already done"); 852 } 853 854 cur.done = 1; 855 cur.out = to; 856 } 857 858 ic.cur = next; 859 } 860 861 func irbranch(ic: *irfunc, cond: *irop, alt: *irblock, next: *irblock) { 862 var cur: *irblock; 863 var o: *irop; 864 865 o = mkirop(ic, IOP_BRANCH, cond, nil); 866 iraddop(ic, o); 867 868 cur = ic.cur; 869 if cur { 870 if cur.done { 871 cdie(ic.c, "block already done"); 872 } 873 874 cur.done = 1; 875 cur.alt = alt; 876 cur.out = next; 877 } 878 879 ic.cur = next; 880 } 881 882 func irreturn(ic: *irfunc, value: *irop) { 883 var cur: *irblock; 884 var o: *irop; 885 886 o = mkirop(ic, IOP_RETURN, value, nil); 887 iraddop(ic, o); 888 889 cur = ic.cur; 890 if cur { 891 if cur.done { 892 cdie(ic.c, "block already done"); 893 } 894 895 cur.done = 1; 896 } 897 898 ic.cur = nil; 899 } 900 901 func stmt_to_ir(ic: *irfunc, n: *node) { 902 var loopctx: irloopctx; 903 var cond_body: *irblock; 904 var cond_next: *irblock; 905 var cond_out: *irblock; 906 var label: *irblock; 907 var value: *irop; 908 var kind: int; 909 910 if !n { 911 return; 912 } 913 914 ic.c.filename = n.filename; 915 ic.c.lineno = n.lineno; 916 ic.c.colno = n.colno; 917 918 kind = n.kind; 919 if kind == N_CONDLIST { 920 // Create join point for out 921 cond_out = mkirblock(ic); 922 923 loop { 924 // No more conditions 925 if !n { 926 break; 927 } 928 929 // Final else branch 930 if !n.a.a { 931 stmt_to_ir(ic, n.a.b); 932 break; 933 } 934 935 cond_body = mkirblock(ic); 936 cond_next = mkirblock(ic); 937 938 // Compile condition, else branch to out 939 value = expr_to_ir(ic, n.a.a); 940 irbranch(ic, value, cond_next, cond_body); 941 942 // Compile body on the taken branch 943 stmt_to_ir(ic, n.a.b); 944 irjump(ic, cond_out, cond_next); 945 946 n = n.b; 947 } 948 949 // Jump to out 950 irjump(ic, cond_out, cond_out); 951 } else if kind == N_STMTLIST { 952 loop { 953 if !n { 954 break; 955 } 956 957 // Compile each statement in the list 958 stmt_to_ir(ic, n.a); 959 960 n = n.b; 961 } 962 } else if kind == N_LOOP { 963 // Push a new loopctx onto the stack 964 loopctx.up = ic.loopctx; 965 loopctx.top = mkirblock(ic); 966 loopctx.out = mkirblock(ic); 967 ic.loopctx = &loopctx; 968 969 // Jump to top 970 irjump(ic, loopctx.top, loopctx.top); 971 972 // Compile the body 973 stmt_to_ir(ic, n.a); 974 975 // Jump to top 976 irjump(ic, loopctx.top, loopctx.out); 977 978 // Pop the loopctx 979 ic.loopctx = loopctx.up; 980 } else if kind == N_BREAK { 981 if !ic.loopctx { 982 cdie(ic.c, "break not in loop"); 983 } 984 985 // jump to out 986 irjump(ic, ic.loopctx.out, nil); 987 } else if kind == N_CONTINUE { 988 if !ic.loopctx { 989 cdie(ic.c, "continue not in loop"); 990 } 991 992 // jump to top 993 irjump(ic, ic.loopctx.top, nil); 994 } else if kind == N_RETURN { 995 if n.a { 996 value = expr_to_ir(ic, n.a); 997 } else { 998 value = mkirconst(ic, 0); 999 } 1000 irreturn(ic, value); 1001 } else if kind == N_LABEL { 1002 // jump to label and fill in it's definition 1003 label = irfind_block(ic, n.a.s, 0); 1004 irjump(ic, label, label); 1005 } else if kind == N_GOTO { 1006 // jump 1007 label = irfind_block(ic, n.a.s, 0); 1008 irjump(ic, label, nil); 1009 } else if kind == N_VARDECL { 1010 // Nothing to do. 1011 // Vardecl creates a variable for the whole function. 1012 // Crossing the declaration itself does nothing. 1013 } else { 1014 value = expr_to_ir(ic, n); 1015 iraddop(ic, value); 1016 } 1017 } 1018 1019 func irfind_block(ic: *irfunc, name: *byte, make: int): *irblock { 1020 var link: **irlabel; 1021 var l: *irlabel; 1022 var dir: int; 1023 1024 link = &ic.labels_tree; 1025 loop { 1026 l = *link; 1027 1028 if !l { 1029 break; 1030 } 1031 1032 dir = strcmp(name, l.name); 1033 1034 if dir == 0 { 1035 if make { 1036 cdie(ic.c, "duplicate label"); 1037 } 1038 1039 return l.block; 1040 } else if dir < 0 { 1041 link = &l.left; 1042 } else { // dir > 0 1043 link = &l.right; 1044 } 1045 } 1046 1047 if !make { 1048 cdie(ic.c, "no such label"); 1049 } 1050 1051 l = alloc(ic.a, sizeof(*l)) as *irlabel; 1052 1053 l.name = name; 1054 l.left = nil; 1055 l.right = nil; 1056 l.block = mkirblock(ic); 1057 1058 *link = l; 1059 1060 return l.block; 1061 } 1062 1063 func labels_to_ir(ic: *irfunc, n: *node) { 1064 var kind: int; 1065 var name: *byte; 1066 1067 if !n { 1068 return; 1069 } 1070 1071 ic.c.filename = n.filename; 1072 ic.c.lineno = n.lineno; 1073 ic.c.colno = n.colno; 1074 1075 kind = n.kind; 1076 if kind == N_CONDLIST { 1077 loop { 1078 if !n { 1079 break; 1080 } 1081 1082 labels_to_ir(ic, n.a.b); 1083 1084 n = n.b; 1085 } 1086 } else if kind == N_STMTLIST { 1087 loop { 1088 if !n { 1089 break; 1090 } 1091 1092 labels_to_ir(ic, n.a); 1093 1094 n = n.b; 1095 } 1096 } else if kind == N_LOOP { 1097 labels_to_ir(ic, n.a); 1098 } else if kind == N_LABEL { 1099 name = n.a.s; 1100 irfind_block(ic, name, 1); 1101 } 1102 } 1103 1104 func args_to_ir(ic: *irfunc, n: *node) { 1105 var name: *byte; 1106 var t: *type; 1107 1108 loop { 1109 if !n { 1110 break; 1111 } 1112 1113 name = n.a.a.s; 1114 1115 t = prototype(ic.c, n.a.b); 1116 1117 iraddarg(ic, name, t); 1118 1119 n = n.b; 1120 } 1121 } 1122 1123 func locals_to_ir(ic: *irfunc, n: *node) { 1124 var name: *byte; 1125 var t: *type; 1126 var kind: int; 1127 1128 if !n { 1129 return; 1130 } 1131 1132 ic.c.filename = n.filename; 1133 ic.c.lineno = n.lineno; 1134 ic.c.colno = n.colno; 1135 1136 kind = n.kind; 1137 if kind == N_CONDLIST { 1138 loop { 1139 if !n { 1140 break; 1141 } 1142 1143 locals_to_ir(ic, n.a.b); 1144 1145 n = n.b; 1146 } 1147 } else if kind == N_STMTLIST { 1148 loop { 1149 if !n { 1150 break; 1151 } 1152 1153 locals_to_ir(ic, n.a); 1154 1155 n = n.b; 1156 } 1157 } else if kind == N_LOOP { 1158 locals_to_ir(ic, n.a); 1159 } else if kind == N_VARDECL { 1160 name = n.a.s; 1161 1162 t = prototype(ic.c, n.b); 1163 1164 iraddvar(ic, name, t); 1165 } 1166 } 1167 1168 func mkirfunc(c: *compiler, name: *byte): *irfunc { 1169 var ic: *irfunc; 1170 1171 ic = alloc(c.a, sizeof(*ic)) as *irfunc; 1172 1173 ic.c = c; 1174 ic.a = c.a; 1175 ic.s = c.s; 1176 1177 mkirblock(ic); 1178 ic.cur = ic.blocks[0]; 1179 1180 ic.name = name; 1181 1182 return ic; 1183 } 1184 1185 func func_to_ir(c: *compiler, n: *node): *irfunc { 1186 var ic: *irfunc; 1187 var value: *irop; 1188 var t: *type; 1189 1190 if !n { 1191 return nil; 1192 } 1193 1194 ic = mkirfunc(c, n.a.a.s); 1195 1196 ic.filename = n.filename; 1197 ic.lineno = n.lineno; 1198 ic.colno = n.colno; 1199 1200 args_to_ir(ic, n.a.b.a); 1201 1202 locals_to_ir(ic, n.b); 1203 1204 labels_to_ir(ic, n.b); 1205 1206 stmt_to_ir(ic, n.b); 1207 1208 t = prototype(c, n.a.b); 1209 if t.val.kind == TY_VOID { 1210 value = mkirconst(ic, 0); 1211 irreturn(ic, value); 1212 } 1213 1214 return ic; 1215 } 1216 1217 // Depth-first reset all the marks 1218 func irreset(b: *irblock) { 1219 if !b { 1220 return; 1221 } 1222 1223 if !b.mark { 1224 return; 1225 } 1226 1227 b.mark = 0; 1228 1229 irreset(b.out); 1230 irreset(b.alt); 1231 } 1232 1233 func irshow4(out: *file, o: *irop) { 1234 var kind: int; 1235 1236 if !o { 1237 fputs(out, "(nil)"); 1238 return; 1239 } 1240 1241 kind = o.kind; 1242 if kind == IOP_VAR { 1243 fputs(out, "(var "); 1244 fputd(out, o.n); 1245 fputs(out, ")"); 1246 } else if kind == IOP_VARREF { 1247 fputs(out, "(varref "); 1248 fputd(out, o.n); 1249 fputs(out, ")"); 1250 } else if kind == IOP_FUNC { 1251 fputs(out, "(func "); 1252 fputs(out, o.s); 1253 fputs(out, ")"); 1254 } else if kind == IOP_CONST { 1255 fputs(out, "(const "); 1256 fputd(out, o.n); 1257 fputs(out, ")"); 1258 } else if kind == IOP_STR { 1259 fputs(out, "(str)"); 1260 } else if kind == IOP_LOAD { 1261 fputs(out, "(load "); 1262 irshow4(out, o.a); 1263 fputs(out, ")"); 1264 } else if kind == IOP_STORE { 1265 fputs(out, "(store "); 1266 irshow4(out, o.a); 1267 fputs(out, " "); 1268 irshow4(out, o.b); 1269 fputs(out, ")"); 1270 } else if kind == IOP_RETVAL { 1271 fputs(out, "(retval "); 1272 irshow4(out, o.a); 1273 fputs(out, ")"); 1274 } else if kind == IOP_ARG { 1275 fputs(out, "(arg "); 1276 fputd(out, o.n); 1277 fputs(out, " "); 1278 irshow4(out, o.a); 1279 fputs(out, ")"); 1280 } else if kind == IOP_NEG { 1281 fputs(out, "(neg "); 1282 irshow4(out, o.a); 1283 fputs(out, ")"); 1284 } else if kind == IOP_NOT { 1285 fputs(out, "(not "); 1286 irshow4(out, o.a); 1287 fputs(out, ")"); 1288 } else if kind == IOP_ADD { 1289 fputs(out, "(add "); 1290 irshow4(out, o.a); 1291 fputs(out, " "); 1292 irshow4(out, o.b); 1293 fputs(out, ")"); 1294 } else if kind == IOP_AND { 1295 fputs(out, "(and "); 1296 irshow4(out, o.a); 1297 fputs(out, " "); 1298 irshow4(out, o.b); 1299 fputs(out, ")"); 1300 } else if kind == IOP_OR { 1301 fputs(out, "(or "); 1302 irshow4(out, o.a); 1303 fputs(out, " "); 1304 irshow4(out, o.b); 1305 fputs(out, ")"); 1306 } else if kind == IOP_XOR { 1307 fputs(out, "(xor "); 1308 irshow4(out, o.a); 1309 fputs(out, " "); 1310 irshow4(out, o.b); 1311 fputs(out, ")"); 1312 } else if kind == IOP_DIV { 1313 fputs(out, "(div "); 1314 irshow4(out, o.a); 1315 fputs(out, " "); 1316 irshow4(out, o.b); 1317 fputs(out, ")"); 1318 } else if kind == IOP_MOD { 1319 fputs(out, "(mod "); 1320 irshow4(out, o.a); 1321 fputs(out, " "); 1322 irshow4(out, o.b); 1323 fputs(out, ")"); 1324 } else if kind == IOP_LSH { 1325 fputs(out, "(lsh "); 1326 irshow4(out, o.a); 1327 fputs(out, " "); 1328 irshow4(out, o.b); 1329 fputs(out, ")"); 1330 } else if kind == IOP_RSH { 1331 fputs(out, "(rsh "); 1332 irshow4(out, o.a); 1333 fputs(out, " "); 1334 irshow4(out, o.b); 1335 fputs(out, ")"); 1336 } else if kind == IOP_MUL { 1337 fputs(out, "(mul "); 1338 irshow4(out, o.a); 1339 fputs(out, " "); 1340 irshow4(out, o.b); 1341 fputs(out, ")"); 1342 } else if kind == IOP_SUB { 1343 fputs(out, "(sub "); 1344 irshow4(out, o.a); 1345 fputs(out, " "); 1346 irshow4(out, o.b); 1347 fputs(out, ")"); 1348 } else if kind == IOP_EQ { 1349 fputs(out, "(eq "); 1350 irshow4(out, o.a); 1351 fputs(out, " "); 1352 irshow4(out, o.b); 1353 fputs(out, ")"); 1354 } else if kind == IOP_NE { 1355 fputs(out, "(ne "); 1356 irshow4(out, o.a); 1357 fputs(out, " "); 1358 irshow4(out, o.b); 1359 fputs(out, ")"); 1360 } else if kind == IOP_GT { 1361 fputs(out, "(gt "); 1362 irshow4(out, o.a); 1363 fputs(out, " "); 1364 irshow4(out, o.b); 1365 fputs(out, ")"); 1366 } else if kind == IOP_GE { 1367 fputs(out, "(ge "); 1368 irshow4(out, o.a); 1369 fputs(out, " "); 1370 irshow4(out, o.b); 1371 fputs(out, ")"); 1372 } else if kind == IOP_LT { 1373 fputs(out, "(lt "); 1374 irshow4(out, o.a); 1375 fputs(out, " "); 1376 irshow4(out, o.b); 1377 fputs(out, ")"); 1378 } else if kind == IOP_LE { 1379 fputs(out, "(le "); 1380 irshow4(out, o.a); 1381 fputs(out, " "); 1382 irshow4(out, o.b); 1383 fputs(out, ")"); 1384 } else if kind == IOP_CALL { 1385 fputs(out, "(call "); 1386 irshow4(out, o.a); 1387 fputs(out, ")"); 1388 } else if kind == IOP_JUMP { 1389 fputs(out, "(jump)"); 1390 } else if kind == IOP_BRANCH { 1391 fputs(out, "(branch "); 1392 irshow4(out, o.a); 1393 fputs(out, ")"); 1394 } else if kind == IOP_RETURN { 1395 fputs(out, "(return "); 1396 irshow4(out, o.a); 1397 fputs(out, ")"); 1398 } else { 1399 fputd(nil, kind); 1400 die("invalid iop"); 1401 } 1402 } 1403 1404 func irshow3(out: *file, b: *irblock) { 1405 var i: int; 1406 1407 fputd(out, b.mark); 1408 fputs(out, "{\n"); 1409 1410 i = 0; 1411 loop { 1412 if i == b.ops_len { 1413 break; 1414 } 1415 1416 fputs(out, " "); 1417 irshow4(out, b.ops[i]); 1418 fputs(out, "\n"); 1419 1420 i = i + 1; 1421 } 1422 1423 fputs(out, "}\n"); 1424 } 1425 1426 // Depth-first visit all nodes 1427 func irshow2(out: *file, b: *irblock, id: *int) { 1428 if !b { 1429 return; 1430 } 1431 1432 if b.mark { 1433 return; 1434 } 1435 1436 b.mark = *id; 1437 *id = *id + 1; 1438 1439 irshow3(out, b); 1440 1441 if b.out { 1442 irshow2(out, b.out, id); 1443 } 1444 1445 if b.alt { 1446 irshow2(out, b.alt, id); 1447 } 1448 } 1449 1450 func irshow(out: *file, b: *irblock) { 1451 var id: int; 1452 id = 1; 1453 irshow2(out, b, &id); 1454 irreset(b); 1455 } 1456 1457 func iruseop(ic: *irfunc, ib: *irblock, op: *irop) { 1458 var kind: int; 1459 1460 kind = op.kind; 1461 if kind == IOP_VAR || kind == IOP_VARREF { 1462 ic.vars[op.n].mark = 1; 1463 } else if kind == IOP_STORE { 1464 if op.a.kind != IOP_VAR { 1465 iruseop(ic, ib, op.a); 1466 } 1467 iruseop(ic, ib, op.b); 1468 } else if kind == IOP_ADD || kind == IOP_AND 1469 || kind == IOP_OR || kind == IOP_XOR || kind == IOP_DIV 1470 || kind == IOP_MOD || kind == IOP_LSH || kind == IOP_RSH 1471 || kind == IOP_MUL || kind == IOP_SUB || kind == IOP_EQ 1472 || kind == IOP_NE || kind == IOP_GT || kind == IOP_GE 1473 || kind == IOP_LT || kind == IOP_LE { 1474 // Binary operators 1475 iruseop(ic, ib, op.a); 1476 iruseop(ic, ib, op.b); 1477 } else if kind == IOP_NEG || kind == IOP_NOT || kind == IOP_LOAD 1478 || kind == IOP_ARG || kind == IOP_CALL || kind == IOP_BRANCH 1479 || kind == IOP_RETURN { 1480 // Unary operators 1481 iruseop(ic, ib, op.a); 1482 } else if kind == IOP_RETVAL { 1483 if op.a.kind != IOP_VAR { 1484 iruseop(ic, ib, op.a); 1485 } 1486 } else if kind == IOP_FUNC || kind == IOP_CONST || kind == IOP_STR || kind == IOP_JUMP { 1487 // No variable possible 1488 } else { 1489 die("invalid op"); 1490 } 1491 } 1492 1493 // Find dead variables 1494 func irblock_dead_var(ic: *irfunc, ib: *irblock) { 1495 var op: *irop; 1496 var kind: int; 1497 var i: int; 1498 1499 if ib.mark { 1500 return; 1501 } 1502 1503 ib.mark = 1; 1504 1505 if !ib.done { 1506 die("block not closed"); 1507 } 1508 1509 loop { 1510 if i == ib.ops_len { 1511 break; 1512 } 1513 1514 iruseop(ic, ib, ib.ops[i]); 1515 1516 i = i + 1; 1517 } 1518 1519 op = ib.ops[ib.ops_len - 1]; 1520 kind = op.kind; 1521 1522 // Convert useless branches to jumps 1523 if kind == IOP_BRANCH { 1524 irblock_dead_var(ic, ib.out); 1525 irblock_dead_var(ic, ib.alt); 1526 } else if kind == IOP_CALL { 1527 irblock_dead_var(ic, ib.out); 1528 } else if kind == IOP_JUMP { 1529 irblock_dead_var(ic, ib.out); 1530 } else if kind != IOP_RETURN { 1531 die("invalid block"); 1532 } 1533 } 1534 1535 // Eliminate expressions which have no possible side effects 1536 func irblock_dead_expr(ic: *irfunc, b: *irblock) { 1537 var i: int; 1538 var j: int; 1539 var o: *irop; 1540 var kind: int; 1541 1542 if !b.done { 1543 return; 1544 } 1545 1546 i = 0; 1547 j = 0; 1548 loop { 1549 if i == b.ops_len { 1550 break; 1551 } 1552 1553 o = b.ops[i]; 1554 1555 kind = o.kind; 1556 if kind == IOP_STORE || kind == IOP_RETVAL { 1557 if o.a.kind != IOP_VAR || !ic.vars[o.a.n].dead { 1558 b.ops[j] = o; 1559 j = j + 1; 1560 } 1561 } else if kind == IOP_ARG || kind == IOP_CALL || kind == IOP_JUMP 1562 || kind == IOP_BRANCH || kind == IOP_RETURN { 1563 b.ops[j] = o; 1564 j = j + 1; 1565 } 1566 1567 1568 i = i + 1; 1569 } 1570 1571 b.ops_len = j; 1572 } 1573 1574 func mkirfold(ic: *irfunc, s: *irop, n: int): *irop { 1575 var o: *irop; 1576 1577 o = mkirop(ic, IOP_CONST, nil, nil); 1578 1579 o.filename = s.filename; 1580 o.lineno = s.lineno; 1581 o.colno = s.colno; 1582 o.n = n; 1583 1584 return o; 1585 } 1586 1587 func irexpr_fold(ic: *irfunc, o: *irop): *irop { 1588 var a: *irop; 1589 var b: *irop; 1590 var c: *irop; 1591 var n: int; 1592 var kind: int; 1593 var ret: *irop; 1594 1595 // Recursive fold the first operand 1596 if o.a { 1597 a = o.a; 1598 a = irexpr_fold(ic, o.a); 1599 } else { 1600 // If the op has zero operands, there's nothing to do. 1601 return o; 1602 } 1603 1604 // Recursive fold the second operand 1605 if o.b { 1606 b = o.b; 1607 b = irexpr_fold(ic, o.b); 1608 } 1609 1610 kind = o.kind; 1611 1612 // Eliminate *& redundant operations 1613 if (kind == IOP_LOAD && a.kind == IOP_VARREF) { 1614 ret = mkirop(ic, IOP_VAR, nil, nil); 1615 ret.n = a.n; 1616 ret.filename = o.filename; 1617 ret.lineno = o.lineno; 1618 ret.colno = o.colno; 1619 return ret; 1620 } 1621 1622 // Check if a is a constant 1623 if a.kind != IOP_CONST { 1624 goto out; 1625 } 1626 1627 // Simplify unary operations 1628 if kind == IOP_NEG { 1629 return mkirfold(ic, o, -a.n); 1630 } else if kind == IOP_NOT { 1631 return mkirfold(ic, o, ~a.n); 1632 } 1633 1634 // Check if b is a constant 1635 if !b || b.kind != IOP_CONST { 1636 goto out; 1637 } 1638 1639 // Simplify binary operations 1640 if kind == IOP_ADD { 1641 return mkirfold(ic, o, a.n + b.n); 1642 } else if kind == IOP_AND { 1643 return mkirfold(ic, o, a.n & b.n); 1644 } else if kind == IOP_OR { 1645 return mkirfold(ic, o, a.n | b.n); 1646 } else if kind == IOP_XOR { 1647 return mkirfold(ic, o, a.n ^ b.n); 1648 } else if kind == IOP_DIV { 1649 return mkirfold(ic, o, a.n / b.n); 1650 } else if kind == IOP_MOD { 1651 return mkirfold(ic, o, a.n % b.n); 1652 } else if kind == IOP_LSH { 1653 return mkirfold(ic, o, a.n << b.n); 1654 } else if kind == IOP_RSH { 1655 return mkirfold(ic, o, a.n >> b.n); 1656 } else if kind == IOP_MUL { 1657 return mkirfold(ic, o, a.n * b.n); 1658 } else if kind == IOP_SUB { 1659 return mkirfold(ic, o, a.n - b.n); 1660 } else if kind == IOP_EQ { 1661 return mkirfold(ic, o, a.n == b.n); 1662 } else if kind == IOP_NE { 1663 return mkirfold(ic, o, a.n != b.n); 1664 } else if kind == IOP_GT { 1665 return mkirfold(ic, o, a.n > b.n); 1666 } else if kind == IOP_GE { 1667 return mkirfold(ic, o, a.n >= b.n); 1668 } else if kind == IOP_LT { 1669 return mkirfold(ic, o, a.n < b.n); 1670 } else if kind == IOP_LE { 1671 return mkirfold(ic, o, a.n <= b.n); 1672 } else { 1673 goto out; 1674 } 1675 1676 out: 1677 1678 // Do some simple algebraic identities on a 1679 if a && a.kind == IOP_CONST { 1680 n = a.n; 1681 1682 if n == 0 { 1683 if kind == IOP_ADD || kind == IOP_OR || kind == IOP_XOR { 1684 return b; 1685 } 1686 1687 if kind == IOP_SUB { 1688 ret = mkirop(ic, IOP_NEG, b, nil); 1689 ret.filename = o.filename; 1690 ret.lineno = o.lineno; 1691 ret.colno = o.colno; 1692 return ret; 1693 } 1694 1695 if kind == IOP_AND || kind == IOP_MUL || kind == IOP_LSH || kind == IOP_RSH { 1696 return mkirfold(ic, o, 0); 1697 } 1698 } else if n == 1 { 1699 if kind == IOP_MUL { 1700 return b; 1701 } 1702 } else if n == -1 { 1703 if kind == IOP_MUL { 1704 ret = mkirop(ic, IOP_NEG, b, nil); 1705 ret.filename = o.filename; 1706 ret.lineno = o.lineno; 1707 ret.colno = o.colno; 1708 return ret; 1709 } 1710 1711 if kind == IOP_XOR { 1712 ret = mkirop(ic, IOP_NOT, b, nil); 1713 ret.filename = o.filename; 1714 ret.lineno = o.lineno; 1715 ret.colno = o.colno; 1716 return ret; 1717 } 1718 1719 if kind == IOP_AND { 1720 return b; 1721 } 1722 } 1723 } 1724 1725 // Do some simple algebraic identities on b 1726 if b && b.kind == IOP_CONST { 1727 n = b.n; 1728 1729 if n == 0 { 1730 if kind == IOP_ADD || kind == IOP_OR || kind == IOP_XOR 1731 || kind == IOP_SUB || kind == IOP_LSH || kind == IOP_RSH { 1732 return a; 1733 } 1734 1735 if kind == IOP_AND || kind == IOP_MUL { 1736 return mkirfold(ic, o, 0); 1737 } 1738 } else if n == 1 { 1739 if kind == IOP_DIV || kind == IOP_MUL { 1740 return a; 1741 } 1742 } else if n == -1 { 1743 if kind == IOP_MUL { 1744 ret = mkirop(ic, IOP_NEG, a, nil); 1745 ret.filename = o.filename; 1746 ret.lineno = o.lineno; 1747 ret.colno = o.colno; 1748 return ret; 1749 } 1750 1751 if kind == IOP_XOR { 1752 ret = mkirop(ic, IOP_NOT, a, nil); 1753 ret.filename = o.filename; 1754 ret.lineno = o.lineno; 1755 ret.colno = o.colno; 1756 return ret; 1757 } 1758 1759 if kind == IOP_AND { 1760 return a; 1761 } 1762 } 1763 } 1764 1765 // If neither side folded, then just return the op unmodified 1766 if o.a == a && o.b == b { 1767 return o; 1768 } 1769 1770 // Otherwise, make a new one with the folded operands 1771 ret = mkirop(ic, kind, a, b); 1772 ret.filename = o.filename; 1773 ret.lineno = o.lineno; 1774 ret.colno = o.colno; 1775 ret.t = o.t; 1776 ret.n = o.n; 1777 return ret; 1778 } 1779 1780 // Fold constant expressions 1781 func irblock_fold(ic: *irfunc, b: *irblock) { 1782 var i: int; 1783 var o: *irop; 1784 var ret: *irop; 1785 1786 if b.mark { 1787 return; 1788 } 1789 1790 if !b.done { 1791 die("block not closed"); 1792 } 1793 1794 b.mark = 1; 1795 1796 i = 0; 1797 loop { 1798 if i == b.ops_len { 1799 break; 1800 } 1801 1802 o = irexpr_fold(ic, b.ops[i]); 1803 b.ops[i] = o; 1804 1805 i = i + 1; 1806 } 1807 1808 i = b.ops_len - 1; 1809 o = b.ops[i]; 1810 1811 // Fold constant branches into jumps 1812 if o.kind == IOP_BRANCH && o.a.kind == IOP_CONST { 1813 ret = mkirop(ic, IOP_JUMP, nil, nil); 1814 ret.filename = o.filename; 1815 ret.lineno = o.lineno; 1816 ret.colno = o.colno; 1817 1818 b.ops[i] = ret; 1819 1820 if !o.a.n { 1821 b.out = b.alt; 1822 } 1823 1824 b.alt = nil; 1825 } 1826 1827 // Remove useless branches 1828 if o.kind == IOP_BRANCH && b.out == b.alt { 1829 ret = mkirop(ic, IOP_JUMP, nil, nil); 1830 ret.filename = o.filename; 1831 ret.lineno = o.lineno; 1832 ret.colno = o.colno; 1833 1834 b.ops[i] = ret; 1835 1836 b.alt = nil; 1837 } 1838 1839 // Continue 1840 if o.kind == IOP_BRANCH { 1841 irblock_fold(ic, b.out); 1842 irblock_fold(ic, b.alt); 1843 } else if o.kind == IOP_JUMP || o.kind == IOP_CALL { 1844 irblock_fold(ic, b.out); 1845 } else if o.kind == IOP_RETURN { 1846 // End of block. 1847 } else { 1848 die("invalid block"); 1849 } 1850 } 1851 1852 func irblock_flow2(ic: *irfunc, ib: *irblock) { 1853 var kind: int; 1854 var op: *irop; 1855 1856 // If we visit a block twice, mark it as having two incoming links 1857 if ib.mark { 1858 ib.mark = 2; 1859 return; 1860 } 1861 ib.mark = 1; 1862 1863 op = ib.ops[ib.ops_len - 1]; 1864 kind = op.kind; 1865 1866 // Convert useless branches to jumps 1867 if kind == IOP_BRANCH && ib.out == ib.alt { 1868 kind = IOP_JUMP; 1869 op = mkirop(ic, IOP_JUMP, nil, nil); 1870 ib.ops[ib.ops_len - 1] = op; 1871 ib.alt = nil; 1872 } 1873 1874 // Follow the alt link of a branch 1875 if kind == IOP_BRANCH { 1876 irblock_flow2(ic, ib.alt); 1877 1878 if ib.alt.ops_len == 1 && ib.alt.ops[0].kind == IOP_JUMP { 1879 ib.alt = ib.alt.out; 1880 } 1881 } 1882 1883 // Follow the out link of a jump/call/branch 1884 if kind == IOP_BRANCH || kind == IOP_CALL || kind == IOP_JUMP { 1885 irblock_flow2(ic, ib.out); 1886 1887 if ib.out.ops_len == 1 && ib.out.ops[0].kind == IOP_JUMP { 1888 ib.out = ib.out.out; 1889 } 1890 } 1891 } 1892 1893 func irblock_flow3(ic: *irfunc, ib: *irblock) { 1894 var out: *irblock; 1895 var kind: int; 1896 var i: int; 1897 1898 // Attempt to merge once 1899 if ib.mark == 3 { 1900 return; 1901 } 1902 ib.mark = 3; 1903 1904 loop { 1905 kind = ib.ops[ib.ops_len - 1].kind; 1906 1907 // Merge down the alt branch first 1908 if kind == IOP_BRANCH { 1909 irblock_flow3(ic, ib.alt); 1910 break; 1911 } 1912 1913 // Only merge blocks that end in a jump 1914 if kind != IOP_JUMP { 1915 break; 1916 } 1917 1918 out = ib.out; 1919 1920 // If a block has two incoming edges, then don't merge. 1921 // But continue attempting to merge down the chain. 1922 if out.mark == 2 { 1923 ib = out; 1924 ib.mark = 3; 1925 continue; 1926 } 1927 1928 // If this chain reached a merge point then go to the next chain. 1929 if out.mark == 3 { 1930 break; 1931 } 1932 1933 // Delete the jump. 1934 ib.out = nil; 1935 ib.ops_len = ib.ops_len - 1; 1936 ib.done = 0; 1937 1938 // Concatenate the blocks. 1939 i = 0; 1940 loop { 1941 if i == out.ops_len { 1942 break; 1943 } 1944 1945 iraddop(ic, out.ops[i]); 1946 1947 i = i + 1; 1948 } 1949 1950 // Update our links. 1951 ib.out = out.out; 1952 ib.alt = out.alt; 1953 ib.done = 1; 1954 } 1955 } 1956 1957 func irfunc_flow(ic: *irfunc) { 1958 // Merge blocks that have one incoming edge 1959 irblock_flow2(ic, ic.blocks[0]); 1960 irblock_flow3(ic, ic.blocks[0]); 1961 irreset(ic.blocks[0]); 1962 } 1963 1964 func irfunc_dead(ic: *irfunc) { 1965 var i: int; 1966 1967 // Find dead variables 1968 irblock_dead_var(ic, ic.blocks[0]); 1969 irreset(ic.blocks[0]); 1970 1971 i = 0; 1972 loop { 1973 if i == ic.vars_len { 1974 break; 1975 } 1976 1977 if i >= ic.arg_count && !ic.vars[i].mark { 1978 ic.vars[i].dead = 1; 1979 } 1980 1981 ic.vars[i].mark = 0; 1982 1983 i = i + 1; 1984 } 1985 1986 // Eliminate dead operations 1987 i = 0; 1988 loop { 1989 if i == ic.blocks_len { 1990 break; 1991 } 1992 1993 irblock_dead_expr(ic, ic.blocks[i]); 1994 1995 i = i + 1; 1996 } 1997 } 1998 1999 func irfunc_fold(ic: *irfunc) { 2000 var i: int; 2001 2002 // Try to evaluate constants as much as possible 2003 irblock_fold(ic, ic.blocks[0]); 2004 irreset(ic.blocks[0]); 2005 } 2006 2007 func irop_occurs(op: *irop, n: int): int { 2008 if !op { 2009 return 0; 2010 } 2011 2012 if op.kind == IOP_VAR { 2013 if op.n == n { 2014 return 1; 2015 } else { 2016 return 0; 2017 } 2018 } 2019 2020 if irop_occurs(op.a, n) { 2021 return 1; 2022 } 2023 2024 if irop_occurs(op.b, n) { 2025 return 1; 2026 } 2027 2028 return 0; 2029 } 2030 2031 func irop_kill(ic: *irfunc, vals: **irop, n: int) { 2032 var i: int; 2033 2034 loop { 2035 if i == ic.vars_len { 2036 break; 2037 } 2038 2039 if irop_occurs(vals[i], n) { 2040 vals[i] = nil; 2041 } 2042 2043 i = i + 1; 2044 } 2045 } 2046 2047 func irop_basic_value(ic: *irfunc, vals: **irop, op: *irop): *irop { 2048 var a: *irop; 2049 var b: *irop; 2050 var v: *irop; 2051 var ret: *irop; 2052 var kind: int; 2053 var i: int; 2054 2055 kind = op.kind; 2056 a = op.a; 2057 b = op.b; 2058 2059 if kind == IOP_STORE { 2060 if a.kind == IOP_VAR { 2061 // Record stores to variables 2062 irop_kill(ic, vals, a.n); 2063 2064 // Compute the new value 2065 b = irop_basic_value(ic, vals, b); 2066 2067 if a.n < 0 || a.n >= ic.vars_len { 2068 die("WTF"); 2069 } 2070 2071 // Record the new value 2072 vals[a.n] = b; 2073 2074 // Kill all values that referred to the old value 2075 irop_kill(ic, vals, a.n); 2076 2077 // If the value didn't then reuse op. 2078 if b == op.b { 2079 return op; 2080 } 2081 2082 ret = mkirop(ic, IOP_STORE, a, b); 2083 ircopyloc(ret, op); 2084 ret.t = op.t; 2085 return ret; 2086 } else if a.kind == IOP_LOAD { 2087 i = 0; 2088 loop { 2089 if i == ic.vars_len { 2090 break; 2091 } 2092 vals[i] = nil; 2093 i = i + 1; 2094 } 2095 return op; 2096 } else { 2097 die("invalid store"); 2098 } 2099 } else if kind == IOP_VAR { 2100 v = vals[op.n]; 2101 if !v { 2102 return op; 2103 } 2104 return v; 2105 vals[op.n] = nil; 2106 ret = irop_basic_value(ic, vals, v); 2107 vals[op.n] = v; 2108 return ret; 2109 } else if kind == IOP_RETVAL { 2110 return op; 2111 } else if kind == IOP_ARG || kind == IOP_LOAD || kind == IOP_NEG 2112 || kind == IOP_NOT || kind == IOP_CALL || kind == IOP_BRANCH 2113 || kind == IOP_RETURN { 2114 // Unary operators 2115 a = irop_basic_value(ic, vals, a); 2116 if a == op.a { 2117 return op; 2118 } 2119 2120 ret = mkirop(ic, kind, a, nil); 2121 ircopyloc(ret, op); 2122 ret.t = op.t; 2123 ret.n = op.n; 2124 2125 return ret; 2126 } else if kind == IOP_VARREF || kind == IOP_FUNC || kind == IOP_CONST 2127 || kind == IOP_STR || kind == IOP_JUMP { 2128 // Null operators 2129 return op; 2130 } else if kind == IOP_ADD || kind == IOP_AND || kind == IOP_OR 2131 || kind == IOP_XOR || kind == IOP_DIV || kind == IOP_MOD 2132 || kind == IOP_LSH || kind == IOP_RSH || kind == IOP_MUL 2133 || kind == IOP_SUB || kind == IOP_EQ || kind == IOP_NE 2134 || kind == IOP_GT || kind == IOP_GE || kind == IOP_LT 2135 || kind == IOP_LE { 2136 // Binary operators 2137 a = irop_basic_value(ic, vals, a); 2138 b = irop_basic_value(ic, vals, b); 2139 if a == op.a && b == op.b { 2140 return op; 2141 } 2142 2143 ret = mkirop(ic, kind, a, b); 2144 ircopyloc(ret, op); 2145 ret.t = op.t; 2146 2147 return ret; 2148 } else { 2149 die("invalid op"); 2150 return nil; 2151 } 2152 return nil; 2153 } 2154 2155 // This is a VERY dumb way to do this. 2156 func irblock_basic_value(ic: *irfunc, ib: *irblock) { 2157 var i: int; 2158 var nvals: int; 2159 var vals: **irop; 2160 var op: *irop; 2161 2162 if !ib.done { 2163 die("block not closed"); 2164 } 2165 2166 if ib.mark { 2167 return; 2168 } 2169 2170 ib.mark = 1; 2171 2172 nvals = ic.vars_len; 2173 vals = alloc(ic.a, 8 * nvals) as **irop; 2174 2175 assert_zero(vals as *byte, 8 * nvals); 2176 2177 i = 0; 2178 loop { 2179 if i == ib.ops_len { 2180 break; 2181 } 2182 2183 op = ib.ops[i]; 2184 op = irop_basic_value(ic, vals, op); 2185 ib.ops[i] = op; 2186 2187 i = i + 1; 2188 } 2189 2190 free(ic.a, vals as *byte); 2191 alloc(ic.a, 16); 2192 2193 op = ib.ops[ib.ops_len - 1]; 2194 2195 // Continue 2196 if op.kind == IOP_BRANCH { 2197 irblock_basic_value(ic, ib.out); 2198 irblock_basic_value(ic, ib.alt); 2199 } else if op.kind == IOP_JUMP || op.kind == IOP_CALL { 2200 irblock_basic_value(ic, ib.out); 2201 } else if op.kind == IOP_RETURN { 2202 // End of block. 2203 } else { 2204 die("invalid block"); 2205 } 2206 } 2207 2208 func irfunc_basic_value(ic: *irfunc) { 2209 // Forward simple stores to their use 2210 irblock_basic_value(ic, ic.blocks[0]); 2211 irreset(ic.blocks[0]); 2212 } 2213 2214 func irblock_backlink(ic: *irfunc, ib: *irblock, from: *irblock) { 2215 var kind: int; 2216 2217 // Add an incoming edge. 2218 if from { 2219 if ib.back { 2220 ib.back[ib.back_len] = from; 2221 } 2222 ib.back_len = ib.back_len + 1; 2223 } 2224 2225 // Descend to out/alt blocks once. 2226 if ib.mark { 2227 return; 2228 } 2229 ib.mark = 1; 2230 2231 // Add incoming edges for unique blocks. 2232 kind = ib.ops[ib.ops_len - 1].kind; 2233 if kind == IOP_CALL || kind == IOP_JUMP { 2234 irblock_backlink(ic, ib.out, ib); 2235 } else if kind == IOP_BRANCH { 2236 irblock_backlink(ic, ib.out, ib); 2237 if ib.out != ib.alt { 2238 irblock_backlink(ic, ib.alt, ib); 2239 } 2240 } else if kind == IOP_RETURN { 2241 if ic.returns { 2242 ic.returns[ic.returns_len] = ib; 2243 } 2244 ic.returns_len = ic.returns_len + 1; 2245 } else { 2246 die("invalid block"); 2247 } 2248 } 2249 2250 func irfunc_backlink(ic: *irfunc) { 2251 var ib: *irblock; 2252 var i: int; 2253 var j: int; 2254 2255 // Clear the reachable returns 2256 if ic.returns { 2257 free(ic.a, ic.returns as *byte); 2258 } 2259 ic.returns = nil; 2260 ic.returns_len = 0; 2261 2262 // Clear the known backlinks 2263 i = 0; 2264 loop { 2265 if i == ic.blocks_len { 2266 break; 2267 } 2268 2269 ib = ic.blocks[i]; 2270 2271 if ib.back { 2272 free(ic.a, ib.back as *byte); 2273 } 2274 ib.back = nil; 2275 ib.back_len = 0; 2276 2277 i = i + 1; 2278 } 2279 2280 // Walk the call graph to find the reachable blocks 2281 irblock_backlink(ic, ic.blocks[0], nil); 2282 2283 // Allocate space for returns 2284 ic.returns = alloc(ic.a, ic.returns_len * sizeof(*ic.returns)) as **irblock; 2285 2286 // Find returns, clear marks, and allocate backlinks 2287 i = 0; 2288 j = 0; 2289 loop { 2290 if i == ic.blocks_len { 2291 break; 2292 } 2293 2294 ib = ic.blocks[i]; 2295 2296 if ib.back_len { 2297 ib.back = alloc(ic.a, ib.back_len * sizeof(*ib.back)) as **irblock; 2298 } 2299 2300 ib.back_len = 0; 2301 ib.mark = 0; 2302 2303 i = i + 1; 2304 } 2305 2306 // Fill in the backlink arrays 2307 irblock_backlink(ic, ic.blocks[0], nil); 2308 irreset(ic.blocks[0]); 2309 } 2310 2311 func ir_optimize(ic: *irfunc) { 2312 // Too many bugs... 2313 return; 2314 2315 // Do the easy simplifications first. 2316 irfunc_dead(ic); 2317 irfunc_fold(ic); 2318 irfunc_flow(ic); 2319 irfunc_backlink(ic); 2320 2321 // Do some data flow analysis within a basic block 2322 irfunc_basic_value(ic); 2323 2324 // Do them again. 2325 irfunc_dead(ic); 2326 irfunc_fold(ic); 2327 irfunc_flow(ic); 2328 //irfunc_backlink(ic); 2329 2330 // Do instruction selection 2331 // Do register allocation 2332 }