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=hQ
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
69# An unaligned label. The address of an unaligned label must never be saved
70# on the stack or used in a context where it can be confused with an Erlang term.
71
72label L
73
74# An label aligned to a certain boundary. This is used in two cases:
75#
76# * When the label points to the start of a function, as the ErtsCodeInfo
77#   struct must be word-aligned.
78# * When the address is stored on the stack or otherwise needs to be properly
79#   tagged as a continuation pointer.
80aligned_label L t
81
82i_func_info I a a I
83int_code_end
84
85i_generic_breakpoint
86i_debug_breakpoint
87i_return_time_trace
88i_return_to_trace
89trace_jump W
90i_yield
91%hot
92
93return
94
95#
96# A tail call will not refer to the current function on error unless it's a
97# BIF, so we can omit the line instruction for non-BIFs.
98#
99
100move S X0=x==0 | line Loc | call_ext_last Ar Func=u$is_not_bif D => \
101     move S X0 | call_ext_last Ar Func D
102move S X0=x==0 | line Loc | call_ext_only Ar Func=u$is_not_bif => \
103     move S X0 | call_ext_only Ar Func
104
105move S X0=x==0 | line Loc | call_last Ar Func D => \
106     move S X0 | call_last Ar Func D
107move S X0=x==0 | line Loc | call_only Ar Func => \
108     move S X0 | call_only Ar Func
109
110# The line number in int_func_start/5 can be NIL.
111func_line n => empty_func_line
112
113empty_func_line
114func_line I
115
116line n =>
117line I
118
119allocate t t?
120allocate_heap t I t?
121
122deallocate t
123
124init y
125
126trim N Remaining => i_trim N
127
128i_trim t
129
130test_heap I t?
131
132# Translate instructions generated by a compiler before OTP 24.
133allocate_zero Ns Live => allocate_heap_zero Ns u Live
134allocate_heap_zero Ns Nh Live => allocate_heap_zero(Ns, Nh, Live)
135
136init_yregs I *
137
138# Selecting values.
139
140# The size of the dispatch code for a jump table is about 40
141# bytes. Therefore we shouldn't use a jump table if there are too few
142# values.
143
144select_val S Fail=fn Size=u Rest=* | use_jump_tab(Size, Rest, 6) => \
145  jump_tab(S, Fail, Size, Rest)
146is_integer Fail=f S | select_val S=s Fail=fn Size=u Rest=* | use_jump_tab(Size, Rest, 6) => \
147  jump_tab(S, Fail, Size, Rest)
148
149is_integer TypeFail=f S | select_val S=s Fail=fn Size=u Rest=* | \
150	   mixed_types(Size, Rest) => \
151  split_values(S, TypeFail, Fail, Size, Rest)
152
153select_val S Fail=fn Size=u Rest=* | mixed_types(Size, Rest) => \
154  split_values(S, Fail, Fail, Size, Rest)
155
156is_integer Fail=f S | select_val S=d Fail=fn Size=u Rest=* | \
157  fixed_size_values(Size, Rest) => select_val(S, Fail, Size, Rest)
158
159is_atom Fail=f S | select_val S=d Fail=fn Size=u Rest=* | \
160  fixed_size_values(Size, Rest) => select_val(S, Fail, Size, Rest)
161
162select_val S Fail=fn Size=u Rest=* | floats_or_bignums(Size, Rest) => \
163  select_literals(S, Fail, Size, Rest)
164
165select_val S Fail=fn Size=u Rest=* | fixed_size_values(Size, Rest) => \
166  select_val(S, Fail, Size, Rest)
167
168is_tuple Fail=f S | select_tuple_arity S=d Fail=f Size=u Rest=* => \
169  select_tuple_arity(S, Fail, Size, Rest)
170
171select_tuple_arity S=d Fail=f Size=u Rest=* => \
172  select_tuple_arity(S, Fail, Size, Rest)
173
174i_select_val_bins s fn I *
175
176i_select_val_lins s fn I *
177
178i_select_tuple_arity S f? I *
179
180i_jump_on_val s fn W I *
181
182is_number f? s
183
184jump f
185
186
187#
188# List matching instructions. The combination of test for a nonempty list followed
189# by get_{list/hd/tl} are common, so we will optimize that.
190#
191is_nonempty_list Fail nqia => jump Fail
192is_nonempty_list Fail Src | get_list Src Hd Tl => is_nonempty_list_get_list Fail Src Hd Tl
193is_nonempty_list Fail Src | get_hd Src Hd => is_nonempty_list_get_hd Fail Src Hd
194is_nonempty_list Fail Src | get_tl Src Tl => is_nonempty_list_get_tl Fail Src Tl
195
196is_nonempty_list f? S
197
198get_list S d d
199get_hd S d
200get_tl S d
201
202is_nonempty_list_get_list f S d d
203is_nonempty_list_get_hd f S d
204is_nonempty_list_get_tl f S d
205
206# Old-style catch.
207catch y f
208catch_end y
209
210# Try/catch.
211try Y F => catch Y F
212
213try_case y
214try_end y
215
216try_case_end s
217
218# Destructive set tuple element
219
220set_tuple_element s S P
221
222#
223# Get tuple element. Since this instruction is frequently used, we will try
224# to only fetch the pointer to the tuple once for a sequence of BEAM instructions
225# that fetch multiple elements from the same tuple.
226#
227
228current_tuple/1
229current_tuple/2
230
231is_tuple Fail=f Src | test_arity Fail Src Arity => \
232   i_is_tuple_of_arity Fail Src Arity | current_tuple Src
233
234test_arity Fail Src Arity => i_test_arity Fail Src Arity | current_tuple Src
235
236is_tuple NotTupleFail Tuple | is_tagged_tuple WrongRecordFail Tuple Arity Atom => \
237   i_is_tagged_tuple_ff NotTupleFail WrongRecordFail Tuple Arity Atom | current_tuple Tuple
238
239is_tagged_tuple Fail Tuple Arity Atom => \
240   i_is_tagged_tuple Fail Tuple Arity Atom | current_tuple Tuple
241
242is_tuple Fail=f Src => i_is_tuple Fail Src | current_tuple Src
243
244i_is_tuple_of_arity f? s A
245i_test_arity f? s A
246
247i_is_tagged_tuple f? s A a
248i_is_tagged_tuple_ff f? f? s A a
249
250i_is_tuple f? s
251
252# Generate instruction sequence for fetching the tuple element and remember
253# that we have a current tuple pointer.
254
255get_tuple_element Tuple Pos Dst => \
256  load_tuple_ptr Tuple | i_get_tuple_element Tuple Pos Dst | current_tuple Tuple
257current_tuple Tuple | get_tuple_element Tuple Pos Dst => \
258  i_get_tuple_element Tuple Pos Dst | current_tuple Tuple
259
260# Drop the current_tuple instruction if the tuple is overwritten.
261i_get_tuple_element Tuple Pos Tuple | current_tuple Tuple => i_get_tuple_element Tuple Pos Tuple
262
263# This is a current_tuple instruction instruction not followed by get_tuple_element.
264# Invalidate the current tuple pointer.
265
266current_tuple Tuple =>
267
268load_tuple_ptr s
269
270# If both positions and destinations are in consecutive memory, fetch and store
271# two words at once.
272i_get_tuple_element Tuple Pos1 Dst1 | current_tuple Tuple | \
273   get_tuple_element Tuple Pos2 Dst2 | consecutive_words(Pos1, Dst1, Pos2, Dst2) => \
274      get_two_tuple_elements Tuple Pos1 Dst1 Dst2 | current_tuple Tuple Dst2
275i_get_tuple_element Tuple Pos1 Dst1 | current_tuple Tuple | \
276   get_tuple_element Tuple Pos2 Dst2 | consecutive_words(Pos1, Dst2, Pos2, Dst1) => \
277      get_two_tuple_elements Tuple Pos1 Dst1 Dst2 | current_tuple Tuple Dst2
278
279# Drop the current_tuple instruction if the tuple is overwritten.
280current_tuple Tuple Tuple =>
281current_tuple Tuple Dst => current_tuple Tuple
282
283# The first operand will only be used in the debug-compiled runtime
284# system to verify that the register holding the tuple pointer agrees
285# with the source tuple operand.
286i_get_tuple_element s P S
287get_two_tuple_elements s P S S
288
289#
290# Expection rasing instructions. Infrequently executed.
291#
292
293%cold
294case_end s
295
296badmatch s
297
298if_end
299
300raise s s
301
302# Workaround the limitation that generators must always return at least one instruction.
303delete_me/0
304delete_me =>
305
306system_limit/1
307system_limit p => system_limit_body
308system_limit Fail=f => jump Fail
309
310system_limit_body
311
312%hot
313
314#
315# Optimize moves of consecutive memory addresses.
316#
317
318move Src=c Dst => i_move Src Dst
319
320move Src SrcDst | move SrcDst Dst => i_move Src SrcDst | move SrcDst Dst
321
322# Try to move two words at once. Always arrange the source operands in
323# consecutive order; the destination operands may be in consecutive or
324# reverse consecutive order.
325
326move S1=d D1=d | move S2=d D2=d | consecutive_words(S1, D1, S2, D2) => move_two_words S1 D1 S2 D2
327move S1=d D1=d | move S2=d D2=d | consecutive_words(S1, D2, S2, D1) => move_two_words S1 D1 S2 D2
328move S1=d D1=d | move S2=d D2=d | consecutive_words(S2, D1, S1, D2) => move_two_words S2 D2 S1 D1
329move S1=d D1=d | move S2=d D2=d | consecutive_words(S2, D2, S1, D1) => move_two_words S2 D2 S1 D1
330
331move Src Dst => i_move Src Dst
332
333#
334# Move instructions.
335#
336
337swap d d
338i_move s d
339move_two_words s d s d
340
341#
342# Receive operations. We conservatively align all labels before any
343# of the receive instructions.
344#
345# As the labels may be stored in the process structure, we must align them to
346# the nearest 4-byte boundary to ensure they're properly tagged as continuation
347# pointers.
348#
349
350label L | loop_rec Fail Reg => \
351    aligned_label L u=4 | loop_rec Fail Reg
352label L | wait_timeout Fail Src => \
353    aligned_label L u=4 | wait_timeout Fail Src
354label L | wait Fail => \
355    aligned_label L u=4 | wait Fail
356label L | timeout => \
357    aligned_label L u=4 | timeout
358
359loop_rec Fail x==0 | smp_mark_target_label(Fail) => i_loop_rec Fail
360
361aligned_label L A | wait_timeout Fail Src | smp_already_locked(L) => \
362    aligned_label L A | wait_timeout_locked Src Fail
363wait_timeout Fail Src => wait_timeout_unlocked Src Fail
364
365aligned_label L A | wait Fail | smp_already_locked(L) => \
366    aligned_label L A | wait_locked Fail
367wait Fail => wait_unlocked Fail
368
369aligned_label L A | timeout | smp_already_locked(L) => \
370    aligned_label L A | timeout_locked
371
372remove_message
373timeout
374timeout_locked
375i_loop_rec f
376loop_rec_end f
377wait_locked f
378wait_unlocked f
379
380# Note that a timeout value must fit in 32 bits.
381wait_timeout_unlocked s f
382wait_timeout_locked s f
383
384send
385
386#
387# Optimized comparisons with one immediate/literal operand.
388#
389
390is_eq_exact Lbl S S =>
391is_eq_exact Lbl C=c R=xy => is_eq_exact Lbl R C
392
393is_eq_exact Lbl R=xy n => is_nil Lbl R
394is_eq_exact Lbl R=xy C=ia => i_is_eq_exact_immed Lbl R C
395is_eq_exact Lbl R=xy C=q => is_eq_exact_literal(Lbl, R, C)
396
397is_ne_exact Lbl S S => jump Lbl
398is_ne_exact Lbl C=c R=xy => is_ne_exact Lbl R C
399
400is_ne_exact Lbl R=xy C=ian => i_is_ne_exact_immed Lbl R C
401is_ne_exact Lbl R=xy C=q => i_is_ne_exact_literal Lbl R C
402
403i_is_eq_exact_immed f? s c
404
405i_is_eq_exact_literal/4
406i_is_eq_exact_literal f? s c I
407
408i_is_ne_exact_immed f? s c
409
410i_is_ne_exact_literal f? s c
411
412is_eq_exact f? s s
413
414is_ne_exact f? s s
415
416is_lt f? s s
417is_ge f? s s
418
419is_eq Fail=f Const=c Reg=xy => is_eq Fail Reg Const
420is_eq f? s s
421
422is_ne Fail=f Const=c Reg=xy => is_ne Fail Reg Const
423is_ne f? s s
424
425#
426# Putting tuples.
427#
428# Code compiled with OTP 22 and later uses put_tuple2 to
429# to construct a tuple.
430#
431# Code compiled before OTP 22 uses put_tuple + one put instruction
432# per element. Translate to put_tuple2.
433#
434
435i_put_tuple/2
436put_tuple Arity Dst => i_put_tuple Dst u
437
438i_put_tuple Dst Arity Puts=* | put S1 | put S2 | \
439  put S3 | put S4 | put S5 => \
440	    tuple_append_put5(Arity, Dst, Puts, S1, S2, S3, S4, S5)
441
442i_put_tuple Dst Arity Puts=* | put S => \
443	    tuple_append_put(Arity, Dst, Puts, S)
444
445i_put_tuple Dst Arity Puts=* => put_tuple2 Dst Arity Puts
446
447put_tuple2 S A *
448
449#
450# Putting lists.
451#
452
453store_cons/2
454put_list Hd Tl Dst => put_cons Hd Tl | store_cons u=1 Dst
455store_cons Len Dst | put_list Hd Dst Dst | distinct(Dst, Hd) => combine_conses(Len, Dst, Hd)
456store_cons Len Dst | put_list Hd Dst OtherDst => store_cons Len Dst | append_cons u Hd | store_cons u=1 OtherDst
457
458put_cons s s
459append_cons I s
460store_cons I d
461
462#
463# Some more only used by the emulator
464#
465
466%cold
467normal_exit
468continue_exit
469call_bif W
470call_bif_mfa a a I
471call_nif W W W
472call_error_handler
473error_action_code
474return_trace
475%hot
476
477#
478# Type tests. Note that the operands for most type tests are `s` to
479# ensure that literal operands will work. The BEAM compiler starting
480# from OTP 22 will never emit type tests with literal operands even if
481# all optimizations are turned off, but loading unoptimized code from
482# older releases and code generated by alternative code generators.
483#
484
485is_integer f? s
486is_list f? s
487is_atom f? s
488is_float f? s
489
490is_nil Fail=f n =>
491is_nil Fail=f qia => jump Fail
492is_nil f? S
493
494# XXX Deprecated.
495is_bitstr Fail Term => is_bitstring Fail Term
496
497is_binary f? s
498is_bitstring f? s
499
500is_reference f? s
501is_pid f? s
502is_port f? s
503
504is_boolean f? s
505
506is_function2 f? s s
507
508#################################################################
509# External function and bif calls.
510#################################################################
511
512# Expands into call_light_bif/2
513call_light_bif/1
514
515#
516# The load_nif/2 BIF is an instruction.
517#
518
519call_ext u==2 u$func:erlang:load_nif/2 => \
520    i_load_nif
521call_ext_last u==2 u$func:erlang:load_nif/2 D => \
522    i_load_nif | deallocate D | return
523call_ext_only u==2 u$func:erlang:load_nif/2 => \
524    i_load_nif | return
525
526%cold
527i_load_nif
528%hot
529
530#
531# apply/2 is an instruction, not a BIF.
532#
533
534call_ext u==2 u$func:erlang:apply/2 => i_apply_fun
535call_ext_last u==2 u$func:erlang:apply/2 D => i_apply_fun_last D
536call_ext_only u==2 u$func:erlang:apply/2 => i_apply_fun_only
537
538#
539# The apply/3 BIF is an instruction.
540#
541
542call_ext u==3 u$func:erlang:apply/3 => i_apply
543call_ext_last u==3 u$func:erlang:apply/3 D => i_apply_last D
544call_ext_only u==3 u$func:erlang:apply/3 => i_apply_only
545
546#
547# The yield/0 BIF is an instruction
548#
549
550call_ext u==0 u$func:erlang:yield/0 => i_yield
551call_ext_last u==0 u$func:erlang:yield/0 D => i_yield | deallocate D | return
552call_ext_only u==0 u$func:erlang:yield/0 => i_yield | return
553
554#
555# The hibernate/3 BIF is an instruction.
556#
557call_ext u==3 u$func:erlang:hibernate/3 => i_hibernate
558call_ext_last u==3 u$func:erlang:hibernate/3 D => i_hibernate
559call_ext_only u==3 u$func:erlang:hibernate/3 => i_hibernate
560
561call_ext u==0 u$func:os:perf_counter/0 => \
562    i_perf_counter
563call_ext_last u==0 u$func:os:perf_counter/0 D => \
564    i_perf_counter | deallocate D | return
565call_ext_only u==0 u$func:os:perf_counter/0 => \
566    i_perf_counter | return
567
568#
569# BIFs like process_info/1,2 require up-to-date information about the current
570# emulator state, which the ordinary call_light_bif instruction doesn't save.
571#
572
573call_ext u Bif=u$is_bif | is_heavy_bif(Bif) => \
574    i_call_ext Bif
575call_ext_last u Bif=u$is_bif D | is_heavy_bif(Bif) => \
576    i_call_ext Bif | deallocate D | return
577call_ext_only Ar=u Bif=u$is_bif | is_heavy_bif(Bif) => \
578    allocate u Ar | i_call_ext Bif | deallocate u | return
579
580#
581# The general case for BIFs that have no special requirements.
582#
583
584call_ext u Bif=u$is_bif => \
585    call_light_bif Bif
586call_ext_last u Bif=u$is_bif D => \
587    call_light_bif Bif | deallocate D | return
588call_ext_only Ar=u Bif=u$is_bif => \
589    allocate u Ar | call_light_bif Bif | deallocate u | return
590
591#
592# Any remaining calls are calls to Erlang functions, not BIFs.
593# We rename the instructions to internal names.  This is necessary,
594# to avoid an end-less loop, because we want to call a few BIFs
595# with call instructions.
596#
597
598call_ext Ar Func        => i_call_ext Func
599call_ext_last Ar Func D => i_call_ext_last Func D
600call_ext_only Ar Func   => i_call_ext_only Func
601
602i_validate t
603
604i_apply
605i_apply_last t
606i_apply_only
607
608i_apply_fun
609i_apply_fun_last t
610i_apply_fun_only
611
612call_light_bif Bif => call_light_bif Bif Bif
613call_light_bif b e
614
615%cold
616
617i_hibernate
618i_perf_counter
619
620%hot
621
622#
623# Calls to non-building and guard BIFs.
624#
625
626bif0 u$bif:erlang:self/0 Dst=d => self Dst
627bif0 u$bif:erlang:node/0 Dst=d => node Dst
628
629bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=n Dst => \
630    jump Fail
631bif1 Fail=f Bif=u$bif:erlang:hd/1 Src Dst => \
632    is_nonempty_list Fail Src | get_hd Src Dst
633bif1 Fail Bif=u$bif:erlang:hd/1 Src Dst => \
634    bif_hd Fail Src Dst
635
636bif_hd j? s d
637
638bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=n Dst => \
639    jump Fail
640bif1 Fail=f Bif=u$bif:erlang:tl/1 Src Dst => \
641    is_nonempty_list Fail Src | get_tl Src Dst
642
643bif1 Fail Bif=u$bif:erlang:get/1 Src=s Dst=d => get(Src, Dst)
644
645bif2 Fail u$bif:erlang:element/2 S1=ixy S2 Dst => bif_element Fail S1 S2 Dst
646
647bif_element j? s s d
648
649bif1 Fail Bif S1 Dst | never_fails(Bif) => nofail_bif1 S1 Bif Dst
650bif2 Fail Bif S1 S2 Dst | never_fails(Bif) => nofail_bif2 S1 S2 Bif Dst
651
652bif1 Fail Bif S1 Dst    => i_bif1 S1 Fail Bif Dst
653bif2 Fail Bif S1 S2 Dst => i_bif2 S1 S2 Fail Bif Dst
654
655nofail_bif2 S1=d S2=ian Bif Dst | is_eq_exact_bif(Bif) => bif_is_eq_exact_immed S1 S2 Dst
656nofail_bif2 S1=d S2=ian Bif Dst | is_ne_exact_bif(Bif) => bif_is_ne_exact_immed S1 S2 Dst
657
658i_get_hash c I d
659i_get s d
660
661self d
662
663node d
664
665nofail_bif1 s b d
666nofail_bif2 s s b d
667
668i_bif1 s j? b d
669i_bif2 s s j? b d
670i_bif3 s s s j? b d
671
672bif_is_eq_exact_immed S c d
673bif_is_ne_exact_immed S c d
674
675#
676# Internal calls.
677#
678
679call Ar Func        => i_call Func
680call_last Ar Func D => i_call_last Func D
681call_only Ar Func   => i_call_only Func
682
683i_call f
684i_call_last f t
685i_call_only f
686
687i_call_ext e
688i_call_ext_last e t
689i_call_ext_only e
690
691# Fun calls.
692
693call_fun Arity | deallocate D | return => i_call_fun_last Arity D
694call_fun Arity => i_call_fun Arity
695
696i_call_fun t
697i_call_fun_last t t
698
699#
700# A fun with an empty environment can be converted to a literal.
701# As a further optimization, the we try to move the fun to its
702# final destination directly.
703
704make_fun2 OldIndex=u => make_fun2(OldIndex)
705make_fun3 OldIndex=u Dst=d NumFree=u Env=* => make_fun3(OldIndex, Dst, NumFree, Env)
706
707%cold
708
709i_make_fun3 F S t *
710
711# Psuedo-instruction for signalling lambda load errors. Never actually runs.
712i_lambda_error t
713
714%hot
715
716is_function f? S
717is_function Fail=f c => jump Fail
718
719# The start and end of a function.
720int_func_start/5
721int_func_end/0
722
723func_prologue/2
724
725int_func_start Func_Label Func_Line M F A | \
726  label Entry_Label | line Entry_Line => \
727    int_func_start Func_Label Func_Line M F A | \
728    func_prologue Entry_Label Entry_Line
729
730int_func_start Func_Label Func_Line M F A | \
731  label Entry_Label => \
732    int_func_start Func_Label Func_Line M F A | \
733    func_prologue Entry_Label n
734
735int_func_start Func_Label Func_Line M F A | \
736  func_prologue Entry_Label Entry_Line | \
737  is_mfa_bif(M, F, A) => \
738    aligned_label Func_Label u=8 | \
739    func_line Func_Line | \
740    i_func_info Func_Label M F A | \
741      aligned_label Entry_Label u=8 | \
742      line Entry_Line | \
743      i_breakpoint_trampoline | \
744      call_bif_mfa M F A
745
746int_func_start Func_Label Func_Line M F A | \
747  func_prologue Entry_Label Entry_Line => \
748    aligned_label Func_Label u=8 | \
749    func_line Func_Line | \
750    i_func_info Func_Label M F A | \
751      aligned_label Entry_Label u=8 | \
752      line Entry_Line | \
753      i_breakpoint_trampoline | \
754      i_test_yield
755
756
757int_func_end | needs_nif_padding() => i_nif_padding
758int_func_end =>
759
760# Handles yielding on function ingress (rather than on each call).
761i_test_yield
762
763# Ensures that the prior function is large enough to allow NIF patching.
764i_nif_padding
765
766# Handles tracing, early NIF calls, and so on.
767i_breakpoint_trampoline
768
769# ================================================================
770# Bit syntax matching obsoleted in OTP 22.
771# ================================================================
772
773%cold
774bs_start_match2 Fail=f ica X Y D => jump Fail
775bs_start_match2 Fail Bin X Y D => i_bs_start_match2 Bin Fail X Y D
776i_bs_start_match2 S f t t d
777
778bs_save2 Reg Index => bs_save(Reg, Index)
779i_bs_save2 x t
780
781bs_restore2 Reg Index => bs_restore(Reg, Index)
782i_bs_restore2 S t
783
784bs_context_to_binary S
785%warm
786
787# ================================================================
788# New bit syntax matching (R11B).
789# ================================================================
790
791%warm
792
793# Matching integers
794bs_match_string Fail Ms Bits Val => i_bs_match_string Ms Fail Bits Val
795
796i_bs_match_string S f W W
797
798# Fetching integers from binaries.
799bs_get_integer2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \
800    get_integer2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
801
802i_bs_get_integer S f? t t s d
803
804i_bs_get_integer_8 S t f? d
805i_bs_get_integer_16 S t f? d
806i_bs_get_integer_32 S t f? d
807i_bs_get_integer_64 S t f? t d
808
809# Fetching binaries from binaries.
810bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \
811			get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
812
813i_bs_get_binary2 S f t? s t d
814i_bs_get_binary_all2 S f? t t d
815
816# Fetching float from binaries.
817bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => \
818		get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
819
820bs_get_float2 Fail=f Ms=x Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail
821
822i_bs_get_float2 S f? t s t d
823
824# Miscellanous
825
826bs_skip_bits2 Fail=f Ms=xy Sz=sq Unit=u Flags=u => \
827			skip_bits2(Fail, Ms, Sz, Unit, Flags)
828
829i_bs_skip_bits_imm2 f? S W
830i_bs_skip_bits2 S S f? t
831
832bs_test_tail2 f? S t
833
834bs_test_unit f? S t
835
836# Gets a bitstring from the tail of a context.
837bs_get_tail S d t
838
839# New bs_start_match variant for contexts with external position storage.
840#
841# bs_get/set_position is used to save positions into registers instead of
842# "slots" in the context itself, which lets us continue matching even after
843# we've passed it off to another function.
844
845bs_start_match4 a==am_no_fail Live=u Src=xy Ctx=d => \
846    bs_start_match3 p Src Live Ctx
847bs_start_match4 Fail=f Live=u Src=xy Ctx=d => \
848    bs_start_match3 Fail Src Live Ctx
849
850%if ARCH_64
851
852# This instruction nops on 64-bit platforms
853bs_start_match4 a==am_resume Live Same Same =>
854bs_start_match4 a==am_resume Live Ctx Dst => move Ctx Dst
855
856%else
857
858bs_start_match4 a==am_resume Live Ctx Dst => \
859    bs_start_match4 a=am_no_fail Live Ctx Dst
860
861%endif
862
863bs_start_match3 Fail=j ica Live Dst => jump Fail
864bs_start_match3 Fail Bin Live Dst => i_bs_start_match3 Bin Live Fail Dst
865
866i_bs_start_match3 S t j d
867
868# Match context position instructions. 64-bit assumes that all positions can
869# fit into an unsigned small.
870
871%if ARCH_64
872    bs_get_position Src Dst Live => i_bs_get_position Src Dst
873    i_bs_get_position S S
874    bs_set_position S S
875%else
876    bs_get_position S d t?
877    bs_set_position S S
878%endif
879
880#
881# Utf8/utf16/utf32 support. (R12B-5)
882#
883bs_get_utf8 Fail=f Ms=xy u u Dst=d => i_bs_get_utf8 Ms Fail Dst
884i_bs_get_utf8 S f? d
885
886bs_skip_utf8 Fail=f Ms=xy u u => i_bs_skip_utf8 Ms Fail
887i_bs_skip_utf8 S f?
888
889bs_get_utf16 Fail=f Ms=xy u Flags=u Dst=d => i_bs_get_utf16 Ms Fail Flags Dst
890bs_skip_utf16 Fail=f Ms=xy u Flags=u => i_bs_skip_utf16 Ms Fail Flags
891
892i_bs_get_utf16 S f? t d
893i_bs_skip_utf16 S f? t
894
895bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst=d => \
896	bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | \
897	i_bs_validate_unicode_retract Fail Dst Ms
898bs_skip_utf32 Fail=f Ms=xy Live=u Flags=u => \
899	bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | \
900	i_bs_validate_unicode_retract Fail x Ms
901
902i_bs_validate_unicode_retract j s S
903%hot
904
905#
906# Constructing binaries
907#
908%warm
909
910bs_init2 Fail Sz Words Regs Flags Dst | binary_too_big(Sz) => system_limit Fail
911
912bs_init2 Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init Sz Regs Dst
913
914bs_init2 Fail Sz=u Words Regs Flags Dst => \
915   i_bs_init_heap Sz Words Regs Dst
916
917bs_init2 Fail Sz Words=u==0 Regs Flags Dst => \
918  i_bs_init_fail Sz Fail Regs Dst
919bs_init2 Fail Sz Words Regs Flags Dst => \
920  i_bs_init_fail_heap Sz Words Fail Regs Dst
921
922i_bs_init_fail S j? t? S
923
924i_bs_init_fail_heap s I j? t? S
925
926i_bs_init W t? S
927
928i_bs_init_heap W I t? S
929
930
931bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail
932
933bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => \
934    i_bs_init_bits Sz Regs Dst
935bs_init_bits Fail Sz=u Words Regs Flags Dst => \
936    i_bs_init_bits_heap Sz Words Regs Dst
937
938bs_init_bits Fail Sz Words=u==0 Regs Flags Dst => \
939  i_bs_init_bits_fail Sz Fail Regs Dst
940bs_init_bits Fail Sz Words Regs Flags Dst => \
941  i_bs_init_bits_fail_heap Sz Words Fail Regs Dst
942
943i_bs_init_bits_fail S j? t? S
944
945i_bs_init_bits_fail_heap s I j? t? S
946
947i_bs_init_bits W t? S
948i_bs_init_bits_heap W I t? S
949
950bs_add Fail S1=i==0 S2 Unit=u==1 D => move S2 D
951
952bs_add j? s s t? x
953
954bs_append Fail Size Extra Live Unit Bin Flags Dst => \
955  i_bs_append Fail Extra Live Unit Size Bin Dst
956
957bs_private_append Fail Size Unit Bin Flags Dst => \
958  i_bs_private_append Fail Unit Size Bin Dst
959
960i_bs_private_append Fail Unit Size Bin Dst=y => \
961  i_bs_private_append Fail Unit Size Bin x | move x Dst
962
963bs_init_writable
964
965i_bs_append j? I t? t s s S
966i_bs_private_append j? t s S x
967
968#
969# Storing integers into binaries.
970#
971
972bs_put_integer Fail=j Sz=sq Unit=u Flags=u Src=s => \
973			put_integer(Fail, Sz, Unit, Flags, Src)
974
975i_new_bs_put_integer j? S t s
976i_new_bs_put_integer_imm s j? W t
977
978#
979# Utf8/utf16/utf32 support. (R12B-5)
980#
981
982bs_utf8_size j Src Dst=d => i_bs_utf8_size Src Dst
983bs_utf16_size j Src Dst=d => i_bs_utf16_size Src Dst
984
985bs_put_utf8 Fail u Src => i_bs_put_utf8 Fail Src
986
987bs_put_utf32 Fail=j Flags=u Src=s => \
988   i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src
989
990i_bs_utf8_size s x
991i_bs_utf16_size s x
992
993i_bs_put_utf8 j? s
994bs_put_utf16 j? t s
995
996i_bs_validate_unicode j? s
997
998#
999# Storing floats into binaries.
1000#
1001
1002# Will fail. No need to keep the instruction, because bs_add or
1003# bs_init* would already have raised an exception.
1004bs_put_float Fail Sz=q Unit Flags Val =>
1005
1006bs_put_float Fail=j Sz=s Unit=u Flags=u Src=s => \
1007			put_float(Fail, Sz, Unit, Flags, Src)
1008
1009i_new_bs_put_float j? S t s
1010i_new_bs_put_float_imm j? W t s
1011
1012#
1013# Storing binaries into binaries.
1014#
1015
1016bs_put_binary Fail=j Sz=s Unit=u Flags=u Src=s => \
1017			put_binary(Fail, Sz, Unit, Flags, Src)
1018
1019i_new_bs_put_binary j? s t s
1020i_new_bs_put_binary_imm j? W s
1021i_new_bs_put_binary_all s j? t
1022
1023#
1024# Warning: The i_bs_put_string and i_new_bs_put_string instructions
1025# are specially treated in the loader.
1026# Don't change the instruction format unless you change the loader too.
1027#
1028
1029bs_put_string W W
1030
1031#
1032# New floating point instructions (R8).
1033#
1034
1035fadd p FR1 FR2 FR3 => i_fadd FR1 FR2 FR3
1036fsub p FR1 FR2 FR3 => i_fsub FR1 FR2 FR3
1037fmul p FR1 FR2 FR3 => i_fmul FR1 FR2 FR3
1038fdiv p FR1 FR2 FR3 => i_fdiv FR1 FR2 FR3
1039fnegate p FR1 FR2 => i_fnegate FR1 FR2
1040
1041fmove Arg=l Dst=d => fstore Arg Dst
1042fmove Arg=dq Dst=l => fload Arg Dst
1043
1044fstore l d
1045fload Sq l
1046
1047fconv s l
1048
1049i_fadd l l l
1050i_fsub l l l
1051i_fmul l l l
1052i_fdiv l l l
1053i_fnegate l l
1054
1055fclearerror =>
1056fcheckerror p =>
1057
1058%hot
1059
1060#
1061# New apply instructions in R10B.
1062#
1063
1064apply t
1065apply_last t t
1066
1067#
1068# Handle compatibility with OTP 17 here.
1069#
1070
1071i_put_map_assoc/4
1072
1073# We KNOW that in OTP 20 (actually OTP 18 and higher), a put_map_assoc instruction
1074# is always preceded by an is_map test. That means that put_map_assoc can never
1075# fail and does not need any failure label.
1076
1077put_map_assoc Fail Map Dst Live Size Rest=* | compiled_with_otp_20_or_higher() => \
1078	      i_put_map_assoc Map Dst Live Size Rest
1079
1080# Translate the put_map_assoc instruction if the module was compiled by a compiler
1081# before 20. This is only necessary if the OTP 17 compiler was used, but we
1082# have no safe and relatively easy way to know whether OTP 18/19 was used.
1083
1084put_map_assoc Fail=p Map Dst Live Size Rest=* => \
1085	      ensure_map Map | i_put_map_assoc Map Dst Live Size Rest
1086put_map_assoc Fail=f Map Dst Live Size Rest=* => \
1087	      is_map Fail Map | i_put_map_assoc Map Dst Live Size Rest
1088
1089ensure_map Lit=q | literal_is_map(Lit) =>
1090
1091%cold
1092ensure_map s
1093%hot
1094
1095#
1096# Map instructions. First introduced in R17.
1097#
1098
1099sorted_put_map_assoc/4
1100i_put_map_assoc Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \
1101  sorted_put_map_assoc Map Dst Live Size Rest
1102
1103sorted_put_map_exact/5
1104put_map_exact F Map Dst Live Size Rest=* | map_key_sort(Size, Rest) => \
1105  sorted_put_map_exact F Map Dst Live Size Rest
1106
1107sorted_put_map_assoc Map Dst Live Size Rest=* | is_empty_map(Map) => \
1108   new_map Dst Live Size Rest
1109sorted_put_map_assoc Src=s Dst Live Size Rest=* => \
1110   update_map_assoc Src Dst Live Size Rest
1111
1112sorted_put_map_exact Fail Src Dst Live Size Rest=* => \
1113   update_map_exact Src Fail Dst Live Size Rest
1114
1115new_map Dst Live Size Rest=* | is_small_map_literal_keys(Size, Rest) => \
1116  new_small_map_lit(Dst, Live, Size, Rest)
1117
1118new_map d t I *
1119i_new_small_map_lit d t q I *
1120update_map_assoc s d t I *
1121update_map_exact s j? d t I *
1122
1123is_map f? s
1124
1125## Transform has_map_fields #{ K1 := _, K2 := _ } to has_map_elements
1126
1127has_map_fields Fail Src Size Rest=* => \
1128   has_map_fields(Fail, Src, Size, Rest)
1129
1130## Transform get_map_elements(s) #{ K1 := V1, K2 := V2 }
1131
1132get_map_elements Fail Src Size=u==2 Rest=* => \
1133    get_map_element(Fail, Src, Size, Rest)
1134get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => \
1135   get_map_elements(Fail, Src, Size, Rest)
1136
1137i_get_map_elements f? s I *
1138
1139i_get_map_element_hash Fail Src=c Key Hash Dst => \
1140    move Src x | i_get_map_element_hash Fail x Key Hash Dst
1141i_get_map_element_hash f? S c I S
1142
1143i_get_map_element Fail Src=c Key Dst => \
1144    move Src x | i_get_map_element Fail x Key Dst
1145i_get_map_element f? S S S
1146
1147#
1148# Convert the plus operations to a generic plus instruction.
1149#
1150gen_plus/5
1151gen_minus/5
1152
1153gc_bif1 Fail Live u$bif:erlang:splus/1 Src Dst => \
1154   gen_plus Fail Live Src i Dst
1155gc_bif2 Fail Live u$bif:erlang:splus/2 S1 S2 Dst => \
1156   gen_plus Fail Live S1 S2 Dst
1157
1158gc_bif1 Fail Live u$bif:erlang:sminus/1 Src Dst => \
1159   i_unary_minus Src Fail Dst
1160gc_bif2 Fail Live u$bif:erlang:sminus/2 S1 S2 Dst => \
1161   gen_minus Fail Live S1 S2 Dst
1162
1163#
1164# Optimize addition and subtraction of small literals using
1165# the i_increment/3 instruction (in bodies, not in guards).
1166#
1167
1168gen_plus p Live Int=i Reg=d Dst => \
1169	increment(Reg, Int, Dst)
1170gen_plus p Live Reg=d Int=i Dst => \
1171	increment(Reg, Int, Dst)
1172
1173gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \
1174	increment_from_minus(Reg, Int, Dst)
1175
1176#
1177# Arithmetic instructions.
1178#
1179
1180# It is OK to swap arguments for '+' in a guard. It is also
1181# OK to turn minus into plus in a guard.
1182gen_plus Fail=f Live S1=c S2 Dst => i_plus S2 S1 Fail Dst
1183gen_minus Fail=f Live S1 S2=i Dst | negation_is_small(S2) => \
1184    plus_from_minus(Fail, Live, S1, S2, Dst)
1185
1186gen_plus Fail Live S1 S2 Dst => i_plus S1 S2 Fail Dst
1187
1188gen_minus Fail Live S1 S2 Dst => i_minus S1 S2 Fail Dst
1189
1190gc_bif2 Fail Live u$bif:erlang:stimes/2 S1 S2 Dst => \
1191  i_times Fail S1 S2 Dst
1192
1193gc_bif2 Fail Live u$bif:erlang:div/2 S1 S2 Dst => \
1194  i_m_div Fail S1 S2 Dst
1195
1196# Fused 'rem'/'div' pair.
1197gc_bif2 Fail Live u$bif:erlang:rem/2 LHS RHS Remainder | \
1198    gc_bif2 A B u$bif:erlang:intdiv/2 LHS RHS Quotient | \
1199    distinct(LHS, Remainder) | \
1200    distinct(RHS, Remainder) => \
1201      i_rem_div LHS RHS Fail Remainder Quotient
1202
1203# As above but with a `line` in between
1204gc_bif2 Fail Live u$bif:erlang:rem/2 LHS RHS Remainder | \
1205    line Loc | \
1206    gc_bif2 A B u$bif:erlang:intdiv/2 LHS RHS Quotient | \
1207    distinct(LHS, Remainder) | \
1208    distinct(RHS, Remainder) => \
1209      i_rem_div LHS RHS Fail Remainder Quotient
1210
1211# Fused 'div'/'rem' pair
1212gc_bif2 Fail Live u$bif:erlang:intdiv/2 LHS RHS Quotient | \
1213    gc_bif2 A B u$bif:erlang:rem/2 LHS RHS Remainder | \
1214    distinct(LHS, Quotient) | \
1215    distinct(RHS, Quotient) => \
1216      i_div_rem LHS RHS Fail Quotient Remainder
1217
1218# As above but with a `line` in between
1219gc_bif2 Fail Live u$bif:erlang:intdiv/2 LHS RHS Quotient | \
1220    line Loc | \
1221    gc_bif2 A B u$bif:erlang:rem/2 LHS RHS Remainder | \
1222    distinct(LHS, Quotient) | \
1223    distinct(RHS, Quotient) => \
1224      i_div_rem LHS RHS Fail Quotient Remainder
1225
1226gc_bif2 Fail Live u$bif:erlang:intdiv/2 S1 S2 Dst => \
1227  i_int_div Fail S1 S2 Dst
1228gc_bif2 Fail Live u$bif:erlang:rem/2 S1 S2 Dst => \
1229  i_rem S1 S2 Fail Dst
1230
1231gc_bif2 Fail Live u$bif:erlang:bsl/2 S1 S2 Dst => \
1232  i_bsl S1 S2 Fail Dst
1233gc_bif2 Fail Live u$bif:erlang:bsr/2 S1 S2 Dst => \
1234  i_bsr S1 S2 Fail Dst
1235
1236gc_bif2 Fail Live u$bif:erlang:band/2 S1 S2 Dst => \
1237  i_band S1 S2 Fail Dst
1238
1239gc_bif2 Fail Live u$bif:erlang:bor/2 S1 S2 Dst => \
1240  i_bor Fail S1 S2 Dst
1241
1242gc_bif2 Fail Live u$bif:erlang:bxor/2 S1 S2 Dst => \
1243  i_bxor Fail S1 S2 Dst
1244
1245gc_bif1 Fail Live u$bif:erlang:bnot/1 Src Dst => \
1246  i_bnot Fail Src Dst
1247
1248i_increment S W d
1249
1250i_plus s s j? d
1251i_minus s s j? d
1252
1253i_unary_minus s j? d
1254
1255i_times j? s s d
1256
1257i_m_div j? s s d
1258
1259i_rem_div s s j? d d
1260i_div_rem s s j? d d
1261i_int_div j? s s d
1262i_rem s s j? d
1263
1264i_bsl s s j? d
1265i_bsr s s j? d
1266
1267i_band s s j? d
1268i_bor j? s s d
1269i_bxor j? s s d
1270
1271i_bnot j? s d
1272
1273#
1274# Old guard BIFs that creates heap fragments are no longer allowed.
1275#
1276bif1 Fail u$bif:erlang:length/1 s d => too_old_compiler
1277bif1 Fail u$bif:erlang:size/1 s d => too_old_compiler
1278bif1 Fail u$bif:erlang:abs/1 s d => too_old_compiler
1279bif1 Fail u$bif:erlang:float/1 s d => too_old_compiler
1280bif1 Fail u$bif:erlang:round/1 s d => too_old_compiler
1281bif1 Fail u$bif:erlang:trunc/1 s d => too_old_compiler
1282
1283#
1284# Handle the length/1 guard BIF specially to make it trappable.
1285#
1286
1287gc_bif1 Fail=j Live u$bif:erlang:length/1 Src Dst => \
1288   i_length_setup Fail Live Src | i_length Fail Live Dst
1289
1290i_length_setup j? t s
1291i_length j? t d
1292
1293#
1294# Guard BIFs.
1295#
1296gc_bif1 Fail Live Bif Src Dst      => i_bif1 Src Fail Bif Dst
1297gc_bif2 Fail Live Bif S1 S2 Dst    => i_bif2 S1 S2 Fail Bif Dst
1298gc_bif3 Fail Live Bif S1 S2 S3 Dst => i_bif3 S1 S2 S3 Fail Bif Dst
1299
1300#
1301# The following instruction is specially handled in beam_load.c
1302# to produce a user-friendly message if an unsupported guard BIF is
1303# encountered.
1304#
1305unsupported_guard_bif/3
1306unsupported_guard_bif A B C | never() =>
1307
1308#
1309# R13B03
1310#
1311on_load
1312
1313#
1314# R14A.
1315#
1316# Superseded in OTP 24 by 'recv_marker_reserve' and friends.
1317#
1318
1319recv_mark f => i_recv_mark
1320i_recv_mark
1321
1322recv_set Fail | label Lbl | loop_rec Lf Reg => \
1323   i_recv_set | label Lbl | loop_rec Lf Reg
1324i_recv_set
1325
1326#
1327# OTP 21.
1328#
1329
1330build_stacktrace
1331raw_raise
1332
1333#
1334# Specialized move instructions. Since they don't require a second
1335# instruction, we have intentionally placed them after any other
1336# transformation rules that starts with a move instruction in order to
1337# produce better code for the transformation engine.
1338#
1339
1340move n D=y => init D
1341
1342#
1343# OTP 24
1344#
1345
1346recv_marker_reserve S
1347recv_marker_bind S S
1348recv_marker_clear S
1349recv_marker_use S
1350