github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-block.c (about) 1 /* 2 * jit-block.c - Functions for manipulating blocks. 3 * 4 * Copyright (C) 2004 Southern Storm Software, Pty Ltd. 5 * 6 * This file is part of the libjit library. 7 * 8 * The libjit library is free software: you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public License 10 * as published by the Free Software Foundation, either version 2.1 of 11 * the License, or (at your option) any later version. 12 * 13 * The libjit library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with the libjit library. If not, see 20 * <http://www.gnu.org/licenses/>. 21 */ 22 23 #include "jit-internal.h" 24 #include <stdlib.h> 25 26 /*@ 27 28 @cindex jit-block.h 29 30 @*/ 31 32 /* helper data structure for CFG DFS traversal */ 33 typedef struct _jit_block_stack_entry 34 { 35 jit_block_t block; 36 int index; 37 } _jit_block_stack_entry_t; 38 39 40 static void 41 create_edge(jit_function_t func, jit_block_t src, jit_block_t dst, int flags, int create) 42 { 43 _jit_edge_t edge; 44 45 /* Create edge if required */ 46 if(create) 47 { 48 /* Allocate memory for it */ 49 edge = jit_memory_pool_alloc(&func->builder->edge_pool, struct _jit_edge); 50 if(!edge) 51 { 52 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 53 } 54 55 /* Initialize edge fields */ 56 edge->src = src; 57 edge->dst = dst; 58 edge->flags = flags; 59 60 /* Store edge pointers in source and destination nodes */ 61 src->succs[src->num_succs] = edge; 62 dst->preds[dst->num_preds] = edge; 63 } 64 65 /* Count it */ 66 ++(src->num_succs); 67 ++(dst->num_preds); 68 } 69 70 static void 71 build_edges(jit_function_t func, int create) 72 { 73 jit_block_t src, dst; 74 jit_insn_t insn; 75 int opcode, flags; 76 jit_label_t *labels; 77 int index, num_labels; 78 79 /* TODO: Handle catch, finally, filter blocks. */ 80 81 for(src = func->builder->entry_block; src != func->builder->exit_block; src = src->next) 82 { 83 /* Check the last instruction of the block */ 84 insn = _jit_block_get_last(src); 85 opcode = insn ? insn->opcode : JIT_OP_NOP; 86 if(opcode >= JIT_OP_RETURN && opcode <= JIT_OP_RETURN_SMALL_STRUCT) 87 { 88 flags = _JIT_EDGE_RETURN; 89 dst = func->builder->exit_block; 90 } 91 else if(opcode == JIT_OP_BR) 92 { 93 flags = _JIT_EDGE_BRANCH; 94 dst = jit_block_from_label(func, (jit_label_t) insn->dest); 95 if(!dst) 96 { 97 /* Bail out on undefined label */ 98 jit_exception_builtin(JIT_RESULT_UNDEFINED_LABEL); 99 } 100 } 101 else if(opcode > JIT_OP_BR && opcode <= JIT_OP_BR_NFGE_INV) 102 { 103 flags = _JIT_EDGE_BRANCH; 104 dst = jit_block_from_label(func, (jit_label_t) insn->dest); 105 if(!dst) 106 { 107 /* Bail out on undefined label */ 108 jit_exception_builtin(JIT_RESULT_UNDEFINED_LABEL); 109 } 110 } 111 else if(opcode == JIT_OP_THROW || opcode == JIT_OP_RETHROW) 112 { 113 flags = _JIT_EDGE_EXCEPT; 114 dst = jit_block_from_label(func, func->builder->catcher_label); 115 if(!dst) 116 { 117 dst = func->builder->exit_block; 118 } 119 } 120 else if(opcode == JIT_OP_CALL_FINALLY || opcode == JIT_OP_CALL_FILTER) 121 { 122 flags = _JIT_EDGE_EXCEPT; 123 dst = jit_block_from_label(func, (jit_label_t) insn->dest); 124 if(!dst) 125 { 126 /* Bail out on undefined label */ 127 jit_exception_builtin(JIT_RESULT_UNDEFINED_LABEL); 128 } 129 } 130 else if(opcode >= JIT_OP_CALL && opcode <= JIT_OP_CALL_EXTERNAL_TAIL) 131 { 132 flags = _JIT_EDGE_EXCEPT; 133 dst = jit_block_from_label(func, func->builder->catcher_label); 134 if(!dst) 135 { 136 dst = func->builder->exit_block; 137 } 138 } 139 else if(opcode == JIT_OP_JUMP_TABLE) 140 { 141 labels = (jit_label_t *) insn->value1->address; 142 num_labels = (int) insn->value2->address; 143 for(index = 0; index < num_labels; index++) 144 { 145 dst = jit_block_from_label(func, labels[index]); 146 if(!dst) 147 { 148 /* Bail out on undefined label */ 149 jit_exception_builtin(JIT_RESULT_UNDEFINED_LABEL); 150 } 151 create_edge(func, src, dst, _JIT_EDGE_BRANCH, create); 152 } 153 dst = 0; 154 } 155 else 156 { 157 dst = 0; 158 } 159 160 /* create a branch or exception edge if appropriate */ 161 if(dst) 162 { 163 create_edge(func, src, dst, flags, create); 164 } 165 /* create a fall-through edge if appropriate */ 166 if(!src->ends_in_dead) 167 { 168 create_edge(func, src, src->next, _JIT_EDGE_FALLTHRU, create); 169 } 170 } 171 } 172 173 static void 174 alloc_edges(jit_function_t func) 175 { 176 jit_block_t block; 177 178 for(block = func->builder->entry_block; block; block = block->next) 179 { 180 /* Allocate edges to successor nodes */ 181 if(block->num_succs == 0) 182 { 183 block->succs = 0; 184 } 185 else 186 { 187 block->succs = jit_calloc(block->num_succs, sizeof(_jit_edge_t)); 188 if(!block->succs) 189 { 190 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 191 } 192 /* Reset edge count for the next build pass */ 193 block->num_succs = 0; 194 } 195 196 /* Allocate edges to predecessor nodes */ 197 if(block->num_preds == 0) 198 { 199 block->preds = 0; 200 } 201 else 202 { 203 block->preds = jit_calloc(block->num_preds, sizeof(_jit_edge_t)); 204 if(!block->preds) 205 { 206 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 207 } 208 /* Reset edge count for the next build pass */ 209 block->num_preds = 0; 210 } 211 } 212 } 213 214 static void 215 detach_edge_src(_jit_edge_t edge) 216 { 217 jit_block_t block; 218 int index; 219 220 block = edge->src; 221 for(index = 0; index < block->num_succs; index++) 222 { 223 if(block->succs[index] == edge) 224 { 225 for(block->num_succs--; index < block->num_succs; index++) 226 { 227 block->succs[index] = block->succs[index + 1]; 228 } 229 block->succs = jit_realloc(block->succs, block->num_succs * sizeof(_jit_edge_t)); 230 return; 231 } 232 } 233 } 234 235 static void 236 detach_edge_dst(_jit_edge_t edge) 237 { 238 jit_block_t block; 239 int index; 240 241 block = edge->dst; 242 for(index = 0; index < block->num_preds; index++) 243 { 244 if(block->preds[index] == edge) 245 { 246 for(block->num_preds--; index < block->num_preds; index++) 247 { 248 block->preds[index] = block->preds[index + 1]; 249 } 250 block->preds = jit_realloc(block->preds, 251 block->num_preds * sizeof(_jit_edge_t)); 252 return; 253 } 254 } 255 } 256 257 static void 258 attach_edge_dst(_jit_edge_t edge, jit_block_t block) 259 { 260 _jit_edge_t *preds; 261 262 preds = jit_realloc(block->preds, (block->num_preds + 1) * sizeof(_jit_edge_t)); 263 if(!preds) 264 { 265 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 266 } 267 268 preds[block->num_preds++] = edge; 269 block->preds = preds; 270 edge->dst = block; 271 } 272 273 /* Delete edge along with references to it */ 274 static void 275 delete_edge(jit_function_t func, _jit_edge_t edge) 276 { 277 detach_edge_src(edge); 278 detach_edge_dst(edge); 279 jit_memory_pool_dealloc(&func->builder->edge_pool, edge); 280 } 281 282 /* Block may not be deleted right when it was found useless from 283 the control flow perspective as it might be referenced from 284 elsewhere, for instance, from some jit_value_t */ 285 static void 286 delete_block(jit_block_t block) 287 { 288 jit_free(block->succs); 289 block->succs = 0; 290 jit_free(block->preds); 291 block->preds = 0; 292 jit_free(block->insns); 293 block->insns = 0; 294 295 block->next = block->func->builder->deleted_blocks; 296 block->func->builder->deleted_blocks = block; 297 } 298 299 /* The block is empty if it contains nothing apart from an unconditional branch */ 300 static int 301 is_empty_block(jit_block_t block) 302 { 303 int index, opcode; 304 305 index = block->num_insns; 306 if(index == 0) 307 { 308 return 1; 309 } 310 311 opcode = block->insns[--index].opcode; 312 if(opcode != JIT_OP_NOP && opcode != JIT_OP_MARK_OFFSET && opcode != JIT_OP_BR) 313 { 314 return 0; 315 } 316 317 while(index > 0) 318 { 319 opcode = block->insns[--index].opcode; 320 if(opcode != JIT_OP_NOP && opcode != JIT_OP_MARK_OFFSET) 321 { 322 return 0; 323 } 324 } 325 326 return 1; 327 } 328 329 #ifdef _JIT_BLOCK_DEBUG 330 static void 331 label_loop_check(jit_function_t func, jit_block_t block, jit_label_t label) 332 { 333 jit_label_t block_label = block->label; 334 while(block_label != jit_label_undefined) 335 { 336 if(block_label == label) 337 { 338 abort(); 339 } 340 block_label = func->builder->label_info[block_label].alias; 341 } 342 } 343 #endif 344 345 /* Merge labels of the src block with labels of the dst block but retain 346 the address_of labels. This requires the address_of labels to be used 347 exclusively as such, no branches are allowed to use address_of labels. 348 This is ensured by the split_address_of() function. */ 349 static void 350 merge_labels(jit_function_t func, jit_block_t src, jit_block_t dst) 351 { 352 _jit_label_info_t *info; 353 jit_label_t label, alias; 354 355 label = src->label; 356 src->label = jit_label_undefined; 357 358 #ifdef _JIT_BLOCK_DEBUG 359 label_loop_check(func, dst, label); 360 #endif 361 362 while(label != jit_label_undefined) 363 { 364 info = &func->builder->label_info[label]; 365 alias = info->alias; 366 367 if((info->flags & JIT_LABEL_ADDRESS_OF) == 0) 368 { 369 info->block = dst; 370 info->alias = dst->label; 371 dst->label = label; 372 } 373 else 374 { 375 info->alias = src->label; 376 src->label = label; 377 } 378 379 label = alias; 380 } 381 } 382 383 /* Merge empty block with its successor */ 384 static void 385 merge_empty(jit_function_t func, jit_block_t block, int *changed) 386 { 387 _jit_edge_t succ_edge, pred_edge, fallthru_edge; 388 jit_block_t succ_block; 389 int index; 390 391 /* Find block successor */ 392 succ_edge = block->succs[0]; 393 succ_block = succ_edge->dst; 394 395 /* Retarget labels bound to this block to the successor block. */ 396 merge_labels(func, block, succ_block); 397 398 /* Retarget all incoming edges except a fallthrough edge */ 399 fallthru_edge = 0; 400 for(index = 0; index < block->num_preds; index++) 401 { 402 pred_edge = block->preds[index]; 403 if(pred_edge->flags == _JIT_EDGE_FALLTHRU) 404 { 405 fallthru_edge = pred_edge; 406 } 407 else 408 { 409 *changed = 1; 410 attach_edge_dst(pred_edge, succ_block); 411 } 412 } 413 414 /* Unless the block is taken address of, the incoming fallthrough edge 415 can be retargeted and then the block deleted if the outgoing edge is 416 also fallthrough. */ 417 if(!block->address_of && fallthru_edge && succ_edge->flags == _JIT_EDGE_FALLTHRU) 418 { 419 *changed = 1; 420 attach_edge_dst(fallthru_edge, succ_block); 421 fallthru_edge = 0; 422 } 423 424 /* Free the block if there is no incoming edge left and it is not taken 425 address of. Otherwise adjust the preds array accordingly. */ 426 if(fallthru_edge) 427 { 428 if(block->num_preds > 1) 429 { 430 block->num_preds = 1; 431 block->preds = jit_realloc(block->preds, sizeof(_jit_edge_t)); 432 block->preds[0] = fallthru_edge; 433 } 434 } 435 else if(block->address_of) 436 { 437 if(block->num_preds > 0) 438 { 439 block->num_preds = 0; 440 jit_free(block->preds); 441 block->preds = 0; 442 } 443 } 444 else 445 { 446 detach_edge_dst(succ_edge); 447 jit_memory_pool_dealloc(&func->builder->edge_pool, succ_edge); 448 _jit_block_detach(block, block); 449 delete_block(block); 450 } 451 } 452 453 /* Combine non-empty block with its successor */ 454 static void 455 combine_block(jit_function_t func, jit_block_t block, int *changed) 456 { 457 jit_block_t succ_block; 458 int branch, num_insns, max_insns; 459 jit_insn_t insns; 460 461 /* Find block successor */ 462 succ_block = block->succs[0]->dst; 463 464 /* Does block end with a (redundant) branch instruction? */ 465 branch = (block->succs[0]->flags == _JIT_EDGE_BRANCH); 466 467 /* If the branch is there then preallocate memory for it, 468 doing it here simplifies handling of the out-of-memory 469 condition */ 470 if(branch && !succ_block->max_insns) 471 { 472 succ_block->insns = jit_malloc(sizeof(struct _jit_insn)); 473 if(!succ_block->insns) 474 { 475 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 476 } 477 succ_block->max_insns = 1; 478 } 479 480 /* Allocate enough memory for combined instructions */ 481 max_insns = block->max_insns; 482 num_insns = block->num_insns + succ_block->num_insns; 483 if(num_insns > max_insns) 484 { 485 max_insns = num_insns; 486 insns = (jit_insn_t) jit_realloc(block->insns, 487 max_insns * sizeof(struct _jit_insn)); 488 if(!insns) 489 { 490 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 491 } 492 } 493 else 494 { 495 insns = block->insns; 496 } 497 498 /* Copy instruction from the successor block after the instructions 499 of the original block */ 500 if(succ_block->num_insns) 501 { 502 jit_memcpy(insns + block->num_insns, 503 succ_block->insns, 504 succ_block->num_insns * sizeof(struct _jit_insn)); 505 } 506 507 /* Move combined instructions to the successor, but if there was 508 a branch in the original block then keep the branch around, 509 merge_empty() will take care of it if it may be optimized away. 510 To reduce the number of allocations, swap the arrays around 511 rather than allocating a fresh array for the empty block. */ 512 block->insns = succ_block->insns; 513 block->max_insns = succ_block->max_insns; 514 if(branch) 515 { 516 /* Copy the branch instruction */ 517 jit_memcpy(block->insns, 518 insns + block->num_insns - 1, 519 sizeof(struct _jit_insn)); 520 /* In the combined block turn branch into NOP */ 521 insns[block->num_insns - 1].opcode = JIT_OP_NOP; 522 } 523 block->num_insns = branch; 524 succ_block->insns = insns; 525 succ_block->max_insns = max_insns; 526 succ_block->num_insns = num_insns; 527 528 merge_empty(func, block, changed); 529 } 530 531 /* Allow branch optimization by splitting the label that is both a branch target 532 and an address-of opcode source into two separate labels with single role. 533 TODO: handle jump tables. */ 534 static void 535 split_address_of(jit_function_t func, jit_block_t block, jit_label_t label) 536 { 537 int index; 538 jit_insn_t insn; 539 jit_label_t branch_label; 540 jit_label_t *jump_labels; 541 int jump_index, num_labels; 542 543 branch_label = jit_label_undefined; 544 545 for(index = 0; index < block->num_preds; index++) 546 { 547 if(block->preds[index]->flags != _JIT_EDGE_BRANCH) 548 { 549 continue; 550 } 551 552 if(branch_label == jit_label_undefined) 553 { 554 branch_label = (func->builder->next_label)++; 555 if(!_jit_block_record_label(block, branch_label)) 556 { 557 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 558 } 559 } 560 561 insn = _jit_block_get_last(block->preds[index]->src); 562 if(insn->opcode != JIT_OP_JUMP_TABLE) 563 { 564 insn->dest = (jit_value_t)branch_label; 565 } 566 else 567 { 568 jump_labels = (jit_label_t *) insn->value1->address; 569 num_labels = (int) insn->value2->address; 570 for(jump_index = 0; jump_index < num_labels; jump_index++) 571 { 572 if(jump_labels[jump_index] == label) 573 { 574 jump_labels[jump_index] = branch_label; 575 } 576 } 577 } 578 } 579 } 580 581 /* Mark blocks that might be taken address of */ 582 static void 583 set_address_of(jit_function_t func) 584 { 585 int index, count; 586 jit_block_t block; 587 588 count = func->builder->max_label_info; 589 for(index = 0; index < count; index++) 590 { 591 block = func->builder->label_info[index].block; 592 if(block && (func->builder->label_info[index].flags & JIT_LABEL_ADDRESS_OF) != 0) 593 { 594 block->address_of = 1; 595 split_address_of(func, block, index); 596 } 597 } 598 } 599 600 /* Delete block along with references to it */ 601 static void 602 eliminate_block(jit_block_t block) 603 { 604 _jit_edge_t edge; 605 int index; 606 607 /* Detach block from the list */ 608 _jit_block_detach(block, block); 609 610 /* Remove control flow graph edges */ 611 for(index = 0; index < block->num_succs; index++) 612 { 613 edge = block->succs[index]; 614 detach_edge_dst(edge); 615 jit_memory_pool_dealloc(&block->func->builder->edge_pool, edge); 616 } 617 for(index = 0; index < block->num_preds; index++) 618 { 619 edge = block->preds[index]; 620 detach_edge_src(edge); 621 jit_memory_pool_dealloc(&block->func->builder->edge_pool, edge); 622 } 623 624 /* Finally delete the block */ 625 delete_block(block); 626 } 627 628 #if 0 629 630 /* Visit all successive blocks recursively */ 631 static void 632 visit_reachable(jit_block_t block) 633 { 634 int index; 635 636 if(!block->visited) 637 { 638 block->visited = 1; 639 for(index = 0; index < block->num_succs; index++) 640 { 641 visit_reachable(block->succs[index]->dst); 642 } 643 } 644 } 645 646 #endif 647 648 /* Eliminate unreachable blocks */ 649 static void 650 eliminate_unreachable(jit_function_t func) 651 { 652 jit_block_t block, next_block; 653 654 block = func->builder->entry_block; 655 while(block != func->builder->exit_block) 656 { 657 next_block = block->next; 658 if(block->visited) 659 { 660 block->visited = 0; 661 } 662 else if(!block->address_of) 663 { 664 eliminate_block(block); 665 } 666 block = next_block; 667 } 668 } 669 670 /* Clear visited blocks */ 671 static void 672 clear_visited(jit_function_t func) 673 { 674 jit_block_t block; 675 676 for(block = func->builder->entry_block; block; block = block->next) 677 { 678 block->visited = 0; 679 } 680 } 681 682 /* TODO: maintain the block count as the blocks are created/deleted */ 683 static int 684 count_blocks(jit_function_t func) 685 { 686 int count; 687 jit_block_t block; 688 689 count = 0; 690 for(block = func->builder->entry_block; block; block = block->next) 691 { 692 ++count; 693 } 694 return count; 695 } 696 697 /* Release block order memory */ 698 static void 699 free_order(jit_function_t func) 700 { 701 jit_free(func->builder->block_order); 702 func->builder->block_order = NULL; 703 func->builder->num_block_order = 0; 704 } 705 706 int 707 _jit_block_init(jit_function_t func) 708 { 709 func->builder->entry_block = _jit_block_create(func); 710 if(!func->builder->entry_block) 711 { 712 return 0; 713 } 714 715 func->builder->exit_block = _jit_block_create(func); 716 if(!func->builder->exit_block) 717 { 718 return 0; 719 } 720 721 func->builder->entry_block->next = func->builder->exit_block; 722 func->builder->exit_block->prev = func->builder->entry_block; 723 return 1; 724 } 725 726 void 727 _jit_block_free(jit_function_t func) 728 { 729 jit_block_t block, next; 730 731 free_order(func); 732 733 block = func->builder->entry_block; 734 while(block) 735 { 736 next = block->next; 737 _jit_block_destroy(block); 738 block = next; 739 } 740 741 block = func->builder->deleted_blocks; 742 while(block) 743 { 744 next = block->next; 745 _jit_block_destroy(block); 746 block = next; 747 } 748 749 func->builder->entry_block = 0; 750 func->builder->exit_block = 0; 751 } 752 753 void 754 _jit_block_build_cfg(jit_function_t func) 755 { 756 /* Count the edges */ 757 build_edges(func, 0); 758 759 /* Allocate memory for edges */ 760 alloc_edges(func); 761 762 /* Actually build the edges */ 763 build_edges(func, 1); 764 } 765 766 static int 767 _jit_invert_condition (int opcode) 768 { 769 switch(opcode) 770 { 771 case JIT_OP_BR_IEQ: opcode = JIT_OP_BR_INE; break; 772 case JIT_OP_BR_INE: opcode = JIT_OP_BR_IEQ; break; 773 case JIT_OP_BR_ILT: opcode = JIT_OP_BR_IGE; break; 774 case JIT_OP_BR_ILT_UN: opcode = JIT_OP_BR_IGE_UN; break; 775 case JIT_OP_BR_ILE: opcode = JIT_OP_BR_IGT; break; 776 case JIT_OP_BR_ILE_UN: opcode = JIT_OP_BR_IGT_UN; break; 777 case JIT_OP_BR_IGT: opcode = JIT_OP_BR_ILE; break; 778 case JIT_OP_BR_IGT_UN: opcode = JIT_OP_BR_ILE_UN; break; 779 case JIT_OP_BR_IGE: opcode = JIT_OP_BR_ILT; break; 780 case JIT_OP_BR_IGE_UN: opcode = JIT_OP_BR_ILT_UN; break; 781 case JIT_OP_BR_LEQ: opcode = JIT_OP_BR_LNE; break; 782 case JIT_OP_BR_LNE: opcode = JIT_OP_BR_LEQ; break; 783 case JIT_OP_BR_LLT: opcode = JIT_OP_BR_LGE; break; 784 case JIT_OP_BR_LLT_UN: opcode = JIT_OP_BR_LGE_UN; break; 785 case JIT_OP_BR_LLE: opcode = JIT_OP_BR_LGT; break; 786 case JIT_OP_BR_LLE_UN: opcode = JIT_OP_BR_LGT_UN; break; 787 case JIT_OP_BR_LGT: opcode = JIT_OP_BR_LLE; break; 788 case JIT_OP_BR_LGT_UN: opcode = JIT_OP_BR_LLE_UN; break; 789 case JIT_OP_BR_LGE: opcode = JIT_OP_BR_LLT; break; 790 case JIT_OP_BR_LGE_UN: opcode = JIT_OP_BR_LLT_UN; break; 791 case JIT_OP_BR_FEQ: opcode = JIT_OP_BR_FNE; break; 792 case JIT_OP_BR_FNE: opcode = JIT_OP_BR_FEQ; break; 793 case JIT_OP_BR_FLT: opcode = JIT_OP_BR_FGE_INV; break; 794 case JIT_OP_BR_FLE: opcode = JIT_OP_BR_FGT_INV; break; 795 case JIT_OP_BR_FGT: opcode = JIT_OP_BR_FLE_INV; break; 796 case JIT_OP_BR_FGE: opcode = JIT_OP_BR_FLT_INV; break; 797 case JIT_OP_BR_FLT_INV: opcode = JIT_OP_BR_FGE; break; 798 case JIT_OP_BR_FLE_INV: opcode = JIT_OP_BR_FGT; break; 799 case JIT_OP_BR_FGT_INV: opcode = JIT_OP_BR_FLE; break; 800 case JIT_OP_BR_FGE_INV: opcode = JIT_OP_BR_FLT; break; 801 case JIT_OP_BR_DEQ: opcode = JIT_OP_BR_DNE; break; 802 case JIT_OP_BR_DNE: opcode = JIT_OP_BR_DEQ; break; 803 case JIT_OP_BR_DLT: opcode = JIT_OP_BR_DGE_INV; break; 804 case JIT_OP_BR_DLE: opcode = JIT_OP_BR_DGT_INV; break; 805 case JIT_OP_BR_DGT: opcode = JIT_OP_BR_DLE_INV; break; 806 case JIT_OP_BR_DGE: opcode = JIT_OP_BR_DLT_INV; break; 807 case JIT_OP_BR_DLT_INV: opcode = JIT_OP_BR_DGE; break; 808 case JIT_OP_BR_DLE_INV: opcode = JIT_OP_BR_DGT; break; 809 case JIT_OP_BR_DGT_INV: opcode = JIT_OP_BR_DLE; break; 810 case JIT_OP_BR_DGE_INV: opcode = JIT_OP_BR_DLT; break; 811 case JIT_OP_BR_NFEQ: opcode = JIT_OP_BR_NFNE; break; 812 case JIT_OP_BR_NFNE: opcode = JIT_OP_BR_NFEQ; break; 813 case JIT_OP_BR_NFLT: opcode = JIT_OP_BR_NFGE_INV; break; 814 case JIT_OP_BR_NFLE: opcode = JIT_OP_BR_NFGT_INV; break; 815 case JIT_OP_BR_NFGT: opcode = JIT_OP_BR_NFLE_INV; break; 816 case JIT_OP_BR_NFGE: opcode = JIT_OP_BR_NFLT_INV; break; 817 case JIT_OP_BR_NFLT_INV: opcode = JIT_OP_BR_NFGE; break; 818 case JIT_OP_BR_NFLE_INV: opcode = JIT_OP_BR_NFGT; break; 819 case JIT_OP_BR_NFGT_INV: opcode = JIT_OP_BR_NFLE; break; 820 case JIT_OP_BR_NFGE_INV: opcode = JIT_OP_BR_NFLT; break; 821 default: abort(); 822 } 823 return opcode; 824 } 825 826 void 827 _jit_block_clean_cfg(jit_function_t func) 828 { 829 int index, changed; 830 jit_block_t block; 831 jit_insn_t insn; 832 833 /* 834 * The code below is based on the Clean algorithm described in 835 * "Engineering a Compiler" by Keith D. Cooper and Linda Torczon, 836 * section 10.3.1 "Eliminating Useless and Unreachable Code" 837 * (originally presented in a paper by Rob Shillner and John Lu 838 * http://www.cs.princeton.edu/~ras/clean.ps). 839 * 840 * Because libjit IR differs from ILOC the algorithm here has 841 * some differences too. 842 */ 843 844 if(!_jit_block_compute_postorder(func)) 845 { 846 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 847 } 848 849 set_address_of(func); 850 eliminate_unreachable(func); 851 852 loop: 853 changed = 0; 854 855 /* Go through blocks in post order skipping the entry and exit blocks */ 856 for(index = 1; index < (func->builder->num_block_order - 1); index++) 857 { 858 block = func->builder->block_order[index]; 859 if(block->num_succs == 0) 860 { 861 continue; 862 } 863 864 /* Take care of redundant branches that is, if possible, either 865 replace a branch with NOP turning it to a fallthrough case 866 or reduce a conditional branch to unconditional */ 867 if(block->succs[0]->flags == _JIT_EDGE_BRANCH) 868 { 869 insn = _jit_block_get_last(block); 870 if(insn->opcode == JIT_OP_JUMP_TABLE) 871 { 872 /* skip jump tables, handle only branches */ 873 continue; 874 } 875 if(block->succs[0]->dst == block->next) 876 { 877 /* Replace useless branch with NOP */ 878 changed = 1; 879 insn->opcode = JIT_OP_NOP; 880 if(block->num_succs == 2) 881 { 882 /* For conditional branch delete the branch 883 edge while leaving the fallthough edge 884 intact */ 885 #ifdef _JIT_BLOCK_DEBUG 886 printf("%d cbranch->fallthru %d\n", index, block->label); 887 #endif 888 delete_edge(func, block->succs[0]); 889 } 890 else 891 { 892 /* For unconditional branch replace the branch 893 edge with a fallthrough edge */ 894 #ifdef _JIT_BLOCK_DEBUG 895 printf("%d ubranch->fallthru %d\n", index, block->label); 896 #endif 897 block->ends_in_dead = 0; 898 block->succs[0]->flags = _JIT_EDGE_FALLTHRU; 899 } 900 } 901 else if(block->num_succs == 2 902 && block->next->num_succs == 1 903 && block->next->succs[0]->flags == _JIT_EDGE_BRANCH 904 && block->succs[0]->dst == block->next->succs[0]->dst 905 && is_empty_block(block->next)) 906 { 907 /* For conditional branch followed by unconditional 908 that has the same target make the first branch 909 unconditional too, remove the fallthrough edge while 910 leaving the branch edge intact */ 911 #ifdef _JIT_BLOCK_DEBUG 912 printf("%d cbranch->ubranch %d\n", index, block->label); 913 #endif 914 changed = 1; 915 insn->opcode = JIT_OP_BR; 916 block->ends_in_dead = 1; 917 delete_edge(func, block->succs[1]); 918 } 919 else if(block->num_succs == 2 920 && is_empty_block(block->next) 921 && block->next->num_succs == 1 922 /* This transformation is not safe if 923 the block we're rewriting has other 924 predecessors, or has had its 925 address taken. */ 926 && block->next->num_preds == 1 927 && block->next->address_of == 0 928 && block->next->succs[0]->flags == _JIT_EDGE_BRANCH 929 && block->succs[0]->dst == block->next->next) 930 { 931 /* We have a conditional branch, that 932 branches around the next block, and 933 the next block consists of just a 934 jump, like: 935 936 if l7 != 3 then goto .L0 937 goto .L1 938 .L0: 939 940 In this case we can invert the 941 condition and retarget the jump, 942 resulting in: 943 944 if l7 == 3 then goto .L1 945 nop 946 .L0: 947 */ 948 insn->opcode = _jit_invert_condition(insn->opcode); 949 detach_edge_dst(block->succs[0]); 950 attach_edge_dst(block->succs[0], block->next->succs[0]->dst); 951 insn->dest = (jit_value_t) block->next->succs[0]->dst->label; 952 detach_edge_dst(block->next->succs[0]); 953 attach_edge_dst(block->next->succs[0], block->next->next); 954 block->next->succs[0]->flags = _JIT_EDGE_FALLTHRU; 955 /* Rewrite the last instruction of the 956 unnecessary block to be a NOP. */ 957 block->next->insns[block->next->num_insns - 1].opcode = JIT_OP_NOP; 958 block->next->ends_in_dead = 0; 959 changed = 1; 960 } 961 } 962 963 /* Try to simplify basic blocks that end with fallthrough or 964 unconditional branch */ 965 if(block->num_succs == 1 966 && (block->succs[0]->flags == _JIT_EDGE_BRANCH 967 || block->succs[0]->flags == _JIT_EDGE_FALLTHRU)) 968 { 969 if(is_empty_block(block)) 970 { 971 /* Remove empty block */ 972 #ifdef _JIT_BLOCK_DEBUG 973 printf("%d merge_empty %d\n", index, block->label); 974 #endif 975 merge_empty(func, block, &changed); 976 } 977 else if(block->succs[0]->dst->num_preds == 1 978 && block->succs[0]->dst->address_of == 0) 979 { 980 /* Combine with the successor block if it has 981 only one predecessor */ 982 #ifdef _JIT_BLOCK_DEBUG 983 printf("%d combine_block %d\n", index, block->label); 984 #endif 985 combine_block(func, block, &changed); 986 } 987 988 /* TODO: "hoist branch" part of the Clean algorithm. 989 It is somewhat complicated as libjit conditional 990 branches differ too much from ILOC conditional 991 branches */ 992 } 993 } 994 995 if(changed) 996 { 997 if(!_jit_block_compute_postorder(func)) 998 { 999 jit_exception_builtin(JIT_RESULT_OUT_OF_MEMORY); 1000 } 1001 clear_visited(func); 1002 goto loop; 1003 } 1004 } 1005 1006 int 1007 _jit_block_compute_postorder(jit_function_t func) 1008 { 1009 int num_blocks, index, num, top; 1010 jit_block_t *blocks, block, succ; 1011 _jit_block_stack_entry_t *stack; 1012 1013 if(func->builder->block_order) 1014 { 1015 free_order(func); 1016 } 1017 1018 num_blocks = count_blocks(func); 1019 1020 blocks = (jit_block_t *) jit_malloc(num_blocks * sizeof(jit_block_t)); 1021 if(!blocks) 1022 { 1023 return 0; 1024 } 1025 1026 stack = (_jit_block_stack_entry_t *) jit_malloc(num_blocks * sizeof(_jit_block_stack_entry_t)); 1027 if(!stack) 1028 { 1029 jit_free(blocks); 1030 return 0; 1031 } 1032 1033 func->builder->entry_block->visited = 1; 1034 stack[0].block = func->builder->entry_block; 1035 stack[0].index = 0; 1036 top = 1; 1037 num = 0; 1038 do 1039 { 1040 block = stack[top - 1].block; 1041 index = stack[top - 1].index; 1042 1043 if(index == block->num_succs) 1044 { 1045 blocks[num++] = block; 1046 --top; 1047 } 1048 else 1049 { 1050 succ = block->succs[index]->dst; 1051 if(succ->visited) 1052 { 1053 stack[top - 1].index = index + 1; 1054 } 1055 else 1056 { 1057 succ->visited = 1; 1058 stack[top].block = succ; 1059 stack[top].index = 0; 1060 ++top; 1061 } 1062 } 1063 } 1064 while(top); 1065 1066 jit_free(stack); 1067 if(num < num_blocks) 1068 { 1069 blocks = jit_realloc(blocks, num * sizeof(jit_block_t)); 1070 } 1071 1072 func->builder->block_order = blocks; 1073 func->builder->num_block_order = num; 1074 return 1; 1075 } 1076 1077 jit_block_t 1078 _jit_block_create(jit_function_t func) 1079 { 1080 jit_block_t block; 1081 1082 /* Allocate memory for the block */ 1083 block = jit_cnew(struct _jit_block); 1084 if(!block) 1085 { 1086 return 0; 1087 } 1088 1089 /* Initialize the block */ 1090 block->func = func; 1091 block->label = jit_label_undefined; 1092 1093 return block; 1094 } 1095 1096 void 1097 _jit_block_destroy(jit_block_t block) 1098 { 1099 /* Free all the memory owned by the block. CFG edges are not freed 1100 because each edge is shared between two blocks so the ownership 1101 of the edge is ambiguous. Sometimes an edge may be redirected to 1102 another block rather than freed. Therefore edges are freed (or 1103 not freed) separately. However succs and preds arrays are freed, 1104 these contain pointers to edges, not edges themselves. */ 1105 jit_meta_destroy(&block->meta); 1106 jit_free(block->succs); 1107 jit_free(block->preds); 1108 jit_free(block->insns); 1109 jit_free(block); 1110 } 1111 1112 void 1113 _jit_block_detach(jit_block_t first, jit_block_t last) 1114 { 1115 last->next->prev = first->prev; 1116 first->prev->next = last->next; 1117 } 1118 1119 void 1120 _jit_block_attach_after(jit_block_t block, jit_block_t first, jit_block_t last) 1121 { 1122 first->prev = block; 1123 last->next = block->next; 1124 block->next->prev = last; 1125 block->next = first; 1126 } 1127 1128 void 1129 _jit_block_attach_before(jit_block_t block, jit_block_t first, jit_block_t last) 1130 { 1131 first->prev = block->prev; 1132 last->next = block; 1133 block->prev->next = first; 1134 block->prev = last; 1135 } 1136 1137 /* Make space for the label in the label info table */ 1138 static int 1139 ensure_label_table(jit_function_t func, jit_label_t label) 1140 { 1141 jit_label_t num; 1142 _jit_label_info_t *info; 1143 1144 if(label >= func->builder->max_label_info) 1145 { 1146 num = func->builder->max_label_info; 1147 if(num < 64) 1148 { 1149 num = 64; 1150 } 1151 while(num <= label) 1152 { 1153 num *= 2; 1154 } 1155 1156 info = (_jit_label_info_t *) jit_realloc(func->builder->label_info, 1157 num * sizeof(_jit_label_info_t)); 1158 if(!info) 1159 { 1160 return 0; 1161 } 1162 1163 jit_memzero(info + func->builder->max_label_info, 1164 sizeof(_jit_label_info_t) * (num - func->builder->max_label_info)); 1165 func->builder->label_info = info; 1166 func->builder->max_label_info = num; 1167 } 1168 1169 return 1; 1170 } 1171 1172 int 1173 _jit_block_record_label(jit_block_t block, jit_label_t label) 1174 { 1175 jit_builder_t builder; 1176 1177 if(!ensure_label_table(block->func, label)) 1178 { 1179 return 0; 1180 } 1181 1182 builder = block->func->builder; 1183 1184 /* Bail out on previously recorded label */ 1185 if(builder->label_info[label].block) 1186 { 1187 return 0; 1188 } 1189 1190 /* Record label info to the table */ 1191 builder->label_info[label].block = block; 1192 builder->label_info[label].alias = block->label; 1193 block->label = label; 1194 1195 return 1; 1196 } 1197 1198 int 1199 _jit_block_record_label_flags(jit_function_t func, jit_label_t label, int flags) 1200 { 1201 if(!ensure_label_table(func, label)) 1202 { 1203 return 0; 1204 } 1205 1206 func->builder->label_info[label].flags = flags; 1207 return 1; 1208 } 1209 1210 jit_insn_t 1211 _jit_block_add_insn(jit_block_t block) 1212 { 1213 int max_insns; 1214 jit_insn_t insns; 1215 1216 /* Make space for the instruction in the block's instruction list */ 1217 if(block->num_insns == block->max_insns) 1218 { 1219 max_insns = block->max_insns ? block->max_insns * 2 : 4; 1220 insns = (jit_insn_t) jit_realloc(block->insns, 1221 max_insns * sizeof(struct _jit_insn)); 1222 if(!insns) 1223 { 1224 return 0; 1225 } 1226 1227 block->insns = insns; 1228 block->max_insns = max_insns; 1229 } 1230 1231 /* Zero-init the instruction */ 1232 jit_memzero(&block->insns[block->num_insns], sizeof(struct _jit_insn)); 1233 1234 /* Return the instruction, which is now ready to fill in */ 1235 return &block->insns[block->num_insns++]; 1236 } 1237 1238 jit_insn_t 1239 _jit_block_get_last(jit_block_t block) 1240 { 1241 if(block->num_insns > 0) 1242 { 1243 return &block->insns[block->num_insns - 1]; 1244 } 1245 else 1246 { 1247 return 0; 1248 } 1249 } 1250 1251 int 1252 _jit_block_is_final(jit_block_t block) 1253 { 1254 for(block = block->next; block; block = block->next) 1255 { 1256 if(block->num_insns) 1257 { 1258 return 0; 1259 } 1260 } 1261 return 1; 1262 } 1263 1264 /*@ 1265 * @deftypefun jit_function_t jit_block_get_function (jit_block_t @var{block}) 1266 * Get the function that a particular @var{block} belongs to. 1267 * @end deftypefun 1268 @*/ 1269 jit_function_t 1270 jit_block_get_function(jit_block_t block) 1271 { 1272 if(block) 1273 { 1274 return block->func; 1275 } 1276 else 1277 { 1278 return 0; 1279 } 1280 } 1281 1282 /*@ 1283 * @deftypefun jit_context_t jit_block_get_context (jit_block_t @var{block}) 1284 * Get the context that a particular @var{block} belongs to. 1285 * @end deftypefun 1286 @*/ 1287 jit_context_t 1288 jit_block_get_context(jit_block_t block) 1289 { 1290 if(block) 1291 { 1292 return block->func->context; 1293 } 1294 else 1295 { 1296 return 0; 1297 } 1298 } 1299 1300 /*@ 1301 * @deftypefun jit_label_t jit_block_get_label (jit_block_t @var{block}) 1302 * Get the label associated with a block. 1303 * @end deftypefun 1304 @*/ 1305 jit_label_t 1306 jit_block_get_label(jit_block_t block) 1307 { 1308 if(block) 1309 { 1310 return block->label; 1311 } 1312 return jit_label_undefined; 1313 } 1314 1315 /*@ 1316 * @deftypefun jit_label_t jit_block_get_next_label (jit_block_t @var{block}, jit_label_t @var{label}) 1317 * Get the next label associated with a block. 1318 * @end deftypefun 1319 @*/ 1320 jit_label_t 1321 jit_block_get_next_label(jit_block_t block, jit_label_t label) 1322 { 1323 jit_builder_t builder; 1324 if(block) 1325 { 1326 if(label == jit_label_undefined) 1327 { 1328 return block->label; 1329 } 1330 builder = block->func->builder; 1331 if(builder 1332 && label < builder->max_label_info 1333 && block == builder->label_info[label].block) 1334 { 1335 return builder->label_info[label].alias; 1336 } 1337 } 1338 return jit_label_undefined; 1339 } 1340 1341 /*@ 1342 * @deftypefun jit_block_t jit_block_next (jit_function_t @var{func}, jit_block_t @var{previous}) 1343 * Iterate over the blocks in a function, in order of their creation. 1344 * The @var{previous} argument should be NULL on the first call. 1345 * This function will return NULL if there are no further blocks to iterate. 1346 * @end deftypefun 1347 @*/ 1348 jit_block_t 1349 jit_block_next(jit_function_t func, jit_block_t previous) 1350 { 1351 if(previous) 1352 { 1353 return previous->next; 1354 } 1355 else if(func && func->builder) 1356 { 1357 return func->builder->entry_block; 1358 } 1359 else 1360 { 1361 return 0; 1362 } 1363 } 1364 1365 /*@ 1366 * @deftypefun jit_block_t jit_block_previous (jit_function_t @var{func}, jit_block_t @var{previous}) 1367 * Iterate over the blocks in a function, in reverse order of their creation. 1368 * The @var{previous} argument should be NULL on the first call. 1369 * This function will return NULL if there are no further blocks to iterate. 1370 * @end deftypefun 1371 @*/ 1372 jit_block_t 1373 jit_block_previous(jit_function_t func, jit_block_t previous) 1374 { 1375 if(previous) 1376 { 1377 return previous->prev; 1378 } 1379 else if(func && func->builder) 1380 { 1381 return func->builder->exit_block; 1382 } 1383 else 1384 { 1385 return 0; 1386 } 1387 } 1388 1389 /*@ 1390 * @deftypefun jit_block_t jit_block_from_label (jit_function_t @var{func}, jit_label_t @var{label}) 1391 * Get the block that corresponds to a particular @var{label}. 1392 * Returns NULL if there is no block associated with the label. 1393 * @end deftypefun 1394 @*/ 1395 jit_block_t 1396 jit_block_from_label(jit_function_t func, jit_label_t label) 1397 { 1398 if(func && func->builder && label < func->builder->max_label_info) 1399 { 1400 return func->builder->label_info[label].block; 1401 } 1402 else 1403 { 1404 return 0; 1405 } 1406 } 1407 1408 /*@ 1409 * @deftypefun int jit_block_set_meta (jit_block_t @var{block}, int @var{type}, void *@var{data}, jit_meta_free_func @var{free_data}) 1410 * Tag a block with some metadata. Returns zero if out of memory. 1411 * If the @var{type} already has some metadata associated with it, then 1412 * the previous value will be freed. Metadata may be used to store 1413 * dependency graphs, branch prediction information, or any other 1414 * information that is useful to optimizers or code generators. 1415 * 1416 * Metadata type values of 10000 or greater are reserved for internal use. 1417 * @end deftypefun 1418 @*/ 1419 int 1420 jit_block_set_meta(jit_block_t block, int type, void *data, jit_meta_free_func free_data) 1421 { 1422 return jit_meta_set(&(block->meta), type, data, free_data, block->func); 1423 } 1424 1425 /*@ 1426 * @deftypefun {void *} jit_block_get_meta (jit_block_t @var{block}, int @var{type}) 1427 * Get the metadata associated with a particular tag. Returns NULL 1428 * if @var{type} does not have any metadata associated with it. 1429 * @end deftypefun 1430 @*/ 1431 void * 1432 jit_block_get_meta(jit_block_t block, int type) 1433 { 1434 return jit_meta_get(block->meta, type); 1435 } 1436 1437 /*@ 1438 * @deftypefun void jit_block_free_meta (jit_block_t @var{block}, int @var{type}) 1439 * Free metadata of a specific type on a block. Does nothing if 1440 * the @var{type} does not have any metadata associated with it. 1441 * @end deftypefun 1442 @*/ 1443 void 1444 jit_block_free_meta(jit_block_t block, int type) 1445 { 1446 jit_meta_free(&(block->meta), type); 1447 } 1448 1449 /*@ 1450 * @deftypefun int jit_block_is_reachable (jit_block_t @var{block}) 1451 * Determine if a block is reachable from some other point in 1452 * its function. Unreachable blocks can be discarded in their 1453 * entirety. If the JIT is uncertain as to whether a block is 1454 * reachable, or it does not wish to perform expensive flow 1455 * analysis to find out, then it will err on the side of caution 1456 * and assume that it is reachable. 1457 * @end deftypefun 1458 @*/ 1459 int 1460 jit_block_is_reachable(jit_block_t block) 1461 { 1462 jit_block_t entry; 1463 1464 /* Simple-minded reachability analysis that bothers only with 1465 fall-through control flow. The block is considered reachable 1466 if a) it is the entry block b) it has any label c) there is 1467 fall-through path to it from one of the above. */ 1468 entry = block->func->builder->entry_block; 1469 while(block != entry && block->label == jit_label_undefined) 1470 { 1471 block = block->prev; 1472 if(block->ends_in_dead) 1473 { 1474 /* There is no fall-through path from the prev block */ 1475 return 0; 1476 } 1477 } 1478 1479 return 1; 1480 } 1481 1482 /*@ 1483 * @deftypefun int jit_block_ends_in_dead (jit_block_t @var{block}) 1484 * Determine if a block ends in a "dead" marker. That is, control 1485 * will not fall out through the end of the block. 1486 * @end deftypefun 1487 @*/ 1488 int 1489 jit_block_ends_in_dead(jit_block_t block) 1490 { 1491 return block->ends_in_dead; 1492 } 1493 1494 /*@ 1495 * @deftypefun int jit_block_current_is_dead (jit_function_t @var{func}) 1496 * Determine if the current point in the function is dead. That is, 1497 * there are no existing branches or fall-throughs to this point. 1498 * This differs slightly from @code{jit_block_ends_in_dead} in that 1499 * this can skip past zero-length blocks that may not appear to be 1500 * dead to find the dead block at the head of a chain of empty blocks. 1501 * @end deftypefun 1502 @*/ 1503 int 1504 jit_block_current_is_dead(jit_function_t func) 1505 { 1506 jit_block_t block = jit_block_previous(func, 0); 1507 return !block || jit_block_ends_in_dead(block) || !jit_block_is_reachable(block); 1508 }