content: -- | This module represents a type-safe port of Erlang's general instructions.
  --   If this is your first exposure to BEAM, __I highly recommend Erik Stenman's book:
  --   <https://happi.github.io/theBeamBook>__.
  --   The documentation in this module point there derives directly from there,
  --   the <https://github.com/jerlang/jerlang Jerlang> project,
  --   and <https://github.com/erlang/otp/blob/master/lib/compiler/src/genop.tab Erlang's source code>.
  
  module Codec.Beam.Instructions
    ( label, func_info, on_load, line
    -- * Function and BIF calls
    , call, call_last, call_only, call_ext, call_ext_last, bif0, bif1, bif2, call_ext_only, apply, apply_last, gc_bif1, gc_bif2, gc_bif3
    -- * Allocating, deallocating and returning
    , allocate, allocate_heap, allocate_zero, allocate_heap_zero, test_heap, init', deallocate, return', trim
    -- * Sending and receiving
    , send, remove_message, timeout, loop_rec, loop_rec_end, wait, wait_timeout, recv_mark, recv_set
    -- * Comparision
    , is_lt, is_ge, is_eq, is_ne, is_eq_exact, is_ne_exact
    -- * Type tests
    , is_integer, is_float, is_number, is_atom, is_pid, is_reference, is_port, is_nil, is_binary, is_list, is_nonempty_list, is_tuple, test_arity, is_boolean, is_function, is_function2, is_bitstr, is_map, is_tagged_tuple
    -- * Indexing and jumping
    , select_val, select_tuple_arity, jump
    -- * Moving, extracting, modifying
    , move, get_list, get_tuple_element, set_tuple_element
    -- * Building terms
    , put_list, put_tuple, put
    -- * Raising errors
    , badmatch, if_end, case_end
    -- * @fun@ support
    , call_fun, make_fun2
    -- * Binary matching
    , bs_start_match2, bs_get_integer2, bs_get_float2, bs_get_binary2, bs_skip_bits2, bs_test_tail2, bs_save2, bs_restore2, bs_context_to_binary, bs_test_unit, bs_match_string, bs_append, bs_private_append
    -- * Binary construction
    , bs_init2, bs_put_integer, bs_put_binary, bs_put_float, bs_put_string, bs_add, bs_init_writable, bs_init_bits, bs_get_utf8, bs_skip_utf8, bs_get_utf16, bs_skip_utf16, bs_get_utf32, bs_skip_utf32, bs_utf8_size, bs_put_utf8, bs_utf16_size, bs_put_utf16, bs_put_utf32
    -- * Floating point arithmetic
    , fclearerror, fcheckerror, fmove, fconv, fadd, fsub, fmul, fdiv, fnegate
    -- * Try, catch, raise
    , try, try_end, try_case, try_case_end, raise, catch, catch_end
    -- * Maps
    , put_map_assoc, put_map_exact, has_map_fields, get_map_elements
    ) where
  
  import Codec.Beam.Internal.Syntax
  import Data.Text (Text)
  
  -- | Label gives this code address a name and marks the start of
  --   a basic block.
  label
    :: Label -- ^ unique identifier
    -> Op
  label a1 = Op 1 [FromNewLabel a1]
  
  -- | Define a function M:F/A in the current module.
  func_info
    :: Text -- ^ function name
    -> Int  -- ^ arity
    -> Op
  func_info a1 a2 = Op 2 [FromNewFunction a1 a2, FromAtom a1, FromUntagged a2]
  
  -- | Call the function at label.
  --   Save the next instruction as the return address in the CP register.
  call
    :: Int -- ^ arity
    -> Label
    -> Op
  call a1 a2 = Op 4 [FromUntagged a1, FromLabel a2]
  
  -- | Deallocate and do a tail recursive call to the function at label.
  --   Do not update the CP register.
  --   Before the call deallocate Deallocate words of stack.
  call_last
    :: Int -- ^ arity
    -> Label
    -> Int -- ^ number of stack words to deallocate
    -> Op
  call_last a1 a2 a3 = Op 5 [FromUntagged a1, FromLabel a2, FromUntagged a3]
  
  -- | Do a tail recursive call to the function at Label.
  --   Do not update the CP register.
  call_only
    :: Int -- ^ arity
    -> Label
    -> Op
  call_only a1 a2 = Op 6 [FromUntagged a1, FromLabel a2]
  
  -- | Call the function of arity pointed to by Destination.
  --   Save the next instruction as the return address in the CP register.
  call_ext :: Import -> Op
  call_ext a1 = Op 7 [FromUntagged (_import_arity a1), FromImport a1]
  
  -- | Deallocate and do a tail call to function
  --   pointed to by Destination.
  --   Do not update the CP register.
  --   Deallocate some words from the stack before the call.
  call_ext_last :: Import -> Int -> Op
  call_ext_last a1 a2 = Op 8 [FromUntagged (_import_arity a1), FromImport a1, FromUntagged a2]
  
  -- | Call the bif and store the result in register.
  bif0 :: (Bif0 a1, NoGC a1, IsRegister a2) => a1 -> a2 -> Op
  bif0 a1 a2 = Op 9 [FromImport (importBif0 a1), fromRegister a2]
  
  -- | Call the bif with the source, and store the result in register.
  --   On failure jump to label.
  bif1 :: (Bif1 a2, NoGC a2, IsSource a3, IsRegister a4) => Label -> a2 -> a3 -> a4 -> Op
  bif1 a1 a2 a3 a4 = Op 10 [FromLabel a1, FromImport (importBif1 a2), fromSource a3, fromRegister a4]
  
  -- | Call the bif with the sources, and store the result in register.
  --   On failure jump to label.
  bif2 :: (Bif2 a2, NoGC a2, IsSource a3, IsSource a4, IsRegister a5) => Label -> a2 -> a3 -> a4 -> a5 -> Op
  bif2 a1 a2 a3 a4 a5 = Op 11 [FromLabel a1, FromImport (importBif2 a2), fromSource a3, fromSource a4, fromRegister a5]
  
  -- | Allocate space for some words on the stack. If a GC is needed
  --   during allocation there are a number of live X registers.
  --   Also save the continuation pointer (CP) on the stack.
  allocate
    :: Int -- ^ stack words needed
    -> Int -- ^ live X registers
    -> Op
  allocate a1 a2 = Op 12 [FromUntagged a1, FromUntagged a2]
  
  -- | Allocate space for some words on the stack and ensure there is
  --   space for words on the heap. If a GC is needed
  --   save Live number of X registers.
  --   Also save the continuation pointer (CP) on the stack.
  allocate_heap
    :: Int -- ^ stack words needed
    -> Int -- ^ heap words needed
    -> Int -- ^ live X registers
    -> Op
  allocate_heap a1 a2 a3 = Op 13 [FromUntagged a1, FromUntagged a2, FromUntagged a3]
  
  -- | Allocate space for some words on the stack. If a GC is needed
  --   during allocation there are a number of live X registers.
  --   Clear the new stack words. (By writing NIL.)
  --   Also save the continuation pointer (CP) on the stack.
  allocate_zero
    :: Int -- ^ stack words needed
    -> Int -- ^ live X registers
    -> Op
  allocate_zero a1 a2 = Op 14 [FromUntagged a1, FromUntagged a2]
  
  -- | Allocate space for some words on the stack and ensure there is
  --   space for words on the heap. If a GC is needed
  --   save Live number of X registers.
  --   Clear the new stack words. (By writing NIL.)
  --   Also save the continuation pointer (CP) on the stack.
  allocate_heap_zero
    :: Int -- ^ stack words needed
    -> Int -- ^ heap words needed
    -> Int -- ^ live X registers
    -> Op
  allocate_heap_zero a1 a2 a3 = Op 15 [FromUntagged a1, FromUntagged a2, FromUntagged a3]
  
  -- | Ensure there is space for HeapNeed words on the heap. If a GC is needed
  --   save live number of X registers.
  test_heap
    :: Int -- ^ heap words needed
    -> Int -- ^ live number of X registers
    -> Op
  test_heap a1 a2 = Op 16 [FromUntagged a1, FromUntagged a2]
  
  -- | Clear the stack word. (By writing NIL.)
  init' :: Y -> Op
  init' a1 = Op 17 [FromY a1]
  
  -- | Restore the continuation pointer (CP) from the stack and deallocate
  --   N+1 words from the stack (the + 1 is for the CP).
  deallocate :: Int -> Op
  deallocate a1 = Op 18 [FromUntagged a1]
  
  -- | Return to the address in the continuation pointer (CP).
  return' :: Op
  return'  = Op 19 []
  
  -- | Send argument in x(1) as a message to the destination process in x(0).
  --   The message in x(1) ends up as the result of the send in x(0).
  send :: Op
  send  = Op 20 []
  
  -- | Unlink the current message from the message queue and store a
  --   pointer to the message in x(0). Remove any timeout.
  remove_message :: Op
  remove_message  = Op 21 []
  
  -- | Reset the save point of the mailbox and clear the timeout flag.
  timeout :: Op
  timeout  = Op 22 []
  
  -- | Loop over the message queue, if it is empty jump to label.
  loop_rec :: Label -> X -> Op
  loop_rec a1 a2 = Op 23 [FromLabel a1, FromX a2]
  
  -- | Advance the save pointer to the next message and jump back to label.
  loop_rec_end :: Label -> Op
  loop_rec_end a1 = Op 24 [FromLabel a1]
  
  -- | Suspend the processes and set the entry point to the beginning of the 
  --   receive loop at label.
  wait :: Label -> Op
  wait a1 = Op 25 [FromLabel a1]
  
  -- | Sets up a timeout of source milliseconds and saves the address of the
  --   following instruction as the entry point if the timeout triggers.
  wait_timeout :: (IsSource a2) => Label -> a2 -> Op
  wait_timeout a1 a2 = Op 26 [FromLabel a1, fromSource a2]
  
  -- | Compare two terms and jump to label if first is not less than second.
  is_lt :: (IsSource a2, IsSource a3) => Label -> a2 -> a3 -> Op
  is_lt a1 a2 a3 = Op 39 [FromLabel a1, fromSource a2, fromSource a3]
  
  -- | Compare two terms and jump to label if first is less than second.
  is_ge :: (IsSource a2, IsSource a3) => Label -> a2 -> a3 -> Op
  is_ge a1 a2 a3 = Op 40 [FromLabel a1, fromSource a2, fromSource a3]
  
  -- | Compare two terms and jump to label if first is not (numerically) equal to second.
  is_eq :: (IsSource a2, IsSource a3) => Label -> a2 -> a3 -> Op
  is_eq a1 a2 a3 = Op 41 [FromLabel a1, fromSource a2, fromSource a3]
  
  -- | Compare two terms and jump to label if first is (numerically) equal to second.
  is_ne :: (IsSource a2, IsSource a3) => Label -> a2 -> a3 -> Op
  is_ne a1 a2 a3 = Op 42 [FromLabel a1, fromSource a2, fromSource a3]
  
  -- | Compare two terms and jump to label if first is not exactly equal to second.
  is_eq_exact :: (IsSource a2, IsSource a3) => Label -> a2 -> a3 -> Op
  is_eq_exact a1 a2 a3 = Op 43 [FromLabel a1, fromSource a2, fromSource a3]
  
  -- | Compare two terms and jump to label if first is exactly equal to second.
  is_ne_exact :: (IsSource a2, IsSource a3) => Label -> a2 -> a3 -> Op
  is_ne_exact a1 a2 a3 = Op 44 [FromLabel a1, fromSource a2, fromSource a3]
  
  -- | Test the type of source and jump to label if it is not an integer.
  is_integer :: (IsSource a2) => Label -> a2 -> Op
  is_integer a1 a2 = Op 45 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not a float.
  is_float :: (IsSource a2) => Label -> a2 -> Op
  is_float a1 a2 = Op 46 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not a number.
  is_number :: (IsSource a2) => Label -> a2 -> Op
  is_number a1 a2 = Op 47 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not a atom.
  is_atom :: (IsSource a2) => Label -> a2 -> Op
  is_atom a1 a2 = Op 48 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not a pid.
  is_pid :: (IsSource a2) => Label -> a2 -> Op
  is_pid a1 a2 = Op 49 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not a reference.
  is_reference :: (IsSource a2) => Label -> a2 -> Op
  is_reference a1 a2 = Op 50 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not a port.
  is_port :: (IsSource a2) => Label -> a2 -> Op
  is_port a1 a2 = Op 51 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not nil.
  is_nil :: (IsSource a2) => Label -> a2 -> Op
  is_nil a1 a2 = Op 52 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not a binary.
  is_binary :: (IsSource a2) => Label -> a2 -> Op
  is_binary a1 a2 = Op 53 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not a cons or nil.
  is_list :: (IsSource a2) => Label -> a2 -> Op
  is_list a1 a2 = Op 55 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not a cons.
  is_nonempty_list :: (IsSource a2) => Label -> a2 -> Op
  is_nonempty_list a1 a2 = Op 56 [FromLabel a1, fromSource a2]
  
  -- | Test the type of source and jump to label if it is not a tuple.
  is_tuple :: (IsSource a2) => Label -> a2 -> Op
  is_tuple a1 a2 = Op 57 [FromLabel a1, fromSource a2]
  
  -- | Test the arity of (the tuple in) source and jump to label if it is not equal to arity.
  test_arity :: (IsSource a2) => Label -> a2 -> Int -> Op
  test_arity a1 a2 a3 = Op 58 [FromLabel a1, fromSource a2, FromUntagged a3]
  
  
  -- | Jump to the destination label corresponding to source
  --   in the destinations list, if no arity matches, jump to fail label.
  select_val :: (IsSource a1) => a1 -> Label -> [(Label, Source)] -> Op
  select_val a1 a2 a3 = Op 59 [fromSource a1, FromLabel a2, fromDestinations a3]
  
  -- | Check the arity of the source tuple and jump to the corresponding
  --   destination label, if no arity matches, jump to FailLabel.
  select_tuple_arity :: (IsSource a1) => a1 -> Label -> [(Label, Source)] -> Op
  select_tuple_arity a1 a2 a3 = Op 60 [fromSource a1, FromLabel a2, fromDestinations a3]
  
  -- | Jump to label.
  jump :: Label -> Op
  jump a1 = Op 61 [FromLabel a1]
  
  -- | Old-style catch.
  catch :: Y -> Label -> Op
  catch a1 a2 = Op 62 [FromY a1, FromLabel a2]
  
  catch_end :: Y -> Op
  catch_end a1 = Op 63 [FromY a1]
  
  -- | Move the source (a literal or a register) to
  --   the destination register.
  move :: (IsSource a1, IsRegister a2) => a1 -> a2 -> Op
  move a1 a2 = Op 64 [fromSource a1, fromRegister a2]
  
  -- | Get the head and tail (or car and cdr) parts of a list
  --   (a cons cell) from the initial register and put them into the registers.
  get_list
    :: (IsRegister a1, IsRegister a2, IsRegister a3)
    => a1 -- ^ where to get the list
    -> a2 -- ^ where to put the head (car)
    -> a3 -- ^ where to put the tail (cdr)
    -> Op
  get_list a1 a2 a3 = Op 65 [fromRegister a1, fromRegister a2, fromRegister a3]
  
  -- | Get a particular element number from the tuple in source and put
  --   it in the destination register.
  get_tuple_element
    :: (IsRegister a1, IsRegister a3)
    => a1  -- ^ where to get the tuple
    -> Int -- ^ target element index, __0-based__
    -> a3  -- ^ where to put the element
    -> Op
  get_tuple_element a1 a2 a3 = Op 66 [fromRegister a1, FromUntagged a2, fromRegister a3]
  
  -- | Update the element at position of the tuple in register
  --   with the new source element.
  set_tuple_element :: (IsSource a1, IsRegister a2) => a1 -> a2 -> Int -> Op
  set_tuple_element a1 a2 a3 = Op 67 [fromSource a1, fromRegister a2, FromUntagged a3]
  
  
  -- | Build a list, from the front, and puts the resulting list in the register.
  --   Just like Erlang's @|@ or Haskell's @:@.
  put_list
    :: (IsSource a1, IsSource a2, IsRegister a3)
      => a1 -- ^ the new head
      -> a2 -- ^ the new tail
      -> a3
      -> Op
  put_list a1 a2 a3 = Op 69 [fromSource a1, fromSource a2, fromRegister a3]
  
  -- | Constructs an empty tuple on the heap (size+1 words)
  --   and places its address into the Destination register.
  --   No elements are set at this moment.
  --   Put_tuple instruction is always followed by multiple
  --   'put' instructions which destructively set its elements one by one.
  put_tuple :: (IsRegister a2) => Int -> a2 -> Op
  put_tuple a1 a2 = Op 70 [FromUntagged a1, fromRegister a2]
  
  put :: (IsSource a1) => a1 -> Op
  put a1 = Op 71 [fromSource a1]
  
  badmatch :: (IsSource a1) => a1 -> Op
  badmatch a1 = Op 72 [fromSource a1]
  
  if_end :: Op
  if_end  = Op 73 []
  
  case_end :: (IsSource a1) => a1 -> Op
  case_end a1 = Op 74 [fromSource a1]
  
  -- | Call @fun@ object (in x[Arity]) with args (in x[0..Arity-1])
  --   Raises @badarity@ if the arity doesn’t match the function object.
  --   Raises @badfun@ if a non-function is passed.
  call_fun
    :: Int -- ^ arity
    -> Op
  call_fun a1 = Op 75 [FromUntagged a1]
  
  -- | Test the type of the source and jump to label if it is not a
  --   function (i.e. fun or closure).
  is_function :: (IsSource a2) => Label -> a2 -> Op
  is_function a1 a2 = Op 77 [FromLabel a1, fromSource a2]
  
  -- | Do a tail recursive call to the function at label.
  --   Do not update the CP register.
  call_ext_only :: Import -> Op
  call_ext_only a1 = Op 78 [FromUntagged (_import_arity a1), FromImport a1]
  
  bs_put_integer :: (IsSource a2, IsSource a5) => Label -> a2 -> Int -> Int -> a5 -> Op
  bs_put_integer a1 a2 a3 a4 a5 = Op 89 [FromLabel a1, fromSource a2, FromUntagged a3, FromUntagged a4, fromSource a5]
  
  bs_put_binary :: (IsSource a2, IsSource a5) => Label -> a2 -> Int -> Int -> a5 -> Op
  bs_put_binary a1 a2 a3 a4 a5 = Op 90 [FromLabel a1, fromSource a2, FromUntagged a3, FromUntagged a4, fromSource a5]
  
  bs_put_float :: (IsSource a2, IsSource a5) => Label -> a2 -> Int -> Int -> a5 -> Op
  bs_put_float a1 a2 a3 a4 a5 = Op 91 [FromLabel a1, fromSource a2, FromUntagged a3, FromUntagged a4, fromSource a5]
  
  bs_put_string :: Int -> Int -> Op
  bs_put_string a1 a2 = Op 92 [FromUntagged a1, FromUntagged a2]
  
  fclearerror :: Op
  fclearerror  = Op 94 []
  
  fcheckerror :: Label -> Op
  fcheckerror a1 = Op 95 [FromLabel a1]
  
  fmove :: (IsSourceF a1, IsRegisterF a2) => a1 -> a2 -> Op
  fmove a1 a2 = Op 96 [fromSourceF a1, fromRegisterF a2]
  
  fconv :: (IsSource a1) => a1 -> F -> Op
  fconv a1 a2 = Op 97 [fromSource a1, FromF a2]
  
  fadd :: F -> F -> F -> Op
  fadd a1 a2 a3 = Op 98 [FromLabel (Label 0), FromF a1, FromF a2, FromF a3]
  
  fsub :: F -> F -> F -> Op
  fsub a1 a2 a3 = Op 99 [FromLabel (Label 0), FromF a1, FromF a2, FromF a3]
  
  fmul :: F -> F -> F -> Op
  fmul a1 a2 a3 = Op 100 [FromLabel (Label 0), FromF a1, FromF a2, FromF a3]
  
  fdiv :: F -> F -> F -> Op
  fdiv a1 a2 a3 = Op 101 [FromLabel (Label 0), FromF a1, FromF a2, FromF a3]
  
  fnegate :: F -> F -> Op
  fnegate a1 a2 = Op 102 [FromLabel (Label 0), FromF a1, FromF a2]
  
  make_fun2 :: Lambda -> Op
  make_fun2 a1 = Op 103 [FromLambda a1]
  
  try :: Y -> Label -> Op
  try a1 a2 = Op 104 [FromY a1, FromLabel a2]
  
  try_end :: Y -> Op
  try_end a1 = Op 105 [FromY a1]
  
  try_case :: Y -> Op
  try_case a1 = Op 106 [FromY a1]
  
  try_case_end :: (IsSource a1) => a1 -> Op
  try_case_end a1 = Op 107 [fromSource a1]
  
  raise :: (IsSource a1, IsSource a2) => a1 -> a2 -> Op
  raise a1 a2 = Op 108 [fromSource a1, fromSource a2]
  
  bs_init2 :: (IsSource a2, IsRegister a6) => Label -> a2 -> Int -> Int -> Int -> a6 -> Op
  bs_init2 a1 a2 a3 a4 a5 a6 = Op 109 [FromLabel a1, fromSource a2, FromUntagged a3, FromUntagged a4, FromUntagged a5, fromRegister a6]
  
  bs_add :: (IsSource a2, IsSource a3, IsRegister a5) => Label -> a2 -> a3 -> Int -> a5 -> Op
  bs_add a1 a2 a3 a4 a5 = Op 111 [FromLabel a1, fromSource a2, fromSource a3, FromUntagged a4, fromRegister a5]
  
  -- | Apply function object (in x[arity]) with args (in x[0..arity-1])
  apply
    :: Int -- ^ arity
    -> Op
  apply a1 = Op 112 [FromUntagged a1]
  
  -- | Same as 'apply' but does not save the CP and deallocates words
  apply_last
    :: Int -- ^ arity
    -> Int -- ^ words to deallocate
    -> Op
  apply_last a1 a2 = Op 113 [FromUntagged a1, FromUntagged a2]
  
  -- | Test the type of source and jump to label if it is not a boolean.
  is_boolean :: (IsSource a2) => Label -> a2 -> Op
  is_boolean a1 a2 = Op 114 [FromLabel a1, fromSource a2]
  
  -- | Test the type of the source and jump to label if it is not a
  --   function of the particular arity.
  is_function2
    :: (IsSource a2, IsSource a3)
    => Label
    -> a2 -- ^ possible function
    -> a3 -- ^ possible arity
    -> Op
  is_function2 a1 a2 a3 = Op 115 [FromLabel a1, fromSource a2, fromSource a3]
  
  bs_start_match2 :: (IsSource a2, IsRegister a5) => Label -> a2 -> Int -> Int -> a5 -> Op
  bs_start_match2 a1 a2 a3 a4 a5 = Op 116 [FromLabel a1, fromSource a2, FromUntagged a3, FromUntagged a4, fromRegister a5]
  
  bs_get_integer2 :: (IsSource a4, IsRegister a7) => Label -> X -> Int -> a4 -> Int -> Int -> a7 -> Op
  bs_get_integer2 a1 a2 a3 a4 a5 a6 a7 = Op 117 [FromLabel a1, FromX a2, FromUntagged a3, fromSource a4, FromUntagged a5, FromUntagged a6, fromRegister a7]
  
  bs_get_float2 :: (IsSource a4, IsRegister a7) => Label -> X -> Int -> a4 -> Int -> Int -> a7 -> Op
  bs_get_float2 a1 a2 a3 a4 a5 a6 a7 = Op 118 [FromLabel a1, FromX a2, FromUntagged a3, fromSource a4, FromUntagged a5, FromUntagged a6, fromRegister a7]
  
  bs_get_binary2 :: (IsSource a4, IsRegister a7) => Label -> X -> Int -> a4 -> Int -> Int -> a7 -> Op
  bs_get_binary2 a1 a2 a3 a4 a5 a6 a7 = Op 119 [FromLabel a1, FromX a2, FromUntagged a3, fromSource a4, FromUntagged a5, FromUntagged a6, fromRegister a7]
  
  bs_skip_bits2 :: (IsSource a3) => Label -> X -> a3 -> Int -> Int -> Op
  bs_skip_bits2 a1 a2 a3 a4 a5 = Op 120 [FromLabel a1, FromX a2, fromSource a3, FromUntagged a4, FromUntagged a5]
  
  bs_test_tail2 :: Label -> X -> Int -> Op
  bs_test_tail2 a1 a2 a3 = Op 121 [FromLabel a1, FromX a2, FromUntagged a3]
  
  bs_save2 :: (IsRegister a1) => a1 -> Int -> Op
  bs_save2 a1 a2 = Op 122 [fromRegister a1, FromUntagged a2]
  
  bs_restore2 :: (IsRegister a1) => a1 -> Int -> Op
  bs_restore2 a1 a2 = Op 123 [fromRegister a1, FromUntagged a2]
  
  
  -- | Call the bif with the argument, and store the result in the register.
  --   On failure jump to label.
  --   Do a garbage collection if necessary to allocate space on the heap
  --   for the result.
  gc_bif1
    :: (Bif1 a3, IsSource a4, IsRegister a5)
    => Label -- ^ jump here on failure
    -> Int   -- ^ number of X-registers to save
    -> a3    -- ^ BIF, something like 'Codec.Beam.Bifs.erlang_localtime'
    -> a4    -- ^ argument
    -> a5    -- ^ where to put the result
    -> Op
  gc_bif1 a1 a2 a3 a4 a5 = Op 124 [FromLabel a1, FromUntagged a2, FromImport (importBif1 a3), fromSource a4, fromRegister a5]
  
  -- | Same as 'gc_bif1', but with two source arguments.
  gc_bif2 :: (Bif2 a3, IsSource a4, IsSource a5, IsRegister a6) => Label -> Int -> a3 -> a4 -> a5 -> a6 -> Op
  gc_bif2 a1 a2 a3 a4 a5 a6 = Op 125 [FromLabel a1, FromUntagged a2, FromImport (importBif2 a3), fromSource a4, fromSource a5, fromRegister a6]
  
  is_bitstr :: (IsSource a2) => Label -> a2 -> Op
  is_bitstr a1 a2 = Op 129 [FromLabel a1, fromSource a2]
  
  bs_context_to_binary :: (IsRegister a1) => a1 -> Op
  bs_context_to_binary a1 = Op 130 [fromRegister a1]
  
  bs_test_unit :: Label -> X -> Int -> Op
  bs_test_unit a1 a2 a3 = Op 131 [FromLabel a1, FromX a2, FromUntagged a3]
  
  bs_match_string :: Label -> X -> Int -> Int -> Op
  bs_match_string a1 a2 a3 a4 = Op 132 [FromLabel a1, FromX a2, FromUntagged a3, FromUntagged a4]
  
  bs_init_writable :: Op
  bs_init_writable  = Op 133 []
  
  bs_append :: (IsSource a2, IsSource a6, IsRegister a8) => Label -> a2 -> Int -> Int -> Int -> a6 -> Int -> a8 -> Op
  bs_append a1 a2 a3 a4 a5 a6 a7 a8 = Op 134 [FromLabel a1, fromSource a2, FromUntagged a3, FromUntagged a4, FromUntagged a5, fromSource a6, FromUntagged a7, fromRegister a8]
  
  bs_private_append :: (IsSource a2, IsSource a4, IsRegister a6) => Label -> a2 -> Int -> a4 -> Int -> a6 -> Op
  bs_private_append a1 a2 a3 a4 a5 a6 = Op 135 [FromLabel a1, fromSource a2, FromUntagged a3, fromSource a4, FromUntagged a5, fromRegister a6]
  
  -- | Reduce the stack usage by some number of words,
  --   keeping the CP on the top of the stack.
  trim
    :: Int -- ^ words to remove
    -> Int -- ^ words ro keep
    -> Op
  trim a1 a2 = Op 136 [FromUntagged a1, FromUntagged a2]
  
  bs_init_bits :: (IsSource a2, IsRegister a6) => Label -> a2 -> Int -> Int -> Int -> a6 -> Op
  bs_init_bits a1 a2 a3 a4 a5 a6 = Op 137 [FromLabel a1, fromSource a2, FromUntagged a3, FromUntagged a4, FromUntagged a5, fromRegister a6]
  
  bs_get_utf8 :: (IsRegister a5) => Label -> X -> Int -> Int -> a5 -> Op
  bs_get_utf8 a1 a2 a3 a4 a5 = Op 138 [FromLabel a1, FromX a2, FromUntagged a3, FromUntagged a4, fromRegister a5]
  
  bs_skip_utf8 :: Label -> X -> Int -> Int -> Op
  bs_skip_utf8 a1 a2 a3 a4 = Op 139 [FromLabel a1, FromX a2, FromUntagged a3, FromUntagged a4]
  
  bs_get_utf16 :: (IsRegister a5) => Label -> X -> Int -> Int -> a5 -> Op
  bs_get_utf16 a1 a2 a3 a4 a5 = Op 140 [FromLabel a1, FromX a2, FromUntagged a3, FromUntagged a4, fromRegister a5]
  
  bs_skip_utf16 :: Label -> X -> Int -> Int -> Op
  bs_skip_utf16 a1 a2 a3 a4 = Op 141 [FromLabel a1, FromX a2, FromUntagged a3, FromUntagged a4]
  
  bs_get_utf32 :: (IsRegister a5) => Label -> X -> Int -> Int -> a5 -> Op
  bs_get_utf32 a1 a2 a3 a4 a5 = Op 142 [FromLabel a1, FromX a2, FromUntagged a3, FromUntagged a4, fromRegister a5]
  
  bs_skip_utf32 :: Label -> X -> Int -> Int -> Op
  bs_skip_utf32 a1 a2 a3 a4 = Op 143 [FromLabel a1, FromX a2, FromUntagged a3, FromUntagged a4]
  
  bs_utf8_size :: (IsSource a2, IsRegister a3) => Label -> a2 -> a3 -> Op
  bs_utf8_size a1 a2 a3 = Op 144 [FromLabel a1, fromSource a2, fromRegister a3]
  
  bs_put_utf8 :: (IsSource a3) => Label -> Int -> a3 -> Op
  bs_put_utf8 a1 a2 a3 = Op 145 [FromLabel a1, FromUntagged a2, fromSource a3]
  
  bs_utf16_size :: (IsSource a2, IsRegister a3) => Label -> a2 -> a3 -> Op
  bs_utf16_size a1 a2 a3 = Op 146 [FromLabel a1, fromSource a2, fromRegister a3]
  
  bs_put_utf16 :: (IsSource a3) => Label -> Int -> a3 -> Op
  bs_put_utf16 a1 a2 a3 = Op 147 [FromLabel a1, FromUntagged a2, fromSource a3]
  
  bs_put_utf32 :: (IsSource a3) => Label -> Int -> a3 -> Op
  bs_put_utf32 a1 a2 a3 = Op 148 [FromLabel a1, FromUntagged a2, fromSource a3]
  
  on_load :: Op
  on_load  = Op 149 []
  
  -- | Save the end of the message queue and the address of
  --   the label so that a recv_set instruction can start
  -- | scanning the inbox from this position.
  recv_mark :: Label -> Op
  recv_mark a1 = Op 150 [FromLabel a1]
  
  -- | Check that the saved mark points to label and set the
  --   save pointer in the message queue to the last position
  --   of the message queue saved by the recv_mark instruction.
  recv_set :: Label -> Op
  recv_set a1 = Op 151 [FromLabel a1]
  
  -- | Same as 'gc_bif1', but with three source arguments.
  gc_bif3 :: (Bif3 a3, IsSource a4, IsSource a5, IsSource a6, IsRegister a7) => Label -> Int -> a3 -> a4 -> a5 -> a6 -> a7 -> Op
  gc_bif3 a1 a2 a3 a4 a5 a6 a7 = Op 152 [FromLabel a1, FromUntagged a2, FromImport (importBif3 a3), fromSource a4, fromSource a5, fromSource a6, fromRegister a7]
  
  line :: Int -> Op
  line a1 = Op 153 [FromUntagged a1]
  
  put_map_assoc :: (IsSource a2, IsRegister a3) => Label -> a2 -> a3 -> [(Source, Source)] -> Op
  put_map_assoc a1 a2 a3 a4 = Op 154 [FromLabel a1, fromSource a2, fromRegister a3, FromUntagged (length a4 + 1), fromPairs fromSource fromSource a4]
  
  put_map_exact :: (IsSource a2, IsRegister a3) => Label -> a2 -> a3 -> [(Source, Source)] -> Op
  put_map_exact a1 a2 a3 a4 = Op 155 [FromLabel a1, fromSource a2, fromRegister a3, FromUntagged (length a4 + 1), fromPairs fromSource fromSource a4]
  
  is_map :: (IsSource a2) => Label -> a2 -> Op
  is_map a1 a2 = Op 156 [FromLabel a1, fromSource a2]
  
  has_map_fields :: (IsSource a2) => Label -> a2 -> [Source] -> Op
  has_map_fields a1 a2 a3 = Op 157 [FromLabel a1, fromSource a2, FromList (map fromSource a3)]
  
  -- | Get multiple values out of a map
  get_map_elements
    :: (IsSource a2)
      => Label                  -- ^ jump here on failure
      -> a2                     -- ^ where the map is
      -> [(Source, Register)] -- ^ list of (what key to use, where to put value)
      -> Op
  get_map_elements a1 a2 a3 = Op 158 [FromLabel a1, fromSource a2, fromPairs fromSource fromRegister a3]
  
  -- | Test the type of source and jumps to label if it is not a tuple.
  --   Test the arity of Reg and jumps to label if it is not of the given size.
  --   Test the first element of the tuple and jumps to label if it is not given atom.
  is_tagged_tuple :: (IsSource a2) => Label -> a2 -> Int -> Text -> Op
  is_tagged_tuple a1 a2 a3 a4 = Op 159 [FromLabel a1, fromSource a2, FromUntagged a3, FromAtom a4]
  