/* Jitter: runtime VM-independent header for generated executors.

   Copyright (C) 2016, 2017, 2019, 2020, 2021 Luca Saiu
   Written by Luca Saiu

   This file is part of GNU Jitter.

   GNU Jitter is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   GNU Jitter is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GNU Jitter.  If not, see <https://www.gnu.org/licenses/>. */


/* This header is used internally by machine-generated executors.  It
   is not for the user to see.

   For example, some functionality defined here may depend on
   JITTER_VM_PREFIX_LOWER_CASE and JITTER_VM_PREFIX_UPPER_CASE, which are
   defined by machine-generated code in a .c file, without polluting the user
   name space. */

#ifndef JITTER_EXECUTOR_H_
#define JITTER_EXECUTOR_H_

/* Fail if this is not included from generated code.
 * ************************************************************************** */

/* This header relies on internal machinery and defines macros that the user
   should never see out of VM instruction code; using such macros from some
   other context, even by mistake, is unsupported and might lead to subtle
   bugs. */
#ifndef JITTER_THIS_CAN_INCLUDE_JITTER_EXECUTOR_H
# error "The header <jitter/jitter-executor.h> must only be included from C"
# error "files machine-generated by Jitter, and is not for the user to see."
# error "You are probably including the header directly."
# error "Don't."
#endif // #ifndef JITTER_THIS_CAN_INCLUDE_JITTER_EXECUTOR_H




/* Include headers.
 * ************************************************************************** */

#include <jitter/jitter.h>
#include <jitter/jitter-fast-branch.h>
#if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT)
# include <jitter/jitter-sections.h>
#endif // #if defined (JITTER_HAVE_KNOWN_BINARY_FORMAT)
# include <jitter/jitter-defect.h>
#if defined (JITTER_ENABLE_ASSEMBLY)
# include <jitter/machine/jitter-machine.h>
#endif //#if defined (JITTER_ENABLE_ASSEMBLY)




/* Unique string generation in (GNU) CPP.
 * ************************************************************************** */

/* Expand to a string literal, different at every expansion.  This is convenient for
   inline assembly comments, to prevent GCC from factoring code which is meant
   to be duplicated -- typically to avoid tail-merging in replicated VM
   instruction code.
   Notice that the unique identifier generated in inline asm code by "%=" is not
   enough to prevent tail-merging: GCC sees two identical string literals containing
   "%=" as, indeed, equal.
   This relies on __COUNTER__ , a GNU C preprocessor extension, but the advanced
   dispatches requiring this rely on GCC anyway. */
#define JITTER_STRING_LITERAL_UNIQUE  \
  " [" JITTER_STRINGIFY(__COUNTER__) "] "

/* Expand to an integer literal, different at any expansion.  This has similar
   applications to JITTER_STRING_LITERAL_UNIQUE , but is meant for C
   identifiers.  Again, this relies on the GNU C preprocessor. */
#define JITTER_INTEGER_LITERAL_UNIQUE  \
  __COUNTER__




/* Architecture-specific initialisation, finalisation, pre-C-call and post-C-
 * -call.
 * ************************************************************************** */

/* Some ports may add their own custom code to be executed at initialisation and
   finalisation of the executor.

   This feature is meant for tasks such as reading and then restoring the state
   of some register not visible from C.  Since in such a context it is useful to
   introduce automatic variables visible from VM instruction bodies these macros
   have a trailing underscore in their names, and are expanded in a context
   where it is safe not to protect the definition with a do { ... } while
   (false) loop. */

/* This feature is only meant for minimal-threading and no-threading.  Disable
   any architecture-specific execution begin and end code when using simple
   dispatches. */
#if (! defined(JITTER_DISPATCH_MINIMAL_THREADING))  \
    && (! defined(JITTER_DISPATCH_NO_THREADING))
# undef JITTER_EXECUTION_BEGINNING_
# undef JITTER_EXECUTION_END_
# undef JITTER_EXECUTION_PRE_C_CALL_
# undef JITTER_EXECUTION_POST_C_CALL_
#endif

/* Set missing statements to fallback values doing nothing. */
#if ! defined (JITTER_EXECUTION_BEGINNING_)
# define JITTER_EXECUTION_BEGINNING_ {}
#endif // #if ! defined (JITTER_EXECUTION_BEGINNING_)
#if ! defined (JITTER_EXECUTION_END_)
# define JITTER_EXECUTION_END_ {}
#endif // #if ! defined (JITTER_EXECUTION_END_)
#if ! defined (JITTER_EXECUTION_PRE_C_CALL_)
# define JITTER_EXECUTION_PRE_C_CALL_ {}
#endif // #if ! defined (JITTER_EXECUTION_PRE_C_CALL_)
#if ! defined (JITTER_EXECUTION_POST_C_CALL_)
# define JITTER_EXECUTION_POST_C_CALL_ {}
#endif // #if ! defined (JITTER_EXECUTION_POST_C_CALL_)




/* Function wrapping.
 * ************************************************************************** */

/* The machinery in this section is only used for complex dispatches. */
#if defined(JITTER_DISPATCH_MINIMAL_THREADING) \
    || defined(JITTER_DISPATCH_NO_THREADING)
  /* If we arrived here then the system should have the requirements for
     function wrapping; but let us try and go on in any case, in order to make
     porting easier. */
# if ! defined (JITTER_HAVE_FUNCTION_WRAPPERS_REQUIREMENTS)
#   warning "using a complex dispatch requiring function wrappers, without"
#   warning "having the prerequisites for function wrapping: trying to go on,"
#   warning "but expect problems with function wrappers."
# endif
#endif // complex dispatches

/* This is a realistic example of wrapping functions:
long
f (int a, bool b)
{
  printf ("Hello from f\n");
  return b ? a : -1;
}

void
g (const char *foo)
{
  printf ("Hello from g: \"%s\"\n", foo);
}

#define F(...)                             \
  JITTER_PRE_POST ((printf ("before f\n")),  \
                   (f (__VA_ARGS__)),      \
                   (printf ("after f\n")))
#define G(...)                             \
  JITTER_PRE_POST ((printf ("before g\n")),  \
                   (g (__VA_ARGS__)),      \
                   (printf ("after g\n")))

  printf ("%li\n", F (10, true));
  G ("some text");
*/

/* I use asm constraints on _jitter_useless_variable to prevent reordering of
   the "pre" and "post" statements.  This asm statement is volatile; if the pre
   and post statements are also volatile, then none can be reordered with
   respect to the others. */
#define JITTER_PRE_POST_FORCE_SEQUENCE_()                                   \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE ("# Pretend to use [useless]")    \
                : /* outputs */ [useless] "+m" (_jitter_useless_variable))

/* Expand to an expression which, if the discriminand expression, which is not
   evaluated, has a void type, yields the result of the ifvoid expression, and
   otherise yields the result of the ifnonvoid expression.  This is a helper for
   JITTER_PRE_POST . */
#define JITTER_IF_VOID_ELSE(discriminand, ifvoid, ifnonvoid)       \
  __builtin_choose_expr                                            \
     (__builtin_types_compatible_p (typeof (discriminand), void),  \
      (ifvoid),                                                    \
      (ifnonvoid))

/* Like JITTER_PRE_POST, below, assuming that e has a void type.  This is in
   fact a helper for JITTER_PRE_POST . */
#define JITTER_PRE_POST_VOID(pre, expression, post)  \
  ({                                                 \
     JITTER_PRE_POST_FORCE_SEQUENCE_ ();             \
     do { pre; } while (false);                      \
     JITTER_PRE_POST_FORCE_SEQUENCE_ ();             \
     (expression);                                   \
     JITTER_PRE_POST_FORCE_SEQUENCE_ ();             \
     do { post; } while (false);                     \
     JITTER_PRE_POST_FORCE_SEQUENCE_ ();             \
   })

/* Like JITTER_PRE_POST, below, assuming that e has a non-void type.  This is in
   fact a helper for JITTER_PRE_POST . */                         \
#define JITTER_PRE_POST_NONVOID(pre, expression, post)            \
  ({                                                              \
     JITTER_PRE_POST_FORCE_SEQUENCE_ ();                          \
     do { pre; } while (false);                                   \
     JITTER_PRE_POST_FORCE_SEQUENCE_ ();                          \
     typeof (expression) _jitter_pre_post_result = (expression);  \
     JITTER_PRE_POST_FORCE_SEQUENCE_ ();                          \
     do { post; } while (false);                                  \
     JITTER_PRE_POST_FORCE_SEQUENCE_ ();                          \
     _jitter_pre_post_result;                                     \
   })

/* Given a statement "pre", an expression "e" and a statement "post" expand to
   an expression which will evaluate, in order:
   - pre
   - e
   - post
   The expansion result will be the result of e if its type is not void;
   otherwise it will be void.  */
#define JITTER_PRE_POST(pre, e, post)                             \
  /* The difficulty here is to have the non-void case compile     \
     correctly when the expression is in fact void: this trick    \
     (using an integer result in unreachable code) lets me avoid  \
     a void-typed variable in the expansion. */                   \
  JITTER_IF_VOID_ELSE                                             \
    ((e),                                                         \
     JITTER_PRE_POST_VOID (({ pre; }),                            \
                           (e),                                   \
                           ({ post; })),                          \
     JITTER_PRE_POST_NONVOID (({ pre; }),                         \
                              JITTER_IF_VOID_ELSE                 \
                                 (/* not void-typed */ (e),       \
                                  /* unreachable */ 42,           \
                                  (e)),                           \
                              ({ post; })))




/* Calling a C function from a VM instruction through a pointer.
 * ************************************************************************** */

/* A C function called through a pointer will still need the pre- and post-
   statement as described in the previous section.  In order to automatically
   add such code the user should write
     JITTER_CALL_C (operator, operand0, ..., operandN)
   instead of simply
     operator (operand0, ..., operandN)
   .  The same machinery employed in the previous section makes sure that the
   expansion is correct with respect to types, in particular when the result is
   void.  Like in the section above if the return type is not void, the result
   is *not* lost. */
#if defined(JITTER_DISPATCH_SWITCH)               \
    || defined(JITTER_DISPATCH_DIRECT_THREADING)
  /* The dispatch is simple: there is actually no need to wrap this function
     call. */
# define JITTER_CALL_C(operator, ...)  \
    (operator) (__VA_ARGS__)
#else
  /* The dispatch is complex.  Use the machinery from the previous section
     to insert pre- and post-statements. */
# define JITTER_CALL_C(operator, ...)                     \
    JITTER_PRE_POST (({ JITTER_EXECUTION_PRE_C_CALL_; }),   \
                     ((operator) (__VA_ARGS__)),          \
                     ({ JITTER_EXECUTION_POST_C_CALL_; }))
#endif /* simple dispatch */

/* The functionality in this section, when employed directly in user code, is
   intended for C functions called through a C pointer: however any call to a
   C function from a relocatable VM instruction could use this same machinery.
   This is in fact the case in generated code: every machine-generated
   function wrapper relies on JITTER_CALL_C internally. */




/* Miscellaneous machinery for the executor, possibly to move.
 * ************************************************************************** */

/* Expand to a line-comment prefix for assembly as a string.  "\n# " is a sensible
   default working on most architectures, but this can be overridden in the
   architecture-specific header
   machine/ARCHICTECTURE/jitter/machine/jitter-machine.h .
   Rationale for the newline: on SH, at least with the GNU assembler, comments
   are introduced by "#" at the beginning of a line or by "!" anywhere else; but
   "!" is not supported on other architectures. */
#ifndef JITTER_ASM_COMMENT_PREFIX
# define JITTER_ASM_COMMENT_PREFIX  \
    "\n# "
#endif // #ifndef JITTER_ASM_COMMENT_PREFIX

/* Expand to a string literal suitable to be part inline asm, containing a
   comment-opening text and a terminating "\n\t" sequence. */
#define JITTER_ASM_COMMENT(_jitter_string_literal)         \
  JITTER_ASM_COMMENT_PREFIX _jitter_string_literal "\n\t"

/* Expand to a string literal suitable to be part inline asm, containing a
   comment-opening text, a unique identifier making the generated literal
   different from all others, and a terminating "\n\t" sequence. */
#define JITTER_ASM_COMMENT_UNIQUE(_jitter_string_literal)   \
  JITTER_ASM_COMMENT_PREFIX _jitter_string_literal " "      \
  JITTER_STRING_LITERAL_UNIQUE "\n\t"

/* Expand to an inline asm C statement containing the given comment, and a
   terminating "\n\t" sequence. */
#define JITTER_COMMENT_IN_ASM_(_jitter_string_literal)       \
  asm volatile (JITTER_ASM_COMMENT(_jitter_string_literal))

/* Expand to a string literal containing an asm comment, including containing
   the given text and a unique identifier which will prevent GCC from merging
   different expansions with the same argument. */
#define JITTER_COMMENT_IN_ASM_UNIQUE_(_jitter_string_literal)       \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE(_jitter_string_literal))




/* Debugging features to be used with disassembly.
 * ************************************************************************** */

// FIXME: I should move this section to a different header.

/* "Debugging nops" serve to generate nop instructions containing recognizable
   integer arguments, to be read back by humans disassembling compiled code.
   If there is no architecture-specific code for generating debugging nops, just
   generate nothing in their place. */
#ifndef _JITTER_ASM_DEBUGGING_NOP
# define _JITTER_ASM_DEBUGGING_NOP(integer_literal_as_string)  \
  ""
#endif // #ifndef _JITTER_ASM_DEBUGGING_NOP

/* Debugging nops: user macro, generating a readable asm comment followed (where
   possible) by the nop.
   The argument must be an integer literal in Gas syntax, with no surrounding
   quotes.  The machine-specific macro will emit the appropriate prefix to
   interpret the digit sequence as a hexadecimal constant.
   The expansion of this macro should be used in an *extended* asm statement,
   since '%' characters appearing, for example, as register prefixes, will
   appear escaped as "%%".
   For portability with respect to architectures only supporting small operands,
   the arguments should be non-negative and representable in 7 bits (Rationale:
   one way to implement a "nop" is by adding a short immediate to a register,
   followed by adding it back with the opposite sign; another alternative is
   xoring and a literal constant into the register itself, twice). */
#define JITTER_ASM_DEBUGGING_NOP(integer_literal)                 \
  JITTER_ASM_COMMENT_UNIQUE ("Debugging nop: "                    \
                             JITTER_STRINGIFY (integer_literal))  \
  _JITTER_ASM_DEBUGGING_NOP(JITTER_STRINGIFY (integer_literal))   \
  "\n\t"

/* A machine code snipped causing a trap, written in text form in a syntax
   suitable for extended inline asm.  If no machine-specific definition exists,
   define a stub here. */
#ifndef _JITTER_ASM_CRASH
# define _JITTER_ASM_CRASH                                      \
    JITTER_ASM_COMMENT_PREFIX "unimplemented for this machine"
#endif // #ifndef _JITTER_ASM_DEBUGGING_NOP

/* Expand to a C statement causing a trap.
   This is meant to catch bugs, by delimiting code past the end of VM
   specialized instruction which is not supposed to be replicated.  If such
   code is ever executed it is useful to make the failure well visible.
   It is important that this does not use __builtin_unreachable .  The
   code this is used in is in fact unreachable, but GCC must not be
   informed about the fact, as the code serves to keep the register
   assignment compatible across different program points: the compiler
   must see some impossible control transfers as possible. */
#define JITTER_CRASH_                                        \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE ("Cause a crash")  \
                _JITTER_ASM_CRASH "\n\t"                     \
                : /* outputs */)




/* Macros to let GCC see variables as changed.
 * ************************************************************************** */

// FIXME: use in the definitions below.
#define JITTER_MARK_AS_ASM_OUTPUT_(_jitter_constraint, _jitter_lvalue)  \
  asm (JITTER_ASM_COMMENT_UNIQUE("Pretend to set "                      \
                                 JITTER_STRINGIFY(_jitter_lvalue)       \
                                 " with a "                             \
                                 _jitter_constraint                     \
                                 " constraint in "                      \
                                 "%[the_jitter_lvalue]")                \
       : [the_jitter_lvalue] _jitter_constraint (_jitter_lvalue))

// FIXME: comment
#define JITTER_MARK_RVALUE_AS_READ_BY_ASSEMBLY(variable)               \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE(                             \
                   "Pretend to read the register or memory variable "  \
                   JITTER_STRINGIFY(variable) " in "                   \
                   "%[_variable]")                                     \
                :                                                      \
                : [_variable] "X" (variable))
#define JITTER_MARK_LVALUE_AS_DEFINED_BY_ASSEMBLY(variable)             \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE(                              \
                   "Pretend to write the register or memory variable "  \
                   JITTER_STRINGIFY(variable) " in "                    \
                   "%[_variable]")                                      \
                : [_variable] "=X" (variable))
#define JITTER_MARK_LVALUE_AS_SET_BY_ASSEMBLY(variable)                \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE(                             \
                  "Pretend to read and write the register or memory "  \
                  "variable " JITTER_STRINGIFY(variable) " in "        \
                  "%[_variable]")                                      \
                : [_variable] "+g" (variable))

#define JITTER_MARK_REGISTER_AS_DEFINED_BY_ASSEMBLY(variable)  \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE(                     \
                   "Pretend to write the register variable "   \
                   JITTER_STRINGIFY(variable) " in "           \
                   "%[register_variable]")                     \
                : [register_variable] "=r" (variable))
#define JITTER_MARK_REGISTER_AS_SET_BY_ASSEMBLY(variable)              \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE(                             \
                   "Pretend to read and write the register variable "  \
                                   JITTER_STRINGIFY(variable) " in "   \
                                   "%[register_variable]")             \
                : [register_variable] "+r" (variable))

#define JITTER_MARK_MEMORY_AS_DEFINED_BY_ASSEMBLY(variable)  \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE(                   \
                   "Pretend to write the memory variable "   \
                     JITTER_STRINGIFY(variable))             \
                : "=m" (variable))
#define JITTER_MARK_MEMORY_AS_SET_BY_ASSEMBLY(variable)              \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE(                           \
                   "Pretend to read and write the memory variable "  \
                   JITTER_STRINGIFY(variable))                       \
                : "+m" (variable))
#define JITTER_MARK_ARRAY_ELEMENT_AS_SET_BY_ASSEMBLY(variable, offset)     \
  asm volatile (JITTER_ASM_COMMENT_UNIQUE(                                 \
                   "Pretend to read and write a memory word from "         \
                   JITTER_STRINGIFY(variable)                              \
                   " at offset " JITTER_STRINGIFY(offset))                 \
                : "+m" (* (jitter_int*) ((char*) (variable) + (offset))))




/* Fallback defect descriptors.
 * ************************************************************************** */

/* If defect descriptors are not supported, provide a dummy compatibility macro
   expanding to an empty string.
   FIXME: use defect descriptors, when possible, with minimal threading. */
#ifndef JITTER_ASM_DEFECT_DESCRIPTOR
# define JITTER_ASM_DEFECT_DESCRIPTOR ""
#endif // #ifndef JITTER_ASM_DEFECT_DESCRIPTOR



/* Macros to let GCC see jumps to indeterminate locations.
 * ************************************************************************** */

// FIXME: comment.
#define JITTER_IP_INPUT_CONSTRAINT "r"

#define JITTER_PRETEND_TO_UPDATE_IP_                          \
  JITTER_MARK_AS_ASM_OUTPUT_("+" JITTER_IP_INPUT_CONSTRAINT,  \
                             jitter_ip)

/* Expand to zero assembly instructions, but with inline asm constraints
   affecting GCC's program representation as if the generated code could either
   jump to the content of jitter_anywhere_variable or fall thru. */
#define JITTER_PRETEND_TO_POSSIBLY_JUMP_ANYWHERE()                     \
  do                                                                   \
    {                                                                  \
      asm goto (JITTER_ASM_DEFECT_DESCRIPTOR                           \
                JITTER_ASM_COMMENT_UNIQUE(                             \
                   "# Pretending to possibly jump to "                 \
                   "%l[jitter_fake_target] thru %[_jitter_ip]")        \
                :                                                      \
                : [_jitter_ip] JITTER_IP_INPUT_CONSTRAINT (jitter_ip)  \
                :                                                      \
                : jitter_fake_target);                                 \
    }                                                                  \
  while (false)




/* Macros expanding to per-instruction labels and variable names.
 * ************************************************************************** */

/* Expand to the label at the beginning of the user code for the specialized
   instruction with the given name, in case of relocatable instructions;
   otherwise expand to the label at the beginning of the relocatable stub
   for non-relocatable instructions. */
#define JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_OF(name)  \
  JITTER_CONCATENATE_THREE(jitter_specialized_instruction_, name, _beginning_label)

/* Expand to the label at the end of the user code for the specialized
   instruction with the given name. */
#define JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(name)  \
  JITTER_CONCATENATE_THREE(jitter_specialized_instruction_, name, _end_label)

/* Expand to the label at the beginning of the user code for the specialized
   instruction with the given name, in case of non-relocatable instructions. */
#define JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL_OF(name)  \
  JITTER_CONCATENATE_THREE(jitter_specialized_instruction_, name, _non_relocatable_code_label)

/* Expand to the name of the variable defined as
   JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL_OF(name) .  The
   variable is always stack-allocated and can be safely read from relocated
   code. */
#define JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE_OF(name)  \
  JITTER_CONCATENATE_THREE(jitter_specialized_instruction_, name, _non_relocatable_code_variable)




/* User macros to access VM state data structures (from VM instructions).
 * ************************************************************************** */

/* Expand to the current VM state runtime, as a struct.  This is only to be
   used from the executor, where the required automatic variable is visible. */
#define _JITTER_STATE_RUNTIME  \
  jitter_state_runtime

/* The macro _JITTER_STATE_BACKING expands to the current VM state backing, as a
   struct.  It is defined in machine-generated code. */

/* Expand to an l-value referring the named field in the current VM state
   runtime. */
#define _JITTER_STATE_RUNTIME_FIELD(field_name)  \
  (_JITTER_STATE_RUNTIME.field_name)

/* Expand to an l-value referring the named field in the current VM state
   backing. */
#define _JITTER_STATE_BACKING_FIELD(field_name)  \
  (_JITTER_STATE_BACKING.field_name)

/* The macros _JITTER_STATE_RUNTIME_FIELD and _JITTER_STATE_BACKING_FIELD are
   meant to be accessed by their aliases VMPREFIX_STATE_RUNTIME_FIELD and
   VMPREFIX_STATE_BACKING_FIELD , defined in machine-generated code. */




/* Nullary macros expanding to per-instruction labels and variable names.
 * ************************************************************************** */

/* These rely on JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME , whose definitions
   is machine-generated to be visible from user instruction code.  Using these
   zero-argument macros is more convenient.

   CPP expansion semantics allows these macros to be used even in the expansion
   of other macros. */

/* Expand to the specialized instruction begin label for the current instruction. */
#define JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL  \
  JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_OF(    \
    JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME)

/* Expand to the stringification of
   JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL . */
#define JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_AS_STRING   \
  JITTER_STRINGIFY(JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL)

/* Expand to the specialized instruction end label for the current instruction. */
#define JITTER_SPECIALIZED_INSTRUCTION_END_LABEL  \
  JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(    \
    JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME)

/* Expand to the label at the beginning of the user code for the current
   instruction, in case of non-relocatable instructions; expand to some
   probably unbound identifier otherwise. */
#define JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL  \
  JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL_OF(    \
     JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME)

/* Expand to the name of the variable defined as
   JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_LABEL .  The variable is
   always stack-allocated and can be safely read from relocated code.  Expand to
   some probably unbound identifier for relocatable instructions. */
#define JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE  \
  JITTER_SPECIALIZED_INSTRUCTION_NON_RELOCATABLE_CODE_VARIABLE_OF(    \
     JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME)




/* VM routine termination.
 * ************************************************************************** */

/* Exit the executor function and return to C.  The user version of this macro,
   JITTER_EXIT with no underscore at the beginning, is only usable from
   branching instructions. */
#ifdef JITTER_REPLICATE
  /* With replication enabled this works like an inter-VM-instruction branch,
     leading out of replicated code... */
# define _JITTER_EXIT()                                                   \
    JITTER_COMPUTED_GOTO (jitter_saved_exit_non_replicated_code_pointer)
#else
  /* ...But in the case of switch dispatching computed gotos may not be usable
     at all, and with direct-threading there is no correctness problem. */
# define _JITTER_EXIT()             \
    do                              \
      {                             \
        goto jitter_exit_vm_label;  \
      }                             \
    while (false)
#endif // #ifdef JITTER_REPLICATE




/* VM instruction prolog and epilog.
 * ************************************************************************** */

/* VM instruction prolog. */
#if   defined(JITTER_DISPATCH_SWITCH)
  /* VM instruction prolog: switch dispatching. */
# define JITTER_INSTRUCTION_PROLOG_(name, mangled_name, residual_arity)  \
  case JITTER_CONCATENATE_THREE(JITTER_VM_PREFIX_LOWER_CASE,             \
                                _specialized_instruction_opcode_,        \
                                mangled_name):
#else
  /* VM instruction prolog: every non-switch dispatches. */
# define JITTER_INSTRUCTION_PROLOG_(name, mangled_name, hotness_attribute)  \
{                                                                           \
  JITTER_SPECIALIZED_INSTRUCTION_BEGIN_LABEL_OF(mangled_name):              \
    __attribute__ ((hotness_attribute)); \
/*JITTER_COMMENT_IN_ASM_UNIQUE_("here comes " JITTER_STRINGIFY (name));*/
#endif // defined(JITTER_DISPATCH_SWITCH)

/* How many words are used to encode the current specialized instruction, given
   its residual arity.  According to the dispatch there may be a word
   for the opcode or the thread, or not.
   This relies on JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY being defined,
   which is the case when this macro is used as intended, from specialized
   instruction code within the executor. */
#if   defined(JITTER_DISPATCH_SWITCH)            \
   || defined(JITTER_DISPATCH_DIRECT_THREADING)
# define JITTER_SPECIALIZED_INSTRUCTION_WORD_NO          \
    (1 + JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY)
#elif defined(JITTER_DISPATCH_MINIMAL_THREADING)
# define JITTER_SPECIALIZED_INSTRUCTION_WORD_NO    \
    JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY
#elif defined(JITTER_DISPATCH_NO_THREADING)
# define JITTER_SPECIALIZED_INSTRUCTION_WORD_NO    \
    JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY
#else
# error "unknown dispatch"
#endif

/* Modify the instruction pointer, if any, to skip the appropriate number of
   residuals for the current instruction plus the opcode or thread, if any.
   This relies on JITTER_SPECIALIZED_INSTRUCTION_RESIDUAL_ARITY being defined,
   which is the case when this macro is used as intended, from specialized
   instruction code within the executor. */
#if   defined(JITTER_DISPATCH_SWITCH)             \
   || defined(JITTER_DISPATCH_DIRECT_THREADING)   \
   || defined(JITTER_DISPATCH_MINIMAL_THREADING)
# define JITTER_SKIP_RESIDUALS_                                         \
    JITTER_SET_IP(jitter_ip + JITTER_SPECIALIZED_INSTRUCTION_WORD_NO);
#elif defined(JITTER_DISPATCH_NO_THREADING)
# define JITTER_SKIP_RESIDUALS_  \
    /* do nothing. */
#else
# error "unknown dispatch"
#endif // #if   defined([dispatch]...

/* A VM instruction epilog. */
#if   defined(JITTER_DISPATCH_SWITCH)
# define JITTER_INSTRUCTION_EPILOG_(name, mangled_name, residual_arity)  \
    JITTER_SKIP_RESIDUALS_;                                              \
    JITTER_BRANCH_TO_IP();
#elif defined(JITTER_DISPATCH_DIRECT_THREADING)
# define JITTER_INSTRUCTION_EPILOG_(name, mangled_name, residual_arity)  \
      JITTER_SKIP_RESIDUALS_;                                            \
      JITTER_BRANCH_TO_IP();                                             \
    }                                                                    \
   JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(mangled_name):            \
     __builtin_unreachable ();
#elif defined(JITTER_DISPATCH_MINIMAL_THREADING)                         \
      || defined(JITTER_DISPATCH_NO_THREADING)
# define JITTER_INSTRUCTION_EPILOG_(name, mangled_name, residual_arity)  \
       JITTER_SKIP_RESIDUALS_;                                           \
     }                                                                   \
/*JITTER_PRETEND_TO_UPDATE_IP_; */ \
/*JITTER_PRETEND_TO_POSSIBLY_JUMP_ANYWHERE();*/ \
/*asm goto ("\n\taddiu $0, $0, 2\n\n" : : "r" (jitter_ip) : : JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(mangled_name)); */\
/*  JITTER_PRETEND_TO_UPDATE_IP_;*/ \
/*asm volatile ("\n\taddiu $0, $0, 4\n\t" JITTER_ASM_COMMENT_UNIQUE("foo1"):);*/ \
/*JITTER_PRETEND_TO_UPDATE_IP_;*/ \
JITTER_PRETEND_TO_UPDATE_IP_;\
     /* Mark the end of the specialized instruction with a label. */     \
    JITTER_SPECIALIZED_INSTRUCTION_END_LABEL_OF(mangled_name):           \
if (jitter_ip != NULL) goto * jitter_ip; \
/*JITTER_PRETEND_TO_POSSIBLY_JUMP_ANYWHERE();*/ \
/*__builtin_unreachable ();*/ \
/*JITTER_PRETEND_TO_UPDATE_IP_;*/ \
/*asm volatile ("\n\taddiu $0, $0, 5\n\t" JITTER_ASM_COMMENT_UNIQUE("foo2"));*/ \
     /* What follows is unreachable, but serves to prevent GCC from      \
        reordering code across labels.  The final indirect branch,       \
        which of course would not branch anywhere correct if it were     \
        actually executed, serves to force the compiler to keep the      \
        register assignment compatible between this program point,       \
        at the end of VM instructions, with the register assignment      \
        at the beginning of every VM instruction, or even at their end.  \
        From GCC's point of view this goto * statement may reach any     \
        label in the function whose address I have taken. */             \
     JITTER_CRASH_;                                                      \
     JITTER_PRETEND_TO_UPDATE_IP_;                                   \
     goto * jitter_ip;
#else
# error "unknown dispatch"
#endif // #if defined(JITTER_DISPATCH_SWITCH)




/* VM branching utility.
 * ************************************************************************** */

/* After a VM branch-and-link operation is performed the rest of the specialized
   instruction code is unreachable; in other words the return program point is
   the beginning of the VM instruction following the calling VM instruction, and
   not the machine instruction following the *machine* calling instruction.
   This restriction is artificial on machines where VM calls are implemented by
   native branch-and-link or call instructions, but is needed for compatibility
   with simpler dispatches where the intuitive semantics is not
   implementable.
   It's important that GCC does not assume that the code past the
   branch-and-link is *automatically* unreachable, as would be the case if we
   simply used __builtin_unreachable.
   This is needed, for example, in the case of a branch-and-link at the end of
   the first branch of a two-way conditional within a VM specialized instruction.
   Without this jump the control after returning would fall back into the second
   branch, which would be incorrect.
   The solution is this macro: instead of marking the code as unreachable let's
   simply jump to the end of the specialized instruction after the call.  In the
   common case where there is no code to skip over GCC will optimize the jump
   away.
   This macro relies on JITTER_SPECIALIZED_INSTRUCTION_MANGLED_NAME having the
   correct definition at the time of the macro call, which is true if the macro
   is used as intended within user code for VM instructions. */
#define JITTER_JUMP_TO_SPECIALIZED_INSTRUCTION_END    \
  do                                                  \
    {                                                 \
      goto JITTER_SPECIALIZED_INSTRUCTION_END_LABEL;  \
    }                                                 \
  while (false)




/* Avoiding GCC tail-merging optimizations with replicated code.
 * ************************************************************************** */

/* The problem is performing the equivalent of goto * while avoiding
   tail-merging, which would be disastrous in replicated code when the shared
   jumping instruction happened to be out of the current VM instruction
   block. */

/* Define a trivial wrapper around GNU C's computed goto.  This will be used for
   direct threading, where tail-merging is not a problem, and for defect
   replacement in non-relocatable instructions, so that even tail-merging or
   PC-relative memory access cannot be a problem.. */
#define JITTER_COMPUTED_GOTO_FALLBACK(target)  \
  do                                           \
    {                                          \
      /* FIXME: the cast at the next line is questionable, and can in fact  \
         hide bugs elsewhere.  I am including it tentatively so as not to   \
         break GCC 12, which I cannot test yet as of 2022-01-25. */         \
      goto * (void*) (target);                 \
    }                                          \
  while (false)

/* Perform the equivalent of a goto * in assembly, using unique inline asm code,
   different from any other.  This is useful to avoid tail-merging, which would
   be disastrous in replicated code when the shared jumping instruction happened
   to be out of the current VM instruction block.

   The gotolabel declared in the inline asm statement is the "jump anywhere"
   label, actually unreachable at run time, but branching to an undetermined
   label; this is enough for GCC to assume the following to be any VM
   instruction.
   The actual jump target, which is always the beginning of the VM instruction,
   is given as the first inline asm input.  The second input, not really used in
   practice but needed to satisfy GCC, is again the "jump anywhere" label as an
   expression -- without it, I've seen GCC 8 snapshots ICE at the following
   __builtin_unreachable () with "error: flow control insn inside a basic
   block".  Omitting __builtin_unreachable () is a no-no, as it enormously
   simplifies the control-flow graph, and provides more opportunities for
   optimization.

   This relies, of course, on the architecture-specific assembly syntax for
   jumping thru a register or memory, along with the appropriate input operand
   constaraint, to be defined in jitter-machine.h .

   JITTER_ASM_COMPUTED_GOTO_TEMPLATE holds the asm template as a string literal,
   using an input argument named _jitter_the_target .
   JITTER_ASM_COMPUTED_GOTO_INPUT_CONSTRAINT is the input constraint for the
   target expression as a string literal, typically "r" but occasionally "rm"
   on CISC architectrues. */
#if    (! defined(JITTER_ASM_COMPUTED_GOTO_TEMPLATE))          \
    || (! defined(JITTER_ASM_COMPUTED_GOTO_INPUT_CONSTRAINT))
  /* Fail if only one of the two architecture-specific macros for computed
     gotos in assembly is defined.  That should never happen. */
# if    defined(JITTER_ASM_COMPUTED_GOTO_TEMPLATE)          \
     || defined(JITTER_ASM_COMPUTED_GOTO_INPUT_CONSTRAINT)
#   error "only one of JITTER_ASM_COMPUTED_GOTO_TEMPLATE"
#   error "and JITTER_ASM_COMPUTED_GOTO_INPUT_CONSTRAINT is defined"
# endif
#else
  /* A few architectures (notably PowerPC) may also need clobbers to jump via
     register, but that is optional.  If no clobbers were defined, define them
     as empty. */
# if ! defined(JITTER_ASM_COMPUTED_GOTO_CLOBBERS)
#   define JITTER_ASM_COMPUTED_GOTO_CLOBBERS /* nothing */
# endif // ! defined(JITTER_ASM_COMPUTED_GOTO_CLOBBERS)
  /* If we arrived here we have all the information to define
     JITTER_COMPUTED_GOTO_IN_ASM . */
# define JITTER_COMPUTED_GOTO_IN_ASM(target)                                   \
    do                                                                         \
      {                                                                        \
        const void *_jitter_the_target = (const void*) (target);               \
        asm goto (JITTER_ASM_DEFECT_DESCRIPTOR                                 \
                  JITTER_ASM_COMMENT_UNIQUE("goto* in assembly to "            \
                                            JITTER_STRINGIFY(target) " "       \
                                            "at %[_jitter_the_target], "       \
                                            "not actually going to "           \
                                            "jitter_fake_target at "        \
                                            "%l[jitter_fake_target]")       \
                  JITTER_ASM_COMPUTED_GOTO_TEMPLATE                            \
                  : /* outputs */                                              \
                  : [_jitter_the_target]                                       \
                    JITTER_ASM_COMPUTED_GOTO_INPUT_CONSTRAINT                  \
                       (_jitter_the_target)                                    \
                    /* inputs */                                               \
                  : JITTER_ASM_COMPUTED_GOTO_CLOBBERS /* clobbers */           \
                  : jitter_fake_target /* gotolabels */);                   \
        /* This is an unconditional branch: the following statement in the     \
           same block is unreachable. */                                       \
        __builtin_unreachable();                                               \
      }                                                                        \
    while (false)
#endif // #if (! defined(JITTER_ASM_COMPUTED_GOTO_TEMPLATE)) || (! defined ...

/* With direct-threading there is no need to worry about branches in
   assembly. */
#if defined (JITTER_DISPATCH_DIRECT_THREADING)
# undef JITTER_COMPUTED_GOTO_IN_ASM
#endif




/* VM branching.
 * ************************************************************************** */

/* Set the VM instruction pointer.  This is only defined for dispatches where an
   instruction pointer exists. */
#if      defined(JITTER_DISPATCH_SWITCH)             \
      || defined(JITTER_DISPATCH_DIRECT_THREADING)   \
      || defined(JITTER_DISPATCH_MINIMAL_THREADING)
# define JITTER_SET_IP(target_pointer)                            \
    do                                                            \
      {                                                           \
        jitter_ip = (const union jitter_word*) (target_pointer);  \
      }                                                           \
    while (false)
#endif // #if      defined(JITTER_DISPATCH_SWITCH) || ...

/* Jump to the current VM instruction pointer.  This is only defined for
   dispatches where an instruction pointer is actually used. */
#if      defined(JITTER_DISPATCH_SWITCH)
# define JITTER_BRANCH_TO_IP()                 \
    do                                         \
      {                                        \
        goto jitter_dispatching_switch_label;  \
      }                                        \
    while (false)
#elif    defined(JITTER_DISPATCH_DIRECT_THREADING)   \
      || defined(JITTER_DISPATCH_MINIMAL_THREADING)
# define JITTER_BRANCH_TO_IP()                 \
    JITTER_COMPUTED_GOTO (jitter_ip->thread)
#endif // #if   defined(...

/* Branch to a given VM label, represented as appropriate for the dispatch. */
#ifdef JITTER_DISPATCH_NO_THREADING
# define _JITTER_BRANCH(target)    \
    JITTER_COMPUTED_GOTO(target)
#else
#define _JITTER_BRANCH(target_pointer)  \
  do                                   \
    {                                  \
      JITTER_SET_IP(target_pointer);   \
      JITTER_BRANCH_TO_IP();           \
    }                                  \
  while (false)
#endif // #ifdef JITTER_DISPATCH_NO_THREADING

/* _JITTER_PROCEDURE_PROLOG is only used by generated code in callee
   instructions, and is not intended for the user.  The user is only supposed to
   read JITTER_LINK , which holds the value set by _JITTER_PROCEDURE_PROLOG --
   either as defined here or in a machine-specific definition. */
# define __JITTER_PROCEDURE_PROLOG_COMMON(link_union)            \
    do                                                           \
      {                                                          \
        (link_union).pointer                                     \
          = (void *) (jitter_state_runtime._jitter_link.label);  \
      }                                                          \
    while (false)
#if    defined(JITTER_DISPATCH_SWITCH)             \
    || defined(JITTER_DISPATCH_DIRECT_THREADING)   \
    || defined(JITTER_DISPATCH_MINIMAL_THREADING)  \
    || (defined(JITTER_DISPATCH_NO_THREADING)      \
        && ! JITTER_MACHINE_SUPPORTS_PROCEDURE)
# undef _JITTER_PROCEDURE_PROLOG
# define _JITTER_PROCEDURE_PROLOG(link_union)  \
    __JITTER_PROCEDURE_PROLOG_COMMON(link_union)
#endif

/* Branch-and-link to a given VM label, represented in a way appropriate for the
   dispatch.
   A branch-and-link operation unconditionally branches to a VM target, and also
   saves the return address (the beginning of the following VM instruction,
   ignoring any code in the caller instruction past the branch-and-link) in some
   implementation-specific resource, only up to the end of the callee
   instruction.
   The saved return access is accessible in reading from the target VM
   instruction, which *must* be a callee instruction, and only reachable thru
   branch-and-link , as JITTER_LINK .

   This is a generic definition which works everywhere but does not exploit the
   hardware branch target predictor like a machine-specific implementation
   could.  Return operations will easily mispredict.

   This macro is reserved for internal use.  The macro intended for the user
   is named JITTER_BRANCH_AND_LINK , and is only visible from caller
   instructions; this forces the user to correctly declare callers so that
   return labels can be handled in every case. */
#if    defined(JITTER_DISPATCH_SWITCH)             \
    || defined(JITTER_DISPATCH_DIRECT_THREADING)   \
    || defined(JITTER_DISPATCH_MINIMAL_THREADING)
# define _JITTER_BRANCH_AND_LINK_FALLBACK(target_rvalue)                      \
    do                                                               \
      {                                                              \
        jitter_state_runtime._jitter_link.label                      \
          = ((const union jitter_word *)                             \
             (jitter_ip + JITTER_SPECIALIZED_INSTRUCTION_WORD_NO));  \
        JITTER_BRANCH(target_rvalue);                                \
      }                                                              \
    while (false)
#elif    defined(JITTER_DISPATCH_NO_THREADING)
    /* This is the solution for no-threading on architectures where procedures
       are not supported or for procedure-related defect replacement, still
       only no-threading. */
#   define _JITTER_BRANCH_AND_LINK_FALLBACK(target_rvalue)                     \
      do                                                                       \
        {                                                                      \
          /* Use the return address from the implicit specialized argument */  \
          jitter_state_runtime._jitter_link.label = _JITTER_RETURN_ADDRESS;    \
          JITTER_BRANCH(target_rvalue);                                        \
        }                                                                      \
      while (false)
#else
# error "unknown dispatch"
#endif

/* Define the branch-and-link operation, using either the fallback version above
   or a native version.  Again this macro, whose name starts with an underscore,
   is not meant for the user. */
#if (defined(JITTER_DISPATCH_NO_THREADING)           \
     && defined(JITTER_MACHINE_SUPPORTS_PROCEDURE))
# define _JITTER_BRANCH_AND_LINK(target_rvalue)                      \
  /* Fast case: a native implementation is available and usable. */  \
  _JITTER_BRANCH_AND_LINK_NATIVE (target_rvalue)
#else
# define _JITTER_BRANCH_AND_LINK(target_rvalue)     \
  /* Slow case. */                                  \
  _JITTER_BRANCH_AND_LINK_FALLBACK (target_rvalue)
#endif

/* Sanity checks, useful for writing new ports. */
#if (defined(JITTER_DISPATCH_NO_THREADING)               \
     && defined(JITTER_MACHINE_SUPPORTS_PROCEDURE)       \
     && ! defined(_JITTER_BRANCH_AND_LINK_WITH_NATIVE))
# error "The machine claims to support procedures but lacks a definition"
# error "for _JITTER_BRANCH_AND_LINK_WITH_NATIVE .  Cannot use no-threading."
#endif // #if ... sanity check.

/* Define the branch-and-link-with fallback operation, in a way similar to
   _JITTER_BRANCH_AND_LINK_FALLBACK just above. */
# define _JITTER_BRANCH_AND_LINK_WITH_FALLBACK(_jitter_target_rvalue,  \
                                               _jitter_new_link)       \
    do                                                                 \
      {                                                                \
        jitter_state_runtime._jitter_link.label                        \
          = (void *) (_jitter_new_link);                               \
        JITTER_BRANCH (_jitter_target_rvalue);                         \
      }                                                                \
    while (false)

#if    defined(JITTER_DISPATCH_SWITCH)                    \
    || defined(JITTER_DISPATCH_DIRECT_THREADING)          \
    || defined(JITTER_DISPATCH_MINIMAL_THREADING)         \
    || (defined(JITTER_DISPATCH_NO_THREADING)             \
        && ! defined(JITTER_MACHINE_SUPPORTS_PROCEDURE))
# undef _JITTER_BRANCH_AND_LINK_WITH
# define _JITTER_BRANCH_AND_LINK_WITH  \
    _JITTER_BRANCH_AND_LINK_WITH_FALLBACK
#elif defined(JITTER_DISPATCH_NO_THREADING)          \
      && defined(JITTER_MACHINE_SUPPORTS_PROCEDURE)
# undef _JITTER_BRANCH_AND_LINK_WITH
# define _JITTER_BRANCH_AND_LINK_WITH \
    _JITTER_BRANCH_AND_LINK_WITH_NATIVE
#else
# error "This should never happen."
#endif

/* An internal definition used for JITTER_RETURN .  This relies on no
   machine-specific features, works with all dispatches, and even works
   when call-related VM instructions are defective. */
# define _JITTER_RETURN_FALLBACK(link_rvalue)  \
    do                                         \
      {                                        \
        JITTER_BRANCH(link_rvalue);            \
      }                                        \
    while (false)

/* Return to the caller, using the label provided as the rvalue parameter as the
   destination.  In its generic implementation this is a simple unconditional
   branch, but of course machine-specific implementation will use native return
   or branch-to-link-register instruction, with better branch target prediction
   performance.
   _JITTER_RETURN will be used (though the user-accessible macro JITTER_RETURN)
   when call-related instructions are not defective. */
#if    defined(JITTER_DISPATCH_SWITCH)                     \
    || defined(JITTER_DISPATCH_DIRECT_THREADING)           \
    || defined(JITTER_DISPATCH_MINIMAL_THREADING)          \
    || (defined(JITTER_DISPATCH_NO_THREADING)              \
        && ! defined (JITTER_MACHINE_SUPPORTS_PROCEDURE))
# undef _JITTER_RETURN
# define _JITTER_RETURN(link_rvalue)  \
    _JITTER_RETURN_FALLBACK(link_rvalue)
#endif


/* VM conditional non-fast branching.
 * ************************************************************************** */

/* These macros are used internally in replacement instructions, as alternatives
   to fast conditional branches.  They are not very useful for human users, as
   they expand to the same code generated by unconditional branches within
   conditionals; however their direct use is not forbidden. */

/* This macro is only used internally in the following macro definitions in this
   section. */
#define _JITTER_BRANCH_IF(outer_operator, type, operand0,    \
                          infix_operator, operand1, target)  \
  do                                                         \
    {                                                        \
      if (outer_operator ((type) (operand0)                  \
                          infix_operator                     \
                          (type) (operand1)))                \
        JITTER_BRANCH (target);                              \
    }                                                        \
  while (false)

/* These are the non-fast counterparts of the similarly named macros in
   jitter-fast-branch.h and the machine-specific headers. */
#define JITTER_BRANCH_IF_ZERO(operand, target)            \
  _JITTER_BRANCH_IF(, jitter_uint, operand, ==, 0, target)
#define JITTER_BRANCH_IF_NONZERO(operand, target)         \
  _JITTER_BRANCH_IF(, jitter_uint, operand, !=, 0, target)
#define JITTER_BRANCH_IF_POSITIVE(operand, target)      \
  _JITTER_BRANCH_IF(, jitter_int, operand, >, 0, target)
#define JITTER_BRANCH_IF_NONPOSITIVE(operand, target)    \
  _JITTER_BRANCH_IF(, jitter_int, operand, <=, 0, target)
#define JITTER_BRANCH_IF_NEGATIVE(operand, target)      \
  _JITTER_BRANCH_IF(, jitter_int, operand, <, 0, target)
#define JITTER_BRANCH_IF_NONNEGATIVE(operand, target)    \
  _JITTER_BRANCH_IF(, jitter_int, operand, >=, 0, target)
#define JITTER_BRANCH_IF_EQUAL(operand0, operand1, target)     \
  _JITTER_BRANCH_IF(, jitter_int, operand0, ==, operand1, target)
#define JITTER_BRANCH_IF_NOTEQUAL(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(, jitter_int, operand0, !=, operand1, target)
#define JITTER_BRANCH_IF_LESS_SIGNED(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(, jitter_int, operand0, <, operand1, target)
#define JITTER_BRANCH_IF_LESS_UNSIGNED(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(, jitter_uint, operand0, <, operand1, target)
#define JITTER_BRANCH_IF_NOTLESS_SIGNED(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(, jitter_int, operand0, >=, operand1, target)
#define JITTER_BRANCH_IF_NOTLESS_UNSIGNED(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(, jitter_uint, operand0, >=, operand1, target)
#define JITTER_BRANCH_IF_GREATER_SIGNED(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(, jitter_int, operand0, >, operand1, target)
#define JITTER_BRANCH_IF_GREATER_UNSIGNED(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(, jitter_uint, operand0, >, operand1, target)
#define JITTER_BRANCH_IF_NOTGREATER_SIGNED(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(, jitter_int, operand0, <=, operand1, target)
#define JITTER_BRANCH_IF_NOTGREATER_UNSIGNED(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(, jitter_uint, operand0, <=, operand1, target)
#define JITTER_BRANCH_IF_AND(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(, jitter_uint, operand0, &, operand1, target)
#define JITTER_BRANCH_IF_NOTAND(operand0, operand1, target)  \
  _JITTER_BRANCH_IF(!, jitter_uint, operand0, &, operand1, target)

/* This factors the common code for branch-on-overflow primitives. */
#define JITTER_BRANCH_IF_OPERATION_OVERFLOWS(operation_name,     \
                                             operand0, operand1, \
                                             target)             \
  do                                                             \
    {                                                            \
      if (JITTER_CONCATENATE_THREE (JITTER_WOULD_,               \
                                    operation_name,              \
                                    _OVERFLOW)                   \
             (jitter_uint, jitter_int,                           \
              (operand0), (operand1),                            \
              JITTER_BITS_PER_WORD))                             \
        JITTER_BRANCH (target);                                  \
    }                                                            \
  while (false)

#define JITTER_BRANCH_IF_PLUS_OVERFLOWS(opd0, opd1, tgt)              \
  JITTER_BRANCH_IF_OPERATION_OVERFLOWS (PLUS, (opd0), (opd1), (tgt))
#define JITTER_BRANCH_IF_MINUS_OVERFLOWS(opd0, opd1, tgt)              \
  JITTER_BRANCH_IF_OPERATION_OVERFLOWS (MINUS, (opd0), (opd1), (tgt))
#define JITTER_BRANCH_IF_TIMES_OVERFLOWS(opd0, opd1, tgt)              \
  JITTER_BRANCH_IF_OPERATION_OVERFLOWS (TIMES, (opd0), (opd1), (tgt))
#define JITTER_BRANCH_IF_DIVIDED_OVERFLOWS(opd0, opd1, tgt)              \
  JITTER_BRANCH_IF_OPERATION_OVERFLOWS (DIVIDED, (opd0), (opd1), (tgt))
#define JITTER_BRANCH_IF_REMAINDER_OVERFLOWS(opd0, opd1, tgt)              \
  JITTER_BRANCH_IF_OPERATION_OVERFLOWS (REMAINDER, (opd0), (opd1), (tgt))
#define JITTER_BRANCH_IF_NEGATE_OVERFLOWS(opd0, tgt)              \
  JITTER_BRANCH_IF_OPERATION_OVERFLOWS (MINUS, 0, (opd0), (tgt))

/* This factors the common code for operate-and-branch-on-overflow primitives. */
#define JITTER_OPERATION_BRANCH_IF_OVERFLOW(res, operation_name,       \
                                            operand0, infix, operand1, \
                                            target)                    \
  do                                                                   \
    {                                                                  \
      const jitter_int _jitter_opd0_value = (jitter_int) (operand0);   \
      const jitter_int _jitter_opd1_value = (jitter_int) (operand1);   \
      if (JITTER_CONCATENATE_THREE (JITTER_WOULD_, operation_name,     \
                                    _OVERFLOW)                         \
             (jitter_uint, jitter_int,                                 \
              _jitter_opd0_value, _jitter_opd1_value,                  \
              JITTER_BITS_PER_WORD))                                   \
        JITTER_BRANCH (target);                                        \
      else                                                             \
        (res) = _jitter_opd0_value infix _jitter_opd1_value;           \
    }                                                                  \
  while (false)

#define JITTER_PLUS_BRANCH_IF_OVERFLOW(res, opd0, opd1, tgt)  \
  JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), PLUS, (opd0), +, (opd1), (tgt))
#define JITTER_MINUS_BRANCH_IF_OVERFLOW(res, opd0, opd1, tgt)  \
  JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), MINUS, (opd0), -, (opd1), (tgt))
#define JITTER_TIMES_BRANCH_IF_OVERFLOW(res, opd0, opd1, tgt)  \
  JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), TIMES, (opd0), *, (opd1), (tgt))
#define JITTER_DIVIDED_BRANCH_IF_OVERFLOW(res, opd0, opd1, tgt)  \
  JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), DIVIDED, (opd0), /, (opd1), (tgt))
#define JITTER_REMAINDER_BRANCH_IF_OVERFLOW(res, opd0, opd1, tgt)  \
  JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), REMAINDER, (opd0), %, (opd1), (tgt))
#define JITTER_NEGATE_BRANCH_IF_OVERFLOW(res, opd0, tgt)  \
  JITTER_OPERATION_BRANCH_IF_OVERFLOW ((res), MINUS, 0, -, (opd0), (tgt))

#endif // #ifndef JITTER_EXECUTOR_H_
