PreviousUpNext

15.4.488  src/lib/compiler/back/top/improve-nextcode/uncurry-nextcode-functions-g.pkg

## uncurry-nextcode-functions-g.pkg 

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



# This file implements one of the nextcode transforms.
# For context, see the comments in
#
#     src/lib/compiler/back/top/highcode/highcode-form.api




#    "It was easy and harmless to do uncurrying as part of
#     'improve_mutually_recursive_anormcode_functions', with the
#     added benefit that it merged two tree traversals into
#     one.  This is particularly important since those phases are
#     worth doing often and both traversals need to build a whole
#     new result expression, which is slower than read-only traversals."
#
#          -- Principled Compilation and Scavenging
#             Stefan Monnier, 2003 [PhD Thesis, U Montreal]
#             http://www.iro.umontreal.ca/~monnier/master.ps.gz 



#    "Simple form of uncurrying which turns a curried
#     function
#
#         fun f x y = e
#
#     into an uncurried function
#
#         fun f'(x, y) = e
#
#     and an uncurry wrapper function
#
#         fun f x y = f'(x,y)
#
#    "The actual uncurrying at the call sites is done
#     later on in the expand phase by inlining the wrapper."
#
#          -- Principled Compilation and Scavenging
#             Stefan Monnier, 2003 [PhD Thesis, U Montreal]
#             http://www.iro.umontreal.ca/~monnier/master.ps.gz 



###                                "I am too good for philosophy
###                                 and not good enough for physics.
###                                 Mathematics is in between."
###
###                                              -- George Pólya



stipulate
    package ncf =  nextcode_form;                               # nextcode_form                         is from   src/lib/compiler/back/top/nextcode/nextcode-form.pkg
    package hct =  highcode_type;                               # highcode_type                         is from   src/lib/compiler/back/top/highcode/highcode-type.pkg
    package hut =  highcode_uniq_types;                         # highcode_uniq_types                   is from   src/lib/compiler/back/top/highcode/highcode-uniq-types.pkg
    package iht =  int_hashtable;                               # int_hashtable                 is from   src/lib/src/int-hashtable.pkg
herein

    api Uncurry_Nextcode_Functions {
        #
        uncurry_nextcode_functions
          :
          { function:   ncf::Function,
            table:      iht::Hashtable( hut::Uniqtypoid ),
            click:      String -> Void
          }
          ->
          ncf::Function;
    };
end;


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

stipulate
    package err =  error_message;                                               # error_message                         is from   src/lib/compiler/front/basics/errormsg/error-message.pkg
    package ncf =  nextcode_form;                                               # nextcode_form                         is from   src/lib/compiler/back/top/nextcode/nextcode-form.pkg
    package hcf =  highcode_form;                                               # highcode_form                         is from   src/lib/compiler/back/top/highcode/highcode-form.pkg
    package tmp =  highcode_codetemp;                                           # highcode_codetemp                     is from   src/lib/compiler/back/top/highcode/highcode-codetemp.pkg
herein

    # We are invoked from:
    #
    #     src/lib/compiler/back/top/improve-nextcode/run-optional-nextcode-improvers-g.pkg

    generic package   uncurry_nextcode_functions_g (
        #             ============================
        #
        mp:  Machine_Properties                                                 # Machine_Properties            is from   src/lib/compiler/back/low/main/main/machine-properties.api
                                                                                # machine_properties_intel32    is from   src/lib/compiler/back/low/main/intel32/machine-properties-intel32.pkg
                                                                                # machine_properties_pwrpc32    is from   src/lib/compiler/back/low/main/pwrpc32/machine-properties-pwrpc32.pkg
                                                                                # machine_properties_sparc32    is from   src/lib/compiler/back/low/main/sparc32/machine-properties-sparc32.pkg
    )
    : (weak) Uncurry_Nextcode_Functions                                         # Uncurry_Nextcode_Functions            is from   src/lib/compiler/back/top/improve-nextcode/uncurry-nextcode-functions-g.pkg
    {

        fun bug s =   err::impossible ("Uncurry: " + s);

        fun freein v
            = 
            g
            where
                fun try (ncf::CODETEMP w) =>   v == w;
                    try (ncf::LABEL    w) =>   v == w;
                    try _                 =>   FALSE;
                end;

                fun any (w ! rest) =>  try w or any rest;
                    any NIL        =>  FALSE;
                end;

                fun any1 ((w, _) ! rest) =>  try w  or  any1 rest;
                    any1 NIL             =>  FALSE;
                end;

                recursive my g
                    =
                    \\  ncf::TAIL_CALL { fn, args } => try fn   or  any args;
                        ncf::JUMPTABLE { i, nexts, ... } => try i  or  list::exists g nexts;
                        #
                        ncf::DEFINE_RECORD          { fields, next, ... } =>  any1 fields  or  g next;
                        ncf::GET_FIELD_I            { record, next, ... } =>  try record   or  g next;
                        ncf::GET_ADDRESS_OF_FIELD_I { record, next, ... } =>  try record   or  g next;
                        #
                        ( ncf::STORE_TO_RAM   { args, next, ... }
                        | ncf::FETCH_FROM_RAM { args, next, ... }
                        | ncf::ARITH           { args, next, ... }
                        | ncf::PURE           { args, next, ... }
                        | ncf::RAW_C_CALL     { args, next, ... }
                        )   =>
                            any args  or  g next;

                        ncf::IF_THEN_ELSE { args, then_next, else_next, ... }
                            =>
                            any args    or
                            g then_next  or
                            g else_next;

                        ncf::DEFINE_FUNS { funs, next } =>  list::exists (g o #5) funs  or  g next;
                    end ;
            end;

        fun uncurry_nextcode_functions
              {
                function => (fkind, fvar, fargs, ctyl, cexp),
                table    => typetable, click
              }
            = 
            {   debug =  *global_controls::compiler::debugnextcode;             # FALSE 

                fun debugprint s  =   if debug  global_controls::print::say s;   fi;
                fun debugflush () =   if debug  global_controls::print::flush(); fi;

                rep_flag = mp::representations;

                type_flag =   *global_controls::compiler::checknextcode1
                          and *global_controls::compiler::checknextcode2
                          and rep_flag;

                default_arrow = hcf::make_lambdacode_arrow_uniqtypoid (hcf::truevoid_uniqtypoid, hcf::truevoid_uniqtypoid);

                fun extend_lty (t,[]) => t;
                    extend_lty (t, a) => default_arrow;
                end;



                #########################################################################
                # Count the number of int and float registers needed for a list of lvars:

                unboxedfloat = mp::unboxed_floats;

                fun is_flt_cty ncf::typ::FLOAT64 =>   unboxedfloat; 
                    is_flt_cty _                 =>   FALSE;
                end;

                num_csgpregs =   mp::num_callee_saves;
                num_csfpregs =   mp::num_float_callee_saves;

                maxgpregs =   mp::num_int_regs   - num_csgpregs - 1;
                maxfpregs =   mp::num_float_regs - num_csfpregs - 2;  

                fun checklimit (cl)
                    = 
                    h (cl, 0, 0)
                    where
                        fun h (ncf::typ::FLOAT64 ! rest, m, n) =>   if unboxedfloat    h (rest, m, n+1);   else   h (rest, m+1, n);   fi;
                            h (_                 ! rest, m, n) =>   h (rest, m+1, n);
                            h ([],                       m, n) =>   (m <= maxgpregs) and (n <= maxfpregs);
                        end;
                    end;

                exception NEWETA;

                fun getty v
                    = 
                    if type_flag 
                        #
                        (int_hashtable::get  typetable  v)
                        except
                            _ =  {   global_controls::print::say ("NEWETA: Can't find the variable " +
                                             (int::to_string v) + " in the typetable ***** \n");
                                     raise exception NEWETA;
                                 };
                    else 
                        hcf::truevoid_uniqtypoid;
                    fi;

                fun addty (f, t)
                    =
                    if type_flag
                        #
                        int_hashtable::set typetable (f, t);
                    fi;

                fun make_var (t)
                    =
                    {   v = tmp::issue_highcode_codetemp();
                        addty (v, t);
                        v;
                    };

                fun copy_lvar v
                    =
                    {   x = tmp::clone_highcode_codetemp (v);
                        addty (x, getty v);
                        x;
                    };

                # fun userfun (f) = case hcf::out (getty (f)) of hcf::ARROW _ => TRUE
                #                               | _ => FALSE

                recursive my reduce
                    = 
                    \\  ncf::DEFINE_RECORD { kind, fields, to_temp,      next                }
                     => ncf::DEFINE_RECORD { kind, fields, to_temp,      next => reduce next };
                        #       
                        ncf::GET_FIELD_I   { i, record, to_temp, type, next                }
                     => ncf::GET_FIELD_I   { i, record, to_temp, type, next => reduce next };
                        #
                        ncf::GET_ADDRESS_OF_FIELD_I { i, record, to_temp,       next                }
                     => ncf::GET_ADDRESS_OF_FIELD_I { i, record, to_temp,       next => reduce next };
                        #
                        ncf::TAIL_CALL funargs             =>  ncf::TAIL_CALL funargs;
                        #
                        ncf::JUMPTABLE { i, xvar, nexts                     }
                     => ncf::JUMPTABLE { i, xvar, nexts => map reduce nexts };

                        ncf::IF_THEN_ELSE { op, args, xvar, then_next,                    else_next                    }
                     => ncf::IF_THEN_ELSE { op, args, xvar, then_next => reduce then_next, else_next => reduce else_next };

                        ncf::FETCH_FROM_RAM { op, args, to_temp, type, next                }
                     => ncf::FETCH_FROM_RAM { op, args, to_temp, type, next => reduce next };

                        ncf::ARITH  { op, args, to_temp, type, next } =>  ncf::ARITH  { op, args, to_temp, type,  next => reduce next  };
                        ncf::PURE  { op, args, to_temp, type, next } =>  ncf::PURE  { op, args, to_temp, type,  next => reduce next  };

                        ncf::RAW_C_CALL { kind, cfun_name, cfun_type, args, to_ttemps,  next                 }
                     => ncf::RAW_C_CALL { kind, cfun_name, cfun_type, args, to_ttemps,  next => reduce next  };

                        ncf::STORE_TO_RAM { op, args,  next                 }
                     => ncf::STORE_TO_RAM { op, args,  next => reduce next  };

                        ncf::DEFINE_FUNS { funs, next }
                            =>
                            {   ncf::DEFINE_FUNS  { funs =>  fold_backward   (\\ (fd, r) = (uncurry fd) @ r)   []   funs,
                                                    next =>  reduce next
                                                  };
                            }
                            where
                                fun uncurry (fd as (ncf::FATE_FN, _, _, _, _))
                                        =>
                                        [ reduce_body fd ];

                                    uncurry
                                        (fd as 
                                            ( fk,
                                              f,
                                              k ! vl, ct ! cl,
                                              body as ncf::DEFINE_FUNS
                                                {
                                                  funs => [(gk, g, ul, cl', body2)],
                                                  #
                                                  next =>
                                                      ncf::TAIL_CALL { fn =>   ncf::CODETEMP c,
                                                                       args =>  [ncf::CODETEMP g']
                                                                     }
                                                }
                                            )
                                        )
                                        =>
                                        if (k==c and g==g'                #  And userfun (g) 
                                        and not (freein k body2)
                                        and not (freein g body2)   #  g not recursive 
                                        and checklimit (cl@cl')
                                        )
                                            ul' = map copy_lvar ul;
                                            vl' = map copy_lvar vl;

                                            k' = copy_lvar k;
                                            g' = copy_lvar g;

                                            newlt = extend_lty (getty (g), (map getty vl));
                                            f' = make_var (newlt);
                                            click "u";

                                            ( ncf::NO_INLINE_INTO,
                                              f,
                                              k' ! vl',
                                              ct ! cl,
                                              ncf::DEFINE_FUNS
                                                {
                                                  funs =>
                                                      [ ( gk,
                                                          g',
                                                          ul',
                                                          cl',
                                                          ncf::TAIL_CALL  { fn =>  ncf::CODETEMP f',
                                                                            args =>  map ncf::CODETEMP (ul' @ vl')
                                                                          }
                                                        )
                                                      ],
                                                  #
                                                  next =>
                                                      ncf::TAIL_CALL { fn =>   ncf::CODETEMP k',
                                                                       args => [ ncf::CODETEMP g' ]
                                                                     }
                                                }
                                            )
                                            !
                                            uncurry (fk, f', ul@vl, cl'@cl, body2 );

                                        else
                                            [reduce_body fd];
                                        fi;

                                    uncurry fd => [reduce_body fd];
                                end 

                             also
                             fun reduce_body (fk, f, vl, cl, e)
                                 =
                                 (fk, f, vl, cl, reduce e);

                        end;
                  end;

                  debugprint "Uncurry: ";
                    debugflush();
                    (fkind, fvar, fargs, ctyl, reduce cexp) then debugprint "\n";
            };
    };                                                  # generic package uncurry_g 
end;                                                    # stipulate




## Copyright 1996 by Bell Laboratories 
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext