// vim: ts=4 sw=4 expandtab ft=c

// Copyright (C) 1995-2001, 2003-2007, 2009, 2011-2012 The University of Melbourne.
// Copyright (C) 2015-2016, 2018-2021 The Mercury team.
// This file is distributed under the terms specified in COPYING.LIB.

// mercury_goto.h - definitions for the "portable assembler" non-local gotos

#ifndef MERCURY_GOTO_H
#define MERCURY_GOTO_H

#include "mercury_conf.h"
#include "mercury_std.h"    // for MR_PASTE2 and MR_STRINGIFY
#include "mercury_types.h"  // for `MR_Code *'
#include "mercury_debug.h"  // for MR_debuggoto()
#include "mercury_label.h"  // for MR_insert_{entry,internal}_label()
#include "mercury_dummy.h"  // for MR_dummy_identify_function()

////////////////////////////////////////////////////////////////////////////

// Definitions for constructing the names of entry and internal labels,
// and the names of their layout structures.

#define MR_entry(label)     MR_PASTE2(_entry_,label)
#define MR_skip(label)      MR_PASTE2(skip_,label)

#define MR_add_prefix(label)                                             \
    MR_PASTE2(mercury__, label)

#define MR_label_name(proc_label, label)                                 \
    MR_PASTE3(proc_label, _i, label)

#define MR_proc_entry_user_name_base(mod, name, arity, mode)             \
    MR_PASTE7(mod, __, name, _, arity, _, mode)
#define MR_proc_entry_uci_name_base(mod, name, type, arity, mode)        \
    MR_PASTE9(name, _, mod, __, type, _, arity, _, mode)

#define MR_proc_entry_user_name(mod, name, arity, mode)                  \
    MR_PASTE2(mercury__,                                                 \
        MR_proc_entry_user_name_base(mod, name, arity, mode))
#define MR_proc_entry_uci_name(mod, name, type, arity, mode)             \
    MR_PASTE2(mercury__,                                                 \
        MR_proc_entry_uci_name_base(mod, name, type, arity, mode))

#define MR_proc_entry_user_name_str(mod, name, arity, mode)              \
    MR_STRINGIFY(MR_proc_entry_user_name(mod, name, arity, mode))
#define MR_proc_entry_uci_name_str(mod, name, type, arity, mode)         \
    MR_STRINGIFY(MR_proc_entry_uci_name(mod, name, type, arity, mode))

#define MR_proc_layout_user_name(mod, name, arity, mode)                 \
    MR_PASTE2(mercury_data__proc_layout__,                               \
        MR_proc_entry_user_name(mod, name, arity, mode))
#define MR_proc_layout_uci_name(mod, name, type, arity, mode)            \
    MR_PASTE2(mercury_data__proc_layout__,                               \
        MR_proc_entry_uci_name(mod, name, type, arity, mode))

#define MR_label_user_name_base(mod, name, a, mode, num)                 \
    MR_label_name(MR_proc_entry_user_name_base(mod, name, a, mode),      \
        num)
#define MR_label_uci_name_base(mod, name, type, a, mode, num)            \
    MR_label_name(MR_proc_entry_uci_name_base(mod, name, type, a, mode), \
        num)

#define MR_label_user_name(mod, name, a, mode, num)                      \
    MR_label_name(MR_proc_entry_user_name(mod, name, a, mode),           \
        num)
#define MR_label_uci_name(mod, name, type, a, mode, num)                 \
    MR_label_name(MR_proc_entry_uci_name(mod, name, type, a, mode),      \
        num)

#define MR_label_user_name_str(mod, name, arity, mode, num)              \
    MR_STRINGIFY(MR_label_user_name(mod, name, arity, mode, num))
#define MR_label_uci_name_str(mod, name, type, arity, mode, num)         \
    MR_STRINGIFY(MR_label_uci_name(mod, name, type, arity, mode, num))

#define MR_label_layout_user_name(mod, name, a, mode, num)               \
    MR_PASTE2(mercury_data__label_layout__,                              \
        MR_label_user_name(mod, name, a, mode, num))
#define MR_label_layout_uci_name(mod, name, type, a, mode, num)          \
    MR_PASTE2(mercury_data__label_layout__,                              \
        MR_label_uci_name(mod, name, type, a, mode, num))

////////////////////////////////////////////////////////////////////////////

#define MR_PROC_LAYOUT_NAME(label)                                       \
    MR_PASTE2(mercury_data__proc_layout__,label)
#define MR_LABEL_LAYOUT_NAME(label)                                      \
    MR_PASTE2(mercury_data__label_layout__,label)
#define MR_USER_LAYOUT_NAME(label)                                       \
    MR_PASTE2(mercury_data__user_event_layout__,label)

#define MR_PROC_LAYOUT(label)                                            \
    ((const MR_ProcLayout *) (MR_Word) &MR_PROC_LAYOUT_NAME(label))
#define MR_LABEL_LAYOUT(label)                                           \
    ((const MR_LabelLayout *) (MR_Word) &MR_LABEL_LAYOUT_NAME(label))

#define MR_PROC_LAYOUT1(label)                                           \
    MR_PROC_LAYOUT(MR_add_prefix(label)),

#define MR_LABEL_LAYOUT1(e, ln1)                                         \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1)),

#define MR_LABEL_LAYOUT2(e, ln1, ln2)                                    \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2)),

#define MR_LABEL_LAYOUT3(e, ln1, ln2, ln3)                               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3)),

#define MR_LABEL_LAYOUT4(e, ln1, ln2, ln3, ln4)                          \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4)),

#define MR_LABEL_LAYOUT5(e, ln1, ln2, ln3, ln4, ln5)                     \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln5)),

#define MR_LABEL_LAYOUT6(e, ln1, ln2, ln3, ln4, ln5, ln6)                \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln5)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln6)),

#define MR_LABEL_LAYOUT7(e, ln1, ln2, ln3, ln4, ln5, ln6, ln7)           \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln5)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln6)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln7)),

#define MR_LABEL_LAYOUT8(e, ln1, ln2, ln3, ln4, ln5, ln6, ln7, ln8)      \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln5)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln6)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln7)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln8)),

#define MR_LABEL_LAYOUT9(e, ln1, ln2, ln3, ln4, ln5, ln6, ln7, ln8, ln9) \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln5)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln6)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln7)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln8)),               \
    MR_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln9)),

#define MR_DECL_LABEL_LAYOUT(label)                                      \
    static const MR_LabelLayout MR_LABEL_LAYOUT_NAME(label);

#define MR_DECL_LABEL_LAYOUT1(e, ln1)                                    \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1))

#define MR_DECL_LABEL_LAYOUT2(e, ln1, ln2)                               \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2))

#define MR_DECL_LABEL_LAYOUT3(e, ln1, ln2, ln3)                          \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3))

#define MR_DECL_LABEL_LAYOUT4(e, ln1, ln2, ln3, ln4)                     \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4))

#define MR_DECL_LABEL_LAYOUT5(e, ln1, ln2, ln3, ln4, ln5)                \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln5))

#define MR_DECL_LABEL_LAYOUT6(e, ln1, ln2, ln3, ln4, ln5, ln6)           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln5))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln6))

#define MR_DECL_LABEL_LAYOUT7(e, ln1, ln2, ln3, ln4, ln5, ln6, ln7)      \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln5))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln6))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln7))

#define MR_DECL_LABEL_LAYOUT8(e, ln1, ln2, ln3, ln4, ln5, ln6, ln7, ln8) \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln5))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln6))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln7))           \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln8))

#define MR_DECL_LABEL_LAYOUT9(e, ln1, ln2, ln3, ln4, ln5, ln6, ln7, ln8, ln9) \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln1))                \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln2))                \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln3))                \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln4))                \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln5))                \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln6))                \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln7))                \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln8))                \
    MR_DECL_LABEL_LAYOUT(MR_label_name(MR_add_prefix(e), ln9))

////////////////////////////////////////////////////////////////////////////

// Passing the name of a label to MR_insert_{internal,entry}_label
// causes that name to be included in the executable as static readonly data.
// Since label names are quite big, we include them only when needed.

#if defined(MR_INSERT_INTERNAL_LABEL_NAMES)
  #define MR_insert_internal(n, a, l)   MR_insert_internal_label(n, a,        \
                                            (const struct MR_LabelLayout *) l)
#else
  #define MR_insert_internal(n, a, l)   MR_insert_internal_label(NULL, a, l)
#endif

#if defined(MR_INSERT_ENTRY_LABEL_NAMES)
  #define MR_insert_entry(n, a, l)  MR_insert_entry_label(n, a, l)
#else
  #define MR_insert_entry(n, a, l)  MR_insert_entry_label(NULL, a, l)
#endif

////////////////////////////////////////////////////////////////////////////

// Taking the address of a label can inhibit gcc's optimization, because it
// assumes that anything can jump there. Therefore we want to do it only if
// we are debugging, or if we need the label address for profiling or for
// accurate garbage collection.
//
// The versions of the macros below with the _ai, _an or _sl suffix always
// insert the label into the label table, the difference between them being
// that the _ai and _an variants do not include a layout structure. If the
// label *has* a layout structure, use the _sl variant. The difference between
// the _ai and the _an variants is that the latter always inserts the name
// of the label as well. This is intended for a small number of labels that
// are frequently needed in debugging, e.g. MR_do_fail.

#define MR_make_label_ai(n, a, l)   MR_insert_internal(n, a, NULL)
#define MR_make_label_an(n, a, l)   MR_insert_internal_label(n, a, NULL)
#define MR_make_label_sl(n, a, l)   MR_insert_internal(n, a, l)

#define MR_make_local_ai(n, a, l)   MR_insert_entry(n, a, NULL)
#define MR_make_local_an(n, a, l)   MR_do_insert_entry_label(n, a, NULL)
#define MR_make_local_sl(n, a, l)   MR_insert_entry(n, a, MR_PROC_LAYOUT(l))

#define MR_make_entry_ai(n, a, l)   MR_insert_entry(n, a, NULL)
#define MR_make_entry_an(n, a, l)   MR_do_insert_entry_label(n, a, NULL)
#define MR_make_entry_sl(n, a, l)   MR_insert_entry(n, a, MR_PROC_LAYOUT(l))

////////////////////////////////////////////////////////////////////////////

#if defined(MR_INSERT_LABELS)
  #define MR_make_label(n, a, l)        MR_make_label_ai(n, a, l)
#else
  #define MR_make_label(n, a, l)        // nothing
#endif

#if defined(MR_INSERT_LABELS) || defined(MR_MPROF_PROFILE_CALLS)
  #define MR_make_local(n, a, l)        MR_make_local_ai(n, a, l)
#else
  #define MR_make_local(n, a, l)        // nothing
#endif

// Note that for the MLDS back-end, the calls to MR_init_entry(), which
// eventually expand to MR_make_entry(), are only output if the right
// compiler options are enabled. So if you change the condition of this
// `#ifdef', and you want your changes to apply to the MLDS back-end too,
// you may also need to change the `need_to_init_entries' predicate
// in compiler/mlds_to_c.m.

#if defined(MR_INSERT_LABELS) || defined(MR_MPROF_PROFILE_CALLS)
  #define MR_make_entry(n, a, l)        MR_make_entry_ai(n, a, l)
#else
  #define MR_make_entry(n, a, l)        // nothing
#endif

#ifdef MR_SPLIT_C_FILES
  #define MR_MODULE_STATIC_OR_EXTERN extern
#else
  #define MR_MODULE_STATIC_OR_EXTERN static
#endif

////////////////////////////////////////////////////////////////////////////

// MACHINE SPECIFIC STUFF REQUIRED FOR NON-LOCAL GOTOS

#if defined(__i386__) || defined(__mc68000__) || defined(__x86_64__)

  // This hack is to prevent gcc 4.x optimizing away stores to succip before
  // jumping to a label in asm_fast.

  #if defined(MR_USE_GCC_GLOBAL_REGISTERS)
    #define MR_FORCE_SUCCIP_STORE                                        \
    __asm__ __volatile__(""                                              \
        : "=r"(MR_succip_word)                                           \
        : "0"(MR_succip_word)                                            \
        )
  #else
    #define MR_FORCE_SUCCIP_STORE   ((void) 0)
  #endif

  // The following hack works around a stack leak on the i386.
  // (and apparently the 68000 and x86_64 too).
  //
  // The problem is that gcc pushes function parameters onto the stack
  // when calling C functions such as GC_malloc(), and only restores
  // the stack pointer in the epilogue. With non-local gotos, we jump out
  // of the function without executing its epilogue, so the stack pointer
  // never gets restored. The result is a memory leak; for example,
  // `mmc --generate-dependencies mercury_compile' exceeds the Slackware Linux
  // default stack space limit of 8M.
  //
  // GNU C has an option `-fno-defer-pop' which is supposed to avoid this
  // sort of thing, but it doesn't work for our code using non-local gotos.
  //
  // We work around this using the dummy assembler code below, which pretends
  // to use the stack pointer, forcing gcc to flush any updates of the stack
  // pointer immediately, rather than deferring them until the function
  // epilogue.
  //
  // I know this is awful. It wasn't _my_ idea to use non-local gotos ;-)

  #if defined(__i386__)
    #define MR_ASM_JUMP(label)                                           \
    { register int stack_pointer __asm__("esp");                         \
    __asm__("" : : "g"(stack_pointer)); }                                \
    MR_FORCE_SUCCIP_STORE;                                               \
    goto *(label)
  #elif defined(__x86_64__)
    #define MR_ASM_JUMP(label)                                           \
    { register int stack_pointer __asm__("rsp");                         \
    __asm__("" : : "g"(stack_pointer)); }                                \
    MR_FORCE_SUCCIP_STORE;                                               \
    goto *(label)
  #elif defined(__mc68000__)
    #define MR_ASM_JUMP(label)                                           \
    { register int stack_pointer __asm__("sp");                          \
    __asm__("" : : "g"(stack_pointer)); }                                \
    goto *(label)
  #endif

  // That hack above needs to be done for all non-local jumps,
  // even if we are not using assembler labels.

  #define MR_JUMP(label)    MR_ASM_JUMP(label)

  // If we are using position-independent code, then we need to set up
  // the correct value of the GOT register (ebx on 386 or a5 on m68000).

  #if MR_PIC

    // At each entry point, where we may have been jump to from code in a
    // different C file, we need to set up `ebx'. We do this by pushing
    // the IP register using a `call' instruction whose target is the
    // very next label. We then pop this off the stack into `ebx', and
    // then use the value obtained to compute the correct value of `ebx'
    // by doing something with _GLOBAL_OFFSET_TABLE_ (I don't understand
    // the details exactly, this code is basically copied from the output
    // of `gcc -fpic -S'.) Note that `0f' means the label `0:' following
    // the current instruction, and `0b' means the label `0:' before
    // the current instruction.
    //
    // Note: this code clobbers `ebx', which is a callee-save register.
    // That means that it is essential that call_engine() save `ebx'
    // before entering Mercury code, and restore it before returning to C code.
    // However, gcc and/or setjmp()/longjmp() will do that for us
    // automatically, precisely because it is a callee-save register.
    //
    // This does not work with GCC 5+ because GCC no longer reserves `ebx'
    // to hold the GOT address; the code we jump into may expect to find
    // the GOT address in a different location.
    //

    #if defined(__i386__)

      #if defined(MR_USE_GCC_NONLOCAL_GOTOS) && (__GNUC__ >= 5)
          #error "Non-local jumps into x86 PIC will not work with GCC 5+"
      #endif

      #define MR_EBX "%%ebx"

      #define MR_INLINE_ASM_FIXUP_REGS                                   \
    "   call 0f\n"                                                       \
    "0:\n"                                                               \
    "   popl " MR_EBX "\n"                                               \
    "   addl $_GLOBAL_OFFSET_TABLE_+[.-0b]," MR_EBX "\n\t"               \
        : :
#if 0
    // The following doesn't seem to be necessary, and leaving it out
    // might make gcc generate slightly better code.

        // tell gcc we clobber ebx and memory
        : : : "%ebx", "memory"
#endif
    #elif defined(__mc68000__)

    // This piece of magic thanks to Roman Hodek
    // <Roman.Hodek@informatik.uni-erlangen.de>

      #define MR_INLINE_ASM_FIXUP_REGS                                   \
        "       lea (%%pc,_GLOBAL_OFFSET_TABLE_@GOTPC),%%a5\n" : : : "memory"

    #endif

    // It is safe to fall through into MR_INLINE_ASM_FIXUP_REGS,
    // but it might be more efficient to branch past it.
    // We should really measure both ways and find out which is
    // better... for the moment, we just fall through, since
    // that keeps the code smaller.

    #if 0
      #define MR_ASM_FALLTHROUGH(label)                                  \
    goto MR_skip(label);
    #endif

  #endif // MR_PIC

  // For Linux-ELF shared libraries, we need to declare that the type of labels
  // is @function (i.e. code, not data), otherwise the dynamic linker seems
  // to get confused, and we end up jumping into the data section.
  // Hence the `.type' directive below.

  #ifdef __ELF__
    #define MR_INLINE_ASM_ENTRY_LABEL_TYPE(label)                        \
    "   .type _entry_" MR_STRINGIFY(label) ",@function\n"
  #endif

#elif defined (__sparc)

  // If we are using position-independent code on the SPARC, then we need to
  // set up the correct value of the GOT register (l7).

  #if (defined(__pic__) || defined(__PIC__)) && !defined(MR_PIC)
    #define MR_PIC 1
  #endif

  #if MR_PIC

    // At each entry point, where we may have been jump to from
    // code in a difference C file, we need to set up `l7'.
    // We do this by getting the value the of the IP register using a `call'
    // instruction whose target is the very next label; this will
    // put the address of the call instruction in register `o7'.
    // We then use the value obtained in register `o7' to compute the correct
    // value of register `l7' by doing something with _GLOBAL_OFFSET_TABLE_
    // (I don't understand the details exactly, this code is
    // basically copied from the output of `gcc -fpic -S'.)
    // Note that `1f' means the label `1:' following the current instruction,
    // and `0b' means the label `0:' before the current instruction.

    #define MR_INLINE_ASM_FIXUP_REGS                                     \
    "0:\n"                                                               \
    "   call 1f\n"                                                       \
    "   nop\n"                                                           \
    "1:\n"                                                               \
    "   sethi %%hi(_GLOBAL_OFFSET_TABLE_-(0b-.)),%%l7\n"                 \
    "   or %%l7,%%lo(_GLOBAL_OFFSET_TABLE_-(0b-.)),%%l7\n"               \
    "   add %%l7,%%o7,%%l7\n"                                            \
        /* tell gcc we clobber l7, o7, and memory */                     \
        : : : "%l7", "%o7", "memory"

    // It is safe to fall through into MR_INLINE_ASM_FIXUP_REGS,
    // but it might be more efficient to branch past it.
    // We should really measure both ways and find out which is better...
    // for the moment, we just fall through, since that keeps the code smaller.

    #if 0
      #define MR_ASM_FALLTHROUGH(label)                                  \
    goto MR_skip(label);
    #endif

  #endif // MR_PIC

  // For Solaris 5.5.1, we need to declare that the type of labels is
  // #function (i.e. code, not data), otherwise the dynamic linker seems
  // to get confused, and we end up jumping into the data section.
  // Hence the `.type' directive below.

  #ifndef MR_CANNOT_GROK_ASM_TYPE_DIRECTIVE
    #define MR_INLINE_ASM_ENTRY_LABEL_TYPE(label)                        \
    "   .type _entry_" MR_STRINGIFY(label) ",#function\n"
  #endif

#elif defined(__arm__)

   // The following code for supporting non-local gotos and PIC on ARM
   // is thanks to Sergey Khorev <iamphet@nm.ru>.

  #if MR_PIC

     // At each entry point, where we may have been jumped to from code
     // in a different C file, we need to set up the PIC register.
     // We do this by adding _GLOBAL_OFFSET_TABLE_ value to the PC register
     // Current instruction address is (PC - 8) hence -(0b + 8)
     // (I don't understand the details exactly, this code is basically copied
     // from the output of `gcc -fpic -S' for a function containing setjmp.)
     // A little bit more detail can be obtained from GCC source
     // (function arm_finalize_pic in gcc/config/arm/arm.c)
     // Note that `0f' means the label `0:' following the current instruction,
     // and `0b' means the label `0:' before the current instruction.
     // GCC doesn't like it when we clobber the PIC register but it seems
     // we can safely keep GCC uninformed because we just do GCC's work
     // and the PIC register is saved over calls.
     // Loading arbitrary immediate values into ARM registers is not possible
     // directly hence the .word directive in the code section and the branch
     // instruction bypassing it.
     // If you change MR_ARM_PIC_REG, update CFLAGS_FOR_PIC (-mpic-register)
     // in configure.ac.

    #define MR_ARM_PIC_REG "sl"

    #define MR_INLINE_ASM_FIXUP_REGS                                     \
       "        ldr " MR_ARM_PIC_REG ", 1f\n"                            \
       "0:\n"                                                            \
       "        add " MR_ARM_PIC_REG ", pc, " MR_ARM_PIC_REG "\n"        \
       "        b 2f\n"                                                  \
       "1:\n"                                                            \
       "        .word   _GLOBAL_OFFSET_TABLE_-(0b+8)\n"                  \
       "2:\n"

     // For Linux-ELF shared libraries, we need to declare that the type of
     // labels is #function (i.e. code, not data), otherwise the dynamic
     // linker seems to get confused, and we end up jumping into the data
     // section. Hence the `.type' directive below.

    #ifdef __ELF__
      #define MR_INLINE_ASM_ENTRY_LABEL_TYPE(label)                      \
        " .type _entry_" MR_STRINGIFY(label) ",#function\n"
    #endif

     // Save a few clock ticks branching past MR_INLINE_ASM_FIXUP_REGS.

    #define MR_ASM_FALLTHROUGH(label)                                    \
      goto MR_skip(label);

  #endif

#elif defined(__aarch64__)

   #if MR_PIC

     // For Linux-ELF shared libraries, we need to declare that the type of
     // labels is #function (i.e. code, not data), otherwise the dynamic
     // linker seems to get confused, and we end up jumping into the data
     // section. Hence the `.type' directive below.

    #ifdef __ELF__
      #define MR_INLINE_ASM_ENTRY_LABEL_TYPE(label)                      \
        " .type _entry_" MR_STRINGIFY(label) ",#function\n"
    #endif

   #endif

#endif

////////////////////////////////////////////////////////////////////////////

// For other architectures, these macros have default definitions.

// MR_INLINE_ASM_FIXUP_REGS is used to fix up the value of
// any registers after an MR_ASM_JUMP to an entry point, if necessary.
// It is an assembler string, possibly followed by `: : : <clobbers>'
// where <clobbers> is an indication to gcc of what gets clobbered.

#ifdef MR_INLINE_ASM_FIXUP_REGS
  #define MR_ASM_FIXUP_REGS                                              \
    __asm__ __volatile__(                                                \
        MR_INLINE_ASM_FIXUP_REGS                                         \
    );
#else
  #define MR_ASM_FIXUP_REGS
  #define MR_INLINE_ASM_FIXUP_REGS
#endif

// MR_ASM_FALLTHROUGH is executed when falling through into an entry point.
// It may call `goto MR_skip(label)' if it wishes to skip past the
// label and the MR_INLINE_ASM_FIXUP_REGS code.

#ifndef MR_ASM_FALLTHROUGH
#define MR_ASM_FALLTHROUGH(label)
#endif

// MR_INLINE_ASM_GLOBALIZE_LABEL is an assembler string to declare
// an entry label as global. The following definition using `.globl'
// should work with the GNU assembler and with most Unix assemblers.

#ifndef MR_INLINE_ASM_GLOBALIZE_LABEL
#define MR_INLINE_ASM_GLOBALIZE_LABEL(label)                             \
    "   .globl _entry_" MR_STRINGIFY(label) "\n"
#endif

// MR_INLINE_ASM_ENTRY_LABEL_TYPE is an assembler string to declare the "type"
// of a label as function (i.e. code), not data, if this is needed.

#ifndef MR_INLINE_ASM_ENTRY_LABEL_TYPE
#define MR_INLINE_ASM_ENTRY_LABEL_TYPE(label)
#endif

// MR_INLINE_ASM_ENTRY_LABEL is an assembler string to define
// an assembler entry label.

#ifndef MR_INLINE_ASM_ENTRY_LABEL
#define MR_INLINE_ASM_ENTRY_LABEL(label)                                 \
    "_entry_" MR_STRINGIFY(label) ":\n"
#endif

// MR_INLINE_ASM_COMMENT is an assembler string to
// define an assembler comment.

#ifndef MR_INLINE_ASM_COMMENT
#define MR_INLINE_ASM_COMMENT(label)                                     \
    "// " MR_STRINGIFY(label) "\n"
#endif

// MR_ASM_JUMP is used to jump to an entry point defined with
// MR_ASM_ENTRY, MR_ASM_STATIC_ENTRY, or MR_ASM_LOCAL_ENTRY.

#ifndef MR_ASM_JUMP
#define MR_ASM_JUMP(address)    goto *(address)
#endif

////////////////////////////////////////////////////////////////////////////

// The code from here on should be architecture-independent.

////////////////////////////////////////////////////////////////////////////

// MR_ASM_ENTRY is used to declare an external entry point
// using a (global) assembler label.

#define MR_ASM_ENTRY(label)                                              \
    MR_ASM_FALLTHROUGH(label)                                            \
    MR_entry(label):                                                     \
    __asm__ __volatile__(                                                \
        MR_INLINE_ASM_GLOBALIZE_LABEL(label)                             \
        MR_INLINE_ASM_ENTRY_LABEL_TYPE(label)                            \
        MR_INLINE_ASM_ENTRY_LABEL(label)                                 \
        MR_INLINE_ASM_FIXUP_REGS                                         \
    );                                                                   \
    MR_skip(label): ;

// MR_ASM_STATIC_ENTRY is the same as MR_ASM_ENTRY,
// except that its scope is local to a C file, rather than global.
// Note that even static entry points must do MR_INLINE_ASM_FIXUP_REGS,
// since although there won't be any direct calls to them from another C file,
// their address may be taken and so there may be indirect calls.

#define MR_ASM_STATIC_ENTRY(label)                                       \
    MR_ASM_FALLTHROUGH(label)                                            \
    MR_entry(label):                                                     \
    __asm__ __volatile__(                                                \
        MR_INLINE_ASM_ENTRY_LABEL_TYPE(label)                            \
        MR_INLINE_ASM_ENTRY_LABEL(label)                                 \
        MR_INLINE_ASM_FIXUP_REGS                                         \
    );                                                                   \
    MR_skip(label): ;

// MR_ASM_LOCAL_ENTRY is the same as MR_ASM_ENTRY,
// except that its scope is local to a MR_BEGIN_MODULE...MR_END_MODULE
// block, rather than being global.
// Note that even local entry points must do MR_INLINE_ASM_FIXUP_REGS, since
// although there won't be any direct calls to them from another
// C file, their address may be taken and so there may be indirect calls.
//
// We need to use MR_ASM_COMMENT here to ensure that the code following
// each label is distinct; this is needed to ensure GCC doesn't try to merge
// two labels which point to identical code, but for which we have different
// information stored in the stack layout structs, etc.

#define MR_ASM_LOCAL_ENTRY(label)                                        \
    MR_ASM_FALLTHROUGH(label)                                            \
    MR_entry(label):                                                     \
    __asm__ __volatile__(                                                \
        MR_INLINE_ASM_COMMENT(label)                                     \
        MR_INLINE_ASM_FIXUP_REGS                                         \
    );                                                                   \
    MR_skip(label): ;

////////////////////////////////////////////////////////////////////////////

#if defined(MR_USE_GCC_NONLOCAL_GOTOS)

  #ifndef MR_GNUC
  #error "You must use gcc if you define MR_USE_GCC_NONLOCAL_GOTOS"
  #endif

  // Define the type of a module initialization function
  typedef void MR_ModuleFunc(void);

  // The following macro expands to a dummy assembler statement which
  // contains no code, but which tells gcc that it uses the specified address
  // as an input value. This is used to trick gcc into thinking that
  // the address is used, in order to suppress unwanted optimizations.
  // (We used to use `volatile_global_pointer = address' to suppress
  // optimization, but this way is better because it doesn't generate
  // any code.)

  #define MR_PRETEND_ADDRESS_IS_USED(address)                            \
    __asm__ __volatile__("" : : "g"(address))
  // Explanation:
  //   __asm__
  //   __volatile__     Don't optimize this asm away.
  //   (
  //       ""           Empty assembler code.
  //       :            No outputs.
  //       : "g" (address)
  //                    One input value, `address'; "g" means that
  //                    it can go in any general-purpose register.
  //   )

  // The following macro expands into a dummy assembler statement that
  // contains no code. It is used to suppress optimizations in gcc 4
  // and above that try to cache memory values in registers before labels
  // that Mercury uses as the target of non-local gotos. It has no effect
  // with versions of gcc before version 4.

  #define MR_PRETEND_REGS_ARE_USED                                       \
    __asm__ __volatile("":::"memory")
  // Explanation:
  //   __asm__
  //   __volatile__     Don't optimize this asm away.
  //   (
  //       ""           Empty assembler code.
  //       :            No outputs.
  //       :            No inputs.
  //       :"memory"    Tells gcc that this "instruction" might clobber
  //                    the register contents so it shouldn't cache
  //                    memory values in registers.
  //   )

  // Since we are jumping into and out of the middle of functions,
  // we need to make sure that gcc thinks that (1) the function's address
  // is used (otherwise it may optimize the whole function away) and
  // (2) the `return' statement is reachable (otherwise its dataflow
  // analysis for delay slot scheduling may think that global
  // register variables which are only assigned to in the function
  // cannot be live, when in fact they really are).
  // That is what the two occurrences of the MR_PRETEND_ADDRESS_IS_USED
  // macro are for.
  // For versions of gcc later than egcs 1.1.2 (which corresponds to gcc 2.91,
  // according to __GNUC_MINOR__), and in particular for gcc 2.95,
  // we also need to include at least one `goto *' with an unknown
  // target, so that gcc doesn't optimize away all the labels
  // because it thinks they are unreachable.
  // The MR_dummy_identify_function() function just returns the address
  // passed to it, so `goto *MR_dummy_identify_function(&& dummy_label);
  // dummy_label:' is the same as `goto dummy_label; label:', i.e. it just
  // falls through. For older versions of gcc, we don't do this, since it
  // adds significantly to the code size.

  #if MR_GNUC > 2 || (MR_GNUC == 2 && __GNUC_MINOR__ > 91)
    // gcc version > egcs 1.1.2
    #define MR_BEGIN_MODULE(module_name)                                 \
    MR_MODULE_STATIC_OR_EXTERN void module_name(void);                   \
    MR_MODULE_STATIC_OR_EXTERN void module_name(void) {                  \
        MR_PRETEND_ADDRESS_IS_USED(module_name);                         \
        MR_PRETEND_ADDRESS_IS_USED(                                      \
            &&MR_PASTE2(module_name,_dummy_label));                      \
        goto *MR_dummy_identify_function(                                \
            &&MR_PASTE2(module_name,_dummy_label));                      \
        MR_PASTE2(module_name,_dummy_label):                             \
        {
  #else // gcc version <= egcs 1.1.2
    #define MR_BEGIN_MODULE(module_name)                                 \
    MR_MODULE_STATIC_OR_EXTERN void module_name(void);                   \
    MR_MODULE_STATIC_OR_EXTERN void module_name(void) {                  \
        MR_PRETEND_ADDRESS_IS_USED(module_name);                         \
        MR_PRETEND_ADDRESS_IS_USED(                                      \
            &&MR_PASTE2(module_name,_dummy_label));                      \
        MR_PASTE2(module_name,_dummy_label):                             \
        {
  #endif // gcc version <= egcs 1.1.2

  // Initialization code for module goes between MR_BEGIN_MODULE
  // and MR_BEGIN_CODE.
  #define MR_BEGIN_CODE } return; {
  // Body of module goes between MR_BEGIN_CODE and MR_END_MODULE.
  #define MR_END_MODULE } }

  #if defined(MR_USE_ASM_LABELS)
    #define MR_declare_entry(label)                                      \
    extern void label(void) __asm__("_entry_" MR_STRINGIFY(label))
    #define MR_declare_static(label)                                     \
    static void label(void) __asm__("_entry_" MR_STRINGIFY(label))
    #define MR_define_extern_entry(label)   MR_declare_entry(label)
    #define MR_define_entry(label)                                       \
        MR_ASM_ENTRY(label)                                              \
    }                                                                    \
    label:                                                               \
    MR_PRETEND_ADDRESS_IS_USED(&&MR_entry(label));                       \
    {                                                                    \
    MR_PRETEND_REGS_ARE_USED;
    #define MR_define_static(label)                                      \
        MR_ASM_STATIC_ENTRY(label)                                       \
    }                                                                    \
    label:                                                               \
    MR_PRETEND_ADDRESS_IS_USED(&&MR_entry(label));                       \
    {                                                                    \
    MR_PRETEND_REGS_ARE_USED;
    // The MR_PRETEND_ADDRESS_IS_USED macro is necessary to prevent
    // an over-zealous gcc from optimizing away `label' and the code that
    // followed. The MR_PRETEND_REGS_ARE_USED macro is used to prevent gcc
    // from caching values in registers before the label.

    #define MR_init_entry(label)                                         \
    MR_PRETEND_ADDRESS_IS_USED(&&label);                                 \
    MR_make_entry(MR_STRINGIFY(label), label, label)
    #define MR_init_entry_ai(label)                                      \
    MR_PRETEND_ADDRESS_IS_USED(&&label);                                 \
    MR_make_entry_ai(MR_STRINGIFY(label), label, label)
    #define MR_init_entry_an(label)                                      \
    MR_PRETEND_ADDRESS_IS_USED(&&label);                                 \
    MR_make_entry_an(MR_STRINGIFY(label), label, label)
    #define MR_init_entry_sl(label)                                      \
    MR_PRETEND_ADDRESS_IS_USED(&&label);                                 \
    MR_make_entry_sl(MR_STRINGIFY(label), label, label)

    #define MR_pretend_address_is_used(label)                            \
    MR_PRETEND_ADDRESS_IS_USED(&&label);
    #define MR_entry_addr_wrapper(label)

    #define MR_ENTRY(label)     (&label)

    #ifndef MR_JUMP
    #define MR_JUMP(label)      MR_ASM_JUMP(label)
    #endif

  #else
    // !defined(MR_USE_ASM_LABELS)

    #define MR_declare_entry(label) extern MR_Code * MR_entry(label)
    #define MR_declare_static(label)    static MR_Code * MR_entry(label)
    #define MR_define_extern_entry(label) MR_Code * MR_entry(label)
    #define MR_define_entry(label)                                       \
    }                                                                    \
    MR_entry(label):                                                     \
    label:                                                               \
    {
    #define MR_define_static(label)                                      \
    }                                                                    \
    MR_entry(label):                                                     \
    label:                                                               \
    {
    #define MR_init_entry(label)                                         \
    MR_make_entry(MR_STRINGIFY(label), &&label, label);                  \
    MR_entry(label) = &&label
    #define MR_init_entry_ai(label)                                      \
    MR_make_entry_ai(MR_STRINGIFY(label), &&label, label);               \
    MR_entry(label) = &&label
    #define MR_init_entry_an(label)                                      \
    MR_make_entry_an(MR_STRINGIFY(label), &&label, label);               \
    MR_entry(label) = &&label
    #define MR_init_entry_sl(label)                                      \
    MR_make_entry_sl(MR_STRINGIFY(label), &&label, label);               \
    MR_entry(label) = &&label
    #define MR_ENTRY(label)     (MR_entry(label))

    #ifndef MR_JUMP
    #define MR_JUMP(label)      goto *(label)
    #endif

  #endif // !defined(MR_USE_ASM_LABELS)

  #define MR_declare_local(label)   // no declaration required
  #define MR_define_local(label)                                         \
        MR_ASM_LOCAL_ENTRY(label)                                        \
    }                                                                    \
    label:                                                               \
    {
  #define MR_init_local(label)                                           \
    MR_make_local(MR_STRINGIFY(label), &&MR_entry(label), label)
  #define MR_init_local_ai(label)                                        \
    MR_make_local_ai(MR_STRINGIFY(label), &&MR_entry(label), label)
  #define MR_init_local_an(label)                                        \
    MR_make_local_an(MR_STRINGIFY(label), &&MR_entry(label), label)
  #define MR_init_local_sl(label)                                        \
    MR_make_local_sl(MR_STRINGIFY(label), &&MR_entry(label), label)

  #define MR_define_label(label)    MR_define_local(label)
  #define MR_declare_label(label)   // no declaration required

  #define MR_init_label(label)                                           \
    MR_make_label(MR_STRINGIFY(label), &&MR_entry(label),                \
        MR_LABEL_LAYOUT(label))
  #define MR_init_label_ai(label)                                        \
    MR_make_label_ai(MR_STRINGIFY(label), &&MR_entry(label),             \
        MR_LABEL_LAYOUT(label))
  #define MR_init_label_an(label)                                        \
    MR_make_label_an(MR_STRINGIFY(label), &&MR_entry(label),             \
        MR_LABEL_LAYOUT(label))
  #define MR_init_label_sl(label)                                        \
    MR_make_label_sl(MR_STRINGIFY(label), &&MR_entry(label),             \
        MR_LABEL_LAYOUT(label))

  #define MR_init_label_ml(label, layout)                                \
    MR_make_label(MR_STRINGIFY(label), &&MR_entry(label), layout)
  #define MR_init_label_ml_ai(label, layout)                             \
    MR_make_label_ai(MR_STRINGIFY(label), &&MR_entry(label), layout)
  #define MR_init_label_ml_an(label, layout)                             \
    MR_make_label_an(MR_STRINGIFY(label), &&MR_entry(label), layout)
  #define MR_init_label_ml_sl(label, layout)                             \
    MR_make_label_sl(MR_STRINGIFY(label), &&MR_entry(label), layout)

  #define MR_LOCAL(label)   (&&MR_entry(label))
  #define MR_LABEL(label)   (&&MR_entry(label))
  #define MR_GOTO(label)    do {                                         \
                    MR_debuggoto(label);                                 \
                    MR_JUMP(label);                                      \
                } while (0)
  #define MR_GOTO_ENTRY(label)  MR_GOTO(MR_ENTRY(label))
  #define MR_GOTO_LOCAL(label)  MR_GOTO_LABEL(label)
  #define MR_GOTO_LABEL(label)  do {                                     \
                    MR_debuggoto(MR_LABEL(label));                       \
                    goto label;                                          \
                } while (0)

  // MR_GOTO_LABEL(label) is the same as MR_GOTO(MR_LABEL(label)) except that
  // it may allow gcc to generate slightly better code.

#else
  // !defined(MR_USE_GCC_NONLOCAL_GOTOS)

  // Define the type of a module initialization function.
  typedef MR_Code * MR_ModuleFunc(void);

  #define MR_BEGIN_MODULE(module_name)                                   \
    MR_MODULE_STATIC_OR_EXTERN MR_Code * module_name(void);              \
    MR_MODULE_STATIC_OR_EXTERN MR_Code * module_name(void) {
  #define MR_BEGIN_CODE         return 0;
  #define MR_END_MODULE         }

  #define MR_declare_entry(label)       extern MR_Code *label(void)
  #define MR_declare_static(label)      static MR_Code *label(void)
  #define MR_define_extern_entry(label)     MR_Code *label(void)
  #define MR_define_entry(label)                                         \
        MR_GOTO_LABEL(label);                                            \
    }                                                                    \
    MR_Code* label(void) {
  #define MR_define_static(label)                                        \
        MR_GOTO_LABEL(label);                                            \
    }                                                                    \
    static MR_Code* label(void) {

  #define MR_init_entry(label)                                           \
    MR_make_entry(MR_STRINGIFY(label), label, label)
  #define MR_init_entry_ai(label)                                        \
    MR_make_entry_ai(MR_STRINGIFY(label), label, label)
  #define MR_init_entry_an(label)                                        \
    MR_make_entry_an(MR_STRINGIFY(label), label, label)
  #define MR_init_entry_sl(label)                                        \
    MR_make_entry_sl(MR_STRINGIFY(label), label, label)

  #define MR_declare_local(label)   static MR_Code *label(void)
  #define MR_define_local(label)                                         \
        MR_GOTO_LABEL(label);                                            \
    }                                                                    \
    static MR_Code* label(void) {

  #define MR_init_local(label)                                           \
    MR_make_local(MR_STRINGIFY(label),    label, label)
  #define MR_init_local_ai(label)                                        \
    MR_make_local_ai(MR_STRINGIFY(label), label, label)
  #define MR_init_local_an(label)                                        \
    MR_make_local_an(MR_STRINGIFY(label), label, label)
  #define MR_init_local_sl(label)                                        \
    MR_make_local_sl(MR_STRINGIFY(label), label, label)

  #define MR_declare_label(label)   static MR_Code *label(void)
  #define MR_define_label(label)                                         \
        MR_GOTO_LABEL(label);                                            \
    }                                                                    \
    static MR_Code* label(void) {

  #define MR_init_label(label)                                           \
    MR_make_label(MR_STRINGIFY(label),    label, MR_LABEL_LAYOUT(label))
  #define MR_init_label_ai(label)                                        \
    MR_make_label_ai(MR_STRINGIFY(label), label, MR_LABEL_LAYOUT(label))
  #define MR_init_label_an(label)                                        \
    MR_make_label_an(MR_STRINGIFY(label), label, MR_LABEL_LAYOUT(label))
  #define MR_init_label_sl(label)                                        \
    MR_make_label_sl(MR_STRINGIFY(label), label, MR_LABEL_LAYOUT(label))

  #define MR_init_label_ml(label, layout)                                \
    MR_make_label(MR_STRINGIFY(label),    label, layout)
  #define MR_init_label_ml_ai(label, layout)                             \
    MR_make_label_ai(MR_STRINGIFY(label), label, layout)
  #define MR_init_label_ml_an(label, layout)                             \
    MR_make_label_an(MR_STRINGIFY(label), label, layout)
  #define MR_init_label_ml_sl(label, layout)                             \
    MR_make_label_sl(MR_STRINGIFY(label), label, layout)

  #define MR_ENTRY(label)   ((MR_Code *) (label))
  #define MR_LOCAL(label)   ((MR_Code *) (label))
  #define MR_LABEL(label)   ((MR_Code *) (label))
  // The call to MR_debuggoto() is in the driver function in mercury_engine.c,
  // which is why the following definitions have no MR_debuggoto().

  #define MR_GOTO(label)    return (label)
  #define MR_GOTO_ENTRY(label)  MR_GOTO(MR_ENTRY(label))
  #define MR_GOTO_LOCAL(label)  MR_GOTO(MR_LOCAL(label))
  #define MR_GOTO_LABEL(label)  MR_GOTO(MR_LABEL(label))

#endif // !defined(MR_USE_GCC_NONLOCAL_GOTOS)

////////////////////////////////////////////////////////////////////////////

#define MR_ENTRY_AP(label)      MR_ENTRY(MR_add_prefix(label))
#define MR_LOCAL_AP(label)      MR_LOCAL(MR_add_prefix(label))
#define MR_LABEL_AP(label)      MR_LABEL(MR_add_prefix(label))
#define MR_GOTO_AP(label)       MR_GOTO(MR_add_prefix(label))
#define MR_GOTO_ENT(label)      MR_GOTO_ENTRY(MR_add_prefix(label))
#define MR_GOTO_LOC(label)      MR_GOTO_LOCAL(MR_add_prefix(label))
#define MR_GOTO_LAB(label)      MR_GOTO_LABEL(MR_add_prefix(label))

#define MR_decl_user_entry(mod, name, arity, mode)                       \
    MR_declare_entry(MR_proc_entry_user_name(mod, name, arity, mode))
#define MR_decl_uci_entry(mod, name, type, arity, mode)                  \
    MR_declare_entry(MR_proc_entry_uci_name(mod, name, type, arity, mode))
#define MR_decl_user_static(mod, name, arity, mode)                      \
    MR_declare_static(MR_proc_entry_user_name(mod, name, arity, mode))
#define MR_decl_uci_static(mod, name, type, arity, mode)                 \
    MR_declare_static(MR_proc_entry_uci_name(mod, name, type, arity, mode))

#define MR_def_user_extern_entry(mod, name, arity, mode)                 \
    MR_define_extern_entry(                                              \
        MR_proc_entry_user_name(mod, name, arity, mode))
#define MR_def_uci_extern_entry(mod, name, type, arity, mode)            \
    MR_define_extern_entry(                                              \
        MR_proc_entry_uci_name(mod, name, type, arity, mode))
#define MR_def_user_entry(mod, name, arity, mode)                        \
    MR_define_entry(MR_proc_entry_user_name(mod, name, arity, mode))
#define MR_def_uci_entry(mod, name, type, arity, mode)                   \
    MR_define_entry(MR_proc_entry_uci_name(mod, name, type, arity, mode))
#define MR_def_user_static(mod, name, arity, mode)                       \
    MR_define_static(MR_proc_entry_user_name(mod, name, arity, mode))
#define MR_def_uci_static(mod, name, type, arity, mode)                  \
    MR_define_static(MR_proc_entry_uci_name(mod, name, type, arity, mode))

////////////////////////////////////////////////////////////////////////////

#if defined(MR_INSERT_LABELS) || defined(MR_MPROF_PROFILE_CALLS)
  #define MR_need_insert_entry(ai)      1
#else
  #define MR_need_insert_entry(ai)      ai
#endif

#if defined(MR_INSERT_LABELS)
  #define MR_need_insert_internal(ai)       1
#else
  #define MR_need_insert_internal(ai)       ai
#endif

#if defined(MR_INSERT_ENTRY_LABEL_NAMES)
  #define MR_need_entry_label_names(an)     1
#else
  #define MR_need_entry_label_names(an)     an
#endif

#if defined(MR_INSERT_INTERNAL_LABEL_NAMES)
  #define MR_need_internal_label_names(an)  1
#else
  #define MR_need_internal_label_names(an)  an
#endif

#define MR_init_entry_select(str, addr, layout, ai, an, sl)              \
    ( MR_need_insert_entry(ai) ?                                         \
        MR_insert_entry_label(                                           \
            MR_need_entry_label_names(an) ? str : NULL,                  \
            addr, sl ? layout : NULL)                                    \
        : (void) 0 )

#define MR_init_internal_select(str, addr, layout, ai, an, sl)           \
    ( MR_need_insert_internal(ai) ?                                      \
        MR_insert_internal_label(                                        \
            MR_need_internal_label_names(an) ? str : NULL,               \
            addr, sl ? layout : NULL)                                    \
        : (void) 0 )

#define MR_init_user_entry_select(mod, name, arity, mode, ai, an, sl)    \
    MR_pretend_address_is_used(                                          \
        MR_proc_entry_user_name(mod, name, arity, mode))                 \
    MR_init_entry_select(                                                \
        MR_proc_entry_user_name_str(mod, name, arity, mode),             \
        MR_entry_addr_wrapper(                                           \
            MR_proc_entry_user_name(mod, name, arity, mode)),            \
        MR_proc_layout_user_name(mod, name, arity, mode),                \
        ai, an, sl)

#define MR_init_uci_entry_select(mod, name, type, arity, mode, ai, an, sl) \
    MR_pretend_address_is_used(                                            \
        MR_proc_entry_uci_name(mod, name, type, arity, mode))              \
    MR_init_entry_select(                                                  \
        MR_proc_entry_uci_name_str(mod, name, type, arity, mode),          \
        MR_entry_addr_wrapper(                                             \
            MR_proc_entry_uci_name(mod, name, type, arity, mode)),         \
        MR_proc_layout_uci_name(mod, name, type, arity, mode),             \
        ai, an, sl)

#define MR_init_user_label_select(mod, name, arity, mode, num, ai, an, sl) \
    MR_init_label_select(                                                  \
        MR_label_user_name_str(mod, name, arity, mode, num),               \
        MR_entry_addr_wrapper(                                             \
            MR_label_user_name(mod, name, arity, mode, num)),              \
        MR_label_layout_user_name(mod, name, arity, mode, num),            \
        ai, an, sl)

#define MR_init_uci_label_select(mod, name, type, arity, mode, num, ai, an, sl)\
    MR_init_label_select(                                                      \
        MR_label_uci_name_str(mod, name, type, arity, mode, num),              \
        MR_entry_addr_wrapper(                                                 \
            MR_label_uci_name(mod, name, type, arity, mode, num)),             \
        MR_label_layout_uci_name(mod, name, type, arity, mode, num),           \
        ai, an, sl)

#define MR_init_user_entry_ai(mod, name, arity, mode)                    \
    MR_init_user_entry_select(mod, name, arity, mode, 1, 0, 0)
#define MR_init_user_entry_an(mod, name, arity, mode)                    \
    MR_init_user_entry_select(mod, name, arity, mode, 1, 1, 0)
#define MR_init_user_entry_sl(mod, name, arity, mode)                    \
    MR_init_user_entry_select(mod, name, arity, mode, 0, 0, 1)

#define MR_init_uci_entry_ai(mod, name, type, arity, mode)               \
    MR_init_uci_entry_select(mod, name, type, arity, mode, 1, 0, 0)
#define MR_init_uci_entry_an(mod, name, type, arity, mode)               \
    MR_init_uci_entry_select(mod, name, type, arity, mode, 1, 1, 0)
#define MR_init_uci_entry_sl(mod, name, type, arity, mode)               \
    MR_init_uci_entry_select(mod, name, type, arity, mode, 0, 0, 1)

#define MR_init_user_local_ai(mod, name, arity, mode, num)               \
    MR_init_user_local_select(mod, name, arity, mode, num, 1, 0, 0)
#define MR_init_user_local_an(mod, name, arity, mode, num)               \
    MR_init_user_local_select(mod, name, arity, mode, num, 1, 1, 0)
#define MR_init_user_local_sl(mod, name, arity, mode, num)               \
    MR_init_user_local_select(mod, name, arity, mode, num, 0, 0, 1)

#define MR_init_uci_local_ai(mod, name, type, arity, mode, num)          \
    MR_init_uci_local_select(mod, name, type, arity, mode, num, 1, 0, 0)
#define MR_init_uci_local_an(mod, name, type, arity, mode, num)          \
    MR_init_uci_local_select(mod, name, type, arity, mode, num, 1, 1, 0)
#define MR_init_uci_local_sl(mod, name, type, arity, mode, num)          \
    MR_init_uci_local_select(mod, name, type, arity, mode, num, 0, 0, 1)

#define MR_def_extern_entry(e)                                           \
    MR_define_extern_entry(MR_add_prefix(e));

#define MR_def_entry(e)                                                  \
    MR_define_entry(MR_add_prefix(e));

#define MR_def_static(e)                                                 \
    MR_define_static(MR_add_prefix(e));

#define MR_def_local(e)                                                  \
    MR_define_local(MR_add_prefix(e));

#define MR_def_label(e, ln)                                              \
    MR_define_label(MR_label_name(MR_add_prefix(e), ln));

#define MR_init_entry1(e)                                                \
    MR_init_entry(MR_add_prefix(e));

#define MR_init_entry1_sl(e)                                             \
    MR_init_entry_sl(MR_add_prefix(e));

#define MR_init_local1(e)                                                \
    MR_init_local(MR_add_prefix(e));

#define MR_init_local1_sl(e)                                             \
    MR_init_local_sl(MR_add_prefix(e));

#define MR_init_label1_sl(e)                                             \
    MR_init_label_sl(MR_add_prefix(e));

////////////////////////////////////////////////////////////////////////////

#define MR_init_label1(e, l1)                                            \
    MR_init_label(MR_label_name(MR_add_prefix(e), l1));

#define MR_init_label2(e, l1, l2)                                        \
    MR_init_label1(e, l1)                                                \
    MR_init_label1(e, l2)

#define MR_init_label3(e, l1, l2, l3)                                    \
    MR_init_label1(e, l1)                                                \
    MR_init_label1(e, l2)                                                \
    MR_init_label1(e, l3)

#define MR_init_label4(e, l1, l2, l3, l4)                                \
    MR_init_label1(e, l1)                                                \
    MR_init_label1(e, l2)                                                \
    MR_init_label1(e, l3)                                                \
    MR_init_label1(e, l4)

#define MR_init_label5(e, l1, l2, l3, l4, l5)                            \
    MR_init_label1(e, l1)                                                \
    MR_init_label1(e, l2)                                                \
    MR_init_label1(e, l3)                                                \
    MR_init_label1(e, l4)                                                \
    MR_init_label1(e, l5)

#define MR_init_label6(e, l1, l2, l3, l4, l5, l6)                        \
    MR_init_label1(e, l1)                                                \
    MR_init_label1(e, l2)                                                \
    MR_init_label1(e, l3)                                                \
    MR_init_label1(e, l4)                                                \
    MR_init_label1(e, l5)                                                \
    MR_init_label1(e, l6)

#define MR_init_label7(e, l1, l2, l3, l4, l5, l6, l7)                    \
    MR_init_label1(e, l1)                                                \
    MR_init_label1(e, l2)                                                \
    MR_init_label1(e, l3)                                                \
    MR_init_label1(e, l4)                                                \
    MR_init_label1(e, l5)                                                \
    MR_init_label1(e, l6)                                                \
    MR_init_label1(e, l7)

#define MR_init_label8(e, l1, l2, l3, l4, l5, l6, l7, l8)                \
    MR_init_label1(e, l1)                                                \
    MR_init_label1(e, l2)                                                \
    MR_init_label1(e, l3)                                                \
    MR_init_label1(e, l4)                                                \
    MR_init_label1(e, l5)                                                \
    MR_init_label1(e, l6)                                                \
    MR_init_label1(e, l7)                                                \
    MR_init_label1(e, l8)

#define MR_init_label9(e, l1, l2, l3, l4, l5, l6, l7, l8, l9)            \
    MR_init_label1(e, l1)                                                \
    MR_init_label1(e, l2)                                                \
    MR_init_label1(e, l3)                                                \
    MR_init_label1(e, l4)                                                \
    MR_init_label1(e, l5)                                                \
    MR_init_label1(e, l6)                                                \
    MR_init_label1(e, l7)                                                \
    MR_init_label1(e, l8)                                                \
    MR_init_label1(e, l9)

#define MR_init_label10(e, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10)      \
    MR_init_label1(e, l1)                                                \
    MR_init_label1(e, l2)                                                \
    MR_init_label1(e, l3)                                                \
    MR_init_label1(e, l4)                                                \
    MR_init_label1(e, l5)                                                \
    MR_init_label1(e, l6)                                                \
    MR_init_label1(e, l7)                                                \
    MR_init_label1(e, l8)                                                \
    MR_init_label1(e, l9)                                                \
    MR_init_label1(e, l10)

////////////////////////////////////////////////////////////////////////////

#define MR_init_label_sl1(e, l1)                                         \
    MR_init_label_sl(MR_label_name(MR_add_prefix(e), l1));

#define MR_init_label_sl2(e, l1, l2)                                     \
    MR_init_label_sl1(e, l1)                                             \
    MR_init_label_sl1(e, l2)

#define MR_init_label_sl3(e, l1, l2, l3)                                 \
    MR_init_label_sl1(e, l1)                                             \
    MR_init_label_sl1(e, l2)                                             \
    MR_init_label_sl1(e, l3)

#define MR_init_label_sl4(e, l1, l2, l3, l4)                             \
    MR_init_label_sl1(e, l1)                                             \
    MR_init_label_sl1(e, l2)                                             \
    MR_init_label_sl1(e, l3)                                             \
    MR_init_label_sl1(e, l4)

#define MR_init_label_sl5(e, l1, l2, l3, l4, l5)                         \
    MR_init_label_sl1(e, l1)                                             \
    MR_init_label_sl1(e, l2)                                             \
    MR_init_label_sl1(e, l3)                                             \
    MR_init_label_sl1(e, l4)                                             \
    MR_init_label_sl1(e, l5)

#define MR_init_label_sl6(e, l1, l2, l3, l4, l5, l6)                     \
    MR_init_label_sl1(e, l1)                                             \
    MR_init_label_sl1(e, l2)                                             \
    MR_init_label_sl1(e, l3)                                             \
    MR_init_label_sl1(e, l4)                                             \
    MR_init_label_sl1(e, l5)                                             \
    MR_init_label_sl1(e, l6)

#define MR_init_label_sl7(e, l1, l2, l3, l4, l5, l6, l7)                 \
    MR_init_label_sl1(e, l1)                                             \
    MR_init_label_sl1(e, l2)                                             \
    MR_init_label_sl1(e, l3)                                             \
    MR_init_label_sl1(e, l4)                                             \
    MR_init_label_sl1(e, l5)                                             \
    MR_init_label_sl1(e, l6)                                             \
    MR_init_label_sl1(e, l7)

#define MR_init_label_sl8(e, l1, l2, l3, l4, l5, l6, l7, l8)             \
    MR_init_label_sl1(e, l1)                                             \
    MR_init_label_sl1(e, l2)                                             \
    MR_init_label_sl1(e, l3)                                             \
    MR_init_label_sl1(e, l4)                                             \
    MR_init_label_sl1(e, l5)                                             \
    MR_init_label_sl1(e, l6)                                             \
    MR_init_label_sl1(e, l7)                                             \
    MR_init_label_sl1(e, l8)

#define MR_init_label_sl9(e, l1, l2, l3, l4, l5, l6, l7, l8, l9)         \
    MR_init_label_sl1(e, l1)                                             \
    MR_init_label_sl1(e, l2)                                             \
    MR_init_label_sl1(e, l3)                                             \
    MR_init_label_sl1(e, l4)                                             \
    MR_init_label_sl1(e, l5)                                             \
    MR_init_label_sl1(e, l6)                                             \
    MR_init_label_sl1(e, l7)                                             \
    MR_init_label_sl1(e, l8)                                             \
    MR_init_label_sl1(e, l9)

#define MR_init_label_sl10(e, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10)   \
    MR_init_label_sl1(e, l1)                                             \
    MR_init_label_sl1(e, l2)                                             \
    MR_init_label_sl1(e, l3)                                             \
    MR_init_label_sl1(e, l4)                                             \
    MR_init_label_sl1(e, l5)                                             \
    MR_init_label_sl1(e, l6)                                             \
    MR_init_label_sl1(e, l7)                                             \
    MR_init_label_sl1(e, l8)                                             \
    MR_init_label_sl1(e, l9)                                             \
    MR_init_label_sl1(e, l10)

////////////////////////////////////////////////////////////////////////////

#define MR_init_label_nvi1(e, m, l1, s1)                                 \
    MR_init_label_ml_sl(MR_label_name(MR_add_prefix(e), l1),             \
        (const MR_LabelLayout *) &MR_no_var_label_layouts(m)[s1]);

#define MR_init_label_nvi2(e, m, l1,s1, l2,s2)                           \
    MR_init_label_nvi1(e, m, l1, s1)                                     \
    MR_init_label_nvi1(e, m, l2, s2)

#define MR_init_label_nvi3(e, m, l1,s1, l2,s2, l3,s3)                    \
    MR_init_label_nvi1(e, m, l1, s1)                                     \
    MR_init_label_nvi1(e, m, l2, s2)                                     \
    MR_init_label_nvi1(e, m, l3, s3)

#define MR_init_label_nvi4(e, m, l1,s1, l2,s2, l3,s3, l4,s4)             \
    MR_init_label_nvi1(e, m, l1, s1)                                     \
    MR_init_label_nvi1(e, m, l2, s2)                                     \
    MR_init_label_nvi1(e, m, l3, s3)                                     \
    MR_init_label_nvi1(e, m, l4, s4)

#define MR_init_label_nvi5(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5)      \
    MR_init_label_nvi1(e, m, l1, s1)                                     \
    MR_init_label_nvi1(e, m, l2, s2)                                     \
    MR_init_label_nvi1(e, m, l3, s3)                                     \
    MR_init_label_nvi1(e, m, l4, s4)                                     \
    MR_init_label_nvi1(e, m, l5, s5)

#define MR_init_label_nvi6(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6) \
    MR_init_label_nvi1(e, m, l1, s1)                                     \
    MR_init_label_nvi1(e, m, l2, s2)                                     \
    MR_init_label_nvi1(e, m, l3, s3)                                     \
    MR_init_label_nvi1(e, m, l4, s4)                                     \
    MR_init_label_nvi1(e, m, l5, s5)                                     \
    MR_init_label_nvi1(e, m, l6, s6)

#define MR_init_label_nvi7(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7) \
    MR_init_label_nvi1(e, m, l1, s1)                                     \
    MR_init_label_nvi1(e, m, l2, s2)                                     \
    MR_init_label_nvi1(e, m, l3, s3)                                     \
    MR_init_label_nvi1(e, m, l4, s4)                                     \
    MR_init_label_nvi1(e, m, l5, s5)                                     \
    MR_init_label_nvi1(e, m, l6, s6)                                     \
    MR_init_label_nvi1(e, m, l7, s7)

#define MR_init_label_nvi8(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7, l8,s8) \
    MR_init_label_nvi1(e, m, l1, s1)                                     \
    MR_init_label_nvi1(e, m, l2, s2)                                     \
    MR_init_label_nvi1(e, m, l3, s3)                                     \
    MR_init_label_nvi1(e, m, l4, s4)                                     \
    MR_init_label_nvi1(e, m, l5, s5)                                     \
    MR_init_label_nvi1(e, m, l6, s6)                                     \
    MR_init_label_nvi1(e, m, l7, s7)                                     \
    MR_init_label_nvi1(e, m, l8, s8)

#define MR_init_label_nvi9(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7, l8,s8, l9,s9) \
    MR_init_label_nvi1(e, m, l1, s1)                                     \
    MR_init_label_nvi1(e, m, l2, s2)                                     \
    MR_init_label_nvi1(e, m, l3, s3)                                     \
    MR_init_label_nvi1(e, m, l4, s4)                                     \
    MR_init_label_nvi1(e, m, l5, s5)                                     \
    MR_init_label_nvi1(e, m, l6, s6)                                     \
    MR_init_label_nvi1(e, m, l7, s7)                                     \
    MR_init_label_nvi1(e, m, l8, s8)                                     \
    MR_init_label_nvi1(e, m, l9, s9)

#define MR_init_label_nvi10(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7, l8,s8, l9,s9, l10,s10) \
    MR_init_label_nvi1(e, m, l1, s1)                                     \
    MR_init_label_nvi1(e, m, l2, s2)                                     \
    MR_init_label_nvi1(e, m, l3, s3)                                     \
    MR_init_label_nvi1(e, m, l4, s4)                                     \
    MR_init_label_nvi1(e, m, l5, s5)                                     \
    MR_init_label_nvi1(e, m, l6, s6)                                     \
    MR_init_label_nvi1(e, m, l7, s7)                                     \
    MR_init_label_nvi1(e, m, l8, s8)                                     \
    MR_init_label_nvi1(e, m, l9, s9)                                     \
    MR_init_label_nvi1(e, m, l10, s10)

////////////////////////////////////////////////////////////////////////////

#define MR_init_label_svi1(e, m, l1, s1)                                 \
    MR_init_label_ml_sl(MR_label_name(MR_add_prefix(e), l1),             \
        (const MR_LabelLayout *) &MR_svar_label_layouts(m)[s1]);

#define MR_init_label_svi2(e, m, l1,s1, l2,s2)                           \
    MR_init_label_svi1(e, m, l1, s1)                                     \
    MR_init_label_svi1(e, m, l2, s2)

#define MR_init_label_svi3(e, m, l1,s1, l2,s2, l3,s3)                    \
    MR_init_label_svi1(e, m, l1, s1)                                     \
    MR_init_label_svi1(e, m, l2, s2)                                     \
    MR_init_label_svi1(e, m, l3, s3)

#define MR_init_label_svi4(e, m, l1,s1, l2,s2, l3,s3, l4,s4)             \
    MR_init_label_svi1(e, m, l1, s1)                                     \
    MR_init_label_svi1(e, m, l2, s2)                                     \
    MR_init_label_svi1(e, m, l3, s3)                                     \
    MR_init_label_svi1(e, m, l4, s4)

#define MR_init_label_svi5(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5)      \
    MR_init_label_svi1(e, m, l1, s1)                                     \
    MR_init_label_svi1(e, m, l2, s2)                                     \
    MR_init_label_svi1(e, m, l3, s3)                                     \
    MR_init_label_svi1(e, m, l4, s4)                                     \
    MR_init_label_svi1(e, m, l5, s5)

#define MR_init_label_svi6(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6) \
    MR_init_label_svi1(e, m, l1, s1)                                     \
    MR_init_label_svi1(e, m, l2, s2)                                     \
    MR_init_label_svi1(e, m, l3, s3)                                     \
    MR_init_label_svi1(e, m, l4, s4)                                     \
    MR_init_label_svi1(e, m, l5, s5)                                     \
    MR_init_label_svi1(e, m, l6, s6)

#define MR_init_label_svi7(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7) \
    MR_init_label_svi1(e, m, l1, s1)                                     \
    MR_init_label_svi1(e, m, l2, s2)                                     \
    MR_init_label_svi1(e, m, l3, s3)                                     \
    MR_init_label_svi1(e, m, l4, s4)                                     \
    MR_init_label_svi1(e, m, l5, s5)                                     \
    MR_init_label_svi1(e, m, l6, s6)                                     \
    MR_init_label_svi1(e, m, l7, s7)

#define MR_init_label_svi8(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7, l8,s8) \
    MR_init_label_svi1(e, m, l1, s1)                                     \
    MR_init_label_svi1(e, m, l2, s2)                                     \
    MR_init_label_svi1(e, m, l3, s3)                                     \
    MR_init_label_svi1(e, m, l4, s4)                                     \
    MR_init_label_svi1(e, m, l5, s5)                                     \
    MR_init_label_svi1(e, m, l6, s6)                                     \
    MR_init_label_svi1(e, m, l7, s7)                                     \
    MR_init_label_svi1(e, m, l8, s8)

#define MR_init_label_svi9(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7, l8,s8, l9,s9) \
    MR_init_label_svi1(e, m, l1, s1)                                     \
    MR_init_label_svi1(e, m, l2, s2)                                     \
    MR_init_label_svi1(e, m, l3, s3)                                     \
    MR_init_label_svi1(e, m, l4, s4)                                     \
    MR_init_label_svi1(e, m, l5, s5)                                     \
    MR_init_label_svi1(e, m, l6, s6)                                     \
    MR_init_label_svi1(e, m, l7, s7)                                     \
    MR_init_label_svi1(e, m, l8, s8)                                     \
    MR_init_label_svi1(e, m, l9, s9)

#define MR_init_label_svi10(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7, l8,s8, l9,s9, l10,s10) \
    MR_init_label_svi1(e, m, l1, s1)                                     \
    MR_init_label_svi1(e, m, l2, s2)                                     \
    MR_init_label_svi1(e, m, l3, s3)                                     \
    MR_init_label_svi1(e, m, l4, s4)                                     \
    MR_init_label_svi1(e, m, l5, s5)                                     \
    MR_init_label_svi1(e, m, l6, s6)                                     \
    MR_init_label_svi1(e, m, l7, s7)                                     \
    MR_init_label_svi1(e, m, l8, s8)                                     \
    MR_init_label_svi1(e, m, l9, s9)                                     \
    MR_init_label_svi1(e, m, l10, s10)

////////////////////////////////////////////////////////////////////////////

#define MR_init_label_lvi1(e, m, l1, s1)                                 \
    MR_init_label_ml_sl(MR_label_name(MR_add_prefix(e), l1),             \
        &MR_lvar_label_layouts(m)[s1]);

#define MR_init_label_lvi2(e, m, l1,s1, l2,s2)                           \
    MR_init_label_lvi1(e, m, l1, s1)                                     \
    MR_init_label_lvi1(e, m, l2, s2)

#define MR_init_label_lvi3(e, m, l1,s1, l2,s2, l3,s3)                    \
    MR_init_label_lvi1(e, m, l1, s1)                                     \
    MR_init_label_lvi1(e, m, l2, s2)                                     \
    MR_init_label_lvi1(e, m, l3, s3)

#define MR_init_label_lvi4(e, m, l1,s1, l2,s2, l3,s3, l4,s4)             \
    MR_init_label_lvi1(e, m, l1, s1)                                     \
    MR_init_label_lvi1(e, m, l2, s2)                                     \
    MR_init_label_lvi1(e, m, l3, s3)                                     \
    MR_init_label_lvi1(e, m, l4, s4)

#define MR_init_label_lvi5(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5)      \
    MR_init_label_lvi1(e, m, l1, s1)                                     \
    MR_init_label_lvi1(e, m, l2, s2)                                     \
    MR_init_label_lvi1(e, m, l3, s3)                                     \
    MR_init_label_lvi1(e, m, l4, s4)                                     \
    MR_init_label_lvi1(e, m, l5, s5)

#define MR_init_label_lvi6(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6) \
    MR_init_label_lvi1(e, m, l1, s1)                                     \
    MR_init_label_lvi1(e, m, l2, s2)                                     \
    MR_init_label_lvi1(e, m, l3, s3)                                     \
    MR_init_label_lvi1(e, m, l4, s4)                                     \
    MR_init_label_lvi1(e, m, l5, s5)                                     \
    MR_init_label_lvi1(e, m, l6, s6)

#define MR_init_label_lvi7(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7) \
    MR_init_label_lvi1(e, m, l1, s1)                                     \
    MR_init_label_lvi1(e, m, l2, s2)                                     \
    MR_init_label_lvi1(e, m, l3, s3)                                     \
    MR_init_label_lvi1(e, m, l4, s4)                                     \
    MR_init_label_lvi1(e, m, l5, s5)                                     \
    MR_init_label_lvi1(e, m, l6, s6)                                     \
    MR_init_label_lvi1(e, m, l7, s7)

#define MR_init_label_lvi8(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7, l8,s8) \
    MR_init_label_lvi1(e, m, l1, s1)                                     \
    MR_init_label_lvi1(e, m, l2, s2)                                     \
    MR_init_label_lvi1(e, m, l3, s3)                                     \
    MR_init_label_lvi1(e, m, l4, s4)                                     \
    MR_init_label_lvi1(e, m, l5, s5)                                     \
    MR_init_label_lvi1(e, m, l6, s6)                                     \
    MR_init_label_lvi1(e, m, l7, s7)                                     \
    MR_init_label_lvi1(e, m, l8, s8)

#define MR_init_label_lvi9(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7, l8,s8, l9,s9) \
    MR_init_label_lvi1(e, m, l1, s1)                                     \
    MR_init_label_lvi1(e, m, l2, s2)                                     \
    MR_init_label_lvi1(e, m, l3, s3)                                     \
    MR_init_label_lvi1(e, m, l4, s4)                                     \
    MR_init_label_lvi1(e, m, l5, s5)                                     \
    MR_init_label_lvi1(e, m, l6, s6)                                     \
    MR_init_label_lvi1(e, m, l7, s7)                                     \
    MR_init_label_lvi1(e, m, l8, s8)                                     \
    MR_init_label_lvi1(e, m, l9, s9)

#define MR_init_label_lvi10(e, m, l1,s1, l2,s2, l3,s3, l4,s4, l5,s5, l6,s6, l7,s7, l8,s8, l9,s9, l10,s10) \
    MR_init_label_lvi1(e, m, l1, s1)                                     \
    MR_init_label_lvi1(e, m, l2, s2)                                     \
    MR_init_label_lvi1(e, m, l3, s3)                                     \
    MR_init_label_lvi1(e, m, l4, s4)                                     \
    MR_init_label_lvi1(e, m, l5, s5)                                     \
    MR_init_label_lvi1(e, m, l6, s6)                                     \
    MR_init_label_lvi1(e, m, l7, s7)                                     \
    MR_init_label_lvi1(e, m, l8, s8)                                     \
    MR_init_label_lvi1(e, m, l9, s9)                                     \
    MR_init_label_lvi1(e, m, l10, s10)

////////////////////////////////////////////////////////////////////////////

#define MR_decl_extern_entry(e)                                          \
    MR_declare_extern_entry(MR_add_prefix(e));

#define MR_decl_entry(e)                                                 \
    MR_declare_entry(MR_add_prefix(e));

#define MR_decl_static(e)                                                \
    MR_declare_static(MR_add_prefix(e));

#define MR_decl_local(e)                                                 \
    MR_declare_local(MR_add_prefix(e));

#define MR_decl_label1(e, l1)                                            \
    MR_declare_label(MR_label_name(MR_add_prefix(e), l1));

#define MR_decl_label2(e, l1, l2)                                        \
    MR_decl_label1(e, l1)                                                \
    MR_decl_label1(e, l2)

#define MR_decl_label3(e, l1, l2, l3)                                    \
    MR_decl_label1(e, l1)                                                \
    MR_decl_label1(e, l2)                                                \
    MR_decl_label1(e, l3)

#define MR_decl_label4(e, l1, l2, l3, l4)                                \
    MR_decl_label1(e, l1)                                                \
    MR_decl_label1(e, l2)                                                \
    MR_decl_label1(e, l3)                                                \
    MR_decl_label1(e, l4)

#define MR_decl_label5(e, l1, l2, l3, l4, l5)                            \
    MR_decl_label1(e, l1)                                                \
    MR_decl_label1(e, l2)                                                \
    MR_decl_label1(e, l3)                                                \
    MR_decl_label1(e, l4)                                                \
    MR_decl_label1(e, l5)

#define MR_decl_label6(e, l1, l2, l3, l4, l5, l6)                        \
    MR_decl_label1(e, l1)                                                \
    MR_decl_label1(e, l2)                                                \
    MR_decl_label1(e, l3)                                                \
    MR_decl_label1(e, l4)                                                \
    MR_decl_label1(e, l5)                                                \
    MR_decl_label1(e, l6)

#define MR_decl_label7(e, l1, l2, l3, l4, l5, l6, l7)                    \
    MR_decl_label1(e, l1)                                                \
    MR_decl_label1(e, l2)                                                \
    MR_decl_label1(e, l3)                                                \
    MR_decl_label1(e, l4)                                                \
    MR_decl_label1(e, l5)                                                \
    MR_decl_label1(e, l6)                                                \
    MR_decl_label1(e, l7)

#define MR_decl_label8(e, l1, l2, l3, l4, l5, l6, l7, l8)                \
    MR_decl_label1(e, l1)                                                \
    MR_decl_label1(e, l2)                                                \
    MR_decl_label1(e, l3)                                                \
    MR_decl_label1(e, l4)                                                \
    MR_decl_label1(e, l5)                                                \
    MR_decl_label1(e, l6)                                                \
    MR_decl_label1(e, l7)                                                \
    MR_decl_label1(e, l8)

#define MR_decl_label9(e, l1, l2, l3, l4, l5, l6, l7, l8, l9)            \
    MR_decl_label1(e, l1)                                                \
    MR_decl_label1(e, l2)                                                \
    MR_decl_label1(e, l3)                                                \
    MR_decl_label1(e, l4)                                                \
    MR_decl_label1(e, l5)                                                \
    MR_decl_label1(e, l6)                                                \
    MR_decl_label1(e, l7)                                                \
    MR_decl_label1(e, l8)                                                \
    MR_decl_label1(e, l9)

#define MR_decl_label10(e, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10)      \
    MR_decl_label1(e, l1)                                                \
    MR_decl_label1(e, l2)                                                \
    MR_decl_label1(e, l3)                                                \
    MR_decl_label1(e, l4)                                                \
    MR_decl_label1(e, l5)                                                \
    MR_decl_label1(e, l6)                                                \
    MR_decl_label1(e, l7)                                                \
    MR_decl_label1(e, l8)                                                \
    MR_decl_label1(e, l9)                                                \
    MR_decl_label1(e, l10)

////////////////////////////////////////////////////////////////////////////

// definitions for computed gotos

#define MR_COMPUTED_GOTO(val, labels)                                    \
    {                                                                    \
        static MR_Code *jump_table[] = {                                 \
            labels                                                       \
        };                                                               \
        MR_GOTO(jump_table[val]);                                        \
    }
#define MR_AND ,    // Used to separate the labels.

#endif // not MERCURY_GOTO_H

////////////////////////////////////////////////////////////////////////////
