1# 2# %CopyrightBegin% 3# 4# Copyright Ericsson AB 1997-2019. All Rights Reserved. 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18# %CopyrightEnd% 19# 20 21# 22# The instructions that follows are only known by the loader and the emulator. 23# They can be changed without recompiling old Beam files. 24# 25# Instructions starting with a "i_" prefix are instructions produced by 26# instruction transformations; thus, they never occur in BEAM files. 27# 28 29# The too_old_compiler/0 instruction is specially handled in beam_load.c 30# to produce a user-friendly message informing the user that the module 31# needs to be re-compiled with a modern compiler. 32 33too_old_compiler/0 34too_old_compiler | never() => 35 36# In R9C and earlier, the loader used to insert special instructions inside 37# the module_info/0,1 functions. (In R10B and later, the compiler inserts 38# an explicit call to an undocumented BIF, so that no loader trickery is 39# necessary.) Since the instructions don't work correctly in R12B, simply 40# refuse to load the module. 41 42func_info M=a a==am_module_info A=u==0 | label L | move n x==0 => too_old_compiler 43func_info M=a a==am_module_info A=u==1 | label L | move n x==0 => too_old_compiler 44 45# The undocumented and unsupported guard BIF is_constant/1 was removed 46# in R13. The is_constant/2 operation is marked as obsolete in genop.tab, 47# so the loader will automatically generate a too_old_compiler message 48# it is used, but we need to handle the is_constant/1 BIF specially here. 49 50bif1 Fail u$func:erlang:is_constant/1 Src Dst => too_old_compiler 51 52# Since the constant pool was introduced in R12B, empty tuples ({}) 53# are literals. Therefore we no longer need to allow put_tuple/2 54# with a tuple size of zero. 55 56put_tuple u==0 d => too_old_compiler 57 58# 59# All the other instructions. 60# 61 62%cold 63label L 64i_func_info I a a I 65int_code_end 66 67i_generic_breakpoint 68i_debug_breakpoint 69i_return_time_trace 70i_return_to_trace 71i_yield 72trace_jump W 73%hot 74 75return 76 77# 78# A tail call will not refer to the current function on error unless it's a 79# BIF, so we can omit the line instruction for non-BIFs. 80# 81 82move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => \ 83 move S X0 | call_ext_last Ar Func D 84move S X0=x==0 | line Loc | call_ext_only Ar Func=u$is_not_bif => \ 85 move S X0 | call_ext_only Ar Func 86 87move S X0=x==0 | line Loc | call_last Ar Func D => \ 88 move S X0 | call_last Ar Func D 89move S X0=x==0 | line Loc | call_only Ar Func => \ 90 move S X0 | call_only Ar Func 91 92# To ensure that a "move Src x(0)" instruction can be combined with 93# the following call instruction, we need to make sure that there is 94# no line/1 instruction between the move and the call. (We don't 95# need to match the call instruction, because reordering the move 96# and line instructions would be harmless even if no call instruction 97# follows.) 98 99move S X0=x==0 | line Loc => line Loc | move S X0 100 101line Loc | func_info M F A => func_info M F A | line Loc 102 103line I 104 105allocate t t? 106allocate_heap t I t? 107 108# This instruction when a BIF is called tail-recursively when 109# ther is stack frame. 110deallocate Q 111 112init y 113allocate_zero t t? 114allocate_heap_zero t I t? 115 116move Src=y Dst=x | trim N Remaining => move_trim Src Dst N 117trim N Remaining => i_trim N 118 119move_trim y x t 120i_trim t 121 122test_heap I t? 123 124allocate_heap S u==0 R => allocate S R 125allocate_heap_zero S u==0 R => allocate_zero S R 126 127init Y1 | init Y2 | init Y3 | succ(Y1,Y2) | succ(Y2,Y3) => init_seq3 Y1 128init_seq3 Y1 | init Y4 | succ3(Y1,Y4) => init_seq4 Y1 129init_seq4 Y1 | init Y5 | succ4(Y1,Y5) => init_seq5 Y1 130 131init_seq3 y 132init_seq4 y 133init_seq5 y 134 135init Y1 | init Y2 | init Y3 => init3 Y1 Y2 Y3 136init Y1 | init Y2 => init2 Y1 Y2 137 138init2 y y 139init3 y y y 140 141 142# Selecting values 143 144select_val S=aiq Fail=f Size=u Rest=* => const_select_val(S, Fail, Size, Rest) 145 146select_val S=s Fail=f Size=u Rest=* | use_jump_tab(Size, Rest) => \ 147 gen_jump_tab(S, Fail, Size, Rest) 148 149is_integer Fail=f S | select_val S=s Fail=f Size=u Rest=* | use_jump_tab(Size, Rest) => \ 150 gen_jump_tab(S, Fail, Size, Rest) 151 152is_integer TypeFail=f S | select_val S=s Fail=f Size=u Rest=* | \ 153 mixed_types(Size, Rest) => \ 154 gen_split_values(S, TypeFail, Fail, Size, Rest) 155 156select_val S=s Fail=f Size=u Rest=* | mixed_types(Size, Rest) => \ 157 gen_split_values(S, Fail, Fail, Size, Rest) 158 159is_integer Fail=f S | select_val S=d Fail=f Size=u Rest=* | \ 160 fixed_size_values(Size, Rest) => gen_select_val(S, Fail, Size, Rest) 161 162is_atom Fail=f S | select_val S=d Fail=f Size=u Rest=* | \ 163 fixed_size_values(Size, Rest) => gen_select_val(S, Fail, Size, Rest) 164 165select_val S=s Fail=f Size=u Rest=* | floats_or_bignums(Size, Rest) => \ 166 gen_select_literals(S, Fail, Size, Rest) 167 168select_val S=d Fail=f Size=u Rest=* | fixed_size_values(Size, Rest) => \ 169 gen_select_val(S, Fail, Size, Rest) 170 171is_tuple Fail=f S | select_tuple_arity S=d Fail=f Size=u Rest=* => \ 172 gen_select_tuple_arity(S, Fail, Size, Rest) 173 174select_tuple_arity S=d Fail=f Size=u Rest=* => \ 175 gen_select_tuple_arity(S, Fail, Size, Rest) 176 177i_select_val_bins xy f? I 178 179i_select_val_lins xy f? I 180 181i_select_val2 xy f? c c 182 183i_select_tuple_arity xy f? I 184 185i_select_tuple_arity2 xy f? A A 186 187i_jump_on_val_zero xy f? I 188 189i_jump_on_val xy f? I W 190 191get_list xy xy xy 192 193# The following get_list instructions using x(0) are frequently used. 194get_list r x x 195get_list r r y 196get_list x r x 197get_list r x y 198get_list r y r 199get_list r x r 200 201get_hd xy xy 202get_tl xy xy 203 204# Old-style catch. 205catch y f 206catch_end y 207 208# Try/catch. 209try Y F => catch Y F 210 211try_case y 212try_end y 213 214%cold 215try_case_end s 216%hot 217 218# Destructive set tuple element 219 220set_tuple_element s S P 221 222# Get tuple element 223 224i_get_tuple_element xy P xy 225 226i_get_tuple_element2 x P x 227i_get_tuple_element2_dst x P x x 228i_get_tuple_element2_dst x P y y 229 230i_get_tuple_element3 x P x 231 232%cold 233is_number f? xy 234%hot 235 236is_number Fail=f i => 237is_number Fail=f na => jump Fail 238is_number Fail Literal=q => move Literal x | is_number Fail x 239 240jump f 241 242# 243# Expection rasing instructions. Infrequently executed. 244# 245 246%cold 247case_end NotInX=cy => move NotInX x | case_end x 248badmatch NotInX=cy => move NotInX x | badmatch x 249 250case_end x 251 252badmatch x 253 254if_end 255 256# Operands for raise/2 are almost always in x(2) and x(1). 257# Optimize for that case. 258raise x==2 x==1 => i_raise 259raise Trace=y Value=y => move Trace x=2 | move Value x=1 | i_raise 260raise Trace Value => move Trace x | move Value x=1 | move x x=2 | i_raise 261 262i_raise 263 264# Internal now, but could be useful to make known to the compiler. 265badarg/1 266badarg p => badarg_body 267badarg Fail=f => jump Fail 268 269badarg_body 270 271system_limit/1 272system_limit p => system_limit_body 273system_limit Fail=f => jump Fail 274 275system_limit_body 276 277%hot 278 279# 280# Move instructions. 281# 282 283move Src=cxy Dst=xy | jump Lbl => move_jump Lbl Src Dst 284 285move_jump f cxy xy 286move_jump f c r 287 288 289# Movement to and from the stack is common. 290# Try to pack as much as we can into one instruction. 291 292# x -> y 293 294move X1=x Y1=y | move X2=x Y2=y | succ(Y1, Y2) => \ 295 move_window2 X1 X2 Y1 296 297move_window2 X1 X2 Y1 | move X3=x Y3=y | offset(Y1, Y3, 2) => \ 298 move_window3 X1 X2 X3 Y1 299 300move_window3 X1 X2 X3 Y1 | move X4=x Y4=y | offset(Y1, Y4, 3) => \ 301 move_window4 X1 X2 X3 X4 Y1 302 303move_window4 X1 X2 X3 X4 Y1=y | move X5=x Y5=y | offset(Y1, Y5, 4) => \ 304 move_window5 X1 X2 X3 X4 X5 Y1 305 306move_window2 x x y 307move_window3 x x x y 308move_window4 x x x x y 309move_window5 x x x x x y 310 311# y -> x 312 313move_src_window/4 314move_src_window/5 315 316move Y1=y X1=x | move Y2=y X2=x | succ(Y1, Y2) => \ 317 move_src_window Y1 Y2 X1 X2 318 319move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x | succ(Y2, Y3) => \ 320 move_src_window Y1 Y3 X1 X2 X3 321move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x | move Y4=y X4=x | succ(Y3, Y4) => \ 322 move_src_window2 Y1 X1 X2 | move_src_window Y3 Y4 X3 X4 323move_src_window Y1 Y2 X1 X2 | move Y3=y X3=x => \ 324 move3 Y1 X1 Y2 X2 Y3 X3 325 326move_src_window Y1 Y3 X1 X2 X3 | move Y4=y X4=x | succ(Y3, Y4) => \ 327 move_src_window4 Y1 X1 X2 X3 X4 328 329move_src_window Y1 y X1 X2 => move_src_window2 Y1 X1 X2 330move_src_window Y1 y X1 X2 X3 => move_src_window3 Y1 X1 X2 X3 331 332move_src_window2 y x x 333move_src_window3 y x x x 334move_src_window4 y x x x x 335 336swap R1=x R2=y => swap R2 R1 337 338swap xy x 339swap y y 340 341swap R1=x R2=x | swap R3=x R1 => swap2 R1 R2 R3 342 343swap2 x x x 344 345# move_shift 346 347move SD=x D=x | move Src=cxy SD=x | distinct(D, Src) => move_shift Src SD D 348move SD=y D=x | move Src=x SD=y | distinct(D, Src) => move_shift Src SD D 349move SD=y D=x | init SD | => move_shift n SD D 350move SD=x D=y | move Src=x SD=x | distinct(D, Src) => move_shift Src SD D 351move SD=x==0 D=y | move Src=y SD=x==0 | distinct(D, Src) => move_shift Src SD D 352 353move_shift cxy x x 354move_shift nx y x 355move_shift x x y 356move_shift y r y 357 358# move2_par x x x x 359 360move X1=x X2=x | move X3=x X4=x | independent_moves(X1, X2, X3, X4) => \ 361 move2_par X1 X2 X3 X4 362move2_par x x x x 363 364# move2_par x x x y 365 366move X1=x X2=x | move X3=x Y1=y | independent_moves(X1, X2, X3, Y1) => \ 367 move2_par X1 X2 X3 Y1 368move X3=x Y1=y | move X1=x X2=x | independent_moves(X3, Y1, X1, X2) => \ 369 move2_par X1 X2 X3 Y1 370move2_par x x x y 371 372# move2_par y x y x 373 374move Y1=y X1=x | move Y2=y X2=x => move2_par Y1 X1 Y2 X2 375move2_par y x y x 376 377# move2_par y x x y 378 379move S1=y S2=x | move X1=x Y1=y | independent_moves(S1, S2, X1, Y1) => \ 380 move2_par S1 S2 X1 Y1 381move X1=x Y1=y | move S1=y S2=x | independent_moves(S1, S2, X1, Y1) => \ 382 move2_par S1 S2 X1 Y1 383move2_par y x x y 384 385# move2_par y x x x 386 387move Y1=y X1=x | move S1=x D1=x | independent_moves(Y1, X1, S1, D1) => \ 388 move2_par Y1 X1 S1 D1 389move S1=x D1=x | move Y1=y X1=x | independent_moves(Y1, X1, S1, D1) => \ 390 move2_par Y1 X1 S1 D1 391move2_par y x x x 392 393# move2_par y y y y 394 395move Y1=y Y2=y | move Y3=y Y4=y | independent_moves(Y1, Y2, Y3, Y4) => \ 396 move2_par Y1 Y2 Y3 Y4 397move2_par y y y y 398 399# move3 400 401move2_par Y1=y X1=x Y2=y X2=x | move Y3=y X3=x => move3 Y1 X1 Y2 X2 Y3 X3 402move2_par X1=x X2=x X3=x X4=x | move X5=x X6=x => move3 X1 X2 X3 X4 X5 X6 403 404move3 y x y x y x 405move3 x x x x x x 406 407move xy xy 408move c xy 409move n x 410 411# The following move instructions using x(0) are frequently used. 412 413move x r 414move r x 415move y r 416move c r 417move r y 418 419# Receive operations. 420 421loop_rec Fail x==0 | smp_mark_target_label(Fail) => i_loop_rec Fail 422 423label L | wait_timeout Fail Src | smp_already_locked(L) => \ 424 label L | wait_timeout_locked Src Fail 425wait_timeout Fail Src => wait_timeout_unlocked Src Fail 426 427wait_timeout_unlocked Src=aiq Fail => gen_literal_timeout(Fail, Src) 428wait_timeout_locked Src=aiq Fail => gen_literal_timeout_locked(Fail, Src) 429 430label L | wait Fail | smp_already_locked(L) => label L | wait_locked Fail 431wait Fail => wait_unlocked Fail 432 433label L | timeout | smp_already_locked(L) => label L | timeout_locked 434 435remove_message 436timeout 437timeout_locked 438i_loop_rec f 439loop_rec_end f 440wait_locked f 441wait_unlocked f 442 443# Note that a timeout value must fit in 32 bits. 444wait_timeout_unlocked_int I f 445wait_timeout_unlocked s f 446wait_timeout_locked_int I f 447wait_timeout_locked s f 448 449%cold 450i_wait_error 451i_wait_error_locked 452%hot 453 454send 455 456# 457# Optimized comparisons with one immediate/literal operand. 458# 459 460is_eq_exact Lbl S S => 461is_eq_exact Lbl C1=c C2=c => move C1 x | is_eq_exact Lbl x C2 462is_eq_exact Lbl C=c R=xy => is_eq_exact Lbl R C 463 464is_eq_exact Lbl R=xy n => is_nil Lbl R 465is_eq_exact Lbl R=xy C=ia => i_is_eq_exact_immed Lbl R C 466is_eq_exact Lbl R=xy C=q => i_is_eq_exact_literal Lbl R C 467 468is_ne_exact Lbl S S => jump Lbl 469is_ne_exact Lbl C1=c C2=c => move C1 x | is_ne_exact Lbl x C2 470is_ne_exact Lbl C=c R=xy => is_ne_exact Lbl R C 471 472is_ne_exact Lbl R=xy C=ian => i_is_ne_exact_immed Lbl R C 473is_ne_exact Lbl R=xy C=q => i_is_ne_exact_literal Lbl R C 474 475i_is_eq_exact_immed f? rxy c 476 477i_is_eq_exact_literal f? xy c 478 479i_is_ne_exact_immed f? xy c 480 481i_is_ne_exact_literal f? xy c 482 483is_eq_exact Lbl Y=y X=x => is_eq_exact Lbl X Y 484is_eq_exact f? x xy 485is_eq_exact f? y y 486 487is_ne_exact f? S S 488 489# When either operand for is_lt or is_ge is a literal, 490# that literal is almost always an integer and almost never 491# an atom. Therefore we use a specialized instruction when 492# one of the operands is a literal. 493 494is_lt Fail Src=x Lit=c => is_lt_literal Fail Src Lit 495is_lt Fail Lit=c Src=x => is_lt_literal Fail Lit Src 496 497is_lt f? x x 498is_lt_literal f? x c 499is_lt_literal f? c x 500%cold 501is_lt f? s s 502%hot 503 504is_ge Fail Src=x Lit=c => is_ge_literal Fail Src Lit 505is_ge Fail Lit=c Src=x => is_ge_literal Fail Lit Src 506 507is_ge f? x x 508is_ge_literal f? x c 509is_ge_literal f? c x 510%cold 511is_ge f? s s 512%hot 513 514is_eq Fail=f Const=c Reg=xy => is_eq Fail Reg Const 515is_eq Fail=f C1=c C2=c => move C1 x | is_eq Fail x C2 516is_eq f? S s 517 518is_ne Fail=f Const=c Reg=xy => is_ne Fail Reg Const 519is_ne Fail=f C1=c C2=c => move C1 x | is_ne Fail x C2 520is_ne f? S s 521 522# 523# Putting tuples. 524# 525# Code compiled with OTP 22 and later uses put_tuple2 to 526# to construct a tuple. 527# 528# Code compiled before OTP 22 uses put_tuple + one put instruction 529# per element. Translate to put_tuple2. 530# 531 532i_put_tuple/2 533put_tuple Arity Dst => i_put_tuple Dst u 534 535i_put_tuple Dst Arity Puts=* | put S1 | put S2 | \ 536 put S3 | put S4 | put S5 => \ 537 tuple_append_put5(Arity, Dst, Puts, S1, S2, S3, S4, S5) 538 539i_put_tuple Dst Arity Puts=* | put S => \ 540 tuple_append_put(Arity, Dst, Puts, S) 541 542i_put_tuple Dst Arity Puts=* => put_tuple2 Dst Arity Puts 543 544put_tuple2 xy I 545 546# 547# Putting lists. 548# 549# The instruction "put_list Const [] Dst" were generated in rare 550# circumstances up to and including OTP 18. Starting with OTP 19, 551# AFAIK, it should never be generated. 552# 553put_list Const=c n Dst => move Const x | put_list x n Dst 554 555put_list Src Dst=x Dst => update_list Src Dst 556 557update_list xyc x 558 559# put_list SrcReg1 SrcReg2 => Dst 560 561put_list xy xy x 562 563# put_list SrcReg [] => Dst 564 565put_list xy n xy 566 567# put_list SrcReg Constant => x 568 569put_list xy c x 570 571# put_list Constant SrcReg => Dst 572 573put_list c xy x 574 575# The following put_list instructions using x(0) are frequently used. 576 577put_list r n rx 578put_list r x rx 579put_list x x r 580 581%cold 582put_list s s d 583%hot 584 585 586# 587# Some more only used by the emulator 588# 589 590%cold 591normal_exit 592continue_exit 593call_bif W 594call_nif W W W 595call_nif_early 596call_error_handler 597error_action_code 598return_trace 599%hot 600 601# 602# Instruction transformations & folded instructions. 603# 604 605# Note: There is no 'move_return y r', since there never are any y registers 606# when we do move_return (if we have y registers, we must do move_deallocate_return). 607 608move S x==0 | return => move_return S 609 610move_return xcn 611 612move S x==0 | deallocate D | return => move_deallocate_return S D 613 614move_deallocate_return xycn Q 615 616deallocate u==0 | return => deallocate_return0 617deallocate u==1 | return => deallocate_return1 618deallocate u==2 | return => deallocate_return2 619deallocate u==3 | return => deallocate_return3 620deallocate u==4 | return => deallocate_return4 621 622deallocate D | return => deallocate_return D 623 624deallocate_return0 625deallocate_return1 626deallocate_return2 627deallocate_return3 628deallocate_return4 629 630deallocate_return Q 631 632test_heap Need u==1 | put_list Y=y x==0 x==0 => test_heap_1_put_list Need Y 633 634test_heap_1_put_list I y 635 636# 637# is_tagged_tuple Fail=f Src=rxy Arity Atom=a 638# 639 640is_tagged_tuple Fail Literal=q Arity Atom => \ 641 move Literal x | is_tagged_tuple Fail x Arity Atom 642is_tagged_tuple Fail=f c Arity Atom => jump Fail 643 644is_tagged_tuple f? rxy A a 645 646# Test tuple & arity (head) 647 648is_tuple Fail Literal=q => move Literal x | is_tuple Fail x 649is_tuple Fail=f c => jump Fail 650is_tuple Fail=f S=xy | test_arity Fail=f S=xy Arity => is_tuple_of_arity Fail S Arity 651 652is_tuple_of_arity f? rxy A 653 654is_tuple f? rxy 655 656test_arity Fail Literal=q Arity => move Literal x | test_arity Fail x Arity 657test_arity Fail=f c Arity => jump Fail 658test_arity Fail Tuple=x Arity | get_tuple_element Tuple Pos Dst=x => \ 659 test_arity_get_tuple_element Fail Tuple Arity Pos Dst 660 661test_arity f? xy A 662 663test_arity_get_tuple_element f? x A P x 664 665is_tuple NotTupleFail Tuple=x | is_tagged_tuple WrongRecordFail Tuple Arity Atom => \ 666 is_tagged_tuple_ff NotTupleFail WrongRecordFail Tuple Arity Atom 667 668is_tagged_tuple_ff f? f? rx A a 669 670get_tuple_element Reg=x P1 D1=x | \ 671 get_tuple_element Reg=x P2 D2=x | \ 672 get_tuple_element Reg=x P3 D3=x | \ 673 succ(P1, P2) | succ(P2, P3) | succ(D1, D2) | succ(D2, D3) | \ 674 distinct(D1, Reg) | distinct(D2, Reg) => \ 675 i_get_tuple_element3 Reg P1 D1 676 677get_tuple_element Reg=x P1 D1=x | \ 678 get_tuple_element Reg=x P2 D2=x | \ 679 succ(P1, P2) | succ(D1, D2) | \ 680 distinct(D1, Reg) => \ 681 i_get_tuple_element2 Reg P1 D1 682 683get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \ 684 succ(P1, P2) | distinct(D1, Reg) => i_get_tuple_element2_dst Reg P1 D1 D2 685 686get_tuple_element Reg=x P1 D1=y | get_tuple_element Reg=x P2 D2=y | \ 687 succ(P1, P2) => i_get_tuple_element2_dst Reg P1 D1 D2 688 689get_tuple_element Reg P Dst => i_get_tuple_element Reg P Dst 690 691is_integer Fail=f i => 692is_integer Fail=f an => jump Fail 693is_integer Fail Literal=q => move Literal x | is_integer Fail x 694 695is_integer Fail=f S=x | allocate Need Regs => is_integer_allocate Fail S Need Regs 696 697is_integer_allocate f? x t t 698 699is_integer f? xy 700 701is_list Fail=f n => 702is_list Fail Literal=q => move Literal x | is_list Fail x 703is_list Fail=f c => jump Fail 704is_list f? x 705%cold 706is_list f? y 707%hot 708 709is_nonempty_list Fail=f S=x | allocate Need Rs => is_nonempty_list_allocate Fail S Need Rs 710 711is_nonempty_list Fail=f S=x | get_list S D1=x D2=x => \ 712 is_nonempty_list_get_list Fail S D1 D2 713 714is_nonempty_list Fail=f S=x | get_hd S Dst=x => \ 715 is_nonempty_list_get_hd Fail S Dst 716 717is_nonempty_list Fail=f S=x | get_tl S Dst=x => \ 718 is_nonempty_list_get_tl Fail S Dst 719 720is_nonempty_list_allocate f? rx t t 721 722is_nonempty_list_get_list f? rx x x 723is_nonempty_list_get_hd f? x x 724is_nonempty_list_get_tl f? x x 725 726is_nonempty_list f? xy 727 728is_atom f? x 729%cold 730is_atom f? y 731%hot 732is_atom Fail=f a => 733is_atom Fail=f niq => jump Fail 734 735is_float f? x 736%cold 737is_float f? y 738%hot 739is_float Fail=f nai => jump Fail 740is_float Fail Literal=q => move Literal x | is_float Fail x 741 742is_nil Fail=f n => 743is_nil Fail=f qia => jump Fail 744 745is_nil f? xy 746 747is_binary Fail Literal=q => move Literal x | is_binary Fail x 748is_binary Fail=f c => jump Fail 749is_binary f? x 750%cold 751is_binary f? y 752%hot 753 754# XXX Deprecated. 755is_bitstr Fail Term => is_bitstring Fail Term 756 757is_bitstring Fail Literal=q => move Literal x | is_bitstring Fail x 758is_bitstring Fail=f c => jump Fail 759is_bitstring f? x 760%cold 761is_bitstring f? y 762%hot 763 764is_reference Fail=f cq => jump Fail 765is_reference f? x 766%cold 767is_reference f? y 768%hot 769 770is_pid Fail=f cq => jump Fail 771is_pid f? x 772%cold 773is_pid f? y 774%hot 775 776is_port Fail=f cq => jump Fail 777is_port f? x 778%cold 779is_port f? y 780%hot 781 782is_boolean Fail=f a==am_true => 783is_boolean Fail=f a==am_false => 784is_boolean Fail=f ac => jump Fail 785 786%cold 787is_boolean f? xy 788%hot 789 790is_function2 Fail=f Fun Arity => gen_is_function2(Fail, Fun, Arity) 791 792%cold 793cold_is_function2 f? x x 794%hot 795hot_is_function2 f? S t 796 797# Allocating & initializing. 798allocate Need Regs | init Y => allocate_init Need Regs Y 799init Y1 | init Y2 => init2 Y1 Y2 800 801allocate_init t t? y 802 803################################################################# 804# External function and bif calls. 805################################################################# 806 807# Expands into call_light_bif(_only)/2 808call_light_bif/1 809call_light_bif_only/1 810call_light_bif_last/2 811 812# 813# The load_nif/2 BIF is an instruction. 814# 815 816call_ext u==2 u$func:erlang:load_nif/2 => i_load_nif 817call_ext_last u==2 u$func:erlang:load_nif/2 D => i_load_nif | deallocate_return D 818call_ext_only u==2 u$func:erlang:load_nif/2 => i_load_nif | return 819 820%cold 821i_load_nif 822%hot 823 824# 825# apply/2 is an instruction, not a BIF. 826# 827 828call_ext u==2 u$func:erlang:apply/2 => i_apply_fun 829call_ext_last u==2 u$func:erlang:apply/2 D => i_apply_fun_last D 830call_ext_only u==2 u$func:erlang:apply/2 => i_apply_fun_only 831 832# 833# The apply/3 BIF is an instruction. 834# 835 836call_ext u==3 u$func:erlang:apply/3 => i_apply 837call_ext_last u==3 u$func:erlang:apply/3 D => i_apply_last D 838call_ext_only u==3 u$func:erlang:apply/3 => i_apply_only 839 840# 841# The yield/0 BIF is an instruction 842# 843 844call_ext u==0 u$func:erlang:yield/0 => i_yield 845call_ext_last u==0 u$func:erlang:yield/0 D => i_yield | deallocate_return D 846call_ext_only u==0 u$func:erlang:yield/0 => i_yield | return 847 848# 849# The hibernate/3 BIF is an instruction. 850# 851call_ext u==3 u$func:erlang:hibernate/3 => i_hibernate 852call_ext_last u==3 u$func:erlang:hibernate/3 D => i_hibernate 853call_ext_only u==3 u$func:erlang:hibernate/3 => i_hibernate 854 855# 856# If VM probes are not enabled, we want to short-circult calls to 857# the dt tag BIFs to make them as cheap as possible. 858# 859 860%unless USE_VM_PROBES 861 862call_ext Arity u$func:erlang:dt_get_tag/0 => \ 863 move a=am_undefined x=0 864call_ext_last Arity u$func:erlang:dt_get_tag/0 D => \ 865 move a=am_undefined x=0 | deallocate D | return 866call_ext_only Arity u$func:erlang:dt_get_tag/0 => \ 867 move a=am_undefined x=0 | return 868 869move Any x==0 | call_ext Arity u$func:erlang:dt_put_tag/1 => \ 870 move a=am_undefined x=0 871move Any x==0 | call_ext_last Arity u$func:erlang:dt_put_tag/1 D => \ 872 move a=am_undefined x=0 | deallocate D | return 873move Any x==0 | call_ext_only Arity u$func:erlang:dt_put_tag/1 => \ 874 move a=am_undefined x=0 | return 875call_ext Arity u$func:erlang:dt_put_tag/1 => \ 876 move a=am_undefined x=0 877call_ext_last Arity u$func:erlang:dt_put_tag/1 D => \ 878 move a=am_undefined x=0 | deallocate D | return 879call_ext_only Arity u$func:erlang:dt_put_tag/1 => \ 880 move a=am_undefined x=0 | return 881 882call_ext Arity u$func:erlang:dt_get_tag_data/0 => \ 883 move a=am_undefined x=0 884call_ext_last Arity u$func:erlang:dt_get_tag_data/0 D => \ 885 move a=am_undefined x=0 | deallocate D | return 886call_ext_only Arity u$func:erlang:dt_get_tag_data/0 => \ 887 move a=am_undefined x=0 | return 888 889move Any x==0 | call_ext Arity u$func:erlang:dt_spread_tag/1 => \ 890 move a=am_true x=0 891move Any x==0 | call_ext_last Arity u$func:erlang:dt_spread_tag/1 D => \ 892 move a=am_true x=0 | deallocate D | return 893move Any x==0 | call_ext_only Arity u$func:erlang:dt_spread_tag/1 => \ 894 move a=am_true x=0 | return 895call_ext Arity u$func:erlang:dt_spread_tag/1 => \ 896 move a=am_true x=0 897call_ext_last Arity u$func:erlang:dt_spread_tag/1 D => \ 898 move a=am_true x=0 | deallocate D | return 899call_ext_only Arity u$func:erlang:dt_spread_tag/1 => \ 900 move a=am_true x=0 | return 901 902move Any x==0 | call_ext Arity u$func:erlang:dt_restore_tag/1 => \ 903 move a=am_true x=0 904move Any x==0 | call_ext_last Arity u$func:erlang:dt_restore_tag/1 D => \ 905 move a=am_true x=0 | deallocate D | return 906move Any x==0 | call_ext_only Arity u$func:erlang:dt_restore_tag/1 => \ 907 move a=am_true x=0 | return 908call_ext Arity u$func:erlang:dt_restore_tag/1 => \ 909 move a=am_true x=0 910call_ext_last Arity u$func:erlang:dt_restore_tag/1 D => \ 911 move a=am_true x=0 | deallocate D | return 912call_ext_only Arity u$func:erlang:dt_restore_tag/1 => \ 913 move a=am_true x=0 | return 914 915move Any x==0 | call_ext Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ 916 move Any x=0 917move Any x==0 | call_ext_last Arity u$func:erlang:dt_prepend_vm_tag_data/1 D => \ 918 move Any x=0 | deallocate D | return 919move Any x==0 | call_ext_only Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ 920 move Any x=0 | return 921call_ext Arity u$func:erlang:dt_prepend_vm_tag_data/1 => 922call_ext_last Arity u$func:erlang:dt_prepend_vm_tag_data/1 D => \ 923 deallocate D | return 924call_ext_only Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ 925 return 926 927move Any x==0 | call_ext Arity u$func:erlang:dt_append_vm_tag_data/1 => \ 928 move Any x=0 929move Any x==0 | call_ext_last Arity u$func:erlang:dt_append_vm_tag_data/1 D => \ 930 move Any x=0 | deallocate D | return 931move Any x==0 | call_ext_only Arity u$func:erlang:dt_append_vm_tag_data/1 => \ 932 move Any x=0 | return 933call_ext Arity u$func:erlang:dt_append_vm_tag_data/1 => 934call_ext_last Arity u$func:erlang:dt_append_vm_tag_data/1 D => \ 935 deallocate D | return 936call_ext_only Arity u$func:erlang:dt_append_vm_tag_data/1 => \ 937 return 938 939# After one of the transformations above there can be a redundant move 940# instruction that can be discarded. 941# 942# The distinct() guard protects against the second move instruction being 943# `{move,{x,0},{x,0}}`, which is never generated by the compiler but could 944# be generated by an alternative code generator or found in handwritten 945# BEAM code. 946 947move Discarded x==0 | move Something Dst=x==0 | distinct(Something, Dst) => \ 948 move Something x=0 949 950%endif 951 952call_ext u==0 u$func:os:perf_counter/0 => \ 953 i_perf_counter 954call_ext_last u==0 u$func:os:perf_counter/0 D => \ 955 i_perf_counter | deallocate_return D 956call_ext_only u==0 u$func:os:perf_counter/0 => \ 957 i_perf_counter | return 958 959# 960# BIFs like process_info/1,2 require up-to-date information about the current 961# emulator state, which the ordinary call_light_bif instruction doesn't save. 962# 963 964call_ext u Bif=u$is_bif | is_heavy_bif(Bif) => \ 965 i_call_ext Bif 966call_ext_last u Bif=u$is_bif D | is_heavy_bif(Bif) => \ 967 i_call_ext Bif | deallocate_return D 968call_ext_only Ar=u Bif=u$is_bif | is_heavy_bif(Bif) => \ 969 allocate u Ar | i_call_ext Bif | deallocate_return u 970 971# 972# The general case for BIFs that have no special requirements. 973# 974 975call_ext u Bif=u$is_bif => call_light_bif Bif 976call_ext_last u Bif=u$is_bif D => call_light_bif_last Bif D 977call_ext_only Ar=u Bif=u$is_bif => call_light_bif_only Bif 978 979# 980# Any remaining calls are calls to Erlang functions, not BIFs. 981# We rename the instructions to internal names. This is necessary, 982# to avoid an end-less loop, because we want to call a few BIFs 983# with call instructions. 984# 985 986move S=c x==0 | call_ext Ar=u Func=u$is_not_bif => i_move_call_ext S Func 987move S=c x==0 | call_ext_last Ar=u Func=u$is_not_bif D => i_move_call_ext_last Func D S 988move S=c x==0 | call_ext_only Ar=u Func=u$is_not_bif => i_move_call_ext_only Func S 989 990call_ext Ar Func => i_call_ext Func 991call_ext_last Ar Func D => i_call_ext_last Func D 992call_ext_only Ar Func => i_call_ext_only Func 993 994i_apply 995i_apply_last Q 996i_apply_only 997 998i_apply_fun 999i_apply_fun_last Q 1000i_apply_fun_only 1001 1002# 1003# When a BIF is traced, these instructions make a body call through the export 1004# entry instead of calling the BIF directly (setting up a temporary stack frame 1005# if needed). We therefore retain the stack frame in call_light_bif_last, and 1006# add a deallocate_return after call_light_bif_only to remove the temporary 1007# stack frame before returning. 1008# 1009 1010call_light_bif Bif=u$is_bif => \ 1011 call_light_bif Bif Bif 1012 1013call_light_bif_last Bif=u$is_bif D => \ 1014 call_light_bif Bif Bif | deallocate_return D 1015 1016call_light_bif_only Bif=u$is_bif => \ 1017 call_light_bif_only Bif Bif | deallocate_return u 1018 1019call_light_bif b e 1020call_light_bif_only b e 1021 1022%cold 1023 1024i_hibernate 1025i_perf_counter 1026 1027%hot 1028 1029# 1030# Calls to non-building and guard BIFs. 1031# 1032 1033bif0 u$bif:erlang:self/0 Dst=d => self Dst 1034bif0 u$bif:erlang:node/0 Dst=d => node Dst 1035 1036bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=x Dst=x => is_nonempty_list_get_hd Fail Src Dst 1037bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=x Dst=x => is_nonempty_list_get_tl Fail Src Dst 1038 1039bif1 Fail Bif=u$bif:erlang:get/1 Src=s Dst=d => gen_get(Src, Dst) 1040 1041bif2 Jump=j u$bif:erlang:element/2 S1=s S2=xy Dst=d => gen_element(Jump, S1, S2, Dst) 1042 1043bif1 p Bif S1 Dst => i_bif1_body S1 Bif Dst 1044bif1 Fail=f Bif S1 Dst => i_bif1 S1 Fail Bif Dst 1045 1046bif2 p Bif S1 S2 Dst => i_bif2_body S2 S1 Bif Dst 1047bif2 Fail=f Bif S1 S2 Dst => i_bif2 S2 S1 Fail Bif Dst 1048 1049i_get_hash c I d 1050i_get s d 1051 1052self xy 1053 1054node x 1055%cold 1056node y 1057%hot 1058 1059# Note: 'I' is sufficient because this instruction will only be used 1060# if the arity fits in 24 bits. 1061i_fast_element xy j? I d 1062 1063i_element xy j? s d 1064 1065i_bif1 s f? b d 1066i_bif1_body s b d 1067i_bif2 s s f? b d 1068i_bif2_body s s b d 1069i_bif3 s s s f? b d 1070i_bif3_body s s s b d 1071 1072# 1073# Internal calls. 1074# 1075 1076move S=cxy x==0 | call Ar P=f => move_call S P 1077 1078move_call/2 1079move_call cxy f 1080 1081move S x==0 | call_last Ar P=f D => move_call_last S P D 1082 1083move_call_last/3 1084move_call_last cxy f Q 1085 1086move S=cx x==0 | call_only Ar P=f => move_call_only S P 1087 1088move_call_only/2 1089move_call_only cx f 1090 1091call Ar Func => i_call Func 1092call_last Ar Func D => i_call_last Func D 1093call_only Ar Func => i_call_only Func 1094 1095i_call f 1096i_call_last f Q 1097i_call_only f 1098 1099i_call_ext e 1100i_call_ext_last e Q 1101i_call_ext_only e 1102 1103i_move_call_ext c e 1104i_move_call_ext_last e Q c 1105i_move_call_ext_only e c 1106 1107# Fun calls. 1108 1109call_fun Arity | deallocate D | return => i_call_fun_last Arity D 1110call_fun Arity => i_call_fun Arity 1111 1112i_call_fun t 1113i_call_fun_last t Q 1114 1115 1116# 1117# A fun with an empty environment can be converted to a literal. 1118# As a further optimization, the we try to move the fun to its 1119# final destination directly. 1120 1121make_fun2 OldIndex=u => gen_make_fun2(OldIndex) 1122 1123move_fun/2 1124move_fun Fun X0 | move X0 Dst | move Src X0 => move Fun Dst | move Src X0 1125move_fun Fun X0 | move A B | move X0 Dst | move Src X0 | \ 1126 independent_moves(Fun, X0, A, B) | distinct(Dst, A) => \ 1127 move Fun Dst | move A B | move Src X0 1128move_fun Fun X0 | move X0 Dst | make_fun2 OldIndex | \ 1129 is_killed_by_make_fun(X0, OldIndex)=> \ 1130 move Fun Dst | make_fun2 OldIndex 1131 1132move_fun Fun Dst => move Fun Dst 1133 1134%cold 1135i_make_fun W t 1136%hot 1137 1138is_function f? xy 1139is_function Fail=f c => jump Fail 1140 1141func_info M F A => i_func_info u M F A 1142 1143# ================================================================ 1144# Bit syntax matching obsoleted in OTP 22. 1145# ================================================================ 1146 1147%cold 1148bs_start_match2 Fail=f ica X Y D => jump Fail 1149bs_start_match2 Fail Bin X Y D => i_bs_start_match2 Bin Fail X Y D 1150i_bs_start_match2 xy f t t d 1151 1152bs_save2 Y=y Index => move Y x | bs_save2 x Index 1153bs_save2 Reg Index => gen_bs_save(Reg, Index) 1154i_bs_save2 x t 1155 1156bs_restore2 Y=y Index => move Y x | bs_restore2 x Index 1157bs_restore2 Reg Index => gen_bs_restore(Reg, Index) 1158i_bs_restore2 x t 1159 1160bs_context_to_binary Y=y | line L | badmatch Y => \ 1161 move Y x | bs_context_to_binary x | line L | badmatch x 1162bs_context_to_binary Y=y => move Y x | bs_context_to_binary x 1163bs_context_to_binary x 1164%warm 1165 1166# ================================================================ 1167# New bit syntax matching (R11B). 1168# ================================================================ 1169 1170%warm 1171 1172# Matching integers 1173bs_match_string Fail Ms Bits Val => i_bs_match_string Ms Fail Bits Val 1174 1175i_bs_match_string xy f W W 1176 1177# Fetching integers from binaries. 1178bs_get_integer2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \ 1179 gen_get_integer2(Fail, Ms, Live, Sz, Unit, Flags, Dst) 1180 1181i_bs_get_integer_small_imm Ms Bits Fail Flags Y=y => \ 1182 i_bs_get_integer_small_imm Ms Bits Fail Flags x | move x Y 1183 1184i_bs_get_integer_imm Ms Bits Live Fail Flags Y=y => \ 1185 i_bs_get_integer_imm Ms Bits Live Fail Flags x | move x Y 1186 1187i_bs_get_integer_small_imm xy W f? t x 1188i_bs_get_integer_imm xy W t f? t x 1189i_bs_get_integer xy f? t t S d 1190i_bs_get_integer_8 xy f? d 1191i_bs_get_integer_16 xy f? d 1192 1193%if ARCH_64 1194i_bs_get_integer_32 xy f? d 1195%endif 1196 1197# Fetching binaries from binaries. 1198bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \ 1199 gen_get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst) 1200 1201i_bs_get_binary_imm2 xy f? t W t d 1202i_bs_get_binary2 xy f t? S t d 1203i_bs_get_binary_all2 xy f? t t d 1204 1205# Fetching float from binaries. 1206bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => \ 1207 gen_get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst) 1208 1209bs_get_float2 Fail=f Ms=x Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail 1210 1211i_bs_get_float2 xy f? t s t d 1212 1213# Miscellanous 1214 1215bs_skip_bits2 Fail=f Ms=xy Sz=sq Unit=u Flags=u => \ 1216 gen_skip_bits2(Fail, Ms, Sz, Unit, Flags) 1217 1218i_bs_skip_bits_imm2 f? xy W 1219i_bs_skip_bits2 xy xy f? t 1220 1221bs_test_tail2 Fail=f Ms=xy Bits=u==0 => bs_test_zero_tail2 Fail Ms 1222bs_test_tail2 Fail=f Ms=xy Bits=u => bs_test_tail_imm2 Fail Ms Bits 1223bs_test_zero_tail2 f? xy 1224bs_test_tail_imm2 f? xy W 1225 1226bs_test_unit F Ms Unit=u==8 => bs_test_unit8 F Ms 1227bs_test_unit f? xy t 1228bs_test_unit8 f? xy 1229 1230# Gets a bitstring from the tail of a context. 1231bs_get_tail xy d t 1232 1233# New bs_start_match variant for contexts with external position storage. 1234# 1235# bs_get/set_position is used to save positions into registers instead of 1236# "slots" in the context itself, which lets us continue matching even after 1237# we've passed it off to another function. 1238 1239bs_start_match4 a==am_no_fail Live=u Src=xy Ctx=d => \ 1240 bs_start_match3 p Src Live Ctx 1241bs_start_match4 Fail=f Live=u Src=xy Ctx=d => \ 1242 bs_start_match3 Fail Src Live Ctx 1243 1244%if ARCH_64 1245 1246# This instruction nops on 64-bit platforms 1247bs_start_match4 a==am_resume Live Same Same => 1248bs_start_match4 a==am_resume Live Ctx Dst => move Ctx Dst 1249 1250bs_start_match3 Fail Bin Live Ctx | bs_get_position Ctx Pos=x Ignored => \ 1251 i_bs_start_match3_gp Bin Live Fail Ctx Pos 1252i_bs_start_match3_gp xy t j d x 1253 1254%else 1255 1256bs_start_match4 a==am_resume Live Ctx Dst => \ 1257 bs_start_match4 a=am_no_fail Live Ctx Dst 1258 1259%endif 1260 1261bs_start_match3 Fail=j ica Live Dst => jump Fail 1262bs_start_match3 Fail Bin Live Dst => i_bs_start_match3 Bin Live Fail Dst 1263 1264i_bs_start_match3 xy t j d 1265 1266# Match context position instructions. 64-bit assumes that all positions can 1267# fit into an unsigned small. 1268 1269%if ARCH_64 1270 bs_get_position Src Dst Live => i_bs_get_position Src Dst 1271 i_bs_get_position xy xy 1272 bs_set_position xy xy 1273%else 1274 bs_get_position xy d t? 1275 bs_set_position xy xy 1276%endif 1277 1278# 1279# Utf8/utf16/utf32 support. (R12B-5) 1280# 1281bs_get_utf8 Fail=f Ms=xy u u Dst=d => i_bs_get_utf8 Ms Fail Dst 1282i_bs_get_utf8 xy f? d 1283 1284bs_skip_utf8 Fail=f Ms=xy u u => i_bs_get_utf8 Ms Fail x 1285 1286bs_get_utf16 Fail=f Ms=xy u Flags=u Dst=d => i_bs_get_utf16 Ms Fail Flags Dst 1287bs_skip_utf16 Fail=f Ms=xy u Flags=u => i_bs_get_utf16 Ms Fail Flags x 1288 1289i_bs_get_utf16 xy f? t d 1290 1291bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst=d => \ 1292 bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | \ 1293 i_bs_validate_unicode_retract Fail Dst Ms 1294bs_skip_utf32 Fail=f Ms=xy Live=u Flags=u => \ 1295 bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | \ 1296 i_bs_validate_unicode_retract Fail x Ms 1297 1298i_bs_validate_unicode_retract j s S 1299%hot 1300 1301# 1302# Constructing binaries 1303# 1304%warm 1305 1306bs_init2 Fail Sz Words Regs Flags Dst | binary_too_big(Sz) => system_limit Fail 1307 1308bs_init2 Fail Sz Words Regs Flags Dst=y => \ 1309 bs_init2 Fail Sz Words Regs Flags x | move x Dst 1310 1311bs_init2 Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init Sz Regs Dst 1312 1313bs_init2 Fail Sz=u Words Regs Flags Dst => \ 1314 i_bs_init_heap Sz Words Regs Dst 1315 1316bs_init2 Fail Sz Words=u==0 Regs Flags Dst => \ 1317 i_bs_init_fail Sz Fail Regs Dst 1318bs_init2 Fail Sz Words Regs Flags Dst => \ 1319 i_bs_init_fail_heap Sz Words Fail Regs Dst 1320 1321i_bs_init_fail xy j? t? x 1322 1323i_bs_init_fail_heap s I j? t? x 1324 1325i_bs_init W t? x 1326 1327i_bs_init_heap W I t? x 1328 1329 1330bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail 1331bs_init_bits Fail Sz Words Regs Flags Dst=y => \ 1332 bs_init_bits Fail Sz Words Regs Flags x | move x Dst 1333 1334bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init_bits Sz Regs Dst 1335bs_init_bits Fail Sz=u Words Regs Flags Dst => i_bs_init_bits_heap Sz Words Regs Dst 1336 1337bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => \ 1338 i_bs_init_bits_fail Sz Fail Regs Dst 1339bs_init_bits Fail Sz Words Regs Flags Dst => \ 1340 i_bs_init_bits_fail_heap Sz Words Fail Regs Dst 1341 1342i_bs_init_bits_fail xy j? t? x 1343 1344i_bs_init_bits_fail_heap s I j? t? x 1345 1346i_bs_init_bits W t? x 1347i_bs_init_bits_heap W I t? x 1348 1349bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D 1350 1351bs_add j? s s t? x 1352 1353bs_append Fail Size Extra Live Unit Bin Flags Dst => \ 1354 move Bin x | i_bs_append Fail Extra Live Unit Size Dst 1355 1356bs_private_append Fail Size Unit Bin Flags Dst => \ 1357 i_bs_private_append Fail Unit Size Bin Dst 1358 1359i_bs_private_append Fail Unit Size Bin Dst=y => \ 1360 i_bs_private_append Fail Unit Size Bin x | move x Dst 1361 1362bs_init_writable 1363 1364i_bs_append j? I t? t s xy 1365i_bs_private_append j? t s S x 1366 1367# 1368# Storing integers into binaries. 1369# 1370 1371bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => \ 1372 gen_put_integer(Fail, Sz, Unit, Flags, Src) 1373 1374i_new_bs_put_integer j? S t s 1375i_new_bs_put_integer_imm xyc j? W t 1376 1377# 1378# Utf8/utf16/utf32 support. (R12B-5) 1379# 1380 1381bs_utf8_size j Src Dst=d => i_bs_utf8_size Src Dst 1382bs_utf16_size j Src Dst=d => i_bs_utf16_size Src Dst 1383 1384bs_put_utf8 Fail u Src => i_bs_put_utf8 Fail Src 1385 1386bs_put_utf32 Fail=j Flags=u Src=s => \ 1387 i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src 1388 1389i_bs_utf8_size S x 1390i_bs_utf16_size S x 1391 1392i_bs_put_utf8 j? S 1393bs_put_utf16 j? t S 1394 1395i_bs_validate_unicode j? S 1396 1397# Handle unoptimized code. 1398i_bs_utf8_size Src=c Dst => move Src x | i_bs_utf8_size x Dst 1399i_bs_utf16_size Src=c Dst => move Src x | i_bs_utf16_size x Dst 1400i_bs_put_utf8 Fail Src=c => move Src x | i_bs_put_utf8 Fail x 1401bs_put_utf16 Fail Flags Src=c => move Src x | bs_put_utf16 Fail Flags x 1402i_bs_validate_unicode Fail Src=c => move Src x | i_bs_validate_unicode Fail x 1403 1404# 1405# Storing floats into binaries. 1406# 1407bs_put_float Fail Sz=q Unit Flags Val => badarg Fail 1408 1409bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => \ 1410 gen_put_float(Fail, Sz, Unit, Flags, Src) 1411 1412i_new_bs_put_float j? S t s 1413i_new_bs_put_float_imm j? W t s 1414 1415# 1416# Storing binaries into binaries. 1417# 1418 1419bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => \ 1420 gen_put_binary(Fail, Sz, Unit, Flags, Src) 1421 1422# In unoptimized code, the binary argument could be a literal. (In optimized code, 1423# there would be a bs_put_string instruction.) 1424i_new_bs_put_binary Fail Size Unit Lit=c => \ 1425 move Lit x | i_new_bs_put_binary Fail Size Unit x 1426i_new_bs_put_binary_imm Fail Size Lit=c => \ 1427 move Lit x | i_new_bs_put_binary_imm Fail Size x 1428i_new_bs_put_binary_all Lit=c Fail Unit => \ 1429 move Lit x | i_new_bs_put_binary_all x Fail Unit 1430 1431i_new_bs_put_binary j? S t S 1432i_new_bs_put_binary_imm j? W S 1433i_new_bs_put_binary_all xy j? t 1434 1435# 1436# Warning: The i_bs_put_string and i_new_bs_put_string instructions 1437# are specially treated in the loader. 1438# Don't change the instruction format unless you change the loader too. 1439# 1440 1441bs_put_string W W 1442 1443# 1444# New floating point instructions (R8). 1445# 1446 1447fadd p FR1 FR2 FR3 => i_fadd FR1 FR2 FR3 1448fsub p FR1 FR2 FR3 => i_fsub FR1 FR2 FR3 1449fmul p FR1 FR2 FR3 => i_fmul FR1 FR2 FR3 1450fdiv p FR1 FR2 FR3 => i_fdiv FR1 FR2 FR3 1451fnegate p FR1 FR2 => i_fnegate FR1 FR2 1452 1453fconv Arg=iqan Dst=l => move Arg x | fconv x Dst 1454 1455fmove Arg=l Dst=d => fstore Arg Dst 1456fmove Arg=dq Dst=l => fload Arg Dst 1457 1458fstore l d 1459fload Sq l 1460 1461fconv S l 1462 1463i_fadd l l l 1464i_fsub l l l 1465i_fmul l l l 1466i_fdiv l l l 1467i_fnegate l l 1468 1469fclearerror | no_fpe_signals() => 1470fcheckerror p | no_fpe_signals() => 1471 1472%unless NO_FPE_SIGNALS 1473fcheckerror p => i_fcheckerror 1474 1475i_fcheckerror 1476fclearerror 1477%endif 1478 1479%hot 1480 1481# 1482# New apply instructions in R10B. 1483# 1484 1485apply t 1486apply_last t Q 1487 1488# 1489# Handle compatibility with OTP 17 here. 1490# 1491 1492i_put_map_assoc/4 1493 1494# We KNOW that in OTP 20 (actually OTP 18 and higher), a put_map_assoc instruction 1495# is always preceded by an is_map test. That means that put_map_assoc can never 1496# fail and does not need any failure label. 1497 1498put_map_assoc Fail Map Dst Live Size Rest=* | compiled_with_otp_20_or_higher() => \ 1499 i_put_map_assoc Map Dst Live Size Rest 1500 1501# Translate the put_map_assoc instruction if the module was compiled by a compiler 1502# before 20. This is only necessary if the OTP 17 compiler was used, but we 1503# have no safe and relatively easy way to know whether OTP 18/19 was used. 1504 1505put_map_assoc Fail=p Map Dst Live Size Rest=* => \ 1506 ensure_map Map | i_put_map_assoc Map Dst Live Size Rest 1507put_map_assoc Fail=f Map Dst Live Size Rest=* => \ 1508 is_map Fail Map | i_put_map_assoc Map Dst Live Size Rest 1509 1510ensure_map Lit=q | literal_is_map(Lit) => 1511ensure_map Src=cqy => move Src x | ensure_map x 1512 1513%cold 1514ensure_map x 1515%hot 1516 1517# 1518# Map instructions. First introduced in R17. 1519# 1520 1521sorted_put_map_assoc/4 1522i_put_map_assoc Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \ 1523 sorted_put_map_assoc Map Dst Live Size Rest 1524 1525sorted_put_map_exact/5 1526put_map_exact F Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \ 1527 sorted_put_map_exact F Map Dst Live Size Rest 1528 1529sorted_put_map_assoc Map Dst Live Size Rest=* | is_empty_map(Map) => \ 1530 new_map Dst Live Size Rest 1531sorted_put_map_assoc Src=xyc Dst Live Size Rest=* => \ 1532 update_map_assoc Src Dst Live Size Rest 1533 1534sorted_put_map_exact Fail Src=xy Dst Live Size Rest=* => \ 1535 update_map_exact Src Fail Dst Live Size Rest 1536# Literal map arguments for an exact update operation are extremely rare. 1537sorted_put_map_exact Fail Src Dst Live Size Rest=* => \ 1538 move Src x | update_map_exact x Fail Dst Live Size Rest 1539 1540new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => \ 1541 gen_new_small_map_lit(Dst, Live, Size, Rest) 1542 1543new_map d t I 1544i_new_small_map_lit d t q 1545update_map_assoc xyc d t I 1546update_map_exact xy j? d t I 1547 1548is_map Fail Lit=q | literal_is_map(Lit) => 1549is_map Fail cq => jump Fail 1550 1551is_map f? xy 1552 1553## Transform has_map_fields #{ K1 := _, K2 := _ } to has_map_elements 1554 1555has_map_fields Fail Src Size Rest=* => \ 1556 gen_has_map_fields(Fail, Src, Size, Rest) 1557 1558## Transform get_map_elements(s) #{ K1 := V1, K2 := V2 } 1559 1560get_map_elements Fail Src Size=u==2 Rest=* => \ 1561 gen_get_map_element(Fail, Src, Size, Rest) 1562get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => \ 1563 gen_get_map_elements(Fail, Src, Size, Rest) 1564 1565i_get_map_elements f? s I 1566 1567i_get_map_element_hash Fail Src=c Key Hash Dst => \ 1568 move Src x | i_get_map_element_hash Fail x Key Hash Dst 1569i_get_map_element_hash f? xy c I xy 1570 1571i_get_map_element Fail Src=c Key Dst => \ 1572 move Src x | i_get_map_element Fail x Key Dst 1573i_get_map_element f? xy xy xy 1574 1575# 1576# Convert the plus operations to a generic plus instruction. 1577# 1578gen_plus/5 1579gen_minus/5 1580 1581gc_bif1 Fail Live u$bif:erlang:splus/1 Src Dst => \ 1582 gen_plus Fail Live Src i Dst 1583gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => \ 1584 gen_plus Fail Live S1 S2 Dst 1585 1586gc_bif1 Fail Live u$bif:erlang:sminus/1 Src Dst => \ 1587 gen_minus Fail Live i Src Dst 1588gc_bif2 Fail Live u$bif:erlang:sminus/2 S1 S2 Dst => \ 1589 gen_minus Fail Live S1 S2 Dst 1590 1591# 1592# Optimize addition and subtraction of small literals using 1593# the i_increment/3 instruction (in bodies, not in guards). 1594# 1595 1596gen_plus p Live Int=i Reg=d Dst => \ 1597 gen_increment(Reg, Int, Dst) 1598gen_plus p Live Reg=d Int=i Dst => \ 1599 gen_increment(Reg, Int, Dst) 1600 1601gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \ 1602 gen_increment_from_minus(Reg, Int, Dst) 1603 1604# 1605# Arithmetic instructions. 1606# 1607 1608# It is OK to swap arguments for '+' in a guard. It is also 1609# OK to turn minus into plus in a guard. 1610gen_plus Fail=f Live S1=c S2 Dst => i_plus S2 S1 Fail Dst 1611gen_minus Fail=f Live S1 S2=i Dst => gen_plus_from_minus(Fail, Live, S1, S2, Dst) 1612 1613gen_plus Fail Live S1 S2 Dst => i_plus S1 S2 Fail Dst 1614 1615gen_minus Fail Live S1 S2 Dst => i_minus S1 S2 Fail Dst 1616 1617gc_bif2 Fail Live u$bif:erlang:stimes/2 S1 S2 Dst => \ 1618 i_times Fail S1 S2 Dst 1619 1620gc_bif2 Fail Live u$bif:erlang:div/2 S1 S2 Dst => \ 1621 i_m_div Fail S1 S2 Dst 1622gc_bif2 Fail Live u$bif:erlang:intdiv/2 S1 S2 Dst => \ 1623 i_int_div Fail S1 S2 Dst 1624 1625gc_bif2 Fail Live u$bif:erlang:rem/2 S1 S2 Dst => \ 1626 i_rem S1 S2 Fail Dst 1627 1628gc_bif2 Fail Live u$bif:erlang:bsl/2 S1 S2 Dst => \ 1629 i_bsl S1 S2 Fail Dst 1630gc_bif2 Fail Live u$bif:erlang:bsr/2 S1 S2 Dst => \ 1631 i_bsr S1 S2 Fail Dst 1632 1633gc_bif2 Fail Live u$bif:erlang:band/2 S1 S2 Dst => \ 1634 i_band S1 S2 Fail Dst 1635 1636gc_bif2 Fail Live u$bif:erlang:bor/2 S1 S2 Dst => \ 1637 i_bor Fail S1 S2 Dst 1638 1639gc_bif2 Fail Live u$bif:erlang:bxor/2 S1 S2 Dst => \ 1640 i_bxor Fail S1 S2 Dst 1641 1642gc_bif1 Fail Live u$bif:erlang:bnot/1 Src Dst=d => i_int_bnot Fail Src Dst 1643 1644i_increment rxy W d 1645 1646# Handle unoptimized code. 1647i_plus S1=c S2=c Fail Dst => move S1 x | i_plus x S2 Fail Dst 1648i_plus S1=c S2=xy Fail Dst => i_plus S2 S1 Fail Dst 1649 1650i_plus xy xyc j? d 1651 1652# A minus instruction with a constant right operand will be 1653# converted to an i_increment instruction, except in guards or 1654# when the negated value of the constant won't fit in a guard. 1655# Therefore, it very rare. 1656i_minus S1 S2=c Fail Dst => move S2 x | i_minus S1 x Fail Dst 1657 1658i_minus xy xy j? d 1659i_minus c xy j? d 1660 1661i_times j? s s d 1662 1663i_m_div j? s s d 1664i_int_div j? s s d 1665 1666i_rem x x j? d 1667i_rem s s j? d 1668 1669i_bsl s s j? d 1670i_bsr s s j? d 1671 1672i_band x c j? d 1673i_band s s j? d 1674 1675i_bor j? s s d 1676i_bxor j? s s d 1677 1678i_int_bnot Fail Src=c Dst => move Src x | i_int_bnot Fail x Dst 1679 1680i_int_bnot j? S d 1681 1682# 1683# Old guard BIFs that creates heap fragments are no longer allowed. 1684# 1685bif1 Fail u$bif:erlang:length/1 s d => too_old_compiler 1686bif1 Fail u$bif:erlang:size/1 s d => too_old_compiler 1687bif1 Fail u$bif:erlang:abs/1 s d => too_old_compiler 1688bif1 Fail u$bif:erlang:float/1 s d => too_old_compiler 1689bif1 Fail u$bif:erlang:round/1 s d => too_old_compiler 1690bif1 Fail u$bif:erlang:trunc/1 s d => too_old_compiler 1691 1692# 1693# Handle the length/1 guard BIF specially to make it trappable. 1694# 1695 1696gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => \ 1697 i_length_setup Live Src | i_length Fail Live Dst 1698 1699i_length_setup Live Src=c => move Src x | i_length_setup Live x 1700 1701i_length_setup t xy 1702i_length j? t d 1703 1704# 1705# Guard BIFs. 1706# 1707gc_bif1 p Live Bif Src Dst => i_bif1_body Src Bif Dst 1708gc_bif1 Fail=f Live Bif Src Dst => i_bif1 Src Fail Bif Dst 1709 1710gc_bif2 p Live Bif S1 S2 Dst => i_bif2_body S2 S1 Bif Dst 1711gc_bif2 Fail=f Live Bif S1 S2 Dst => i_bif2 S2 S1 Fail Bif Dst 1712 1713gc_bif3 p Live Bif S1 S2 S3 Dst => i_bif3_body S3 S2 S1 Bif Dst 1714gc_bif3 Fail=f Live Bif S1 S2 S3 Dst => i_bif3 S3 S2 S1 Fail Bif Dst 1715 1716# 1717# The following instruction is specially handled in beam_load.c 1718# to produce a user-friendly message if an unsupported guard BIF is 1719# encountered. 1720# 1721unsupported_guard_bif/3 1722unsupported_guard_bif A B C | never() => 1723 1724# 1725# R13B03 1726# 1727on_load 1728 1729# 1730# R14A. 1731# 1732# Modified in OTP 21 because it turns out that we don't need the 1733# label after all. 1734# 1735 1736recv_mark f => i_recv_mark 1737i_recv_mark 1738 1739recv_set Fail | label Lbl | loop_rec Lf Reg => \ 1740 i_recv_set | label Lbl | loop_rec Lf Reg 1741i_recv_set 1742 1743# 1744# OTP 21. 1745# 1746 1747build_stacktrace 1748raw_raise 1749 1750# 1751# Specialized move instructions. Since they don't require a second 1752# instruction, we have intentionally placed them after any other 1753# transformation rules that starts with a move instruction in order to 1754# produce better code for the transformation engine. 1755# 1756 1757# move_x1, move_x2 1758 1759move C=aiq X=x==1 => move_x1 C 1760move C=aiq X=x==2 => move_x2 C 1761 1762move n D=y => init D 1763 1764move_x1 c 1765move_x2 c 1766 1767