1// -*- c -*- 2// 3// %CopyrightBegin% 4// 5// Copyright Ericsson AB 2020. All Rights Reserved. 6// 7// Licensed under the Apache License, Version 2.0 (the "License"); 8// you may not use this file except in compliance with the License. 9// You may obtain a copy of the License at 10// 11// http://www.apache.org/licenses/LICENSE-2.0 12// 13// Unless required by applicable law or agreed to in writing, software 14// distributed under the License is distributed on an "AS IS" BASIS, 15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16// See the License for the specific language governing permissions and 17// limitations under the License. 18// 19// %CopyrightEnd% 20// 21 22// Generate the fastest instruction to fetch an integer from a binary. 23gen.get_integer2(Fail, Ms, Live, Size, Unit, Flags, Dst) { 24 BeamOp* op; 25 UWord bits; 26 27 $NewBeamOp(S, op); 28 $NativeEndian(Flags); 29 if (Size.type == TAG_i) { 30 if (!beam_load_safe_mul(Size.val, Unit.val, &bits)) { 31 goto error; 32 } else if ((Flags.val & BSF_SIGNED) != 0) { 33 goto generic; 34 } else if (bits == 8) { 35 $BeamOpNameArity(op, i_bs_get_integer_8, 3); 36 op->a[0] = Ms; 37 op->a[1] = Fail; 38 op->a[2] = Dst; 39 } else if (bits == 16 && (Flags.val & BSF_LITTLE) == 0) { 40 $BeamOpNameArity(op, i_bs_get_integer_16, 3); 41 op->a[0] = Ms; 42 op->a[1] = Fail; 43 op->a[2] = Dst; 44#ifdef ARCH_64 45 } else if (bits == 32 && (Flags.val & BSF_LITTLE) == 0) { 46 $BeamOpNameArity(op, i_bs_get_integer_32, 3); 47 op->a[0] = Ms; 48 op->a[1] = Fail; 49 op->a[2] = Dst; 50#endif 51 } else { 52 generic: 53 if (bits < SMALL_BITS) { 54 $BeamOpNameArity(op, i_bs_get_integer_small_imm, 5); 55 op->a[0] = Ms; 56 op->a[1].type = TAG_u; 57 op->a[1].val = bits; 58 op->a[2] = Fail; 59 op->a[3] = Flags; 60 op->a[4] = Dst; 61 } else { 62 $BeamOpNameArity(op, i_bs_get_integer_imm, 6); 63 op->a[0] = Ms; 64 op->a[1].type = TAG_u; 65 op->a[1].val = bits; 66 op->a[2] = Live; 67 op->a[3] = Fail; 68 op->a[4] = Flags; 69 op->a[5] = Dst; 70 } 71 } 72 } else if (Size.type == TAG_q) { 73 Eterm big = beamfile_get_literal(&S->beam, Size.val); 74 Uint bigval; 75 76 if (!term_to_Uint(big, &bigval)) { 77 error: 78 $BeamOpNameArity(op, jump, 1); 79 op->a[0] = Fail; 80 } else { 81 if (!beam_load_safe_mul(bigval, Unit.val, &bits)) { 82 goto error; 83 } 84 goto generic; 85 } 86 } else if (Size.type == TAG_x || Size.type == TAG_y) { 87 $BeamOpNameArity(op, i_bs_get_integer, 6); 88 op->a[0] = Ms; 89 op->a[1] = Fail; 90 op->a[2] = Live; 91 op->a[3].type = TAG_u; 92 op->a[3].val = (Unit.val << 3) | Flags.val; 93 op->a[4] = Size; 94 op->a[5] = Dst; 95 return op; 96 } else { 97 /* Invalid literal size. */ 98 goto error; 99 } 100 return op; 101} 102 103gen.jump_tab(Src, Fail, Size, Rest) { 104 Sint min, max; 105 Sint i; 106 Sint size; 107 Sint arity; 108 int fixed_args; 109 BeamOp* op; 110 111 ASSERT(Size.val >= 2 && Size.val % 2 == 0); 112 113 /* Don't generate a jump table if there's only one choice */ 114 if (Size.val == 2) { 115 BeamOp* jump; 116 117 $NewBeamOp(S, op); 118 $BeamOpNameArity(op, is_ne_exact, 3); 119 op->a[0] = Rest[1]; 120 op->a[1] = Src; 121 op->a[2] = Rest[0]; 122 123 $NewBeamOp(S, jump); 124 $BeamOpNameArity(jump, jump, 1); 125 jump->a[0] = Fail; 126 127 op->next = jump; 128 jump->next = NULL; 129 return op; 130 } 131 132 /* Calculate the minimum and maximum values and size of jump table. */ 133 ASSERT(Rest[0].type == TAG_i); 134 min = max = Rest[0].val; 135 for (i = 2; i < Size.val; i += 2) { 136 ASSERT(Rest[i].type == TAG_i && Rest[i+1].type == TAG_f); 137 if (Rest[i].val < min) { 138 min = Rest[i].val; 139 } else if (max < Rest[i].val) { 140 max = Rest[i].val; 141 } 142 } 143 size = max - min + 1; 144 145 /* Allocate structure and fill in the fixed fields. */ 146 $NewBeamOp(S, op); 147 op->next = NULL; 148 if (min == 0) { 149 $BeamOpNameArity(op, i_jump_on_val_zero, 3); 150 } else { 151 $BeamOpNameArity(op, i_jump_on_val, 4); 152 } 153 fixed_args = op->arity; 154 arity = fixed_args + size; 155 $BeamOpArity(op, arity); 156 op->a[0] = Src; 157 op->a[1] = Fail; 158 op->a[2].type = TAG_u; 159 op->a[2].val = size; 160 op->a[3].type = TAG_u; 161 op->a[3].val = min; 162 163 /* Fill in the jump table. */ 164 for (i = fixed_args; i < arity; i++) { 165 op->a[i] = Fail; 166 } 167 168 for (i = 0; i < Size.val; i += 2) { 169 Sint index = fixed_args + Rest[i].val - min; 170 ASSERT(fixed_args <= index && index < arity); 171 op->a[index] = Rest[i+1]; 172 } 173 174 return op; 175} 176 177// 178// Generate a select_val instruction. We know that a jump table 179// is not suitable, and that all values are of the same type 180// (integer or atoms). 181// 182gen.select_val(Src, Fail, Size, Rest) { 183 BeamOp* op; 184 BeamOpArg *tmp; 185 int arity = Size.val + 3; 186 int size = Size.val / 2; 187 int i, j, align = 0; 188 189 if (size == 2) { 190 /* 191 * Use a special-cased instruction if there are only two values. 192 */ 193 194 $NewBeamOp(S, op); 195 op->next = NULL; 196 $BeamOpNameArity(op, i_select_val2, 4); 197 $BeamOpArity(op, arity - 1); 198 op->a[0] = Src; 199 op->a[1] = Fail; 200 op->a[2] = Rest[0]; 201 op->a[3] = Rest[2]; 202 op->a[4] = Rest[1]; 203 op->a[5] = Rest[3]; 204 205 return op; 206 } 207 208 if (size <= 10) { 209 /* Use linear search. Reserve place for a sentinel. */ 210 align = 1; 211 } 212 213 arity += 2*align; 214 size += align; 215 216 $NewBeamOp(S, op); 217 op->next = NULL; 218 if (align == 0) { 219 $BeamOpNameArity(op, i_select_val_bins, 3); 220 } else { 221 $BeamOpNameArity(op, i_select_val_lins, 3); 222 } 223 $BeamOpArity(op, arity); 224 op->a[0] = Src; 225 op->a[1] = Fail; 226 op->a[2].type = TAG_u; 227 op->a[2].val = size; 228 229 tmp = (BeamOpArg *) erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(BeamOpArg)*(arity-2*align)); 230 231 for (i = 3; i < arity - 2*align; i++) { 232 tmp[i-3] = Rest[i-3]; 233 } 234 235 /* Sort the values to make them useful for a binary or sentinel search. */ 236 beam_load_sort_select_vals(tmp, size - align); 237 238 j = 3; 239 for (i = 3; i < arity - 2*align; i += 2) { 240 op->a[j] = tmp[i-3]; 241 op->a[j+size] = tmp[i-2]; 242 j++; 243 } 244 245 erts_free(ERTS_ALC_T_LOADER_TMP, (void *) tmp); 246 247 if (align) { 248 /* Add sentinel for linear search. */ 249 op->a[j].type = TAG_u; 250 op->a[j].val = ~((BeamInstr)0); 251 op->a[j+size] = Fail; 252 } 253 254#ifdef DEBUG 255 for (i = 0; i < size - 1; i++) { 256 ASSERT(op->a[i+3].val <= op->a[i+4].val); 257 } 258#endif 259 260 return op; 261} 262 263// 264// Generate a select_val instruction for big numbers. 265// 266gen.select_literals(Src, Fail, Size, Rest) { 267 BeamOp* op; 268 BeamOp* jump; 269 BeamOp** prev_next = &op; 270 271 int i; 272 273 for (i = 0; i < Size.val; i += 2) { 274 BeamOp* op; 275 ASSERT(Rest[i].type == TAG_q); 276 277 $NewBeamOp(S, op); 278 $BeamOpNameArity(op, is_ne_exact, 3); 279 op->a[0] = Rest[i+1]; 280 op->a[1] = Src; 281 op->a[2] = Rest[i]; 282 *prev_next = op; 283 prev_next = &op->next; 284 } 285 286 $NewBeamOp(S, jump); 287 $BeamOpNameArity(jump, jump, 1); 288 jump->next = NULL; 289 jump->a[0] = Fail; 290 *prev_next = jump; 291 return op; 292} 293 294// 295// Replace a select_val instruction with a constant controlling expression 296// with a jump instruction. 297// 298gen.const_select_val(Src, Fail, Size, Rest) { 299 BeamOp* op; 300 int i; 301 302 ASSERT(Size.type == TAG_u); 303 304 $NewBeamOp(S, op); 305 $BeamOpNameArity(op, jump, 1); 306 op->next = NULL; 307 308 /* Search for a literal matching the controlling expression. */ 309 switch (Src.type) { 310 case TAG_q: 311 { 312 Eterm expr = beamfile_get_literal(&S->beam, Src.val); 313 for (i = 0; i < Size.val; i += 2) { 314 if (Rest[i].type == TAG_q) { 315 Eterm term = beamfile_get_literal(&S->beam, Rest[i].val); 316 if (eq(term, expr)) { 317 ASSERT(Rest[i+1].type == TAG_f); 318 op->a[0] = Rest[i+1]; 319 return op; 320 } 321 } 322 } 323 } 324 break; 325 case TAG_i: 326 case TAG_a: 327 for (i = 0; i < Size.val; i += 2) { 328 if (Rest[i].val == Src.val && Rest[i].type == Src.type) { 329 ASSERT(Rest[i+1].type == TAG_f); 330 op->a[0] = Rest[i+1]; 331 return op; 332 } 333 } 334 break; 335 } 336 337 /* 338 * No match. Use the failure label. 339 */ 340 341 op->a[0] = Fail; 342 return op; 343} 344 345// 346// Split a list consisting of both small and bignumbers into two 347// select_val instructions. 348// 349gen.split_values(Src, TypeFail, Fail, Size, Rest) { 350 BeamOp* op1; 351 BeamOp* op2; 352 BeamOp* label; 353 BeamOp* is_integer; 354 int i; 355 356 ASSERT(Size.val >= 2 && Size.val % 2 == 0); 357 358 $NewBeamOp(S, is_integer); 359 $BeamOpNameArity(is_integer, is_integer, 2); 360 is_integer->a[0] = TypeFail; 361 is_integer->a[1] = Src; 362 363 $NewBeamOp(S, label); 364 $BeamOpNameArity(label, label, 1); 365 label->a[0].type = TAG_u; 366 label->a[0].val = beam_load_new_label(S); 367 368 $NewBeamOp(S, op1); 369 $BeamOpNameArity(op1, select_val, 3); 370 $BeamOpArity(op1, 3 + Size.val); 371 op1->a[0] = Src; 372 op1->a[1].type = TAG_f; 373 op1->a[1].val = label->a[0].val; 374 op1->a[2].type = TAG_u; 375 op1->a[2].val = 0; 376 377 $NewBeamOp(S, op2); 378 $BeamOpNameArity(op2, select_val, 3); 379 $BeamOpArity(op2, 3 + Size.val); 380 op2->a[0] = Src; 381 op2->a[1] = Fail; 382 op2->a[2].type = TAG_u; 383 op2->a[2].val = 0; 384 385 /* Split the list. */ 386 ASSERT(Size.type == TAG_u); 387 for (i = 0; i < Size.val; i += 2) { 388 BeamOp* op = (Rest[i].type == TAG_q) ? op2 : op1; 389 int dst = 3 + op->a[2].val; 390 391 ASSERT(Rest[i+1].type == TAG_f); 392 op->a[dst] = Rest[i]; 393 op->a[dst+1] = Rest[i+1]; 394 op->arity += 2; 395 op->a[2].val += 2; 396 } 397 ASSERT(op1->a[2].val > 0); 398 ASSERT(op2->a[2].val > 0); 399 400 /* Order the instruction sequence appropriately. */ 401 if (TypeFail.val == Fail.val) { 402 /* 403 * select_val L1 S ... (small numbers) 404 * label L1 405 * is_integer Fail S 406 * select_val Fail S ... (bignums) 407 */ 408 op1->next = label; 409 label->next = is_integer; 410 is_integer->next = op2; 411 } else { 412 /* 413 * is_integer TypeFail S 414 * select_val L1 S ... (small numbers) 415 * label L1 416 * select_val Fail S ... (bignums) 417 */ 418 is_integer->next = op1; 419 op1->next = label; 420 label->next = op2; 421 op1 = is_integer; 422 } 423 op2->next = NULL; 424 425 return op1; 426} 427 428 429// 430// Tag the list of values with tuple arity tags. 431// 432gen.select_tuple_arity(Src, Fail, Size, Rest) { 433 BeamOp* op; 434 BeamOpArg *tmp; 435 int arity = Size.val + 3; 436 int size = Size.val / 2; 437 int i, j, align = 0; 438 439 /* Verify the validity of the list. */ 440 441 if (Size.val % 2 != 0) { 442 return NULL; 443 } 444 445 for (i = 0; i < Size.val; i += 2) { 446 if (Rest[i].type != TAG_u || Rest[i+1].type != TAG_f) { 447 return NULL; 448 } 449 } 450 451 /* 452 * Use a special-cased instruction if there are only two values. 453 */ 454 if (size == 2) { 455 $NewBeamOp(S, op); 456 $BeamOpNameArity(op, i_select_tuple_arity2, 4); 457 $BeamOpArity(op, arity - 1); 458 op->next = NULL; 459 op->a[0] = Src; 460 op->a[1] = Fail; 461 op->a[2].type = TAG_u; 462 op->a[2].val = Rest[0].val; 463 op->a[3].type = TAG_u; 464 op->a[3].val = Rest[2].val; 465 op->a[4] = Rest[1]; 466 op->a[5] = Rest[3]; 467 468 return op; 469 } 470 471 /* 472 * Generate the generic instruction. 473 * Assumption: 474 * Few different tuple arities to select on (fewer than 20). 475 * Use linear scan approach. 476 */ 477 478 align = 1; 479 480 arity += 2*align; 481 size += align; 482 483 $NewBeamOp(S, op); 484 $BeamOpNameArity(op, i_select_tuple_arity, 3); 485 $BeamOpArity(op, arity); 486 op->next = NULL; 487 op->a[0] = Src; 488 op->a[1] = Fail; 489 op->a[2].type = TAG_u; 490 op->a[2].val = size; 491 492 tmp = (BeamOpArg *) erts_alloc(ERTS_ALC_T_LOADER_TMP, sizeof(BeamOpArg)*(arity-2*align)); 493 494 for (i = 3; i < arity - 2*align; i+=2) { 495 tmp[i-3].type = TAG_v; 496 tmp[i-3].val = make_arityval(Rest[i-3].val); 497 tmp[i-2] = Rest[i-2]; 498 } 499 500 /* Sort the values to make them useful for a binary or sentinel search. */ 501 beam_load_sort_select_vals(tmp, size - align); 502 503 j = 3; 504 for (i = 3; i < arity - 2*align; i += 2) { 505 op->a[j] = tmp[i-3]; 506 op->a[j + size] = tmp[i-2]; 507 j++; 508 } 509 510 erts_free(ERTS_ALC_T_LOADER_TMP, (void *) tmp); 511 512 op->a[j].type = TAG_u; 513 op->a[j].val = ~((BeamInstr)0); 514 op->a[j+size] = Fail; 515 516 return op; 517} 518 519gen.new_small_map_lit(Dst, Live, Size, Rest) { 520 unsigned size = Size.val; 521 Uint lit; 522 unsigned i; 523 BeamOp* op; 524 BeamOpArg* dst; 525 Eterm* tmp; 526 Eterm* thp; 527 Eterm keys; 528 529 $NewBeamOp(S, op); 530 $BeamOpNameArity(op, i_new_small_map_lit, 3); 531 $BeamOpArity(op, 3 + size/2); 532 op->next = NULL; 533 534 tmp = thp = erts_alloc(ERTS_ALC_T_LOADER_TMP, (1 + size/2) * sizeof(*tmp)); 535 keys = make_tuple(thp); 536 *thp++ = make_arityval(size/2); 537 538 dst = op->a+3; 539 540 for (i = 0; i < size; i += 2) { 541 switch (Rest[i].type) { 542 case TAG_a: 543 *thp++ = Rest[i].val; 544 ASSERT(is_atom(Rest[i].val)); 545 break; 546 case TAG_i: 547 *thp++ = make_small(Rest[i].val); 548 break; 549 case TAG_n: 550 *thp++ = NIL; 551 break; 552 case TAG_q: 553 *thp++ = beamfile_get_literal(&S->beam, Rest[i].val); 554 break; 555 } 556 *dst++ = Rest[i + 1]; 557 } 558 559 lit = beamfile_add_literal(&S->beam, keys); 560 erts_free(ERTS_ALC_T_LOADER_TMP, tmp); 561 562 op->a[0] = Dst; 563 op->a[1] = Live; 564 op->a[2].type = TAG_q; 565 op->a[2].val = lit; 566 567 return op; 568} 569 570// Macro for generating a timeout instruction for a literal timeout value. 571gen_literal_timeout(stp, fail, time, succ_instr, fail_instr) { 572 BeamOp* op; 573 Sint timeout; 574 575 $NewBeamOp($stp, op); 576 $BeamOpNameArity(op, $succ_instr, 2); 577 op->a[0].type = TAG_u; 578 op->a[1] = $fail; 579 580 if ($time.type == TAG_i && (timeout = $time.val) >= 0 && 581#if defined(ARCH_64) 582 (timeout >> 32) == 0 583#else 584 1 585#endif 586 ) { 587 op->a[0].val = timeout; 588#if !defined(ARCH_64) 589 } else if ($time.type == TAG_q) { 590 Eterm big = beamfile_get_literal(&S->beam, $time.val); 591 592 if (is_not_big(big)) { 593 goto error; 594 } 595 596 if (big_arity(big) > 1 || big_sign(big)) { 597 goto error; 598 } else { 599 Uint u; 600 (void) term_to_Uint(big, &u); 601 op->a[0].val = (BeamInstr) u; 602 } 603#endif 604 } else { 605#if !defined(ARCH_64) 606 error: 607#endif 608 $BeamOpNameArity(op, $fail_instr, 0); 609 } 610 return op; 611} 612 613gen.literal_timeout(Fail, Time) { 614 $gen_literal_timeout(S, Fail, Time, wait_timeout_unlocked_int, i_wait_error); 615} 616 617gen.literal_timeout_locked(Fail, Time) { 618 $gen_literal_timeout(S, Fail, Time, wait_timeout_locked_int, i_wait_error_locked); 619} 620 621// Generate an instruction for element/2. 622gen.element(Fail, Index, Tuple, Dst) { 623 BeamOp* op; 624 625 $NewBeamOp(S, op); 626 op->next = NULL; 627 628 if (Index.type == TAG_i && Index.val > 0 && 629 Index.val <= ERTS_MAX_TUPLE_SIZE && 630 (Tuple.type == TAG_x || Tuple.type == TAG_y)) { 631 $BeamOpNameArity(op, i_fast_element, 4); 632 op->a[0] = Tuple; 633 op->a[1] = Fail; 634 op->a[2].type = TAG_u; 635 op->a[2].val = Index.val; 636 op->a[3] = Dst; 637 } else { 638 $BeamOpNameArity(op, i_element, 4); 639 op->a[0] = Tuple; 640 op->a[1] = Fail; 641 op->a[2] = Index; 642 op->a[3] = Dst; 643 } 644 645 return op; 646} 647 648// Generate the fastest instruction to fetch a binary from a binary. 649gen.get_binary2(Fail, Ms, Live, Size, Unit, Flags, Dst) { 650 BeamOp* op; 651 652 $NewBeamOp(S, op); 653 $NativeEndian(Flags); 654 655 if (Size.type == TAG_a && Size.val == am_all) { 656 $BeamOpNameArity(op, i_bs_get_binary_all2, 5); 657 op->a[0] = Ms; 658 op->a[1] = Fail; 659 op->a[2] = Live; 660 op->a[3] = Unit; 661 op->a[4] = Dst; 662 } else if (Size.type == TAG_i) { 663 $BeamOpNameArity(op, i_bs_get_binary_imm2, 6); 664 op->a[0] = Ms; 665 op->a[1] = Fail; 666 op->a[2] = Live; 667 op->a[3].type = TAG_u; 668 if (!beam_load_safe_mul(Size.val, Unit.val, &op->a[3].val)) { 669 goto error; 670 } 671 op->a[4] = Flags; 672 op->a[5] = Dst; 673 } else if (Size.type == TAG_q) { 674 Eterm big = beamfile_get_literal(&S->beam, Size.val); 675 Uint bigval; 676 677 if (!term_to_Uint(big, &bigval)) { 678 error: 679 $BeamOpNameArity(op, jump, 1); 680 op->a[0] = Fail; 681 } else { 682 $BeamOpNameArity(op, i_bs_get_binary_imm2, 6); 683 op->a[0] = Ms; 684 op->a[1] = Fail; 685 op->a[2] = Live; 686 op->a[3].type = TAG_u; 687 if (!beam_load_safe_mul(bigval, Unit.val, &op->a[3].val)) { 688 goto error; 689 } 690 op->a[4] = Flags; 691 op->a[5] = Dst; 692 } 693 } else if (Size.type == TAG_x || Size.type == TAG_y) { 694 $BeamOpNameArity(op, i_bs_get_binary2, 6); 695 op->a[0] = Ms; 696 op->a[1] = Fail; 697 op->a[2] = Live; 698 op->a[3] = Size; 699 op->a[4].type = TAG_u; 700 op->a[4].val = (Unit.val << 3) | Flags.val; 701 op->a[5] = Dst; 702 } else { 703 /* Invalid literal size. */ 704 goto error; 705 } 706 op->next = NULL; 707 return op; 708} 709 710gen.is_function2(Fail, Fun, Arity) { 711 BeamOp* op; 712 int literal_arity = Arity.type == TAG_i; 713 int fun_is_reg = Fun.type == TAG_x || Fun.type == TAG_y; 714 715 $NewBeamOp(S, op); 716 717 if (fun_is_reg && literal_arity) { 718 /* 719 * Most common case. Fun in a register and arity 720 * is an integer literal. 721 */ 722 if (Arity.val > MAX_ARG) { 723 /* Arity is negative or too big. */ 724 $BeamOpNameArity(op, jump, 1); 725 op->a[0] = Fail; 726 return op; 727 } else { 728 $BeamOpNameArity(op, hot_is_function2, 3); 729 op->a[0] = Fail; 730 op->a[1] = Fun; 731 op->a[2].type = TAG_u; 732 op->a[2].val = Arity.val; 733 return op; 734 } 735 } else { 736 /* 737 * Handle extremely uncommon cases by a slower sequence. 738 */ 739 BeamOp* move_fun; 740 BeamOp* move_arity; 741 742 $NewBeamOp(S, move_fun); 743 $NewBeamOp(S, move_arity); 744 745 move_fun->next = move_arity; 746 move_arity->next = op; 747 748 $BeamOpNameArity(move_fun, move, 2); 749 move_fun->a[0] = Fun; 750 move_fun->a[1].type = TAG_x; 751 move_fun->a[1].val = 1022; 752 753 $BeamOpNameArity(move_arity, move, 2); 754 move_arity->a[0] = Arity; 755 move_arity->a[1].type = TAG_x; 756 move_arity->a[1].val = 1023; 757 758 $BeamOpNameArity(op, cold_is_function2, 3); 759 op->a[0] = Fail; 760 op->a[1].type = TAG_x; 761 op->a[1].val = 1022; 762 op->a[2].type = TAG_x; 763 op->a[2].val = 1023; 764 return move_fun; 765 } 766} 767 768INIT_YREGS(S, N) { 769 int i; 770 for (i = 0; i < $N; i++) { 771 BeamOp* init; 772 773 $NewBeamOp($S, init); 774 $BeamOpNameArity(init, init, 1); 775 init->a[0] = Yregs[i]; 776 *p = init; 777 p = &init->next; 778 } 779} 780 781gen.allocate(Ns, Live, N, Yregs) { 782 BeamOp* alloc; 783 BeamOp** p; 784 785 $NewBeamOp(S, alloc); 786 alloc->a[0] = Ns; 787 alloc->a[1] = Live; 788 789 if (Ns.val <= 2 * N.val) { 790 /* 791 * At least half of the Y registers need explicit 792 * initialization. It will be cheaper to zero all Y registers. 793 */ 794 $BeamOpNameArity(alloc, allocate_zero, 2); 795 } else { 796 $BeamOpNameArity(alloc, allocate, 2); 797 p = &alloc->next; 798 $INIT_YREGS(S, N.val); 799 } 800 return alloc; 801} 802 803gen.allocate_heap(Ns, Nh, Live, N, Yregs) { 804 BeamOp* alloc; 805 BeamOp** p; 806 807 $NewBeamOp(S, alloc); 808 alloc->a[0] = Ns; 809 alloc->a[1] = Nh; 810 alloc->a[2] = Live; 811 812 if (Ns.val <= 2 * N.val) { 813 /* 814 * At least half of the Y registers need explicit 815 * initialization. It will be cheaper to zero all Y registers. 816 */ 817 $BeamOpNameArity(alloc, allocate_heap_zero, 3); 818 } else { 819 $BeamOpNameArity(alloc, allocate_heap, 3); 820 p = &alloc->next; 821 $INIT_YREGS(S, N.val); 822 } 823 return alloc; 824} 825 826gen.init_yregs(N, Yregs) { 827 BeamOp* first = NULL; 828 BeamOp** p; 829 830 p = &first; 831 $INIT_YREGS(S, N.val); 832 return first; 833} 834