PreviousUpNext

15.4.514  src/lib/compiler/back/top/nextcode/translate-anormcode-to-nextcode-g.pkg

## translate-anormcode-to-nextcode-g.pkg 
#
# Converting anormcode_form::Function
# to          nextcode_form::Function.
#
#
#
# CONTEXT:
#
#     The Mythryl compiler code representations used are, in order:
#
#     1)  Raw Syntax is the initial frontend code representation.
#     2)  Deep Syntax is the second and final frontend code representation.
#     3)  Lambdacode is the first backend code representation, used only transitionally.
#     4)  Anormcode (A-Normal format, which preserves expression tree structure) is the second backend code representation, and the first used for optimization.
#     5)  Nextcode ("continuation-passing style", a single-assignment basic-block-graph form where call and return are essentially the same) is the third and chief backend tophalf code representation.
#     6)  Treecode is the first backend lowhalf code representation, used only transitionally. It is typically slightly specialized for each target architecture, e.g. Intel32 (x86).
#     7)  Machcode is the second and chief backend lowhalf code representation.  It abstracts the target architecture machine instructions.
#     8)  Execode is absolute executable binary machine instructions for the target architecture.
#
#     Our task here is converting from the fourth to the fifth form.
#
#
#
# For anormcode code format see:             src/lib/compiler/back/top/anormcode/anormcode-form.api
# For nextcode  code format see:             src/lib/compiler/back/top/nextcode/nextcode-form.api
# We get invoked (only) from:                src/lib/compiler/back/top/main/backend-tophalf-g.pkg
#
#  This generic defines function   translate_anormcode_to_nextcode
#  which constitutes the transition from the first to the second
#  half of 'highcode', the back end upper half.
#  It is called from   translate_anormcode_to_execode   in
#
#      src/lib/compiler/back/top/main/backend-tophalf-g.pkg
#
#     "[nextcode] Conversion: In this phase [lambdacode] is converted into [nextcode].
#      The [nextcode] language is designed to match the execution model of a
#      von Neumann register machine: functions in [nextcode] can have multiple
#      arguments, and variables (and function arguments) correspond closely to
#      machine registers.  Like the [lambdacode] language, the [nextcode] language
#      here is also typed, but with an even simpler set of types. [...] This phase
#      also determines the argument-passing convention for all function calls and
#      returns, and the representation for all records and concrete sumtypes."
#              
#          -- p33, "Compiling Standard ML For Efficient Execution on Modern Machines"
#             http://flint.cs.yale.edu/flint/publications/zsh-thesis.pdf
#              
# (Anormcode was not supported in the above-described version of the compiler, 1994.)
#
# The real work here is converting from anormcode's tree-structured
# expressions to the 'next'-chained linear expressions of nextcode.
#
# This gets done in fun "loop'"
#
# We also do switch optimization at this point, delegating the work to
#
#     src/lib/compiler/back/top/nextcode/improve-anormcode-switch-fn.pkg

# Compiled by:
#     src/lib/compiler/core.sublib


# *************************************************************************
#                         IMPORTANT NOTES                                 *
#                                                                         *
#          The nextcode code generated by this phase should not           *
#                use OFFSET and RECORD accesspath SELp.                   *
#                  generated by this module.                              *
# *************************************************************************

stipulate
    package acf =  anormcode_form;                      # anormcode_form                is from   src/lib/compiler/back/top/anormcode/anormcode-form.pkg
    package ncf =  nextcode_form;                       # nextcode_form                 is from   src/lib/compiler/back/top/nextcode/nextcode-form.pkg
herein

    api Translate_Anormcode_To_Nextcode {
        #
        translate_anormcode_to_nextcode
            :
            acf::Function
            ->
            ncf::Function;
    };
end;




                                                        # Machine_Properties            is from   src/lib/compiler/back/low/main/main/machine-properties.api

stipulate
    package acf =  anormcode_form;                      # anormcode_form                is from   src/lib/compiler/back/top/anormcode/anormcode-form.pkg
    package acj =  anormcode_junk;                      # anormcode_junk                is from   src/lib/compiler/back/top/anormcode/anormcode-junk.pkg
    package da  =  varhome;                             # varhome                       is from   src/lib/compiler/front/typer-stuff/basics/varhome.pkg
    package di  =  debruijn_index;                      # debruijn_index                is from   src/lib/compiler/front/typer/basics/debruijn-index.pkg
    package hbo =  highcode_baseops;                    # highcode_baseops              is from   src/lib/compiler/back/top/highcode/highcode-baseops.pkg
    package hcf =  highcode_form;                       # highcode_form                 is from   src/lib/compiler/back/top/highcode/highcode-form.pkg
    package iht =  int_hashtable;                       # int_hashtable                 is from   src/lib/src/int-hashtable.pkg
    package im  =  int_binary_map;                      # int_binary_map                is from   src/lib/src/int-binary-map.pkg
    package isf =  improve_anormcode_switch_fn;         # improve_anormcode_switch_fn   is from   src/lib/compiler/back/top/nextcode/improve-anormcode-switch-fn.pkg
    package ncf =  nextcode_form;                       # nextcode_form                 is from   src/lib/compiler/back/top/nextcode/nextcode-form.pkg
    package rat =  recover_anormcode_type_info;         # recover_anormcode_type_info   is from   src/lib/compiler/back/top/improve/recover-anormcode-type-info.pkg
    package tmp =  highcode_codetemp;                   # highcode_codetemp             is from   src/lib/compiler/back/top/highcode/highcode-codetemp.pkg
herein

    # This generic is invoked (only) from:
    #
    #     src/lib/compiler/back/top/main/backend-tophalf-g.pkg
    #
    generic package   translate_anormcode_to_nextcode_g   (
        #             =================================
        #
        machine_properties:  Machine_Properties         # Typically                                       src/lib/compiler/back/low/main/intel32/machine-properties-intel32.pkg
    )
    : (weak) Translate_Anormcode_To_Nextcode            # Translate_Anormcode_To_Nextcode       is from   src/lib/compiler/back/top/nextcode/translate-anormcode-to-nextcode-g.pkg
    {
        fun bug s
            =
            error_message::impossible ("translate_anormcode_to_nextcode_g: " + s);

        say      =  global_controls::print::say;

        make_codetemp =    \\ _ =  tmp::issue_highcode_codetemp ();                             # The '_' is a little trick that lets us do   map make_codetemp xs   to make a list with as many codetemps as there are elements in 'xs'.

        clone_codetemp     =  tmp::clone_highcode_codetemp;                                     # Create and return a fresh codetemp.  If we're tracking human-readable codetemp names for debugging purposes, make the new codetemp have the same name as the original.

        fun with_fresh_codetemp f
            =
            {   v =  make_codetemp ();
                f v;
            };

        nop_fn =    \\ le =  le;                                                                # no-op fn, aka "identity \\".
        offp0  =    ncf::SLOT 0;


        # Test whether two values are
        # equivalent Variable values 

        fun veq (ncf::CODETEMP x, ncf::CODETEMP y)   =>   x == y;
            veq _                                    =>   FALSE;
        end;

        # *************************************************************************
        #              CONSTANTS AND UTILITY FUNCTIONS                            *
        # *************************************************************************

        fun unwrapf64 (u, to_temp, next) =  ncf::PURE { op => ncf::p::UNWRAP_FLOAT64, args => [u], to_temp, type =>  ncf::typ::FLOAT64,       next };
        fun unwrapi32 (u, to_temp, next) =  ncf::PURE { op => ncf::p::UNWRAP_INT1,    args => [u], to_temp, type =>  ncf::typ::INT1,          next };                   # 64-bit issue.  We have at least a naming issue here.

        fun   wrapf64 (u, to_temp, next) =  ncf::PURE { op => ncf::p::WRAP_FLOAT64,   args => [u], to_temp, type =>  ncf::bogus_pointer_type, next };
        fun   wrapi32 (u, to_temp, next) =  ncf::PURE { op => ncf::p::WRAP_INT1,      args => [u], to_temp, type =>  ncf::bogus_pointer_type, next };                   # 64-bit issue.  We have at least a naming issue here.

        fun all_float (ncf::typ::FLOAT64 ! r) =>  all_float r;
            all_float (_                 ! r) =>  FALSE;
            all_float []                      =>  TRUE;
        end;

        fun get_field_from_all_float_record (i, record, to_temp, type, next)            # Get a field from an all-float record.
            =
            ncf::GET_FIELD_I { i, record, to_temp, type, next };

        fun get_field (i, record, to_temp, type, next)                                  # Get a field from a record which is not all floats.
            =
            case type
                #
                ncf::typ::FLOAT64 =>  with_fresh_codetemp (\\ codetemp =  ncf::GET_FIELD_I { i, record, to_temp => codetemp, type => ncf::bogus_pointer_type, next => unwrapf64 (ncf::CODETEMP codetemp, to_temp, next) } );
                ncf::typ::INT1    =>  with_fresh_codetemp (\\ codetemp =  ncf::GET_FIELD_I { i, record, to_temp => codetemp, type => ncf::bogus_pointer_type, next => unwrapi32 (ncf::CODETEMP codetemp, to_temp, next) } );
                #
                _                  =>  ncf::GET_FIELD_I { i, record, to_temp, type, next };
            esac;


        fun all_float_record (fields, _, to_temp, next)
            = 
            ncf::DEFINE_RECORD
              {
                kind   =>  ncf::rk::FLOAT64_BLOCK,
                fields =>  map  (\\ field =  (field, ncf::SLOT 0))  fields,
                to_temp,
                next
              };


        fun record (fields, field_types, to_temp, next)
            =
            {   (do_fields (field_types, fields, [], \\ x = x))
                    ->
                    (fields, header);
                    
                header (ncf::DEFINE_RECORD { kind => ncf::rk::RECORD, fields, to_temp, next });
            }
            where
                fun do_fields  (ncf::typ::FLOAT64 ! more_fieldtypes,  field ! more_fields,   fields',  header')
                        => 
                        with_fresh_codetemp  (\\ codetemp = do_fields ( more_fieldtypes,
                                                                        more_fields,
                                                                        (ncf::CODETEMP codetemp, ncf::SLOT 0) ! fields', 
                                                                        \\ ce =  header' (wrapf64 (field, codetemp, ce))
                                                                      )
                                 );

                    do_fields  (ncf::typ::INT1 ! more_fieldtypes,  field ! more_fields,   fields', header')
                        => 
                        with_fresh_codetemp  (\\ codetemp = do_fields ( more_fieldtypes,
                                                                        more_fields,
                                                                        (ncf::CODETEMP codetemp, ncf::SLOT 0) ! fields', 
                                                                        \\ ce = header' (wrapi32 (field, codetemp, ce))
                                                                      )
                                 );

                    do_fields  (_ ! more_fieldtypes,  field ! more_fields,   fields', header')
                        =>
                        do_fields (more_fieldtypes, more_fields,   (field, offp0) ! fields',  header');

                    do_fields  ([], [],   fields', header')
                        =>
                        (reverse fields', header');

                    do_fields _ =>   bug "unexpected in recordNM in convert";
                end;
            end;

        # *************************************************************************
        #              UTILITY FUNCTIONS FOR PROCESSING THE BASEOPS               *
        # *************************************************************************

        fun translate_number_kind_and_size (hbo::INT   bits) =>  ncf::p::INT bits;
            translate_number_kind_and_size (hbo::UNT   bits) =>  ncf::p::UNT bits;
            translate_number_kind_and_size (hbo::FLOAT bits) =>  ncf::p::FLOAT bits;
        end;

        fun translate_compare_op  compare_op
            = 
            case compare_op
                #               
                { op=>hbo::EQL, kind_and_size=>hbo::INT 31 }
                    =>
                    ncf::p::ieql;

                { op=>hbo::NEQ, kind_and_size=>hbo::INT 31 }
                    =>
                    ncf::p::ineq;

                { op, kind_and_size=>hbo::FLOAT size }
                   => 
                   {   fun c hbo::GT    => ncf::p::f::GT;
                           c hbo::GE    => ncf::p::f::GE;
                           c hbo::LT    => ncf::p::f::LT;
                           c hbo::LE    => ncf::p::f::LE;
                           c hbo::EQL   => ncf::p::f::EQ;
                           c hbo::NEQ   => ncf::p::f::ULG;
                           c _ => bug "translate_compare_op: kind_and_size=hbo::FLOAT";
                       end;

                       ncf::p::COMPARE_FLOATS { op=> c op, size };
                   };

                { op, kind_and_size }
                     => 
                     ncf::p::COMPARE { op => c op, kind_and_size => translate_number_kind_and_size kind_and_size }
                     where
                         fun check (_, hbo::UNT _) => ();
                             check (op, _) => bug ("check" + op);
                         end;

                         fun c hbo::GT  =>  ncf::p::GT;  
                             c hbo::GE  =>  ncf::p::GE; 
                             c hbo::LT  =>  ncf::p::LT; 
                             c hbo::LE  =>  ncf::p::LE;
                             c hbo::LEU =>  { check ("leu", kind_and_size); ncf::p::LE ;};
                             c hbo::LTU =>  { check ("ltu", kind_and_size); ncf::p::LT ;};
                             c hbo::GEU =>  { check ("geu", kind_and_size); ncf::p::GE ;};
                             c hbo::GTU =>  { check ("gtu", kind_and_size); ncf::p::GT ;};
                             c hbo::EQL =>  ncf::p::EQL;
                             c hbo::NEQ =>  ncf::p::NEQ;
                         end;
                     end;
            esac;


        fun translate_compare  (p: hbo::Baseop)
            = 
            case p
                #               
                hbo::IS_BOXED       =>  ncf::p::IS_BOXED;
                hbo::IS_UNBOXED     =>  ncf::p::IS_UNBOXED;
                #
                hbo::COMPARE compare_op =>  translate_compare_op compare_op;
                #
                hbo::POINTER_EQL    =>  ncf::p::POINTER_EQL;
                hbo::POINTER_NEQ    =>  ncf::p::POINTER_NEQ;
                #
                _ => bug "unexpected primops in translate_compare";
            esac;


        fun translate_wrap_op  ncf::typ::INT     =>  ncf::p::IWRAP;
            translate_wrap_op  ncf::typ::INT1    =>  ncf::p::WRAP_INT1;
            translate_wrap_op  ncf::typ::FLOAT64 =>  ncf::p::WRAP_FLOAT64;
            translate_wrap_op  _                 =>  ncf::p::WRAP;
        end;


        fun translate_unwrap_op  ncf::typ::INT     =>  ncf::p::IUNWRAP;
            translate_unwrap_op  ncf::typ::INT1    =>  ncf::p::UNWRAP_INT1;
            translate_unwrap_op  ncf::typ::FLOAT64 =>  ncf::p::UNWRAP_FLOAT64;
            translate_unwrap_op  _                 =>  ncf::p::UNWRAP;
        end;


        fun translate_arithop  hbo::NEGATE      => ncf::p::NEGATE;
            translate_arithop  hbo::ABS         => ncf::p::ABS;
            translate_arithop  hbo::FSQRT       => ncf::p::FSQRT;
            #
            translate_arithop  hbo::FSIN        => ncf::p::FSIN;
            translate_arithop  hbo::FCOS        => ncf::p::FCOS;
            translate_arithop  hbo::FTAN        => ncf::p::FTAN;
            #
            translate_arithop  hbo::DIVIDE      => ncf::p::DIVIDE;                      # Round-to-zero division -- this is the native instruction on Intel32.
            translate_arithop  hbo::DIV         => ncf::p::DIV;                         # Round-to-negative-infinity division  -- this will be much slower on Intel32, has to be faked.
            #
            translate_arithop  hbo::REM         => ncf::p::REM;                         # Round-to-zero remainder -- this is the native instruction on Intel32.
            translate_arithop  hbo::MOD         => ncf::p::MOD;                         # Round-to-negative-infinity remainder -- this will be much slower on Intel32, has to be faked.
            #
            translate_arithop  hbo::ADD         => ncf::p::ADD;
            translate_arithop  hbo::SUBTRACT    => ncf::p::SUBTRACT;
            translate_arithop  hbo::MULTIPLY    => ncf::p::MULTIPLY;
            #
            translate_arithop  hbo::LSHIFT      => ncf::p::LSHIFT;
            translate_arithop  hbo::RSHIFT      => ncf::p::RSHIFT;
            translate_arithop  hbo::RSHIFTL     => ncf::p::RSHIFTL;
            #
            translate_arithop  hbo::BITWISE_NOT => ncf::p::BITWISE_NOT;
            translate_arithop  hbo::BITWISE_AND => ncf::p::BITWISE_AND;
            translate_arithop  hbo::BITWISE_OR  => ncf::p::BITWISE_OR;
            translate_arithop  hbo::BITWISE_XOR => ncf::p::BITWISE_XOR;
        end;

        Baseop_Kind                                                                     # Classify baseops based on memory/purity semantics.
          = STORE_TO_RAM       ncf::p::Store_To_Ram
          | PURE_PRIMOP        ncf::p::Pure
          | FETCH_FROM_RAM     ncf::p::Fetch_From_Ram
          | ARITHMETIC_PRIMOP  ncf::p::Arith
          ;


        fun translate_baseop  (baseop: hbo::Baseop)
            = 
            case baseop
                #              
                hbo::SHRINK_INT (from, to) =>  ARITHMETIC_PRIMOP (ncf::p::SHRINK_INT (from, to));
                hbo::SHRINK_UNT (from, to) =>  ARITHMETIC_PRIMOP (ncf::p::SHRINK_UNT (from, to));
                hbo::COPY       (from, to) =>  PURE_PRIMOP (ncf::p::COPY       (from, to));
                hbo::STRETCH    (from, to) =>  PURE_PRIMOP (ncf::p::STRETCH    (from, to));
                hbo::CHOP       (from, to) =>  PURE_PRIMOP (ncf::p::CHOP       (from, to));

                hbo::SHRINK_INTEGER     to   =>  ARITHMETIC_PRIMOP (ncf::p::SHRINK_INTEGER     to);
                hbo::CHOP_INTEGER       to   =>  PURE_PRIMOP       (ncf::p::CHOP_INTEGER       to);
                hbo::COPY_TO_INTEGER    from =>  PURE_PRIMOP       (ncf::p::COPY_TO_INTEGER    from);
                hbo::STRETCH_TO_INTEGER from =>  PURE_PRIMOP       (ncf::p::STRETCH_TO_INTEGER from);

                hbo::ARITH { op, kind_and_size, overflow=>TRUE  } =>  ARITHMETIC_PRIMOP (ncf::p::ARITH      { op=>translate_arithop op, kind_and_size=>translate_number_kind_and_size kind_and_size } );
                hbo::ARITH { op, kind_and_size, overflow=>FALSE } =>        PURE_PRIMOP (ncf::p::PURE_ARITH { op=>translate_arithop op, kind_and_size=>translate_number_kind_and_size kind_and_size } );

                hbo::ROUND { floor, from, to }
                    =>
                    ARITHMETIC_PRIMOP (ncf::p::ROUND { floor,
                                                       from => translate_number_kind_and_size from,
                                                       to   => translate_number_kind_and_size to
                                                     }
                                      );

                hbo::CONVERT_FLOAT { from, to }
                    =>
                    PURE_PRIMOP (ncf::p::CONVERT_FLOAT { to   =>  translate_number_kind_and_size to,
                                                         from =>  translate_number_kind_and_size from
                                                       }
                                );

                hbo::RO_VECTOR_GET                   =>  PURE_PRIMOP ncf::p::RO_VECTOR_GET;
                hbo::MAKE_REFCELL                    =>  PURE_PRIMOP ncf::p::MAKE_REFCELL;
                hbo::VECTOR_LENGTH_IN_SLOTS          =>  PURE_PRIMOP ncf::p::VECTOR_LENGTH_IN_SLOTS;
                hbo::HEAPCHUNK_LENGTH_IN_WORDS       =>  PURE_PRIMOP ncf::p::HEAPCHUNK_LENGTH_IN_WORDS;
                hbo::GET_BATAG_FROM_TAGWORD          =>  PURE_PRIMOP ncf::p::GET_BATAG_FROM_TAGWORD;
                hbo::MAKE_WEAK_POINTER_OR_SUSPENSION =>  PURE_PRIMOP ncf::p::MAKE_WEAK_POINTER_OR_SUSPENSION;
          #     hbo::THROW                           =>  PURE_PRIMOP ncf::p::CAST; 
                hbo::CAST                            =>  PURE_PRIMOP ncf::p::CAST;
                hbo::MAKE_EXCEPTION_TAG              =>  PURE_PRIMOP ncf::p::MAKE_REFCELL;
                hbo::MAKE_ZERO_LENGTH_VECTOR         =>  PURE_PRIMOP ncf::p::MAKE_ZERO_LENGTH_VECTOR;
                hbo::GET_VECTOR_DATACHUNK            =>  PURE_PRIMOP ncf::p::GETSEQDATA;
                hbo::RECORD_GET                      =>  PURE_PRIMOP ncf::p::RECORD_GET;
                hbo::RAW64_GET                       =>  PURE_PRIMOP ncf::p::RAW64_GET;

                hbo::RW_VECTOR_GET => FETCH_FROM_RAM (ncf::p::GET_VECSLOT_CONTENTS);

                hbo::GET_VECSLOT_NUMERIC_CONTENTS { kind_and_size, immutable=>FALSE, checkbounds=>FALSE } =>  FETCH_FROM_RAM (     ncf::p::GET_VECSLOT_NUMERIC_CONTENTS { kind_and_size=>translate_number_kind_and_size  kind_and_size } );
                hbo::GET_VECSLOT_NUMERIC_CONTENTS { kind_and_size, immutable=>TRUE,  checkbounds=>FALSE } =>     PURE_PRIMOP (ncf::p::PURE_GET_VECSLOT_NUMERIC_CONTENTS { kind_and_size=>translate_number_kind_and_size  kind_and_size } );

                hbo::GET_REFCELL_CONTENTS                       =>  FETCH_FROM_RAM  ncf::p::GET_REFCELL_CONTENTS;
                hbo::GET_RUNTIME_ASM_PACKAGE_RECORD             =>  FETCH_FROM_RAM  ncf::p::GET_RUNTIME_ASM_PACKAGE_RECORD;
                hbo::GET_EXCEPTION_HANDLER_REGISTER             =>  FETCH_FROM_RAM  ncf::p::GET_EXCEPTION_HANDLER_REGISTER;
                hbo::GET_CURRENT_MICROTHREAD_REGISTER           =>  FETCH_FROM_RAM  ncf::p::GET_CURRENT_MICROTHREAD_REGISTER;
                hbo::PSEUDOREG_GET                              =>  FETCH_FROM_RAM  ncf::p::PSEUDOREG_GET;
                hbo::GET_STATE_OF_WEAK_POINTER_OR_SUSPENSION    =>  FETCH_FROM_RAM  ncf::p::GET_STATE_OF_WEAK_POINTER_OR_SUSPENSION;
                hbo::DEFLVAR                                    =>  FETCH_FROM_RAM  ncf::p::DEFLVAR;

                hbo::SET_EXCEPTION_HANDLER_REGISTER                                     =>  STORE_TO_RAM  ncf::p::SET_EXCEPTION_HANDLER_REGISTER;
                hbo::SET_VECSLOT_TO_NUMERIC_VALUE { kind_and_size, checkbounds=>FALSE } =>  STORE_TO_RAM (ncf::p::SET_VECSLOT_TO_NUMERIC_VALUE { kind_and_size=>translate_number_kind_and_size kind_and_size } );
                hbo::SET_VECSLOT_TO_TAGGED_INT_VALUE                                    =>  STORE_TO_RAM  ncf::p::SET_VECSLOT_TO_TAGGED_INT_VALUE;
                hbo::SET_VECSLOT_TO_BOXED_VALUE                                         =>  STORE_TO_RAM  ncf::p::SET_VECSLOT_TO_BOXED_VALUE;
                hbo::RW_VECTOR_SET                                                      =>  STORE_TO_RAM  ncf::p::RW_VECTOR_SET;
                hbo::SET_REFCELL                                                        =>  STORE_TO_RAM  ncf::p::SET_REFCELL;
                hbo::SET_REFCELL_TO_TAGGED_INT_VALUE                                    =>  STORE_TO_RAM  ncf::p::SET_REFCELL_TO_TAGGED_INT_VALUE;
                hbo::SET_CURRENT_MICROTHREAD_REGISTER                                   =>  STORE_TO_RAM  ncf::p::SET_CURRENT_MICROTHREAD_REGISTER;
                hbo::PSEUDOREG_SET                                                      =>  STORE_TO_RAM  ncf::p::PSEUDOREG_SET;
                hbo::SETMARK                                                            =>  STORE_TO_RAM  ncf::p::SETMARK;
                hbo::DISPOSE                                                            =>  STORE_TO_RAM  ncf::p::FREE;
                hbo::SET_STATE_OF_WEAK_POINTER_OR_SUSPENSION                            =>  STORE_TO_RAM  ncf::p::SET_STATE_OF_WEAK_POINTER_OR_SUSPENSION;
                hbo::USELVAR => STORE_TO_RAM (ncf::p::USELVAR);

                hbo::GET_FROM_NONHEAP_RAM nk                                            =>  FETCH_FROM_RAM (ncf::p::GET_FROM_NONHEAP_RAM  { kind_and_size => translate_number_kind_and_size nk } );
                hbo::SET_NONHEAP_RAM      nk                                            =>  STORE_TO_RAM   (ncf::p::SET_NONHEAP_RAM       { kind_and_size => translate_number_kind_and_size nk } );

                hbo::RAW_ALLOCATE_C_RECORD { fblock => FALSE }                          =>  PURE_PRIMOP (ncf::p::ALLOT_RAW_RECORD (THE ncf::rk::INT1_BLOCK));
                hbo::RAW_ALLOCATE_C_RECORD { fblock => TRUE  }                          =>  PURE_PRIMOP (ncf::p::ALLOT_RAW_RECORD (THE ncf::rk::FLOAT64_BLOCK));

                _ => bug ("bad baseop in translate_baseop: " + (hbo::baseop_to_string baseop) + "\n");
           esac;

        # *************************************************************************
        #                  SWITCH OPTIMIZATIONS AND COMPILATIONS                  *
        # *************************************************************************

        # BUG: The definition of e_unt is clearly incorrect since it can raise exceptions
        #        and overflow at code generation time. A clean solution would be 
        #        to add an UNT constructor into the nextcode language -- daunting!
        #        The revolting hack solution would be to put the right int constant 
        #        that gets converted to the right set of bits for the word constant.  XXX BUGGO FIXME

        fun do_switch_fn  rename
            =
            isf::make_anormcode_switch_fn_improver
              {
                e_int    => \\ i =  if (i < -0x20000000 or i >= 0x20000000)   raise exception isf::TOO_BIG;
                                    else                                      ncf::INT i;
                                    fi, 

                e_unt   => \\ w =  # if w >= 0wx20000000 
                                   # then raise exception Switch::TOO_BIG else
                                   ncf::INT (unt::to_int_x w),

                e_real   => (\\ s =  ncf::FLOAT64 s),
                e_switchlimit => 4,
                e_neq    => ncf::p::ineq,
                e_w32neq => ncf::p::COMPARE { op=>ncf::p::NEQ, kind_and_size=>ncf::p::UNT 32 },
                e_i32neq => ncf::p::COMPARE { op=>ncf::p::NEQ, kind_and_size=>ncf::p::INT 32 },
                e_unt1  => ncf::INT1,
                e_int1  => ncf::INT1, 
                e_wneq   => ncf::p::COMPARE { op=>ncf::p::NEQ, kind_and_size=>ncf::p::UNT 31 },
                e_pneq   => ncf::p::POINTER_NEQ,
                e_fneq   => ncf::p::fneq,
                e_less   => ncf::p::ilt,
                e_branch => (\\ (op, x, y, then_next, else_next) =  ncf::IF_THEN_ELSE { op,                       args => [x, y],                                    xvar => make_codetemp(), then_next, else_next }),
                e_strneq => (\\ (w, str,   then_next, else_next) =  ncf::IF_THEN_ELSE { op => ncf::p::STRING_NEQ, args => [ncf::INT (size str), w, ncf::STRING str], xvar => make_codetemp(), then_next, else_next }),

                e_switch => (\\ (i, nexts) =  ncf::JUMPTABLE { i, xvar => make_codetemp(), nexts }),

                e_add    => (\\ (x, y, c)
                                =
                                with_fresh_codetemp
                                    (\\ to_temp
                                        =
                                        ncf::ARITH  { op   =>  ncf::p::iadd,
                                                      args =>  [x, y],
                                                      to_temp,
                                                      type =>  ncf::typ::INT,
                                                      next =>  c (ncf::CODETEMP to_temp)
                                                    }
                            )       ),

                e_gettag => (\\ (arg, c) =  with_fresh_codetemp (\\ to_temp =  ncf::PURE { op => ncf::p::GETCON,                        args =>[arg], to_temp, type =>  ncf::typ::INT,           next => c (ncf::CODETEMP to_temp ) } )), 
                e_unwrap => (\\ (arg, c) =  with_fresh_codetemp (\\ to_temp =  ncf::PURE { op => ncf::p::UNWRAP,                        args =>[arg], to_temp, type =>  ncf::typ::INT,           next => c (ncf::CODETEMP to_temp ) } )),
                e_getexn => (\\ (arg, c) =  with_fresh_codetemp (\\ to_temp =  ncf::PURE { op => ncf::p::GETEXN,                        args =>[arg], to_temp, type =>  ncf::bogus_pointer_type, next => c (ncf::CODETEMP to_temp ) } )), 
                e_length => (\\ (arg, c) =  with_fresh_codetemp (\\ to_temp =  ncf::PURE { op => ncf::p::VECTOR_LENGTH_IN_SLOTS,        args =>[arg], to_temp, type =>  ncf::typ::INT,           next => c (ncf::CODETEMP to_temp ) } )), 

                e_boxed  => (\\ (x, then_next, else_next) =  ncf::IF_THEN_ELSE { op   => ncf::p::IS_BOXED,
                                                                                 args => [x],
                                                                                 xvar => make_codetemp(),
                                                                                 then_next,
                                                                                 else_next
                                                                               }
                            ),

                e_path   =>  \\ (da::HIGHCODE_VARIABLE v, k) =>  k (rename v);
                                _                            =>  bug "unexpected path in do_switch_fn";
                             end
            };

        ###########################################################################
        #       UTILITY FUNCTIONS FOR DEALING WITH META-LEVEL FATES
        ###########################################################################

        Metafate                                                #  An abstract representation of the meta-level fate.
            =
            METAFATE { fate:   List (ncf::Value) -> ncf::Instruction,
                       types:  List( ncf::Type )
                     };


        fun apply_metafate
              ( METAFATE { fate, ... },
                values:                         List (ncf::Value)
              )
            :                                   ncf::Instruction
            =
            fate  values;


        fun make_metafate (fate, types)
            =
            METAFATE { fate, types };

        fun get_types_from_metafate (METAFATE { types, ... } )
            =
            types;


        ###########################################################################
        #                        THE MAIN FUNCTION
        ###########################################################################

        # This function is invoked (only) as phase "translate_anormcode_to_nextcode" in
        # the toplevel highcode driver module, 
        #
        #     src/lib/compiler/back/top/main/backend-tophalf-g.pkg
        #

        fun translate_anormcode_to_nextcode  (function_declaration: acf::Function):  ncf::Function
            = 
            {   (rat::recover_anormcode_type_info (function_declaration, TRUE))
                    ->
                    { get_uniqtypoid_for_anormcode_value, clean_up, ... };
                    

                uniqtypoid_to_nextcode_types =  map ncf::uniqtypoid_to_nextcode_type;

                fun res_ctys f
                    = 
                    {   lt = get_uniqtypoid_for_anormcode_value (acf::VAR f);

                        if   (hcf::uniqtypoid_is_generic_package lt)    uniqtypoid_to_nextcode_types (#2 (hcf::unpack_generic_package_uniqtypoid lt));
                        elif (hcf::uniqtypoid_is_arrow_type      lt)    uniqtypoid_to_nextcode_types (#3 (hcf::unpack_arrow_uniqtypoid lt));
                        else                                          [ ncf::bogus_pointer_type ];
                        fi;
                    };

                fun get_nextcode_type_for_anormcode_value v
                    =
                    ncf::uniqtypoid_to_nextcode_type (get_uniqtypoid_for_anormcode_value v);

                fun is_float_record u
                    = 
                    hcf::if_uniqtypoid_is_type
                      (
                        get_uniqtypoid_for_anormcode_value u, 

                        \\ tc =  hcf::if_uniqtype_is_tuple (
                                     tc,
                                     \\ l =  all_float (map ncf::uniqtype_to_nextcode l),
                                     \\ _ =  FALSE
                                 ),

                        \\ _ =  FALSE
                      );

                bogus_fate_codetemp = make_codetemp(); 

                fun bogus_header next
                    = 
                    {   bogus_knownf = make_codetemp();

                        ncf::DEFINE_FUNS
                          {
                            funs => [ ( ncf::PRIVATE_FN,
                                        bogus_knownf,
                                        [ make_codetemp () ],
                                        [ ncf::bogus_pointer_type ],
                                        #
                                        ncf::TAIL_CALL    { fn =>  ncf::CODETEMP bogus_knownf,
                                                            args =>  [ ncf::STRING "bogus" ]
                                                          }
                                      )
                                    ], 

                            next => ncf::DEFINE_FUNS
                                      {
                                        funs =>
                                            [ ( ncf::FATE_FN,
                                                bogus_fate_codetemp,
                                                [ make_codetemp () ],
                                                [ ncf::bogus_pointer_type ],
                                                #
                                                ncf::TAIL_CALL    { fn =>  ncf::CODETEMP bogus_knownf,
                                                                    args =>  [ncf::STRING "bogus"]
                                                                  }
                                              )
                                            ],
                                        next
                                      }
                          };
                    }; 


                exception RENAME;

                renaming_table  =   iht::make_hashtable  { size_hint => 32,  not_found_exception => RENAME }
                                :   iht::Hashtable( ncf::Value )
                                ;
                    


                fun rename_codetemp (codetemp: tmp::Codetemp):  ncf::Value
                    =
                    iht::get  renaming_table  codetemp
                    except
                        RENAME =  ncf::CODETEMP codetemp;


                fun newname ( codetemp:         tmp::Codetemp,
                              value:            ncf::Value
                            )
                    :                           Void
                    = 
                    {   case value
                            #                          
                            ncf::CODETEMP value' =>  tmp::share_name (codetemp, value');
                            _                    =>  ();
                        esac;

                        iht::set  renaming_table  (codetemp, value);
                    };


                fun newnames ([]: List(tmp::Codetemp),  []: List(ncf::Value)):  Void
                        =>
                        ();

                    newnames ( codetemp ! codetemps,
                               value    ! values
                             )
                        =>
                        {   newname (codetemp, value);
                            newnames (codetemps, values);
                        };

                    newnames _ =>   bug "unexpected case in newnames";
                end;


                
                # "eta reduction" gets rid of functions like
                #     fun foo x = bar x;
                # which simply pass their argument to another function,
                # we we can't do this if the function calls itself like
                #     fun foo x = foo x;
                #
                stipulate
                    fun calls_self
                          ( ncf::TAIL_CALL { fn =>  w as ncf::CODETEMP lv,
                                             args =>  vl
                                           },
                            ul:                            List(ncf::Value)
                          ):                            Null_Or(ncf::Value)
                            => 

                            # If the function is in the global renaming table and it is
                            # renamed to itself, then it is most likely a while loop and
                            # should *not* be eta-reduced

                            if ( case (iht::get  renaming_table  lv)
                                     #
                                     ncf::CODETEMP lv' =>  lv == lv';
                                     _                 =>  FALSE;
                                 esac
                                 except
                                     RENAME =  FALSE
                            )
                                 NULL;
                            else
                                 h (ul, vl)
                                 where
                                     fun h (x ! xs, y ! ys)
                                             => 
                                             (veq (x, y)  and  not (veq (w, y)))
                                                 ??  h (xs, ys)
                                                 ::  NULL;

                                         h ([], [])
                                             =>
                                             THE w;

                                         h _ =>
                                             NULL;
                                     end;
                                 end;
                            fi;

                        calls_self _ => NULL;
                    end;

                herein

                    fun prevent_erroneous_eta_reductions (METAFATE { fate, types } ):           ((ncf::Instruction -> ncf::Instruction), ncf::Value)
                        = 
                        {   vl =  map make_codetemp types;
                            ul =  map ncf::CODETEMP vl;

                            b =  fate ul;

                            case (calls_self (b, ul) )
                                #                         
                                THE w =>        (nop_fn, w);

                                NULL  =>    {   f = make_codetemp();

                                                ( \\ next =   ncf::DEFINE_FUNS {  funs => [(ncf::FATE_FN, f, vl, types, b)],  next  },
                                                  ncf::CODETEMP f
                                                );
                                            };
                            esac;
                        };
                end;

                do_switch                                               # Switch optimization 
                    =
                    do_switch_fn  rename_codetemp;



                fun translate_value (acf::VAR     c) =>  rename_codetemp c;
                    translate_value (acf::UNT1    w) =>  ncf::INT1 w;
                    translate_value (acf::INT     i) =>  ncf::INT i;
                    translate_value (acf::UNT     w) =>  ncf::INT (unt::to_int_x w);
                    translate_value (acf::FLOAT64 r) =>  ncf::FLOAT64 r;
                    translate_value (acf::STRING  s) =>  ncf::STRING s;

                    translate_value (acf::INT1 i)
                        => 
                        {   int1_to_unt1 =  one_word_unt::from_multiword_int
                                            o
                                            one_word_int::to_multiword_int;

                            ncf::INT1 (int1_to_unt1 i);
                        };
                end;


                fun translate_values (vl:  List(acf::Value)):  List(ncf::Value)
                    = 
                    h (vl, [])
                    where
                        fun h (   [], z) =>  reverse z;
                            h (a ! r, z) =>  h (r, (translate_value a) ! z);
                        end;
                    end;


                fun loop'   (tailmap:           im::Map(tmp::Codetemp))
                            #
                            ( expression:       acf::Expression,
                              metafate:         Metafate
                            )
                    :                           ncf::Instruction
                    =
                    {   loop =  loop' tailmap;
                        #
                        case expression
                            #
                            acf::RET vs =>  apply_metafate (metafate, translate_values vs);
                            #
                            acf::LET (vs, e1, e2)
                                =>
                                loop (e1, metafate')
                                where
                                    metafate' = make_metafate
                                                  ( \\ ws = {   newnames (vs, ws);
                                                                loop (e2, metafate);
                                                            },
                                                    map  (get_nextcode_type_for_anormcode_value o acf::VAR)  vs
                                                  );
                                end;

                            acf::MUTUALLY_RECURSIVE_FNS (fds, e)
                                =>
                                {
                                    fun lpfd ((fk, f, fn_parameters, e):   acf::Function):   ncf::Function
                                        = 
                                        {   k = make_codetemp();

                                            cl =   ncf::typ::FATE  !  (map (ncf::uniqtypoid_to_nextcode_type o #2) fn_parameters);                      # #2 gives us the type of a fn parameter.

                                            metafate' =  make_metafate
                                                          ( \\ args = ncf::TAIL_CALL { fn => ncf::CODETEMP k, args },
                                                            res_ctys f
                                                          );

                                            my (vl, body)
                                                =
                                                case fk
                                                    #
                                                    { loop_info => THE (_, acf::TAIL_RECURSIVE_LOOP), ... }
                                                        =>
                                                        {   # For tail recursive loops, we create a
                                                            # local function that takes its fate
                                                            # from the dictionary:

                                                            f' = clone_codetemp f;

                                                            newname (f', ncf::CODETEMP f');                                             # Add an entry for f' in the global renaming table to stop calls_self from marking it for "eta reduction" (elimination):

                                                            vl = k ! (map (clone_codetemp o #1) fn_parameters);                         # #1 yields the codetemp naming a fn parameter.

                                                            vl' = map #1 fn_parameters;
                                                            cl' = map (ncf::uniqtypoid_to_nextcode_type o #2) fn_parameters;

                                                            ( vl,
                                                              ncf::DEFINE_FUNS
                                                                {
                                                                  funs =>
                                                                      [ ( ncf::PRIVATE_TAIL_RECURSIVE_FN,
                                                                          f',
                                                                          vl',
                                                                          cl',
                                                                          loop' (im::set (tailmap, f, f')) (e, metafate')       # Add the function to the tailmap.
                                                                        )
                                                                      ],

                                                                  next =>
                                                                      ncf::TAIL_CALL { fn =>   ncf::CODETEMP f',
                                                                                       args =>   map ncf::CODETEMP (tail vl)
                                                                                     }
                                                                }
                                                            );
                                                         };

                                                    _ =>  ( k ! (map #1 fn_parameters),                                         # #1 gives us the codetemp naming a fn parameter.
                                                            loop (e, metafate')
                                                          );

                                                esac;

                                            (ncf::PUBLIC_FN, f, vl, cl, body);
                                        };

                                    ncf::DEFINE_FUNS  { funs =>  map lpfd fds,
                                                        next =>  loop (e, metafate)
                                                      };
                                };

                            acf::APPLY (f as acf::VAR lv, vs)
                                =>
                                # First check if it's a recursive call to a tail loop:
                                # 
                                case (im::get (tailmap, lv))
                                    #
                                    THE f' =>   ncf::TAIL_CALL { fn =>  ncf::CODETEMP  f',
                                                                 args =>  translate_values vs
                                                               };

                                    NULL   =>   # Code for the non-tail case.
                                                # Sadly this is *not* exceptional

                                                {   (prevent_erroneous_eta_reductions metafate) ->   (header, fff);
                                                    #   
                                                    fn = translate_value f;
                                                    ul   = translate_values vs;

                                                    header (ncf::TAIL_CALL {  fn,  args => fff ! ul  });
                                                };
                                esac;

                            acf::APPLY _                                =>  bug "unexpected ncf::TAIL_CALL in convert";
                            acf::TYPEFUN _                              =>  bug "unexpected TYPEFUN in convert";
                            acf::APPLY_TYPEFUN _                        =>  bug "unexpected APPLY_TYPEFUN in convert";
                            acf::CONSTRUCTOR (dc, ts, u, v, e)          =>  bug "unexpected case CONSTRUCTOR during anormcode-to-nextcode conversion"; 
                            acf::RECORD (acf::RK_VECTOR _, [], v, e)    =>  bug "zero length vectors in convert";

                            acf::RECORD (rk, [], v, e)
                                => 
                                {  newname (v, ncf::INT 0);
                                   loop (e, metafate);
                                };

                            acf::RECORD (record_notes, values, to_temp, e)
                                => 
                                {   types'  =  map get_nextcode_type_for_anormcode_value values;
                                    values' =  translate_values values;
                                    next    =  loop (e, metafate);

                                    case record_notes
                                        # 
                                        acf::RK_TUPLE _
                                            => 
                                            all_float types'
                                                ??   all_float_record (values', types', to_temp, next)
                                                ::   record (values', types', to_temp, next);

                                        acf::RK_VECTOR _
                                            => 
                                            ncf::DEFINE_RECORD
                                              { kind   => ncf::rk::VECTOR,
                                                fields => map (\\ x = (x, offp0)) values',
                                                to_temp,
                                                next
                                              };

                                        _   => record (values', types', to_temp, next);
                                    esac;
                                };

                            acf::GET_FIELD (record, slot, name, expression)                                             # Use codetemp 'name' as a name for record[slot] during execution of 'expression'
                                => 
                                {   type'       =  get_nextcode_type_for_anormcode_value (acf::VAR name);
                                    record'     =  translate_value record;
                                    expression' =  loop (expression, metafate);

                                    if (is_float_record record)   get_field_from_all_float_record (slot, record', name, type', expression');
                                    else                          get_field                       (slot, record', name, type', expression');
                                    fi;
                                };

                            acf::SWITCH (e, l, [ a as (acf::VAL_CASETAG((_, da::CONSTANT 0, _), _, _), _),
                                                 b as (acf::VAL_CASETAG((_, da::CONSTANT 1, _), _, _), _)
                                               ], 
                                      NULL)
                                =>
                                loop (acf::SWITCH (e, l, [b, a], NULL), metafate);

                            acf::SWITCH (u, an_api, l, d)
                                => 
                                {   (prevent_erroneous_eta_reductions metafate) ->   (header, fn);

                                    metafate' = make_metafate ( \\ args = ncf::TAIL_CALL { fn, args },
                                                                get_types_from_metafate metafate
                                                              );

                                    next =  {   df = make_codetemp();
                                                #
                                                fun proc (cn as (acf::VAL_CASETAG (dc, _, v)), e)
                                                        => 
                                                        (cn, loop (acf::LET([v], acf::RET [u], e), metafate'));

                                                    proc (cn, e)
                                                        =>
                                                        (cn, loop (e, metafate'));
                                                 end;

                                                next = do_switch { an_api,
                                                                   expression =>  translate_value u, 
                                                                   cases      =>  map proc l,
                                                                   default    =>  ncf::TAIL_CALL  { fn =>    ncf::CODETEMP df,
                                                                                                    args =>  [ ncf::INT 0 ] 
                                                                                                  }
                                                                 };
                                                case d 
                                                    #
                                                    NULL   => next;
                                                    THE de => ncf::DEFINE_FUNS { next,
                                                                                 funs => [ ( ncf::FATE_FN,
                                                                                             df,
                                                                                             [make_codetemp()],
                                                                                             [ncf::typ::INT],
                                                                                             loop (de, metafate')
                                                                                           )
                                                                                         ]
                                                                               };
                                                esac;
                                            };

                                    header next;
                                }; 

                            acf::RAISE (exception_to_raise, result_type)
                                =>
                                {   apply_metafate (metafate,  (map (\\ _ = ncf::CODETEMP (make_codetemp()))  result_type));            # Execute the metafate for side effects. 
                                    #
                                    h = make_codetemp();                                                                                # Now call the exception handler.       
                                    ncf::FETCH_FROM_RAM
                                      {
                                        op      => ncf::p::GET_EXCEPTION_HANDLER_REGISTER,
                                        args    => [],
                                        to_temp => h,
                                        type    => ncf::typ::FUN,
                                        next    => ncf::TAIL_CALL { fn =>   ncf::CODETEMP h,
                                                                    args => [ ncf::CODETEMP bogus_fate_codetemp,  translate_value exception_to_raise ]
                                                                  }
                                     };
                                };

                            acf::EXCEPT (expression, new_exception_handler)                                                     # Execute 'expression' with 'new_exception_handler' in force, restoring the original exception handler when done.
                                =>
                                {   (prevent_erroneous_eta_reductions metafate) ->   (header, fn);

                                    old_exception_handler_codetemp                                                              # Somewhere to save original exception handler while we're executing.
                                        =
                                        make_codetemp();

                                    metafate'
                                        =
                                        make_metafate
                                                ( \\ args =  ncf::STORE_TO_RAM { op   =>  ncf::p::SET_EXCEPTION_HANDLER_REGISTER,                       # This is the code that will restore the original exception handler at end of 'expression' execution.
                                                                                 args =>  [ncf::CODETEMP old_exception_handler_codetemp],
                                                                                 next =>  ncf::TAIL_CALL { fn, args }
                                                                               },
                                                  get_types_from_metafate metafate
                                                );

                                    body =  {   new_exception_handler_codetemp = make_codetemp();
                                                new_exception_handler_arg_codetemp = make_codetemp();

                                                ncf::DEFINE_FUNS
                                                  {
                                                    funs => [ ( ncf::PUBLIC_FN,
                                                                new_exception_handler_codetemp,                                 # Name for new handler.
                                                                [ make_codetemp(), new_exception_handler_arg_codetemp ],        # Args for new handler.
                                                                [ ncf::typ::FATE, ncf::bogus_pointer_type ],                    # Arg types.
                                                                ncf::STORE_TO_RAM                                               # Handler body.
                                                                  { op   =>  ncf::p::SET_EXCEPTION_HANDLER_REGISTER,            # First thing new handler does is restore original handler.
                                                                    args =>  [ ncf::CODETEMP old_exception_handler_codetemp ],
                                                                    next =>  ncf::TAIL_CALL   { fn =>  translate_value new_exception_handler,
                                                                                                args =>  [ fn, ncf::CODETEMP new_exception_handler_arg_codetemp]
                                                                                              }
                                                                  }
                                                              )
                                                            ],

                                                    next => ncf::STORE_TO_RAM                                                   # Set up new exception handler as the currently active one.
                                                              { op   =>  ncf::p::SET_EXCEPTION_HANDLER_REGISTER,
                                                                args =>  [ ncf::CODETEMP new_exception_handler_codetemp ],
                                                                next =>  loop (expression, metafate')                           # Do 'expression'. Our metafate' will restore original exception handler, then continue normally.
                                                              }
                                                  };
                                            };

                                    ncf::FETCH_FROM_RAM                                                                         # Save original exception handler.
                                      { op   =>  ncf::p::GET_EXCEPTION_HANDLER_REGISTER,
                                        args =>  [],
                                        to_temp =>  old_exception_handler_codetemp,
                                        type =>  ncf::typ::FUN,
                                        next =>  header body
                                      };
                                };

                            acf::BASEOP((_, p as (hbo::CALLCC | hbo::CALL_WITH_CURRENT_CONTROL_FATE), _, _), [f], v, e)
                                =>
                                {   my (kont_decs, fn)
                                        = 
                                        {   k = make_codetemp();
                                            ct = get_nextcode_type_for_anormcode_value f;

                                            ( [ (ncf::FATE_FN, k, [v], [ct], loop (e, metafate)) ],
                                              ncf::CODETEMP k
                                            );
                                        };

                                    my (hdr1, hdr2)
                                        = 
                                        case p
                                            #
                                            hbo::CALLCC
                                                =>
                                                with_fresh_codetemp
                                                    (\\ codetemp
                                                        =
                                                        ( \\ next =  ncf::STORE_TO_RAM    { op      =>  ncf::p::SET_EXCEPTION_HANDLER_REGISTER,
                                                                                            args    =>  [ ncf::CODETEMP codetemp ],
                                                                                            next
                                                                                          },

                                                          \\ next =  ncf::FETCH_FROM_RAM  { op      =>  ncf::p::GET_EXCEPTION_HANDLER_REGISTER,
                                                                                            args    =>  [],
                                                                                            to_temp =>  codetemp,
                                                                                            type    =>  ncf::bogus_pointer_type,
                                                                                            next
                                                                                           }
                                                        )
                                                    );

                                             _ => (nop_fn, nop_fn);
                                        esac;

                                    my (ccont_decs, ccont_var)
                                        = 
                                        {   k =  make_codetemp();       # Captured fate.
                                            x =  make_codetemp(); 

                                            ( [ ( ncf::PUBLIC_FN,
                                                  k,
                                                  [ make_codetemp(), x ],
                                                  [ ncf::typ::FATE, ncf::bogus_pointer_type ], 
                                                  hdr1 (ncf::TAIL_CALL { fn, args => [ncf::CODETEMP x] })
                                                )
                                              ],
                                              k
                                            );
                                        };

                                    ncf::DEFINE_FUNS
                                      {
                                        funs =>  kont_decs, 
                                        #
                                        next =>
                                            hdr2  (ncf::DEFINE_FUNS
                                                    {
                                                      funs =>   ccont_decs,
                                                      # 
                                                      next =>   ncf::TAIL_CALL  { fn =>  translate_value f,
                                                                                  args =>  [fn, ncf::CODETEMP ccont_var]
                                                                                }
                                                    }
                                                  )
                                      };
                                };

                            acf::BASEOP ((_, hbo::MAKE_ISOLATED_FATE, lt, ts), [f], v, e)
                                => 
                                {   my (exndecs, exnvar)
                                        = 
                                        {   h = make_codetemp ();
                                            z = make_codetemp ();
                                            x = make_codetemp ();

                                            ( [ ( ncf::PUBLIC_FN,
                                                  h,
                                                  [z, x],
                                                  [ncf::typ::FATE, ncf::bogus_pointer_type],

                                                  ncf::TAIL_CALL  { fn => ncf::CODETEMP bogus_fate_codetemp,
                                                                    args => [ncf::CODETEMP x]
                                                                  }
                                                )
                                              ],
                                              h
                                            );
                                        };

                                    newfdecs
                                        = 
                                        {   nf = v;

                                            z = make_codetemp ();
                                            x = make_codetemp ();

                                            [ ( ncf::PUBLIC_FN,
                                                v,
                                                [z, x],
                                                [ncf::typ::FATE, ncf::bogus_pointer_type],
                                                ncf::STORE_TO_RAM
                                                  { op   => ncf::p::SET_EXCEPTION_HANDLER_REGISTER,
                                                    args => [ncf::CODETEMP exnvar],
                                                    next => ncf::TAIL_CALL { fn =>  translate_value f,
                                                                             args =>  [ncf::CODETEMP bogus_fate_codetemp, ncf::CODETEMP x]
                                                                           }
                                                  }
                                              )
                                            ]; 
                                        };

                                    ncf::DEFINE_FUNS  { funs =>  exndecs,
                                                        #
                                                        next =>  ncf::DEFINE_FUNS { funs =>  newfdecs,
                                                                                    next =>  loop (e, metafate)
                                                                                  }
                                                      };
                                };

                            acf::BASEOP (po as (_, hbo::THROW, _, _), [u], v, e)
                                => 
                                {   newname (v, translate_value u);
                                    loop (e, metafate);
                                }; 

                            acf::BASEOP (po as (_, hbo::WCAST, _, _), [u], v, e)
                                =>
                                {   newname (v, translate_value u);
                                    loop (e, metafate);
                                };

                            acf::BASEOP (po as (_, hbo::WRAP, _, _), [u], to_temp, next)
                                => 
                                {   ct = ncf::uniqtype_to_nextcode (acj::get_wrap_type po);
                                    #
                                    ncf::PURE { op   =>  translate_wrap_op ct,
                                                args =>  [translate_value u],
                                                to_temp,
                                                type =>  ncf::bogus_pointer_type,
                                                next =>  loop (next, metafate)
                                              };
                                };

                            acf::BASEOP (po as (_, hbo::UNWRAP, _, _), [u], to_temp, next)
                                =>
                                {   type =  ncf::uniqtype_to_nextcode (acj::get_un_wrap_type po);
                                    #
                                    ncf::PURE { op   =>  translate_unwrap_op  type,
                                                args =>  [translate_value u],
                                                to_temp,
                                                type,
                                                next => loop (next, metafate)
                                              };
                                };

                            acf::BASEOP (po as (_, hbo::MARK_EXCEPTION_WITH_STRING, _, _), [x, m], v, e)
                                =>
                                {   bty = hcf::truevoid_uniqtypoid;
                                    ety = hcf::make_tuple_uniqtypoid [bty, bty, bty];

                                    xx = make_codetemp();
                                    x0 = make_codetemp();
                                    x1 = make_codetemp();
                                    x2 = make_codetemp();

                                    y  = make_codetemp();
                                    z  = make_codetemp();
                                    z' = make_codetemp();

                                    ncf::PURE { op => ncf::p::UNWRAP, args => [translate_value x], to_temp => xx, type => ncf::uniqtypoid_to_nextcode_type (ety),             next => 
                                        ncf::GET_FIELD_I     { i => 0, record => ncf::CODETEMP xx, to_temp => x0, type => ncf::bogus_pointer_type, next =>
                                          ncf::GET_FIELD_I   { i => 1, record => ncf::CODETEMP xx, to_temp => x1, type => ncf::bogus_pointer_type, next =>
                                            ncf::GET_FIELD_I { i => 2, record => ncf::CODETEMP xx, to_temp => x2, type => ncf::bogus_pointer_type, next =>
                                              ncf::DEFINE_RECORD { kind => ncf::rk::RECORD, fields => [(translate_value m, offp0),
                                                                (ncf::CODETEMP x2, offp0)], to_temp => z, next =>
                                                     ncf::PURE { op => ncf::p::WRAP, args => [ncf::CODETEMP z], to_temp => z', type => ncf::bogus_pointer_type, next => 
                                                       ncf::DEFINE_RECORD { kind => ncf::rk::RECORD, fields => [(ncf::CODETEMP x0, offp0),
                                                                         (ncf::CODETEMP x1, offp0),
                                                                         (ncf::CODETEMP z', offp0)],
                                                              to_temp => y, next => 
                                                          ncf::PURE { op => ncf::p::WRAP, args => [ncf::CODETEMP y], to_temp => v, type => ncf::bogus_pointer_type, next => 
                                                               loop (e, metafate) } } } } } } } };
                                };

                            acf::BASEOP ((_, hbo::RAW_CCALL NULL, _, _), _ ! _ ! a ! _, v, e)
                                =>
                                # Code generated here should
                                # never be executed anyway,
                                # so we just fake it:
                                {
#                                    print "*** pro-forma raw-ccall\n";
                                    newname (v, translate_value a);
                                    loop (e, metafate);
                                };

                            acf::BASEOP ((_, hbo::RAW_CCALL (THE i), lt, ts), f ! a ! _ ! _, to_temp, e)
                                =>
                                {   i ->   { c_prototype => p,
                                             ml_argument_representations => lib7_args,
                                             ml_result_representation => ml_res_opt,
                                             is_reentrant=>reentrant
                                           };

                                    fun cty hbo::CCR64 =>  ncf::typ::FLOAT64;
                                        cty hbo::CCI32 =>  ncf::typ::INT1;
                                        cty hbo::CCML  =>  ncf::bogus_pointer_type;
                                        cty hbo::CCI64 =>  ncf::bogus_pointer_type;
                                    end;

                                    a' = translate_value a;

                                    rcckind = if reentrant  ncf::REENTRANT_RCC;
                                              else          ncf::FAST_RCC;
                                              fi;

                                    fun rcc args
                                        =
                                        {   al = map ncf::CODETEMP args;

                                            my (al, cfun_name)
                                                = 
                                                case f
                                                    #
                                                    acf::STRING cfun_name =>  (al, cfun_name);
                                                    _                     =>  (translate_value f ! al, "");
                                                esac;

                                            case ml_res_opt
                                                #
                                                NULL => ncf::RAW_C_CALL { kind => rcckind, cfun_name, cfun_type => p, args => al, to_ttemps => [(to_temp, ncf::typ::INT)], next => loop (e, metafate) };
                                                #
                                                THE hbo::CCI64
                                                    =>
                                                    {   v1 =  make_codetemp ();
                                                        v2 =  make_codetemp ();

                                                        ncf::RAW_C_CALL
                                                          { kind        =>  rcckind,
                                                            cfun_name,
                                                            cfun_type   =>  p,
                                                            args        =>  al,
                                                            to_ttemps   =>  [(v1, ncf::typ::INT1), (v2, ncf::typ::INT1)],
                                                            next        =>  record([ncf::CODETEMP v1, ncf::CODETEMP v2],[ncf::typ::INT1, ncf::typ::INT1], to_temp, loop (e, metafate))
                                                          };
                                                    };

                                                THE rt
                                                    =>
                                                    {   v' = make_codetemp ();

                                                        res_cty =  cty  rt;

                                                        ncf::RAW_C_CALL
                                                          { kind        => rcckind,
                                                            cfun_name,
                                                            cfun_type   =>  p,
                                                            args        =>  al,
                                                            to_ttemps   =>  [(v', res_cty)],
                                                            next        =>  ncf::PURE { op   =>  translate_wrap_op res_cty,
                                                                                        args =>  [ncf::CODETEMP v'],
                                                                                        to_temp,
                                                                                        type =>  ncf::bogus_pointer_type,
                                                                                        next =>  loop (e, metafate )
                                                                                      }
                                                          };
                                                    };
                                            esac;
                                        };

                                    sel =  if (is_float_record  a)   get_field_from_all_float_record;
                                           else                      get_field;
                                           fi;

                                    fun build ([], rvl, _)
                                            =>
                                            rcc (reverse rvl);

                                        build (ft ! ftl, rvl, i)
                                            =>
                                            {
                                                t = cty ft;
                                                v = make_codetemp ();

                                                sel (i, a', v, t, build (ftl, v ! rvl, i + 1));
                                            };
                                    end;


                                    case lib7_args
                                        #
                                        [ft] => {

                                            # If there is precisely one arg,
                                            # then it will not come packaged
                                            # into a record:
                                            #
                                            type =  cty ft;
                                            to_temp =  make_codetemp ();

                                            ncf::PURE { op   =>  translate_unwrap_op  type,
                                                        args =>  [a'],
                                                        to_temp,
                                                        type,
                                                        next =>  rcc [to_temp]
                                                      };
                                        };

                                        _ => build (lib7_args, [], 0);
                                    esac;
                                };

                            acf::BASEOP ((_, hbo::RAW_CCALL _, _, _), _, _, _)
                                =>
                                bug "bad raw_ccall";

                            acf::BASEOP ((_, hbo::RAW_ALLOCATE_C_RECORD _, _, _),[x as acf::VAR _], v, e)
                                =>
                                # Code generated here should
                                # never be executed anyway,
                                # so we just fake it:
                                {
#                                    print "*** pro-forma raw-record\n";
                                    newname (v, translate_value x);
                                    loop (e, metafate);
                                };

                            acf::BASEOP (po as (_, p, lt, ts), ul, to_temp, next)
                                => 
                                {   type =  case (#3 (hcf::unpack_arrow_uniqtypoid (hcf::apply_typeagnostic_type_to_arglist_with_single_result (lt, ts))))
                                                #
                                                [x] =>  ncf::uniqtypoid_to_nextcode_type x;
                                                _   =>  bug "unexpected case in acf::BASEOP";
                                            esac;

                                    args = translate_values ul;

                                    case (translate_baseop p)
                                        #
                                        ARITHMETIC_PRIMOP op => ncf::ARITH          { op, args, to_temp, type, next => loop (next, metafate) };
                                        FETCH_FROM_RAM    op => ncf::FETCH_FROM_RAM { op, args, to_temp, type, next => loop (next, metafate) };
                                        PURE_PRIMOP       op => ncf::PURE           { op, args, to_temp, type, next => loop (next, metafate) };
                                        #
                                        STORE_TO_RAM op =>  {   newname (to_temp, ncf::INT 0);
                                                                #
                                                                ncf::STORE_TO_RAM { op, args, next => loop (next, metafate) };
                                                            };
                                    esac;
                                };

                            acf::BRANCH (po as (_, compare, _, _), ul, then_next, else_next)
                                => 
                                {   (prevent_erroneous_eta_reductions metafate) ->   (header, fn);
                                    #
                                    fate =  make_metafate   (\\ args = ncf::TAIL_CALL { fn, args },   get_types_from_metafate metafate);

                                    header (ncf::IF_THEN_ELSE { op        =>  translate_compare  compare,
                                                                args      =>  translate_values ul,
                                                                xvar      =>  make_codetemp(),
                                                                #
                                                                then_next =>  loop (then_next, fate),
                                                                else_next =>  loop (else_next, fate)
                                                              }
                                           );
                                };
                        esac;
                    };


                function_declaration ->   (fk, fn_name_codetemp, fn_parameters, body_expression);                               #  Process the top-level Function_Declaration: 

                return_fate_codetemp =  make_codetemp();                                                                        # Top-level return fate.

                fate =  make_metafate
                          ( \\ args =  ncf::TAIL_CALL {  fn => ncf::CODETEMP return_fate_codetemp,  args },
                            res_ctys fn_name_codetemp
                          );

                body =  loop' im::empty (body_expression, fate);                                                                # Construct the nextcode-form \\ body from the anormcode-form body.  Here's where all the work gets done. :-)

                vl =  return_fate_codetemp ! (map #1 fn_parameters);                                                            # #1 gives us the codetemp naming the parameter.

                cl =  ncf::typ::FATE ! (map (ncf::uniqtypoid_to_nextcode_type o #2) fn_parameters);                                                     # #2 gives us the type for the parameter.

                (ncf::PUBLIC_FN, fn_name_codetemp, vl, cl, bogus_header body)
                then
                    clean_up ();

            };                                                                  # fun translate_anormcode_to_nextcode
    };                                                                          # generic package translate_anormcode_to_nextcode_g 
end;                                                                            # toplevel stipulate 



## COPYRIGHT 1998 BY YALE FLINT PROJECT 
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext