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