github.com/goccy/go-jit@v0.0.0-20200514131505-ff78d45cf6af/internal/ccall/jit-rules.c (about) 1 /* 2 * jit-rules.c - Rules that define the characteristics of the back-end. 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 "jit-rules.h" 25 26 /* 27 * The information blocks for all registers in the system. 28 */ 29 jit_reginfo_t const _jit_reg_info[JIT_NUM_REGS] = {JIT_REG_INFO}; 30 31 #ifdef JIT_CDECL_WORD_REG_PARAMS 32 33 /* 34 * List of registers to use for simple parameter passing. 35 */ 36 static int const cdecl_word_regs[] = JIT_CDECL_WORD_REG_PARAMS; 37 #ifdef JIT_FASTCALL_WORD_REG_PARAMS 38 static int const fastcall_word_regs[] = JIT_FASTCALL_WORD_REG_PARAMS; 39 #endif 40 41 /* 42 * Structure that is used to help with parameter passing. 43 */ 44 typedef struct 45 { 46 jit_nint offset; 47 unsigned int index; 48 unsigned int max_regs; 49 const int *word_regs; 50 jit_value_t word_values[JIT_MAX_WORD_REG_PARAMS]; 51 52 } jit_param_passing_t; 53 54 /* 55 * Round a size up to a multiple of the stack word size. 56 */ 57 #define ROUND_STACK(size) \ 58 (((size) + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1)) 59 #define STACK_WORDS(size) \ 60 (((size) + (sizeof(void *) - 1)) / sizeof(void *)) 61 62 /* 63 * Allocate a word register or incoming frame position to a value. 64 */ 65 static int alloc_incoming_word 66 (jit_function_t func, jit_param_passing_t *passing, 67 jit_value_t value, int extra_offset) 68 { 69 int reg; 70 reg = passing->word_regs[passing->index]; 71 if(reg != -1 && passing->word_values[passing->index] != 0) 72 { 73 /* The value was already forced out previously, so just copy it */ 74 if(!jit_insn_store(func, value, passing->word_values[passing->index])) 75 { 76 return 0; 77 } 78 ++(passing->index); 79 } 80 else if(reg != -1) 81 { 82 if(!jit_insn_incoming_reg(func, value, reg)) 83 { 84 return 0; 85 } 86 ++(passing->index); 87 } 88 else 89 { 90 if(!jit_insn_incoming_frame_posn 91 (func, value, passing->offset + extra_offset)) 92 { 93 return 0; 94 } 95 passing->offset += sizeof(void *); 96 } 97 return 1; 98 } 99 100 /* 101 * Force the remaining word registers out into temporary values, 102 * to protect them from being accidentally overwritten by the code 103 * that deals with multi-word parameters. 104 */ 105 static int force_remaining_out 106 (jit_function_t func, jit_param_passing_t *passing) 107 { 108 unsigned int index = passing->index; 109 jit_value_t value; 110 while(index < passing->max_regs && passing->word_regs[index] != -1) 111 { 112 if(passing->word_values[index] != 0) 113 { 114 /* We've already done this before */ 115 return 1; 116 } 117 value = jit_value_create(func, jit_type_void_ptr); 118 if(!value) 119 { 120 return 0; 121 } 122 if(!jit_insn_incoming_reg(func, value, passing->word_regs[index])) 123 { 124 return 0; 125 } 126 passing->word_values[index] = value; 127 ++index; 128 } 129 return 1; 130 } 131 132 int _jit_create_entry_insns(jit_function_t func) 133 { 134 jit_type_t signature = func->signature; 135 jit_type_t type; 136 jit_value_t value; 137 jit_value_t temp; 138 jit_value_t addr_of; 139 unsigned int num_params; 140 unsigned int param; 141 unsigned int size; 142 jit_param_passing_t passing; 143 jit_nint partial_offset; 144 145 /* Reset the local variable frame size for this function */ 146 func->builder->frame_size = JIT_INITIAL_FRAME_SIZE; 147 148 /* Initialize the parameter passing information block */ 149 passing.offset = JIT_INITIAL_STACK_OFFSET; 150 passing.index = 0; 151 #ifdef JIT_FASTCALL_WORD_REG_PARAMS 152 if(jit_type_get_abi(signature) == jit_abi_fastcall) 153 { 154 passing.word_regs = fastcall_word_regs; 155 } 156 else 157 #endif 158 { 159 passing.word_regs = cdecl_word_regs; 160 } 161 for(size = 0; size < JIT_MAX_WORD_REG_PARAMS; ++size) 162 { 163 passing.word_values[size] = 0; 164 } 165 166 /* If the function is nested, then we need an extra parameter 167 to pass the pointer to the parent's local variable frame */ 168 if(func->nested_parent) 169 { 170 value = jit_value_create(func, jit_type_void_ptr); 171 if(!value) 172 { 173 return 0; 174 } 175 176 jit_function_set_parent_frame(func, value); 177 if(!alloc_incoming_word(func, &passing, value, 0)) 178 { 179 return 0; 180 } 181 } 182 183 /* Allocate the structure return pointer */ 184 value = jit_value_get_struct_pointer(func); 185 if(value) 186 { 187 if(!alloc_incoming_word(func, &passing, value, 0)) 188 { 189 return 0; 190 } 191 } 192 193 /* Determine the maximum number of registers that may be needed 194 to pass the function's parameters */ 195 num_params = jit_type_num_params(signature); 196 passing.max_regs = passing.index; 197 for(param = 0; param < num_params; ++param) 198 { 199 value = jit_value_get_param(func, param); 200 if(value) 201 { 202 size = STACK_WORDS(jit_type_get_size(jit_value_get_type(value))); 203 passing.max_regs += size; 204 } 205 } 206 207 /* Allocate the parameter offsets */ 208 for(param = 0; param < num_params; ++param) 209 { 210 value = jit_value_get_param(func, param); 211 if(!value) 212 { 213 continue; 214 } 215 type = jit_type_remove_tags(jit_value_get_type(value)); 216 switch(type->kind) 217 { 218 case JIT_TYPE_SBYTE: 219 case JIT_TYPE_UBYTE: 220 { 221 if(!alloc_incoming_word 222 (func, &passing, value, _jit_nint_lowest_byte())) 223 { 224 return 0; 225 } 226 } 227 break; 228 229 case JIT_TYPE_SHORT: 230 case JIT_TYPE_USHORT: 231 { 232 if(!alloc_incoming_word 233 (func, &passing, value, _jit_nint_lowest_short())) 234 { 235 return 0; 236 } 237 } 238 break; 239 240 case JIT_TYPE_INT: 241 case JIT_TYPE_UINT: 242 { 243 if(!alloc_incoming_word 244 (func, &passing, value, _jit_nint_lowest_int())) 245 { 246 return 0; 247 } 248 } 249 break; 250 251 case JIT_TYPE_NINT: 252 case JIT_TYPE_NUINT: 253 case JIT_TYPE_SIGNATURE: 254 case JIT_TYPE_PTR: 255 { 256 if(!alloc_incoming_word(func, &passing, value, 0)) 257 { 258 return 0; 259 } 260 } 261 break; 262 263 case JIT_TYPE_LONG: 264 case JIT_TYPE_ULONG: 265 #ifdef JIT_NATIVE_INT64 266 { 267 if(!alloc_incoming_word(func, &passing, value, 0)) 268 { 269 return 0; 270 } 271 } 272 break; 273 #endif 274 /* Fall through on 32-bit platforms */ 275 276 case JIT_TYPE_FLOAT32: 277 case JIT_TYPE_FLOAT64: 278 case JIT_TYPE_NFLOAT: 279 case JIT_TYPE_STRUCT: 280 case JIT_TYPE_UNION: 281 { 282 /* Force the remaining registers out into temporary copies */ 283 if(!force_remaining_out(func, &passing)) 284 { 285 return 0; 286 } 287 288 /* Determine how many words that we need to copy */ 289 size = STACK_WORDS(jit_type_get_size(type)); 290 291 /* If there are no registers left, then alloc on the stack */ 292 if(passing.word_regs[passing.index] == -1) 293 { 294 if(!jit_insn_incoming_frame_posn 295 (func, value, passing.offset)) 296 { 297 return 0; 298 } 299 passing.offset += size * sizeof(void *); 300 break; 301 } 302 303 /* Copy the register components across */ 304 partial_offset = 0; 305 addr_of = jit_insn_address_of(func, value); 306 if(!addr_of) 307 { 308 return 0; 309 } 310 while(size > 0 && passing.word_regs[passing.index] != -1) 311 { 312 temp = passing.word_values[passing.index]; 313 ++(passing.index); 314 if(!jit_insn_store_relative 315 (func, addr_of, partial_offset, temp)) 316 { 317 return 0; 318 } 319 partial_offset += sizeof(void *); 320 --size; 321 } 322 323 /* Copy the stack components across */ 324 while(size > 0) 325 { 326 temp = jit_value_create(func, jit_type_void_ptr); 327 if(!temp) 328 { 329 return 0; 330 } 331 if(!jit_insn_incoming_frame_posn 332 (func, temp, passing.offset)) 333 { 334 return 0; 335 } 336 if(!jit_insn_store_relative 337 (func, addr_of, partial_offset, temp)) 338 { 339 return 0; 340 } 341 passing.offset += sizeof(void *); 342 partial_offset += sizeof(void *); 343 --size; 344 } 345 } 346 break; 347 } 348 } 349 return 1; 350 } 351 352 /* 353 * Record that we need an outgoing register or stack slot for a word value. 354 */ 355 static void need_outgoing_word(jit_param_passing_t *passing) 356 { 357 if(passing->word_regs[passing->index] != -1) 358 { 359 ++(passing->index); 360 } 361 else 362 { 363 passing->offset += sizeof(void *); 364 } 365 } 366 367 /* 368 * Record that we need an outgoing register, containing a particular value. 369 */ 370 static void need_outgoing_value 371 (jit_param_passing_t *passing, jit_value_t value) 372 { 373 passing->word_values[passing->index] = value; 374 ++(passing->index); 375 } 376 377 /* 378 * Count the number of registers that are left for parameter passing. 379 */ 380 static jit_nint count_regs_left(jit_param_passing_t *passing) 381 { 382 int left = 0; 383 unsigned int index = passing->index; 384 while(passing->word_regs[index] != -1) 385 { 386 ++left; 387 ++index; 388 } 389 return left; 390 } 391 392 /* 393 * Determine if a type corresponds to a structure or union. 394 */ 395 static int is_struct_or_union(jit_type_t type) 396 { 397 type = jit_type_normalize(type); 398 if(type) 399 { 400 if(type->kind == JIT_TYPE_STRUCT || type->kind == JIT_TYPE_UNION) 401 { 402 return 1; 403 } 404 } 405 return 0; 406 } 407 408 /* 409 * Push a parameter onto the stack. 410 */ 411 static int push_param 412 (jit_function_t func, jit_param_passing_t *passing, 413 jit_value_t value, jit_type_t type) 414 { 415 jit_nint size = (jit_nint)(jit_type_get_size(value->type)); 416 passing->offset -= ROUND_STACK(size); 417 if(is_struct_or_union(type) && !is_struct_or_union(value->type)) 418 { 419 #ifdef JIT_USE_PARAM_AREA 420 /* Copy the value into the outgoing parameter area, by pointer */ 421 if(!jit_insn_set_param_ptr(func, value, type, passing->offset)) 422 { 423 return 0; 424 } 425 #else 426 /* Push the parameter value onto the stack, by pointer */ 427 if(!jit_insn_push_ptr(func, value, type)) 428 { 429 return 0; 430 } 431 #endif 432 } 433 else 434 { 435 #ifdef JIT_USE_PARAM_AREA 436 /* Copy the value into the outgoing parameter area */ 437 if(!jit_insn_set_param(func, value, passing->offset)) 438 { 439 return 0; 440 } 441 #else 442 /* Push the parameter value onto the stack */ 443 if(!jit_insn_push(func, value)) 444 { 445 return 0; 446 } 447 #endif 448 } 449 return 1; 450 } 451 452 /* 453 * Allocate an outgoing word register to a value. 454 */ 455 static int alloc_outgoing_word 456 (jit_function_t func, jit_param_passing_t *passing, jit_value_t value) 457 { 458 int reg; 459 --(passing->index); 460 reg = passing->word_regs[passing->index]; 461 if(passing->word_values[passing->index] != 0) 462 { 463 /* We copied the value previously, so use the copy instead */ 464 value = passing->word_values[passing->index]; 465 } 466 if(!jit_insn_outgoing_reg(func, value, reg)) 467 { 468 return 0; 469 } 470 return 1; 471 } 472 473 int _jit_create_call_setup_insns 474 (jit_function_t func, jit_type_t signature, 475 jit_value_t *args, unsigned int num_args, 476 int is_nested, jit_value_t parent_frame, jit_value_t *struct_return, int flags) 477 { 478 jit_type_t type; 479 jit_value_t value; 480 jit_nint size; 481 jit_nint regs_left; 482 jit_nint rounded_size; 483 jit_nint partial_offset; 484 jit_param_passing_t passing; 485 jit_value_t return_ptr; 486 jit_value_t partial; 487 unsigned int param; 488 489 /* Initialize the parameter passing information block */ 490 passing.offset = 0; 491 passing.index = 0; 492 #ifdef JIT_FASTCALL_WORD_REG_PARAMS 493 if(jit_type_get_abi(signature) == jit_abi_fastcall) 494 { 495 passing.word_regs = fastcall_word_regs; 496 } 497 else 498 #endif 499 { 500 passing.word_regs = cdecl_word_regs; 501 } 502 for(size = 0; size < JIT_MAX_WORD_REG_PARAMS; ++size) 503 { 504 passing.word_values[size] = 0; 505 } 506 507 /* Determine how many parameters are going to end up in word registers, 508 and compute the largest stack size needed to pass stack parameters */ 509 if(is_nested) 510 { 511 need_outgoing_word(&passing); 512 } 513 type = jit_type_get_return(signature); 514 if(jit_type_return_via_pointer(type)) 515 { 516 value = jit_value_create(func, type); 517 if(!value) 518 { 519 return 0; 520 } 521 *struct_return = value; 522 return_ptr = jit_insn_address_of(func, value); 523 if(!return_ptr) 524 { 525 return 0; 526 } 527 need_outgoing_word(&passing); 528 } 529 else 530 { 531 *struct_return = 0; 532 return_ptr = 0; 533 } 534 partial = 0; 535 for(param = 0; param < num_args; ++param) 536 { 537 type = jit_type_get_param(signature, param); 538 size = STACK_WORDS(jit_type_get_size(type)); 539 if(size <= 1) 540 { 541 /* Allocate a word register or stack position */ 542 need_outgoing_word(&passing); 543 } 544 else 545 { 546 regs_left = count_regs_left(&passing); 547 if(regs_left > 0) 548 { 549 /* May be partly in registers and partly on the stack */ 550 if(is_struct_or_union(type) && 551 !is_struct_or_union(jit_value_get_type(args[param]))) 552 { 553 /* Passing a structure by pointer */ 554 partial = args[param]; 555 } 556 else if(jit_value_is_constant(args[param])) 557 { 558 if(size <= regs_left) 559 { 560 /* We can split the constant, without a temporary */ 561 partial_offset = 0; 562 while(size > 0) 563 { 564 value = jit_value_create_nint_constant 565 (func, jit_type_void_ptr, 566 *((jit_nint *)(args[param]->address + 567 partial_offset))); 568 need_outgoing_value(&passing, value); 569 partial_offset += sizeof(void *); 570 --size; 571 } 572 continue; 573 } 574 else 575 { 576 /* Copy the constant into a temporary local variable */ 577 partial = jit_value_create(func, type); 578 if(!partial) 579 { 580 return 0; 581 } 582 if(!jit_insn_store(func, partial, args[param])) 583 { 584 return 0; 585 } 586 partial = jit_insn_address_of(func, partial); 587 } 588 } 589 else 590 { 591 /* Get the address of this parameter */ 592 partial = jit_insn_address_of(func, args[param]); 593 } 594 if(!partial) 595 { 596 return 0; 597 } 598 partial_offset = 0; 599 while(size > 0 && regs_left > 0) 600 { 601 value = jit_insn_load_relative 602 (func, partial, partial_offset, jit_type_void_ptr); 603 if(!value) 604 { 605 return 0; 606 } 607 need_outgoing_value(&passing, value); 608 --size; 609 --regs_left; 610 partial_offset += sizeof(void *); 611 } 612 passing.offset += size * sizeof(void *); 613 } 614 else 615 { 616 /* Pass this parameter completely on the stack */ 617 passing.offset += size * sizeof(void *); 618 } 619 } 620 } 621 #ifdef JIT_USE_PARAM_AREA 622 if(passing.offset > func->builder->param_area_size) 623 { 624 func->builder->param_area_size = passing.offset; 625 } 626 #else 627 /* Flush deferred stack pops from previous calls if too many 628 parameters have collected up on the stack since last time */ 629 if(!jit_insn_flush_defer_pop(func, 32 - passing.offset)) 630 { 631 return 0; 632 } 633 #endif 634 635 /* Move all of the parameters into their final locations */ 636 param = num_args; 637 while(param > 0) 638 { 639 --param; 640 type = jit_type_get_param(signature, param); 641 size = (jit_nint)(jit_type_get_size(type)); 642 rounded_size = ROUND_STACK(size); 643 size = STACK_WORDS(size); 644 if(rounded_size <= passing.offset) 645 { 646 /* This parameter is completely on the stack */ 647 if(!push_param(func, &passing, args[param], type)) 648 { 649 return 0; 650 } 651 } 652 else if(passing.offset > 0) 653 { 654 /* This parameter is split between the stack and registers */ 655 while(passing.offset > 0) 656 { 657 rounded_size -= sizeof(void *); 658 value = jit_insn_load_relative 659 (func, partial, rounded_size, jit_type_void_ptr); 660 if(!value) 661 { 662 return 0; 663 } 664 if(!push_param(func, &passing, value, jit_type_void_ptr)) 665 { 666 return 0; 667 } 668 --size; 669 } 670 while(size > 0) 671 { 672 if(!alloc_outgoing_word(func, &passing, 0)) 673 { 674 return 0; 675 } 676 --size; 677 } 678 } 679 else 680 { 681 /* This parameter is completely in registers. If the parameter 682 occupies multiple registers, then it has already been split */ 683 while(size > 0) 684 { 685 if(!alloc_outgoing_word(func, &passing, args[param])) 686 { 687 return 0; 688 } 689 --size; 690 } 691 } 692 } 693 694 /* Add nested scope information if required */ 695 if(is_nested) 696 { 697 if(passing.index > 0) 698 { 699 if(!alloc_outgoing_word(func, &passing, parent_frame)) 700 { 701 return 0; 702 } 703 } 704 else 705 { 706 if(!push_param 707 (func, &passing, parent_frame, jit_type_void_ptr)) 708 { 709 return 0; 710 } 711 } 712 } 713 714 /* Add the structure return pointer if required */ 715 if(return_ptr) 716 { 717 if(passing.index > 0) 718 { 719 if(!alloc_outgoing_word(func, &passing, return_ptr)) 720 { 721 return 0; 722 } 723 } 724 else 725 { 726 if(!push_param 727 (func, &passing, return_ptr, jit_type_void_ptr)) 728 { 729 return 0; 730 } 731 } 732 } 733 734 /* The call is ready to proceed */ 735 return 1; 736 } 737 738 #endif /* JIT_CDECL_WORD_REG_PARAMS */ 739 740 void 741 _jit_gen_check_space(jit_gencode_t gen, int space) 742 { 743 if((gen->ptr + space) >= gen->mem_limit) 744 { 745 /* No space left on the current cache page. */ 746 jit_exception_builtin(JIT_RESULT_MEMORY_FULL); 747 } 748 } 749 750 void * 751 _jit_gen_alloc(jit_gencode_t gen, unsigned long size) 752 { 753 void *ptr; 754 _jit_memory_set_break(gen->context, gen->ptr); 755 ptr = _jit_memory_alloc_data(gen->context, size, JIT_BEST_ALIGNMENT); 756 if(!ptr) 757 { 758 jit_exception_builtin(JIT_RESULT_MEMORY_FULL); 759 } 760 gen->mem_limit = _jit_memory_get_limit(gen->context); 761 return ptr; 762 } 763 764 int _jit_int_lowest_byte(void) 765 { 766 union 767 { 768 unsigned char bytes[4]; 769 jit_int value; 770 } volatile un; 771 int posn; 772 un.value = (jit_int)0x01020304; 773 posn = 0; 774 while(un.bytes[posn] != 0x04) 775 { 776 ++posn; 777 } 778 return posn; 779 } 780 781 int _jit_int_lowest_short(void) 782 { 783 union 784 { 785 unsigned char bytes[4]; 786 jit_int value; 787 } volatile un; 788 int posn; 789 un.value = (jit_int)0x01020304; 790 posn = 0; 791 while(un.bytes[posn] != 0x03 && un.bytes[posn] != 0x04) 792 { 793 ++posn; 794 } 795 return posn; 796 } 797 798 int _jit_nint_lowest_byte(void) 799 { 800 #ifdef JIT_NATIVE_INT32 801 return _jit_int_lowest_byte(); 802 #else 803 union 804 { 805 unsigned char bytes[8]; 806 jit_long value; 807 } volatile un; 808 int posn; 809 un.value = (jit_long)0x0102030405060708; 810 posn = 0; 811 while(un.bytes[posn] != 0x08) 812 { 813 ++posn; 814 } 815 return posn; 816 #endif 817 } 818 819 int _jit_nint_lowest_short(void) 820 { 821 #ifdef JIT_NATIVE_INT32 822 return _jit_int_lowest_short(); 823 #else 824 union 825 { 826 unsigned char bytes[8]; 827 jit_long value; 828 } volatile un; 829 int posn; 830 un.value = (jit_long)0x0102030405060708; 831 posn = 0; 832 while(un.bytes[posn] != 0x07 && un.bytes[posn] != 0x08) 833 { 834 ++posn; 835 } 836 return posn; 837 #endif 838 } 839 840 int _jit_nint_lowest_int(void) 841 { 842 #ifdef JIT_NATIVE_INT32 843 return 0; 844 #else 845 union 846 { 847 unsigned char bytes[8]; 848 jit_long value; 849 } volatile un; 850 int posn; 851 un.value = (jit_long)0x0102030405060708; 852 posn = 0; 853 while(un.bytes[posn] <= 0x04) 854 { 855 ++posn; 856 } 857 return posn; 858 #endif 859 }