Changeset e67a82d


Ignore:
Timestamp:
Aug 20, 2020, 11:48:15 PM (5 years ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
d685cb0
Parents:
67ca73e (diff), 013b028 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

fix conflicts

Files:
19 added
120 edited
2 moved

Legend:

Unmodified
Added
Removed
  • benchmark/benchcltr.hfa

    r67ca73e re67a82d  
    11#pragma once
     2#include <assert.h>
     3#include <stdint.h>
    24
    3 #include <assert.h>
    4 #include <kernel.hfa>
    5 #include <thread.hfa>
    6 #include <stats.hfa>
     5#ifdef __cforall
     6        #include <kernel.hfa>
     7        #include <thread.hfa>
     8        #include <stats.hfa>
     9#else
     10#include <time.h>                                                                               // timespec
     11#include <sys/time.h>                                                                   // timeval
     12
     13enum { TIMEGRAN = 1000000000LL };                                       // nanosecond granularity, except for timeval
     14#endif
    715
    816#define BENCH_OPT_SHORT "d:p:t:SPV"
     
    1422        {"procstat",     no_argument      , 0, 'P'}, \
    1523        {"viewhalts",    no_argument      , 0, 'V'},
    16 
    17 #define BENCH_DECL \
    18         double duration = 5; \
    19         int nprocs = 1; \
    20         int nthreads = 1;
    2124
    2225#define BENCH_OPT_CASE \
     
    5255                break;
    5356
     57double duration = 5;
     58int nprocs = 1;
     59int nthreads = 1;
    5460bool silent = false;
     61bool continuous = false;
    5562bool procstats = false;
    5663bool viewhalts = false;
     64
     65#define BENCH_OPT_CFA \
     66        {'d', "duration",  "Duration of the experiments in seconds", duration }, \
     67        {'t', "nthreads",  "Number of threads to use", nthreads }, \
     68        {'p', "nprocs",    "Number of processors to use", nprocs }, \
     69        {'S', "nostats",   "Don't print statistics", silent, parse_settrue }, \
     70        {'C', "constats",  "Regularly print statistics", continuous, parse_settrue }, \
     71        {'P', "procstat",  "Print statistics for each processors", procstats, parse_settrue }, \
     72        {'V', "viewhalts", "Visualize halts, prints timestamp and Processor id for each halt.", viewhalts, parse_settrue },
     73
     74#ifdef __cforall
     75#include <parseargs.hfa>
     76
    5777struct cluster * the_benchmark_cluster = 0p;
    5878struct BenchCluster {
     
    6080};
    6181
    62 void ?{}( BenchCluster & this, int flags, int stats ) {
    63         (this.self){ "Benchmark Cluster", flags };
     82void ?{}( BenchCluster & this, int num_io, const io_context_params & io_params, int stats ) {
     83        (this.self){ "Benchmark Cluster", num_io, io_params };
    6484
    6585        assert( the_benchmark_cluster == 0p );
     
    105125        }
    106126}
     127#else
     128uint64_t getTimeNsec() {
     129        timespec curr;
     130        clock_gettime( CLOCK_REALTIME, &curr );
     131        return (int64_t)curr.tv_sec * TIMEGRAN + curr.tv_nsec;
     132}
     133
     134uint64_t to_miliseconds( uint64_t durtn ) { return durtn / (TIMEGRAN / 1000LL); }
     135double to_fseconds(uint64_t durtn ) { return durtn / (double)TIMEGRAN; }
     136uint64_t from_fseconds(double sec) { return sec * TIMEGRAN; }
     137
     138
     139void wait_duration(double duration, uint64_t & start, uint64_t & end, bool is_tty) {
     140        for(;;) {
     141                usleep(100000);
     142                end = getTimeNsec();
     143                uint64_t delta = end - start;
     144                /*if(is_tty)*/ {
     145                        printf(" %.1f\r", to_fseconds(delta));
     146                        fflush(stdout);
     147                }
     148                if( delta >= from_fseconds(duration) ) {
     149                        break;
     150                }
     151        }
     152}
     153#endif
     154
    107155
    108156void bench_usage( char * argv [] ) {
  • benchmark/io/http/options.cfa

    r67ca73e re67a82d  
    1010
    1111#include <kernel.hfa>
    12 
    13 #include "parseargs.hfa"
    14 
     12#include <parseargs.hfa>
    1513
    1614Options options @= {
  • benchmark/io/readv.cfa

    r67ca73e re67a82d  
    4040int do_read(int fd, struct iovec * iov) {
    4141        // extern ssize_t cfa_preadv2(int, const struct iovec *, int, off_t, int, int = 0, Duration = -1`s, io_cancellation * = 0p, io_context * = 0p);
    42         int sflags = 0;
     42        int sflags = 0
     43        #if defined(CFA_HAVE_IOSQE_ASYNC)
     44                | CFA_IO_ASYNC
     45        #else
     46        #warning no CFA_IO_ASYNC support
     47        #endif
     48        ;
    4349        if(fixed_file) {
    4450                sflags |= CFA_IO_FIXED_FD1;
     
    6369
    6470int main(int argc, char * argv[]) {
    65         BENCH_DECL
     71        int file_flags = 0;
    6672        unsigned num_io = 1;
    67         io_context_params params;
    68         int file_flags = 0;
    6973        unsigned sublen = 16;
     74        unsigned nentries = 0;
    7075
    71         arg_loop:
    72         for(;;) {
    73                 static struct option options[] = {
    74                         BENCH_OPT_LONG
    75                         {"bufsize",       required_argument, 0, 'b'},
    76                         {"submitthread",  no_argument      , 0, 's'},
    77                         {"eagersubmit",   no_argument      , 0, 'e'},
    78                         {"kpollsubmit",   no_argument      , 0, 'k'},
    79                         {"kpollcomplete", no_argument      , 0, 'i'},
    80                         {"fixed-files",   no_argument      , 0, 'f'},
    81                         {"open-direct",   no_argument      , 0, 'o'},
    82                         {"submitlength",  required_argument, 0, 'l'},
    83                         {0, 0, 0, 0}
    84                 };
     76        bool subthrd = false;
     77        bool subeagr = false;
     78        bool odirect = false;
     79        bool kpollsb = false;
     80        bool kpollcp = false;
    8581
    86                 int idx = 0;
    87                 int opt = getopt_long(argc, argv, BENCH_OPT_SHORT "b:sekil:", options, &idx);
     82        cfa_option opt[] = {
     83                BENCH_OPT_CFA
     84                {'b', "bufsize",       "Number of bytes to read per request", buflen},
     85                {'s', "submitthread",  "If set, cluster uses polling thread to submit I/O", subthrd, parse_settrue},
     86                {'e', "eagersubmit",   "If set, cluster submits I/O eagerly but still aggregates submits", subeagr, parse_settrue},
     87                {'f', "fixed-files",   "Pre-register files with the io_contexts", fixed_file, parse_settrue},
     88                {'o', "open-direct",   "Open files with O_DIRECT flag, bypassing the file cache", odirect, parse_settrue},
     89                {'k', "kpollsubmit",   "If set, cluster uses an in kernel thread to poll submission, implies -f, requires elevated permissions", kpollsb, parse_settrue},
     90                {'i', "kpollcomplete", "If set, cluster polls fds for completions instead of relying on interrupts to get notifications, implies -o", kpollcp, parse_settrue},
     91                {'l', "submitlength",  "Size of the buffer that stores ready submissions", sublen},
     92                {'r', "numentries",    "Number of entries each of the io_context have", nentries},
     93                {'n', "numcontexts",   "Number of io_contexts to the cluster", num_io},
     94        };
     95        int opt_cnt = sizeof(opt) / sizeof(cfa_option);
    8896
    89                 const char * arg = optarg ? optarg : "";
    90                 char * end;
    91                 switch(opt) {
    92                         // Exit Case
    93                         case -1:
    94                                 break arg_loop;
    95                         BENCH_OPT_CASE
    96                         case 'b':
    97                                 buflen = strtoul(arg, &end, 10);
    98                                 if(*end != '\0' && buflen < 10) {
    99                                         fprintf(stderr, "Buffer size must be at least 10, was %s\n", arg);
    100                                         goto usage;
    101                                 }
    102                                 break;
    103                         case 's':
    104                                 params.poller_submits = true;
    105                                 break;
    106                         case 'e':
    107                                 params.eager_submits = true;
    108                                 break;
    109                         case 'k':
    110                                 params.poll_submit = true;
    111                         case 'f':
    112                                 fixed_file = true;
    113                                 break;
    114                         case 'i':
    115                                 params.poll_complete = true;
    116                         case 'o':
    117                                 file_flags |= O_DIRECT;
    118                                 break;
    119                         case 'l':
    120                                 sublen = strtoul(arg, &end, 10);
    121                                 if(*end != '\0' && sublen < 16) {
    122                                         fprintf(stderr, "Submit length must be at least 16, was %s\n", arg);
    123                                         goto usage;
    124                                 }
    125                                 // flags |= (sublen << CFA_CLUSTER_IO_BUFFLEN_OFFSET);
    126                                 break;
    127                         default: /* ? */
    128                                 fprintf(stderr, "%d\n", opt);
    129                         usage:
    130                                 bench_usage( argv );
    131                                 fprintf( stderr, "  -b, --buflen=SIZE        Number of bytes to read per request\n" );
    132                                 fprintf( stderr, "  -u, --userthread         If set, cluster uses user-thread to poll I/O\n" );
    133                                 fprintf( stderr, "  -s, --submitthread       If set, cluster uses polling thread to submit I/O\n" );
    134                                 fprintf( stderr, "  -e, --eagersubmit        If set, cluster submits I/O eagerly but still aggregates submits\n" );
    135                                 fprintf( stderr, "  -k, --kpollsubmit        If set, cluster uses IORING_SETUP_SQPOLL\n" );
    136                                 fprintf( stderr, "  -i, --kpollcomplete      If set, cluster uses IORING_SETUP_IOPOLL\n" );
    137                                 fprintf( stderr, "  -l, --submitlength=LEN   Max number of submitions that can be submitted together\n" );
    138                                 exit(EXIT_FAILURE);
     97        char **left;
     98        parse_args( opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", left );
     99
     100        if(kpollcp || odirect) {
     101                if( (buflen % 512) != 0 ) {
     102                        fprintf(stderr, "Buffer length must be a multiple of 512 when using O_DIRECT, was %lu\n\n", buflen);
     103                        print_args_usage(opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", true);
    139104                }
    140105        }
     106
     107        io_context_params params;
     108
     109        if( subthrd ) params.poller_submits = true;
     110        if( subeagr ) params.eager_submits  = true;
     111        if( kpollsb ) params.poll_submit    = true;
     112        if( kpollcp ) params.poll_complete  = true;
     113
     114        if(params.poll_submit  ) fixed_file = true;
     115        if(params.poll_complete) odirect    = true;
     116
     117        params.num_ready = sublen;
     118        params.num_entries = nentries;
     119
     120        if(odirect) file_flags |= O_DIRECT;
    141121
    142122        int lfd = open(__FILE__, file_flags);
  • benchmark/readyQ/yield.cfa

    r67ca73e re67a82d  
    4343
    4444int main(int argc, char * argv[]) {
    45         BENCH_DECL
     45        unsigned num_io = 1;
     46        io_context_params params;
    4647
    47         for(;;) {
    48                 static struct option options[] = {
    49                         BENCH_OPT_LONG
    50                         {0, 0, 0, 0}
    51                 };
     48        cfa_option opt[] = {
     49                BENCH_OPT_CFA
     50        };
     51        int opt_cnt = sizeof(opt) / sizeof(cfa_option);
    5252
    53                 int idx = 0;
    54                 int opt = getopt_long(argc, argv, BENCH_OPT_SHORT, options, &idx);
    55 
    56                 const char * arg = optarg ? optarg : "";
    57                 char * end;
    58                 switch(opt) {
    59                         case -1:
    60                                 goto run;
    61                         BENCH_OPT_CASE
    62                         default: /* ? */
    63                                 fprintf( stderr, "Unkown option '%c'\n", opt);
    64                         usage:
    65                                 bench_usage( argv );
    66                                 exit(1);
    67                 }
    68         }
    69         run:
     53        char **left;
     54        parse_args( argc, argv, opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", left );
    7055
    7156        {
     
    7358
    7459                Time start, end;
    75                 BenchCluster cl = { 0, CFA_STATS_READY_Q };
     60                BenchCluster cl = { num_io, params, CFA_STATS_READY_Q };
    7661                {
    7762                        BenchProc procs[nprocs];
  • configure.ac

    r67ca73e re67a82d  
    2424#Trasforming cc1 will break compilation
    2525M4CFA_PROGRAM_NAME
     26
     27#==============================================================================
     28# New AST toggling support
     29AH_TEMPLATE([CFA_USE_NEW_AST],[Sets whether or not to use the new-ast, this is adefault value and can be overrided by --old-ast and --new-ast])
     30AC_ARG_ENABLE(new-ast,
     31        [  --enable-new-ast     whether or not to use new ast as the default AST algorithm],
     32        [case "${enableval}" in
     33                yes) newast=true ;;
     34                no)  newast=false ;;
     35                *) AC_MSG_ERROR([bad value ${enableval} for --enable-new-ast]) ;;
     36        esac],[newast=false])
     37AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast)
    2638
    2739#==============================================================================
  • driver/cc1.cc

    r67ca73e re67a82d  
    1010// Created On       : Fri Aug 26 14:23:51 2005
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat May 30 18:09:05 2020
    13 // Update Count     : 404
     12// Last Modified On : Sun Aug 16 21:03:02 2020
     13// Update Count     : 413
    1414//
    1515
     
    2424#include <unistd.h>                                                                             // execvp, fork, unlink
    2525#include <sys/wait.h>                                                                   // wait
    26 #include <fcntl.h>
     26#include <fcntl.h>                                                                              // creat
    2727
    2828
     
    5959
    6060
    61 static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );               // "N__=" suffix
     61static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );               // "__CFA_FLAG__=" suffix
    6262
    6363static void checkEnv1( const char * args[], int & nargs ) { // stage 1
     
    111111} // checkEnv2
    112112
    113 
    114 static char tmpname[] = P_tmpdir "/CFAXXXXXX.ifa";
     113#define CFA_SUFFIX ".ifa"
     114
     115static char tmpname[] = P_tmpdir "/CFAXXXXXX" CFA_SUFFIX;
    115116static int tmpfilefd = -1;
    116117static bool startrm = false;
     
    170171                        if ( arg == "-quiet" ) {
    171172                        } else if ( arg == "-imultilib" || arg == "-imultiarch" ) {
    172                                 i += 1;                                                                 // and the argument
     173                                i += 1;                                                                 // and argument
    173174                        } else if ( prefix( arg, "-A" ) ) {
    174175                        } else if ( prefix( arg, "-D__GNU" ) ) {
     
    177178                                //********
    178179                        } else if ( arg == "-D" && prefix( argv[i + 1], "__GNU" ) ) {
    179                                 i += 1;                                                                 // and the argument
     180                                i += 1;                                                                 // and argument
    180181
    181182                                // strip flags controlling cpp step
     
    184185                                cpp_flag = true;
    185186                        } else if ( arg == "-D" && string( argv[i + 1] ) == "__CPP__" ) {
    186                                 i += 1;                                                                 // and the argument
     187                                i += 1;                                                                 // and argument
    187188                                cpp_flag = true;
    188189
     
    194195                                cpp_out = argv[i];
    195196                        } else {
    196                                 args[nargs++] = argv[i];                                // pass the flag along
     197                                args[nargs++] = argv[i];                                // pass flag along
    197198                                // CPP flags with an argument
    198199                                if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
     
    200201                                         arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) {
    201202                                        i += 1;
    202                                         args[nargs++] = argv[i];                        // pass the argument along
     203                                        args[nargs++] = argv[i];                        // pass argument along
    203204                                        #ifdef __DEBUG_H__
    204205                                        cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
    205206                                        #endif // __DEBUG_H__
    206207                                } else if ( arg == "-MD" || arg == "-MMD" ) {
     208                                        // gcc frontend generates the dependency file-name after the -MD/-MMD flag, but it is necessary to
     209                                        // prefix that file name with -MF.
    207210                                        args[nargs++] = "-MF";                          // insert before file
    208211                                        i += 1;
    209                                         args[nargs++] = argv[i];                        // pass the argument along
     212                                        args[nargs++] = argv[i];                        // pass argument along
    210213                                        #ifdef __DEBUG_H__
    211214                                        cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
     
    279282        // Run the C preprocessor and save the output in the given file.
    280283
    281         if ( fork() == 0 ) {                                                             // child process ?
     284        if ( fork() == 0 ) {                                                            // child process ?
    282285                // -o xxx.ii cannot be used to write the output file from cpp because no output file is created if cpp detects
    283286                // an error (e.g., cannot find include file). Whereas, output is always generated, even when there is an error,
     
    319322
    320323        if ( WIFSIGNALED(code) ) {                                                      // child failed ?
     324                rmtmpfile();                                                                    // remove tmpname
    321325                cerr << "CC1 Translator error: stage 1, child failed " << WTERMSIG(code) << endl;
    322326                exit( EXIT_FAILURE );
    323327        } // if
    324328
    325         exit( WEXITSTATUS(code) );                                                      // bad cpp result stops top-level gcc
     329        exit( WEXITSTATUS( code ) );                                            // bad cpp result stops top-level gcc
    326330} // Stage1
    327331
     
    371375                        } else if ( arg == "-fno-diagnostics-color" ) {
    372376                                color_arg = Color_Auto;
    373                         }
     377                        } // if
    374378
    375379                        if ( arg == "-quiet" || arg == "-version" || arg == "-fpreprocessed" ||
    376                                 // Currently CFA does not suppose precompiled .h files.
    377                                 prefix( arg, "--output-pch" ) ) {
     380                                 // Currently CFA does not suppose precompiled .h files.
     381                                 prefix( arg, "--output-pch" ) ) {
    378382
    379383                                // strip inappropriate flags with an argument
     
    388392
    389393                        } else {
    390                                 args[nargs++] = argv[i];                                // pass the flag along
     394                                args[nargs++] = argv[i];                                // pass flag along
    391395                                if ( arg == "-o" ) {
    392396                                        i += 1;
    393397                                        cpp_out = argv[i];
    394                                         args[nargs++] = argv[i];                        // pass the argument along
     398                                        args[nargs++] = argv[i];                        // pass argument along
    395399                                        #ifdef __DEBUG_H__
    396400                                        cerr << "arg:\"" << argv[i] << "\"" << endl;
     
    439443                        } // if
    440444
    441                         cfa_cpp_out = cfa_cpp_out.substr( 0, dot ) + ".ifa";
     445                        cfa_cpp_out = cfa_cpp_out.substr( 0, dot ) + CFA_SUFFIX;
    442446                        if ( creat( cfa_cpp_out.c_str(), 0666 ) == -1 ) {
    443447                                perror( "CC1 Translator error: stage 2, creat" );
     
    460464        // output.  Otherwise, run the cfa-cpp preprocessor on the temporary file and save the result into the output file.
    461465
    462         if ( fork() == 0 ) {                                                            // child runs CFA
     466        if ( fork() == 0 ) {                                                            // child runs CFA preprocessor
    463467                cargs[0] = ( *new string( bprefix + "cfa-cpp" ) ).c_str();
    464468                cargs[ncargs++] = cpp_in;
     
    518522        #endif // __DEBUG_H__
    519523
    520         if ( fork() == 0 ) {                                                            // child runs CFA
     524        if ( fork() == 0 ) {                                                            // child runs gcc
    521525                args[0] = compiler_path.c_str();
    522526                args[nargs++] = "-S";                                                   // only compile and put assembler output in specified file
  • driver/cfa.cc

    r67ca73e re67a82d  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Aug 18 16:40:22 2020
    13 // Update Count     : 435
     12// Last Modified On : Thu Aug 20 23:43:59 2020
     13// Update Count     : 436
    1414//
    1515
    1616#include <iostream>
    17 #include <cstdio>      // perror
    18 #include <cstdlib>     // putenv, exit
    19 #include <climits>     // PATH_MAX
    20 #include <unistd.h>    // execvp
    21 #include <string>      // STL version
    22 #include <string.h>    // strcmp
    23 #include <algorithm>   // find
    24 
     17#include <cstdio>                                                                               // perror
     18#include <cstdlib>                                                                              // putenv, exit
     19#include <climits>                                                                              // PATH_MAX
     20#include <string>                                                                               // STL version
     21#include <algorithm>                                                                    // find
     22
     23#include <unistd.h>                                                                             // execvp
    2524#include <sys/types.h>
    2625#include <sys/stat.h>
     
    3433using std::to_string;
    3534
    36 // #define __DEBUG_H__
    37 
    38 // "N__=" suffix
    39 static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );
    40 
    41 void Putenv( char * argv[], string arg ) {
     35//#define __DEBUG_H__
     36
     37#define xstr(s) str(s)
     38#define str(s) #s
     39
     40static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );               // "__CFA_FLAG__=" suffix
     41
     42static void Putenv( char * argv[], string arg ) {
    4243        // environment variables must have unique names
    4344        static int flags = 0;
     
    4950} // Putenv
    5051
    51 // check if string has prefix
    52 bool prefix( const string & arg, const string & pre ) {
     52static bool prefix( const string & arg, const string & pre ) { // check if string has prefix
    5353        return arg.substr( 0, pre.size() ) == pre;
    5454} // prefix
    5555
    56 inline bool ends_with(const string & str, const string & sfix) {
     56static inline bool ends_with(const string & str, const string & sfix) {
    5757        if (sfix.size() > str.size()) return false;
    5858        return std::equal(str.rbegin(), str.rbegin() + sfix.size(), sfix.rbegin(), sfix.rend());
     
    6060
    6161// check if string has suffix
    62 bool suffix( const string & arg ) {
     62static bool suffix( const string & arg ) {
    6363        enum { NumSuffixes = 3 };
    6464        static const string suffixes[NumSuffixes] = { "cfa", "hfa", "ifa" };
     
    7070} // suffix
    7171
    72 
    7372static inline bool dirExists( const string & path ) {   // check if directory exists
    7473    struct stat info;
     
    7978static inline string dir(const string & path) {
    8079        return path.substr(0, path.find_last_of('/'));
    81 }
     80} // dir
    8281
    8382// Different path modes
     
    118117}
    119118
    120 
    121 #define xstr(s) str(s)
    122 #define str(s) #s
    123119
    124120int main( int argc, char * argv[] ) {
     
    158154        PathMode path = FromProc();
    159155
    160         const char *args[argc + 100];                                           // cfa command line values, plus some space for additional flags
     156        const char * args[argc + 100];                                          // cfa command line values, plus some space for additional flags
    161157        int sargs = 1;                                                                          // starting location for arguments in args list
    162158        int nargs = sargs;                                                                      // number of arguments in args list; 0 => command name
    163159
    164         const char *libs[argc + 20];                                            // non-user libraries must come separately, plus some added libraries and flags
     160        const char * libs[argc + 20];                                           // non-user libraries must come separately, plus some added libraries and flags
    165161        int nlibs = 0;
    166162
     
    180176
    181177                        if ( arg == "-Xlinker" || arg == "-o" ) {
    182                                 args[nargs++] = argv[i];                                // pass argument along
     178                                args[nargs++] = argv[i];                                // pass flag along
    183179                                i += 1;
    184180                                if ( i == argc ) continue;                              // next argument available ?
    185181                                args[nargs++] = argv[i];                                // pass argument along
    186182                                if ( arg == "-o" ) o_file = i;                  // remember file
    187                         } else if ( strncmp(arg.c_str(), "-XCFA", 5) == 0 ) {                           // CFA pass through
    188                                 if(arg.size() == 5) {
     183
     184                                // CFA specific arguments
     185
     186                        } else if ( strncmp(arg.c_str(), "-XCFA", 5) == 0 ) { // CFA pass through
     187                                if ( arg.size() == 5 ) {
    189188                                        i += 1;
    190                                         if ( i == argc ) continue;                              // next argument available ?
     189                                        if ( i == argc ) continue;                      // next argument available ?
    191190                                        Putenv( argv, argv[i] );
    192 
    193                                         // CFA specific arguments
    194                                 }
    195                                 else if(arg[5] == ',') {
     191                                } else if ( arg[5] == ',' ) {                   // CFA specific arguments
    196192                                        Putenv( argv, argv[i] + 6 );
    197 
    198                                         // CFA specific arguments
    199                                 }
    200                                 else {
     193                                } else {                                                                // CFA specific arguments
    201194                                        args[nargs++] = argv[i];
    202                                 }
    203 
     195                                } // if
    204196                        } else if ( arg == "-CFA" ) {
    205197                                CFA_flag = true;                                                // strip the -CFA flag
     
    210202                        } else if ( arg == "-nodebug" ) {
    211203                                debug = false;                                                  // strip the nodebug flag
    212                         } else if ( arg == "-nolib" ) {
    213                                 nolib = true;                                                   // strip the nodebug flag
    214204                        } else if ( arg == "-quiet" ) {
    215205                                quiet = true;                                                   // strip the quiet flag
    216206                        } else if ( arg == "-noquiet" ) {
    217207                                quiet = false;                                                  // strip the noquiet flag
     208                        } else if ( arg == "-no-include-stdhdr" ) {
     209                                noincstd_flag = true;                                   // strip the no-include-stdhdr flag
     210                        } else if ( arg == "-nolib" ) {
     211                                nolib = true;                                                   // strip the nolib flag
    218212                        } else if ( arg == "-help" ) {
    219213                                help = true;                                                    // strip the help flag
    220214                        } else if ( arg == "-nohelp" ) {
    221215                                help = false;                                                   // strip the nohelp flag
    222                         } else if ( arg == "-no-include-stdhdr" ) {
    223                                 noincstd_flag = true;                                   // strip the no-include-stdhdr flag
    224216                        } else if ( arg == "-cfalib") {
    225217                                compiling_libs = true;
     
    235227                        } else if ( arg == "-v" ) {
    236228                                verbose = true;                                                 // verbosity required
    237                                 args[nargs++] = argv[i];                                // pass argument along
     229                                args[nargs++] = argv[i];                                // pass flag along
    238230                        } else if ( arg == "-g" ) {
    239231                                debugging = true;                                               // symbolic debugging required
    240                                 args[nargs++] = argv[i];                                // pass argument along
     232                                args[nargs++] = argv[i];                                // pass flag along
    241233                        } else if ( arg == "-save-temps" ) {
    242                                 args[nargs++] = argv[i];                                // pass argument along
     234                                args[nargs++] = argv[i];                                // pass flag along
    243235                                Putenv( argv, arg );                                    // save cfa-cpp output
    244236                        } else if ( prefix( arg, "-x" ) ) {                     // file suffix ?
    245237                                string lang;
    246                                 args[nargs++] = argv[i];                                // pass argument along
     238                                args[nargs++] = argv[i];                                // pass flag along
    247239                                if ( arg.length() == 2 ) {                              // separate argument ?
    248240                                        i += 1;
     
    261253                        } else if ( prefix( arg, "-std=" ) || prefix( arg, "--std=" ) ) {
    262254                                std_flag = true;                                                // -std=XX provided
    263                                 args[nargs++] = argv[i];                                // pass argument along
     255                                args[nargs++] = argv[i];                                // pass flag along
    264256                        } else if ( arg == "-w" ) {
    265                                 args[nargs++] = argv[i];                                // pass argument along
     257                                args[nargs++] = argv[i];                                // pass flag along
    266258                                Putenv( argv, arg );
    267259                        } else if ( prefix( arg, "-W" ) ) {                     // check before next tests
    268260                                if ( arg == "-Werror" || arg == "-Wall" ) {
    269                                         args[nargs++] = argv[i];                        // pass argument along
     261                                        args[nargs++] = argv[i];                        // pass flag along
    270262                                        Putenv( argv, argv[i] );
    271263                                } else {
     
    281273                                bprefix = arg.substr(2);                                // strip the -B flag
    282274                        } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) {
    283                                 args[nargs++] = argv[i];                                // pass argument along
     275                                args[nargs++] = argv[i];                                // pass flag along
    284276                                if ( arg == "-E" || arg == "-M" || arg == "-MM" ) {
    285277                                        cpp_flag = true;                                        // cpp only
    286278                                } // if
    287279                                link = false;                           // no linkage required
     280                        } else if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
     281                                                arg == "-include" || arg == "-imacros" || arg == "-idirafter" || arg == "-iprefix" ||
     282                                                arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) {
     283                                args[nargs++] = argv[i];                                // pass flag along
     284                                i += 1;
     285                                args[nargs++] = argv[i];                                // pass argument along
    288286                        } else if ( arg[1] == 'l' ) {
    289287                                // if the user specifies a library, load it after user code
     
    337335        string libbase;
    338336        switch(path) {
    339         case Installed:
     337          case Installed:
    340338                args[nargs++] = "-I" CFA_INCDIR;
    341339                // do not use during build
     
    347345                libbase = CFA_LIBDIR;
    348346                break;
    349         case BuildTree:
    350         case Distributed:
     347          case BuildTree:
     348          case Distributed:
    351349                args[nargs++] = "-I" TOP_SRCDIR "libcfa/src";
    352350                // do not use during build
     
    382380        string libdir = libbase + arch + "-" + config;
    383381
    384         if (path != Distributed) {
     382        if ( path != Distributed ) {
    385383                if ( ! nolib && ! dirExists( libdir ) ) {
    386384                        cerr << argv[0] << " internal error, configuration " << config << " not installed." << endl;
     
    402400        string preludedir;
    403401        switch(path) {
    404         case Installed   : preludedir = libdir; break;
    405         case BuildTree   : preludedir = libdir + "/prelude"; break;
    406         case Distributed : preludedir = dir(argv[0]); break;
    407         }
     402          case Installed   : preludedir = libdir; break;
     403          case BuildTree   : preludedir = libdir + "/prelude"; break;
     404          case Distributed : preludedir = dir(argv[0]); break;
     405        } // switch
    408406
    409407        Putenv( argv, "--prelude-dir=" + preludedir );
     
    477475        if ( bprefix.length() == 0 ) {
    478476                switch(path) {
    479                 case Installed   : bprefix = installlibdir; break;
    480                 case BuildTree   : bprefix = srcdriverdir ; break;
    481                 case Distributed : bprefix = dir(argv[0]) ; break;
    482                 }
    483                 if ( bprefix[bprefix.length() - 1] != '/' ) bprefix += '/';
    484                 Putenv( argv, string("-B=") + bprefix );
    485         } // if
     477                  case Installed   : bprefix = installlibdir; break;
     478                  case BuildTree   : bprefix = srcdriverdir ; break;
     479                  case Distributed : bprefix = dir(argv[0]) ; break;
     480                } // switch
     481        } // if
     482        if ( bprefix[bprefix.length() - 1] != '/' ) bprefix += '/';
     483        Putenv( argv, string("-B=") + bprefix );
    486484
    487485        args[nargs++] = "-Xlinker";                                                     // used by backtrace
     
    505503                args[nargs++] = "-Wno-cast-function-type";
    506504                #endif // HAVE_CAST_FUNCTION_TYPE
    507                 if ( ! std_flag ) {                                                             // default c11, if none specified
    508                         args[nargs++] = "-std=gnu11";
     505                if ( ! std_flag && ! x_flag ) {
     506                        args[nargs++] = "-std=gnu11";                           // default c11, if none specified
    509507                } // if
    510508                args[nargs++] = "-fgnu89-inline";
     
    556554        // execute the command and return the result
    557555
    558         execvp( args[0], (char *const *)args );                         // should not return
     556        execvp( args[0], (char * const *)args );                        // should not return
    559557        perror( "CFA Translator error: execvp" );
    560558        exit( EXIT_FAILURE );
  • libcfa/prelude/bootloader.cf

    r67ca73e re67a82d  
    11extern "C" { static inline int invoke_main(int argc, char* argv[], char* envp[]); }
     2int cfa_args_argc;
     3char ** cfa_args_argv;
     4char ** cfa_args_envp;
    25
    36int main(int argc, char* argv[], char* envp[]) {
     7        cfa_args_argc = argc;
     8        cfa_args_argv = argv;
     9        cfa_args_envp = envp;
    410        return invoke_main(argc, argv, envp);
    511}
  • libcfa/src/Makefile.am

    r67ca73e re67a82d  
    4444
    4545headers = common.hfa fstream.hfa heap.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa \
    46                 time.hfa stdlib.hfa memory.hfa \
     46                time.hfa stdlib.hfa parseargs.hfa \
    4747                containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa
    4848
  • libcfa/src/bits/locks.hfa

    r67ca73e re67a82d  
    217217                }
    218218        }
     219
     220        // Semaphore which only supports a single thread and one post
     221        // Semaphore which only supports a single thread
     222        struct oneshot {
     223                struct $thread * volatile ptr;
     224        };
     225
     226        static inline {
     227                void  ?{}(oneshot & this) {
     228                        this.ptr = 0p;
     229                }
     230
     231                void ^?{}(oneshot & this) {}
     232
     233                bool wait(oneshot & this) {
     234                        for() {
     235                                struct $thread * expected = this.ptr;
     236                                if(expected == 1p) return false;
     237                                /* paranoid */ verify( expected == 0p );
     238                                if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     239                                        park( __cfaabi_dbg_ctx );
     240                                        /* paranoid */ verify( this.ptr == 1p );
     241                                        return true;
     242                                }
     243                        }
     244                }
     245
     246                bool post(oneshot & this) {
     247                        struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
     248                        if( got == 0p ) return false;
     249                        unpark( got __cfaabi_dbg_ctx2 );
     250                        return true;
     251                }
     252        }
    219253#endif
  • libcfa/src/common.hfa

    r67ca73e re67a82d  
    1010// Created On       : Wed Jul 11 17:54:36 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 12 08:02:18 2018
    13 // Update Count     : 5
     12// Last Modified On : Sat Aug 15 08:51:29 2020
     13// Update Count     : 14
    1414//
    1515
     
    6767
    6868static inline {
     69        char min( char t1, char t2 ) { return t1 < t2 ? t1 : t2; } // optimization
     70        intptr_t min( intptr_t t1, intptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
     71        uintptr_t min( uintptr_t t1, uintptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
    6972        forall( otype T | { int ?<?( T, T ); } )
    7073        T min( T t1, T t2 ) { return t1 < t2 ? t1 : t2; }
    7174
     75        char max( char t1, char t2 ) { return t1 > t2 ? t1 : t2; } // optimization
     76        intptr_t max( intptr_t t1, intptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
     77        uintptr_t max( uintptr_t t1, uintptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
    7278        forall( otype T | { int ?>?( T, T ); } )
    7379        T max( T t1, T t2 ) { return t1 > t2 ? t1 : t2; }
  • libcfa/src/concurrency/alarm.hfa

    r67ca73e re67a82d  
    2323#include "time.hfa"
    2424
    25 #include <containers/list.hfa>
     25#include "containers/list.hfa"
    2626
    2727struct $thread;
  • libcfa/src/concurrency/coroutine.cfa

    r67ca73e re67a82d  
    215215                return cor;
    216216        }
     217
     218        struct $coroutine * __cfactx_cor_active(void) {
     219                return active_coroutine();
     220        }
    217221}
    218222
  • libcfa/src/concurrency/invoke.c

    r67ca73e re67a82d  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Aug 20 18:54:34 2020
    13 // Update Count     : 30
     12// Last Modified On : Thu Aug 20 23:43:23 2020
     13// Update Count     : 31
    1414//
    1515
     
    2929// Called from the kernel when starting a coroutine or task so must switch back to user mode.
    3030
     31extern struct $coroutine * __cfactx_cor_active(void);
    3132extern struct $coroutine * __cfactx_cor_finish(void);
    3233extern void __cfactx_cor_leave ( struct $coroutine * );
     
    3536extern void disable_interrupts() OPTIONAL_THREAD;
    3637extern void enable_interrupts( __cfaabi_dbg_ctx_param );
     38
     39struct exception_context_t * this_exception_context() {
     40        return &__get_stack( __cfactx_cor_active() )->exception_context;
     41}
    3742
    3843void __cfactx_invoke_coroutine(
     
    146151
    147152#elif defined( __ARM_ARCH_32 )
    148 #warning ARM needs to be upgrade to use two parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it)
     153#error ARM needs to be upgrade to use two parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it)
     154        // More details about the error:
     155        // To avoid the thunk problem, I changed the invoke routine to pass the main explicitly
     156        // instead of relying on an assertion. This effectively hoists any required thunk one level
     157        // which was enough to get to global scope in most cases.
     158        // This means that __cfactx_invoke_... now takes two parameters and the FakeStack needs
     159        // to be adjusted as a consequence of that.
     160        // I don't know how to do that for ARM, hence the #error
     161
    149162        struct FakeStack {
    150163                float fpRegs[16];                                                               // floating point registers
  • libcfa/src/concurrency/invoke.h

    r67ca73e re67a82d  
    2626#ifndef _INVOKE_H_
    2727#define _INVOKE_H_
     28
     29        struct __cfaehm_try_resume_node;
     30        struct __cfaehm_base_exception_t;
     31        struct exception_context_t {
     32                struct __cfaehm_try_resume_node * top_resume;
     33                struct __cfaehm_base_exception_t * current_exception;
     34        };
    2835
    2936        struct __stack_context_t {
     
    5158                // base of stack
    5259                void * base;
     60
     61                // Information for exception handling.
     62                struct exception_context_t exception_context;
    5363        };
    5464
     
    8494        };
    8595
    86         static inline struct __stack_t * __get_stack( struct $coroutine * cor ) { return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2)); }
     96        static inline struct __stack_t * __get_stack( struct $coroutine * cor ) {
     97                return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2));
     98        }
     99
     100        struct exception_context_t * this_exception_context();
    87101
    88102        // struct which calls the monitor is accepting
  • libcfa/src/concurrency/io.cfa

    r67ca73e re67a82d  
    4141        #include "kernel/fwd.hfa"
    4242        #include "io/types.hfa"
     43
     44        // returns true of acquired as leader or second leader
     45        static inline bool try_lock( __leaderlock_t & this ) {
     46                const uintptr_t thrd = 1z | (uintptr_t)active_thread();
     47                bool block;
     48                disable_interrupts();
     49                for() {
     50                        struct $thread * expected = this.value;
     51                        if( 1p != expected && 0p != expected ) {
     52                                /* paranoid */ verify( thrd != (uintptr_t)expected ); // We better not already be the next leader
     53                                enable_interrupts( __cfaabi_dbg_ctx );
     54                                return false;
     55                        }
     56                        struct $thread * desired;
     57                        if( 0p == expected ) {
     58                                // If the lock isn't locked acquire it, no need to block
     59                                desired = 1p;
     60                                block = false;
     61                        }
     62                        else {
     63                                // If the lock is already locked try becomming the next leader
     64                                desired = (struct $thread *)thrd;
     65                                block = true;
     66                        }
     67                        if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break;
     68                }
     69                if( block ) {
     70                        enable_interrupts( __cfaabi_dbg_ctx );
     71                        park( __cfaabi_dbg_ctx );
     72                        disable_interrupts();
     73                }
     74                return true;
     75        }
     76
     77        static inline bool next( __leaderlock_t & this ) {
     78                /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     79                struct $thread * nextt;
     80                for() {
     81                        struct $thread * expected = this.value;
     82                        /* paranoid */ verify( (1 & (uintptr_t)expected) == 1 ); // The lock better be locked
     83
     84                        struct $thread * desired;
     85                        if( 1p == expected ) {
     86                                // No next leader, just unlock
     87                                desired = 0p;
     88                                nextt   = 0p;
     89                        }
     90                        else {
     91                                // There is a next leader, remove but keep locked
     92                                desired = 1p;
     93                                nextt   = (struct $thread *)(~1z & (uintptr_t)expected);
     94                        }
     95                        if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break;
     96                }
     97
     98                if(nextt) {
     99                        unpark( nextt __cfaabi_dbg_ctx2 );
     100                        enable_interrupts( __cfaabi_dbg_ctx );
     101                        return true;
     102                }
     103                enable_interrupts( __cfaabi_dbg_ctx );
     104                return false;
     105        }
    43106
    44107//=============================================================================================
     
    93156//=============================================================================================
    94157        static unsigned __collect_submitions( struct __io_data & ring );
    95         static uint32_t __release_consumed_submission( struct __io_data & ring );
     158        static __u32 __release_consumed_submission( struct __io_data & ring );
    96159
    97160        static inline void process(struct io_uring_cqe & cqe ) {
     
    100163
    101164                data->result = cqe.res;
    102                 unpark( data->thrd __cfaabi_dbg_ctx2 );
     165                post( data->sem );
    103166        }
    104167
     
    136199                unsigned head = *ring.completion_q.head;
    137200                unsigned tail = *ring.completion_q.tail;
    138                 const uint32_t mask = *ring.completion_q.mask;
     201                const __u32 mask = *ring.completion_q.mask;
    139202
    140203                // Nothing was new return 0
     
    143206                }
    144207
    145                 uint32_t count = tail - head;
     208                __u32 count = tail - head;
    146209                /* paranoid */ verify( count != 0 );
    147210                for(i; count) {
     
    182245                                __STATS__( true,
    183246                                        io.complete_q.completed_avg.val += count;
    184                                         io.complete_q.completed_avg.fast_cnt += 1;
     247                                        io.complete_q.completed_avg.cnt += 1;
    185248                                )
    186249                        enable_interrupts( __cfaabi_dbg_ctx );
     
    192255                        // We didn't get anything baton pass to the slow poller
    193256                        else {
     257                                __STATS__( false,
     258                                        io.complete_q.blocks += 1;
     259                                )
    194260                                __cfadbg_print_safe(io_core, "Kernel I/O : Parking io poller %p\n", &this.self);
    195261                                reset = 0;
     
    224290//
    225291
    226         [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) {
     292        [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ) {
    227293                /* paranoid */ verify( data != 0 );
    228294
     
    230296                __attribute((unused)) int len   = 0;
    231297                __attribute((unused)) int block = 0;
    232                 uint32_t cnt = *ring.submit_q.num;
    233                 uint32_t mask = *ring.submit_q.mask;
     298                __u32 cnt = *ring.submit_q.num;
     299                __u32 mask = *ring.submit_q.mask;
    234300
    235301                disable_interrupts();
    236                         uint32_t off = __tls_rand();
     302                        __u32 off = __tls_rand();
    237303                enable_interrupts( __cfaabi_dbg_ctx );
    238304
     
    241307                        // Look through the list starting at some offset
    242308                        for(i; cnt) {
    243                                 uint64_t expected = 0;
    244                                 uint32_t idx = (i + off) & mask;
     309                                __u64 expected = 0;
     310                                __u32 idx = (i + off) & mask;
    245311                                struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx];
    246                                 volatile uint64_t * udata = (volatile uint64_t *)&sqe->user_data;
     312                                volatile __u64 * udata = &sqe->user_data;
    247313
    248314                                if( *udata == expected &&
     
    270336        }
    271337
    272         static inline uint32_t __submit_to_ready_array( struct __io_data & ring, uint32_t idx, const uint32_t mask ) {
     338        static inline __u32 __submit_to_ready_array( struct __io_data & ring, __u32 idx, const __u32 mask ) {
    273339                /* paranoid */ verify( idx <= mask   );
    274340                /* paranoid */ verify( idx != -1ul32 );
     
    277343                __attribute((unused)) int len   = 0;
    278344                __attribute((unused)) int block = 0;
    279                 uint32_t ready_mask = ring.submit_q.ready_cnt - 1;
     345                __u32 ready_mask = ring.submit_q.ready_cnt - 1;
    280346
    281347                disable_interrupts();
    282                         uint32_t off = __tls_rand();
     348                        __u32 off = __tls_rand();
    283349                enable_interrupts( __cfaabi_dbg_ctx );
    284350
    285                 uint32_t picked;
     351                __u32 picked;
    286352                LOOKING: for() {
    287353                        for(i; ring.submit_q.ready_cnt) {
    288354                                picked = (i + off) & ready_mask;
    289                                 uint32_t expected = -1ul32;
     355                                __u32 expected = -1ul32;
    290356                                if( __atomic_compare_exchange_n( &ring.submit_q.ready[picked], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) {
    291357                                        break LOOKING;
     
    297363
    298364                        block++;
    299                         if( try_lock(ring.submit_q.lock __cfaabi_dbg_ctx2) ) {
    300                                 __release_consumed_submission( ring );
    301                                 unlock( ring.submit_q.lock );
    302                         }
    303                         else {
     365
     366                        __u32 released = __release_consumed_submission( ring );
     367                        if( released == 0 ) {
    304368                                yield();
    305369                        }
     
    316380        }
    317381
    318         void __submit( struct io_context * ctx, uint32_t idx ) __attribute__((nonnull (1))) {
     382        void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1))) {
    319383                __io_data & ring = *ctx->thrd.ring;
    320384                // Get now the data we definetely need
    321                 volatile uint32_t * const tail = ring.submit_q.tail;
    322                 const uint32_t mask  = *ring.submit_q.mask;
     385                volatile __u32 * const tail = ring.submit_q.tail;
     386                const __u32 mask  = *ring.submit_q.mask;
    323387
    324388                // There are 2 submission schemes, check which one we are using
     
    332396                }
    333397                else if( ring.eager_submits ) {
    334                         uint32_t picked = __submit_to_ready_array( ring, idx, mask );
    335 
    336                         for() {
    337                                 yield();
    338 
    339                                 // If some one else collected our index, we are done
    340                                 #warning ABA problem
    341                                 if( ring.submit_q.ready[picked] != idx ) {
     398                        __u32 picked = __submit_to_ready_array( ring, idx, mask );
     399
     400                        #if defined(LEADER_LOCK)
     401                                if( !try_lock(ring.submit_q.submit_lock) ) {
    342402                                        __STATS__( false,
    343403                                                io.submit_q.helped += 1;
     
    345405                                        return;
    346406                                }
    347 
    348                                 if( try_lock(ring.submit_q.lock __cfaabi_dbg_ctx2) ) {
     407                                /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     408                                __STATS__( true,
     409                                        io.submit_q.leader += 1;
     410                                )
     411                        #else
     412                                for() {
     413                                        yield();
     414
     415                                        if( try_lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2) ) {
     416                                                __STATS__( false,
     417                                                        io.submit_q.leader += 1;
     418                                                )
     419                                                break;
     420                                        }
     421
     422                                        // If some one else collected our index, we are done
     423                                        #warning ABA problem
     424                                        if( ring.submit_q.ready[picked] != idx ) {
     425                                                __STATS__( false,
     426                                                        io.submit_q.helped += 1;
     427                                                )
     428                                                return;
     429                                        }
     430
    349431                                        __STATS__( false,
    350                                                 io.submit_q.leader += 1;
     432                                                io.submit_q.busy += 1;
    351433                                        )
    352                                         break;
    353                                 }
    354 
    355                                 __STATS__( false,
    356                                         io.submit_q.busy += 1;
    357                                 )
    358                         }
     434                                }
     435                        #endif
    359436
    360437                        // We got the lock
     438                        // Collect the submissions
    361439                        unsigned to_submit = __collect_submitions( ring );
     440
     441                        // Actually submit
    362442                        int ret = __io_uring_enter( ring, to_submit, false );
    363                         if( ret < 0 ) {
    364                                 unlock(ring.submit_q.lock);
    365                                 return;
    366                         }
    367 
    368                         /* paranoid */ verify( ret > 0 || to_submit == 0 || (ring.ring_flags & IORING_SETUP_SQPOLL) );
     443
     444                        #if defined(LEADER_LOCK)
     445                                /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     446                                next(ring.submit_q.submit_lock);
     447                        #else
     448                                unlock(ring.submit_q.submit_lock);
     449                        #endif
     450                        if( ret < 0 ) return;
    369451
    370452                        // Release the consumed SQEs
     
    372454
    373455                        // update statistics
    374                         __STATS__( true,
     456                        __STATS__( false,
    375457                                io.submit_q.submit_avg.rdy += to_submit;
    376458                                io.submit_q.submit_avg.csm += ret;
    377459                                io.submit_q.submit_avg.cnt += 1;
    378460                        )
    379 
    380                         unlock(ring.submit_q.lock);
    381461                }
    382462                else {
    383463                        // get mutual exclusion
    384                         lock(ring.submit_q.lock __cfaabi_dbg_ctx2);
     464                        #if defined(LEADER_LOCK)
     465                                while(!try_lock(ring.submit_q.submit_lock));
     466                        #else
     467                                lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2);
     468                        #endif
    385469
    386470                        /* paranoid */ verifyf( ring.submit_q.sqes[ idx ].user_data != 0,
     
    420504                        __release_consumed_submission( ring );
    421505
    422                         unlock(ring.submit_q.lock);
     506                        #if defined(LEADER_LOCK)
     507                                next(ring.submit_q.submit_lock);
     508                        #else
     509                                unlock(ring.submit_q.submit_lock);
     510                        #endif
    423511
    424512                        __cfadbg_print_safe( io, "Kernel I/O : Performed io_submit for %p, returned %d\n", active_thread(), ret );
     
    426514        }
    427515
     516        // #define PARTIAL_SUBMIT 32
    428517        static unsigned __collect_submitions( struct __io_data & ring ) {
    429518                /* paranoid */ verify( ring.submit_q.ready != 0p );
     
    431520
    432521                unsigned to_submit = 0;
    433                 uint32_t tail = *ring.submit_q.tail;
    434                 const uint32_t mask = *ring.submit_q.mask;
     522                __u32 tail = *ring.submit_q.tail;
     523                const __u32 mask = *ring.submit_q.mask;
     524                #if defined(PARTIAL_SUBMIT)
     525                        #if defined(LEADER_LOCK)
     526                                #error PARTIAL_SUBMIT and LEADER_LOCK cannot co-exist
     527                        #endif
     528                        const __u32 cnt = ring.submit_q.ready_cnt > PARTIAL_SUBMIT ? PARTIAL_SUBMIT : ring.submit_q.ready_cnt;
     529                        const __u32 offset = ring.submit_q.prev_ready;
     530                        ring.submit_q.prev_ready += cnt;
     531                #else
     532                        const __u32 cnt = ring.submit_q.ready_cnt;
     533                        const __u32 offset = 0;
     534                #endif
    435535
    436536                // Go through the list of ready submissions
    437                 for( i; ring.submit_q.ready_cnt ) {
     537                for( c; cnt ) {
     538                        __u32 i = (offset + c) % ring.submit_q.ready_cnt;
     539
    438540                        // replace any submission with the sentinel, to consume it.
    439                         uint32_t idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED);
     541                        __u32 idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED);
    440542
    441543                        // If it was already the sentinel, then we are done
     
    453555        }
    454556
    455         static uint32_t __release_consumed_submission( struct __io_data & ring ) {
    456                 const uint32_t smask = *ring.submit_q.mask;
     557        static __u32 __release_consumed_submission( struct __io_data & ring ) {
     558                const __u32 smask = *ring.submit_q.mask;
    457559
    458560                if( !try_lock(ring.submit_q.release_lock __cfaabi_dbg_ctx2) ) return 0;
    459                 uint32_t chead = *ring.submit_q.head;
    460                 uint32_t phead = ring.submit_q.prev_head;
     561                __u32 chead = *ring.submit_q.head;
     562                __u32 phead = ring.submit_q.prev_head;
    461563                ring.submit_q.prev_head = chead;
    462564                unlock(ring.submit_q.release_lock);
    463565
    464                 uint32_t count = chead - phead;
     566                __u32 count = chead - phead;
    465567                for( i; count ) {
    466                         uint32_t idx = ring.submit_q.array[ (phead + i) & smask ];
     568                        __u32 idx = ring.submit_q.array[ (phead + i) & smask ];
    467569                        ring.submit_q.sqes[ idx ].user_data = 0;
    468570                }
  • libcfa/src/concurrency/io/setup.cfa

    r67ca73e re67a82d  
    228228                if( cluster_context ) {
    229229                        cluster & cltr = *thrd.curr_cluster;
    230                         /* paranoid */ verify( cltr.nprocessors == 0 || &cltr == mainCluster );
     230                        /* paranoid */ verify( cltr.idles.total == 0 || &cltr == mainCluster );
    231231                        /* paranoid */ verify( !ready_mutate_islocked() );
    232232
     
    298298                if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL;
    299299
    300                 uint32_t nentries = params_in.num_entries;
     300                __u32 nentries = params_in.num_entries != 0 ? params_in.num_entries : 256;
     301                if( !is_pow2(nentries) ) {
     302                        abort("ERROR: I/O setup 'num_entries' must be a power of 2\n");
     303                }
     304                if( params_in.poller_submits && params_in.eager_submits ) {
     305                        abort("ERROR: I/O setup 'poller_submits' and 'eager_submits' cannot be used together\n");
     306                }
    301307
    302308                int fd = syscall(__NR_io_uring_setup, nentries, &params );
     
    356362                // Get the pointers from the kernel to fill the structure
    357363                // submit queue
    358                 sq.head    = (volatile uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
    359                 sq.tail    = (volatile uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
    360                 sq.mask    = (   const uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
    361                 sq.num     = (   const uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
    362                 sq.flags   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
    363                 sq.dropped = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
    364                 sq.array   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
     364                sq.head    = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
     365                sq.tail    = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
     366                sq.mask    = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
     367                sq.num     = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
     368                sq.flags   = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
     369                sq.dropped = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
     370                sq.array   = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
    365371                sq.prev_head = *sq.head;
    366372
    367373                {
    368                         const uint32_t num = *sq.num;
     374                        const __u32 num = *sq.num;
    369375                        for( i; num ) {
    370376                                sq.sqes[i].user_data = 0ul64;
     
    372378                }
    373379
    374                 (sq.lock){};
     380                (sq.submit_lock){};
    375381                (sq.release_lock){};
    376382
     
    382388                                sq.ready[i] = -1ul32;
    383389                        }
     390                        sq.prev_ready = 0;
    384391                }
    385392                else {
    386393                        sq.ready_cnt = 0;
    387394                        sq.ready = 0p;
     395                        sq.prev_ready = 0;
    388396                }
    389397
    390398                // completion queue
    391                 cq.head     = (volatile uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.head);
    392                 cq.tail     = (volatile uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.tail);
    393                 cq.mask     = (   const uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_mask);
    394                 cq.num      = (   const uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_entries);
    395                 cq.overflow = (         uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.overflow);
    396                 cq.cqes   = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes);
     399                cq.head      = (volatile __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.head);
     400                cq.tail      = (volatile __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.tail);
     401                cq.mask      = (   const __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_mask);
     402                cq.num       = (   const __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_entries);
     403                cq.overflow  = (         __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.overflow);
     404                cq.cqes = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes);
    397405
    398406                // some paranoid checks
     
    442450        void __ioctx_register($io_ctx_thread & ctx, struct epoll_event & ev) {
    443451                ev.events = EPOLLIN | EPOLLONESHOT;
    444                 ev.data.u64 = (uint64_t)&ctx;
     452                ev.data.u64 = (__u64)&ctx;
    445453                int ret = epoll_ctl(iopoll.epollfd, EPOLL_CTL_ADD, ctx.ring->fd, &ev);
    446454                if (ret < 0) {
  • libcfa/src/concurrency/io/types.hfa

    r67ca73e re67a82d  
    1717
    1818#if defined(CFA_HAVE_LINUX_IO_URING_H)
     19        extern "C" {
     20                #include <linux/types.h>
     21        }
     22
    1923      #include "bits/locks.hfa"
     24
     25        #define LEADER_LOCK
     26        struct __leaderlock_t {
     27                struct $thread * volatile value;        // ($thread) next_leader | (bool:1) is_locked
     28        };
     29
     30        static inline void ?{}( __leaderlock_t & this ) { this.value = 0p; }
    2031
    2132        //-----------------------------------------------------------------------
     
    2334      struct __submition_data {
    2435                // Head and tail of the ring (associated with array)
    25                 volatile uint32_t * head;
    26                 volatile uint32_t * tail;
    27                 volatile uint32_t prev_head;
     36                volatile __u32 * head;
     37                volatile __u32 * tail;
     38                volatile __u32 prev_head;
    2839
    2940                // The actual kernel ring which uses head/tail
    3041                // indexes into the sqes arrays
    31                 uint32_t * array;
     42                __u32 * array;
    3243
    3344                // number of entries and mask to go with it
    34                 const uint32_t * num;
    35                 const uint32_t * mask;
     45                const __u32 * num;
     46                const __u32 * mask;
    3647
    3748                // Submission flags (Not sure what for)
    38                 uint32_t * flags;
     49                __u32 * flags;
    3950
    4051                // number of sqes not submitted (whatever that means)
    41                 uint32_t * dropped;
     52                __u32 * dropped;
    4253
    4354                // Like head/tail but not seen by the kernel
    44                 volatile uint32_t * ready;
    45                 uint32_t ready_cnt;
     55                volatile __u32 * ready;
     56                __u32 ready_cnt;
     57                __u32 prev_ready;
    4658
    47                 __spinlock_t lock;
    48                 __spinlock_t release_lock;
     59                #if defined(LEADER_LOCK)
     60                        __leaderlock_t submit_lock;
     61                #else
     62                        __spinlock_t submit_lock;
     63                #endif
     64                __spinlock_t  release_lock;
    4965
    5066                // A buffer of sqes (not the actual ring)
     
    5874        struct __completion_data {
    5975                // Head and tail of the ring
    60                 volatile uint32_t * head;
    61                 volatile uint32_t * tail;
     76                volatile __u32 * head;
     77                volatile __u32 * tail;
    6278
    6379                // number of entries and mask to go with it
    64                 const uint32_t * mask;
    65                 const uint32_t * num;
     80                const __u32 * mask;
     81                const __u32 * num;
    6682
    6783                // number of cqes not submitted (whatever that means)
    68                 uint32_t * overflow;
     84                __u32 * overflow;
    6985
    7086                // the kernel ring
     
    7995                struct __submition_data submit_q;
    8096                struct __completion_data completion_q;
    81                 uint32_t ring_flags;
     97                __u32 ring_flags;
    8298                int fd;
    8399                bool eager_submits:1;
     
    89105        // IO user data
    90106        struct __io_user_data_t {
    91                 int32_t result;
    92                 $thread * thrd;
     107                __s32 result;
     108                oneshot sem;
    93109        };
    94110
  • libcfa/src/concurrency/iocall.cfa

    r67ca73e re67a82d  
    3232        #include "io/types.hfa"
    3333
    34         extern [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data );
    35         extern void __submit( struct io_context * ctx, uint32_t idx ) __attribute__((nonnull (1)));
    36 
    37         static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd) {
     34        extern [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data );
     35        extern void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1)));
     36
     37        static inline void ?{}(struct io_uring_sqe & this, __u8 opcode, int fd) {
    3838                this.opcode = opcode;
    3939                #if !defined(IOSQE_ASYNC)
     
    5151        }
    5252
    53         static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd, void * addr, uint32_t len, uint64_t off ) {
     53        static inline void ?{}(struct io_uring_sqe & this, __u8 opcode, int fd, void * addr, __u32 len, __u64 off ) {
    5454                (this){ opcode, fd };
    5555                this.off = off;
    56                 this.addr = (uint64_t)(uintptr_t)addr;
     56                this.addr = (__u64)(uintptr_t)addr;
    5757                this.len = len;
    5858        }
     
    101101        #endif
    102102
    103 
    104103        #define __submit_prelude \
    105104                if( 0 != (submit_flags & LINK_FLAGS) ) { errno = ENOTSUP; return -1; } \
    106105                (void)timeout; (void)cancellation; \
    107106                if( !context ) context = __get_io_context(); \
    108                 __io_user_data_t data = { 0, active_thread() }; \
     107                __io_user_data_t data = { 0 }; \
    109108                struct __io_data & ring = *context->thrd.ring; \
    110109                struct io_uring_sqe * sqe; \
    111                 uint32_t idx; \
    112                 [sqe, idx] = __submit_alloc( ring, (uint64_t)(uintptr_t)&data ); \
    113                 sqe->flags = REGULAR_FLAGS & submit_flags;
     110                __u32 idx; \
     111                __u8 sflags = REGULAR_FLAGS & submit_flags; \
     112                [sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&data ); \
     113                sqe->flags = sflags;
    114114
    115115        #define __submit_wait \
    116116                /*__cfaabi_bits_print_safe( STDERR_FILENO, "Preparing user data %p for %p\n", &data, data.thrd );*/ \
    117                 verify( sqe->user_data == (uint64_t)(uintptr_t)&data ); \
     117                verify( sqe->user_data == (__u64)(uintptr_t)&data ); \
    118118                __submit( context, idx ); \
    119                 park( __cfaabi_dbg_ctx ); \
     119                wait( data.sem ); \
    120120                if( data.result < 0 ) { \
    121121                        errno = -data.result; \
     
    149149
    150150        extern int fsync(int fd);
    151         extern int sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags);
     151
     152        #if __OFF_T_MATCHES_OFF64_T
     153                typedef __off64_t off_t;
     154        #else
     155                typedef __off_t off_t;
     156        #endif
     157        typedef __off64_t off64_t;
     158        extern int sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags);
    152159
    153160        struct msghdr;
     
    160167        extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    161168
    162         extern int fallocate(int fd, int mode, uint64_t offset, uint64_t len);
    163         extern int posix_fadvise(int fd, uint64_t offset, uint64_t len, int advice);
     169        extern int fallocate(int fd, int mode, off_t offset, off_t len);
     170        extern int posix_fadvise(int fd, off_t offset, off_t len, int advice);
    164171        extern int madvise(void *addr, size_t length, int advice);
    165172
     
    186193                        __submit_prelude
    187194
    188                         (*sqe){ IORING_OP_READV, fd, iov, iovcnt, offset };
     195                        sqe->opcode = IORING_OP_READV;
     196                        sqe->ioprio = 0;
     197                        sqe->fd = fd;
     198                        sqe->off = offset;
     199                        sqe->addr = (__u64)iov;
     200                        sqe->len = iovcnt;
     201                        sqe->rw_flags = 0;
     202                        sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
    189203
    190204                        __submit_wait
     
    200214                        __submit_prelude
    201215
    202                         (*sqe){ IORING_OP_WRITEV, fd, iov, iovcnt, offset };
     216                        sqe->opcode = IORING_OP_WRITEV;
     217                        sqe->ioprio = 0;
     218                        sqe->fd = fd;
     219                        sqe->off = offset;
     220                        sqe->addr = (__u64)iov;
     221                        sqe->len = iovcnt;
     222                        sqe->rw_flags = 0;
     223                        sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
    203224
    204225                        __submit_wait
     
    213234                __submit_prelude
    214235
    215                 (*sqe){ IORING_OP_FSYNC, fd };
    216 
    217                 __submit_wait
    218         #endif
    219 }
    220 
    221 int cfa_sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
     236                sqe->opcode = IORING_OP_FSYNC;
     237                sqe->ioprio = 0;
     238                sqe->fd = fd;
     239                sqe->off = 0;
     240                sqe->addr = 0;
     241                sqe->len = 0;
     242                sqe->rw_flags = 0;
     243                sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
     244
     245                __submit_wait
     246        #endif
     247}
     248
     249int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
    222250        #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_SYNC_FILE_RANGE)
    223251                return sync_file_range(fd, offset, nbytes, flags);
     
    268296
    269297                (*sqe){ IORING_OP_SEND, sockfd };
    270                 sqe->addr = (uint64_t)buf;
     298                sqe->addr = (__u64)buf;
    271299                sqe->len = len;
    272300                sqe->msg_flags = flags;
     
    283311
    284312                (*sqe){ IORING_OP_RECV, sockfd };
    285                 sqe->addr = (uint64_t)buf;
     313                sqe->addr = (__u64)buf;
    286314                sqe->len = len;
    287315                sqe->msg_flags = flags;
     
    298326
    299327                (*sqe){ IORING_OP_ACCEPT, sockfd };
    300                 sqe->addr = (uint64_t)(uintptr_t)addr;
    301                 sqe->addr2 = (uint64_t)(uintptr_t)addrlen;
     328                sqe->addr  = (__u64)addr;
     329                sqe->addr2 = (__u64)addrlen;
    302330                sqe->accept_flags = flags;
    303331
     
    313341
    314342                (*sqe){ IORING_OP_CONNECT, sockfd };
    315                 sqe->addr = (uint64_t)(uintptr_t)addr;
    316                 sqe->off  = (uint64_t)(uintptr_t)addrlen;
    317 
    318                 __submit_wait
    319         #endif
    320 }
    321 
    322 int cfa_fallocate(int fd, int mode, uint64_t offset, uint64_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
     343                sqe->addr = (__u64)addr;
     344                sqe->off  = (__u64)addrlen;
     345
     346                __submit_wait
     347        #endif
     348}
     349
     350int cfa_fallocate(int fd, int mode, off_t offset, off_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
    323351        #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_FALLOCATE)
    324352                return fallocate( fd, mode, offset, len );
     
    337365}
    338366
    339 int cfa_fadvise(int fd, uint64_t offset, uint64_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
     367int cfa_fadvise(int fd, off_t offset, off_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
    340368        #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_FADVISE)
    341369                return posix_fadvise( fd, offset, len, advice );
     
    344372
    345373                (*sqe){ IORING_OP_FADVISE, fd };
    346                 sqe->off = (uint64_t)offset;
     374                sqe->off = (__u64)offset;
    347375                sqe->len = len;
    348376                sqe->fadvise_advice = advice;
     
    359387
    360388                (*sqe){ IORING_OP_MADVISE, 0 };
    361                 sqe->addr = (uint64_t)addr;
     389                sqe->addr = (__u64)addr;
    362390                sqe->len = length;
    363391                sqe->fadvise_advice = advice;
     
    374402
    375403                (*sqe){ IORING_OP_OPENAT, dirfd };
    376                 sqe->addr = (uint64_t)pathname;
     404                sqe->addr = (__u64)pathname;
    377405                sqe->open_flags = flags;
    378406                sqe->len = mode;
     
    407435                __submit_prelude
    408436
    409                 (*sqe){ IORING_OP_STATX, dirfd, pathname, mask, (uint64_t)statxbuf };
     437                (*sqe){ IORING_OP_STATX, dirfd, pathname, mask, (__u64)statxbuf };
    410438                sqe->statx_flags = flags;
    411439
     
    449477                }
    450478                else {
    451                         sqe->off = (uint64_t)-1;
     479                        sqe->off = (__u64)-1;
    452480                }
    453481                sqe->len = len;
     
    457485                }
    458486                else {
    459                         sqe->splice_off_in = (uint64_t)-1;
     487                        sqe->splice_off_in = (__u64)-1;
    460488                }
    461489                sqe->splice_flags  = flags | (SPLICE_FLAGS & submit_flags);
  • libcfa/src/concurrency/kernel.cfa

    r67ca73e re67a82d  
    102102// Kernel Scheduling logic
    103103static $thread * __next_thread(cluster * this);
    104 static bool __has_next_thread(cluster * this);
     104static $thread * __next_thread_slow(cluster * this);
    105105static void __run_thread(processor * this, $thread * dst);
    106 static bool __wake_one(struct __processor_id_t * id, cluster * cltr);
    107 static void __halt(processor * this);
    108 bool __wake_proc(processor *);
     106static void __wake_one(struct __processor_id_t * id, cluster * cltr);
     107
     108static void push  (__cluster_idles & idles, processor & proc);
     109static void remove(__cluster_idles & idles, processor & proc);
     110static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles );
     111
    109112
    110113//=============================================================================================
     
    116119        // Do it here
    117120        kernelTLS.rand_seed ^= rdtscl();
     121        kernelTLS.ready_rng.fwd_seed = 25214903917_l64u * (rdtscl() ^ (uintptr_t)&runner);
     122        __tls_rand_advance_bck();
    118123
    119124        processor * this = runner.proc;
     
    134139
    135140                $thread * readyThread = 0p;
    136                 for( unsigned int spin_count = 0;; spin_count++ ) {
     141                MAIN_LOOP:
     142                for() {
    137143                        // Try to get the next thread
    138144                        readyThread = __next_thread( this->cltr );
    139145
    140                         // Check if we actually found a thread
    141                         if( readyThread ) {
    142                                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    143                                 /* paranoid */ verifyf( readyThread->state == Ready || readyThread->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", readyThread->state, readyThread->preempted);
    144                                 /* paranoid */ verifyf( readyThread->link.next == 0p, "Expected null got %p", readyThread->link.next );
    145                                 __builtin_prefetch( readyThread->context.SP );
    146 
    147                                 // We found a thread run it
    148                                 __run_thread(this, readyThread);
    149 
    150                                 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     146                        if( !readyThread ) {
     147                                readyThread = __next_thread_slow( this->cltr );
    151148                        }
    152149
    153                         if(__atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST)) break;
    154 
     150                        HALT:
    155151                        if( !readyThread ) {
    156                                 // Block until a thread is ready
    157                                 __halt(this);
     152                                // Don't block if we are done
     153                                if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
     154
     155                                #if !defined(__CFA_NO_STATISTICS__)
     156                                        __tls_stats()->ready.sleep.halts++;
     157                                #endif
     158
     159                                // Push self to idle stack
     160                                push(this->cltr->idles, * this);
     161
     162                                // Confirm the ready-queue is empty
     163                                readyThread = __next_thread_slow( this->cltr );
     164                                if( readyThread ) {
     165                                        // A thread was found, cancel the halt
     166                                        remove(this->cltr->idles, * this);
     167
     168                                        #if !defined(__CFA_NO_STATISTICS__)
     169                                                __tls_stats()->ready.sleep.cancels++;
     170                                        #endif
     171
     172                                        // continue the mai loop
     173                                        break HALT;
     174                                }
     175
     176                                #if !defined(__CFA_NO_STATISTICS__)
     177                                        if(this->print_halts) {
     178                                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl());
     179                                        }
     180                                #endif
     181
     182                                wait( this->idle );
     183
     184                                #if !defined(__CFA_NO_STATISTICS__)
     185                                        if(this->print_halts) {
     186                                                __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl());
     187                                        }
     188                                #endif
     189
     190                                // We were woken up, remove self from idle
     191                                remove(this->cltr->idles, * this);
     192
     193                                // DON'T just proceed, start looking again
     194                                continue MAIN_LOOP;
    158195                        }
     196
     197                        /* paranoid */ verify( readyThread );
     198
     199                        // We found a thread run it
     200                        __run_thread(this, readyThread);
     201
     202                        // Are we done?
     203                        if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    159204                }
    160205
     
    181226// from the processor coroutine to the target thread
    182227static void __run_thread(processor * this, $thread * thrd_dst) {
     228        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     229        /* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted);
     230        /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next );
     231        __builtin_prefetch( thrd_dst->context.SP );
     232
    183233        $coroutine * proc_cor = get_coroutine(this->runner);
    184234
     
    260310        proc_cor->state = Active;
    261311        kernelTLS.this_thread = 0p;
     312
     313        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    262314}
    263315
     
    316368        ready_schedule_lock  ( id );
    317369                push( thrd->curr_cluster, thrd );
    318 
    319                 #if !defined(__CFA_NO_STATISTICS__)
    320                         bool woke =
    321                 #endif
    322                         __wake_one(id, thrd->curr_cluster);
    323 
    324                 #if !defined(__CFA_NO_STATISTICS__)
    325                         if(woke) __tls_stats()->ready.sleep.wakes++;
    326                 #endif
     370                __wake_one(id, thrd->curr_cluster);
    327371        ready_schedule_unlock( id );
    328372
     
    331375
    332376// KERNEL ONLY
    333 static $thread * __next_thread(cluster * this) with( *this ) {
     377static inline $thread * __next_thread(cluster * this) with( *this ) {
    334378        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    335379
    336380        ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
    337                 $thread * head = pop( this );
     381                $thread * thrd = pop( this );
    338382        ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
    339383
    340384        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    341         return head;
     385        return thrd;
    342386}
    343387
    344388// KERNEL ONLY
    345 static bool __has_next_thread(cluster * this) with( *this ) {
     389static inline $thread * __next_thread_slow(cluster * this) with( *this ) {
    346390        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    347391
    348392        ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
    349                 bool not_empty = query( this );
     393                $thread * thrd = pop_slow( this );
    350394        ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
    351395
    352396        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    353         return not_empty;
     397        return thrd;
    354398}
    355399
     
    441485//=============================================================================================
    442486// Wake a thread from the front if there are any
    443 static bool __wake_one(struct __processor_id_t * id, cluster * this) {
     487static void __wake_one(struct __processor_id_t * id, cluster * this) {
     488        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    444489        /* paranoid */ verify( ready_schedule_islocked( id ) );
    445490
    446491        // Check if there is a sleeping processor
    447         processor * p = pop(this->idles);
     492        processor * p;
     493        unsigned idle;
     494        unsigned total;
     495        [idle, total, p] = query(this->idles);
    448496
    449497        // If no one is sleeping, we are done
    450         if( 0p == p ) return false;
     498        if( idle == 0 ) return;
    451499
    452500        // We found a processor, wake it up
    453501        post( p->idle );
    454502
    455         return true;
     503        #if !defined(__CFA_NO_STATISTICS__)
     504                __tls_stats()->ready.sleep.wakes++;
     505        #endif
     506
     507        /* paranoid */ verify( ready_schedule_islocked( id ) );
     508        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     509
     510        return;
    456511}
    457512
    458513// Unconditionnaly wake a thread
    459 bool __wake_proc(processor * this) {
     514void __wake_proc(processor * this) {
    460515        __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
    461516
     
    464519                bool ret = post( this->idle );
    465520        enable_interrupts( __cfaabi_dbg_ctx );
    466 
    467         return ret;
    468 }
    469 
    470 static void __halt(processor * this) with( *this ) {
    471         if( do_terminate ) return;
    472 
    473         #if !defined(__CFA_NO_STATISTICS__)
    474                 __tls_stats()->ready.sleep.halts++;
    475         #endif
    476         // Push self to queue
    477         push(cltr->idles, *this);
    478 
    479         // Makre sure we don't miss a thread
    480         if( __has_next_thread(cltr) ) {
    481                 // A thread was posted, make sure a processor is woken up
    482                 struct __processor_id_t *id = (struct __processor_id_t *) this;
    483                 ready_schedule_lock  ( id );
    484                         __wake_one( id, cltr );
    485                 ready_schedule_unlock( id );
    486                 #if !defined(__CFA_NO_STATISTICS__)
    487                         __tls_stats()->ready.sleep.cancels++;
    488                 #endif
    489         }
    490 
    491         #if !defined(__CFA_NO_STATISTICS__)
    492                 if(this->print_halts) {
    493                         __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl());
    494                 }
    495         #endif
    496 
    497         wait( idle );
    498 
    499         #if !defined(__CFA_NO_STATISTICS__)
    500                 if(this->print_halts) {
    501                         __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl());
    502                 }
    503         #endif
     521}
     522
     523static void push  (__cluster_idles & this, processor & proc) {
     524        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     525        lock( this );
     526                this.idle++;
     527                /* paranoid */ verify( this.idle <= this.total );
     528
     529                insert_first(this.list, proc);
     530        unlock( this );
     531        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     532}
     533
     534static void remove(__cluster_idles & this, processor & proc) {
     535        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     536        lock( this );
     537                this.idle--;
     538                /* paranoid */ verify( this.idle >= 0 );
     539
     540                remove(proc);
     541        unlock( this );
     542        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     543}
     544
     545static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) {
     546        for() {
     547                uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
     548                if( 1 == (l % 2) ) { Pause(); continue; }
     549                unsigned idle    = this.idle;
     550                unsigned total   = this.total;
     551                processor * proc = &this.list`first;
     552                // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it
     553                asm volatile("": : :"memory");
     554                if(l != __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST)) { Pause(); continue; }
     555                return [idle, total, proc];
     556        }
    504557}
    505558
  • libcfa/src/concurrency/kernel.hfa

    r67ca73e re67a82d  
    2020#include "coroutine.hfa"
    2121
    22 #include "containers/stackLockFree.hfa"
     22#include "containers/list.hfa"
    2323
    2424extern "C" {
     
    9999
    100100        // Link lists fields
    101         Link(processor) link;
     101        DLISTED_MGD_IMPL_IN(processor)
    102102
    103103        #if !defined(__CFA_NO_STATISTICS__)
     
    119119static inline void  ?{}(processor & this, const char name[]) { this{name, *mainCluster }; }
    120120
    121 static inline Link(processor) * ?`next( processor * this ) { return &this->link; }
     121DLISTED_MGD_IMPL_OUT(processor)
    122122
    123123//-----------------------------------------------------------------------------
     
    206206void ^?{}(__ready_queue_t & this);
    207207
     208// Idle Sleep
     209struct __cluster_idles {
     210        // Spin lock protecting the queue
     211        volatile uint64_t lock;
     212
     213        // Total number of processors
     214        unsigned total;
     215
     216        // Total number of idle processors
     217        unsigned idle;
     218
     219        // List of idle processors
     220        dlist(processor, processor) list;
     221};
     222
    208223//-----------------------------------------------------------------------------
    209224// Cluster
     
    219234
    220235        // List of idle processors
    221         StackLF(processor) idles;
    222         volatile unsigned int nprocessors;
     236        __cluster_idles idles;
    223237
    224238        // List of threads
  • libcfa/src/concurrency/kernel/fwd.hfa

    r67ca73e re67a82d  
    5050                                uint64_t rand_seed;
    5151                        #endif
     52                        struct {
     53                                uint64_t fwd_seed;
     54                                uint64_t bck_seed;
     55                        } ready_rng;
    5256                } kernelTLS __attribute__ ((tls_model ( "initial-exec" )));
     57
     58
    5359
    5460                static inline uint64_t __tls_rand() {
     
    5864                                return __xorshift64( kernelTLS.rand_seed );
    5965                        #endif
     66                }
     67
     68                #define M  (1_l64u << 48_l64u)
     69                #define A  (25214903917_l64u)
     70                #define AI (18446708753438544741_l64u)
     71                #define C  (11_l64u)
     72                #define D  (16_l64u)
     73
     74                static inline unsigned __tls_rand_fwd() {
     75
     76                        kernelTLS.ready_rng.fwd_seed = (A * kernelTLS.ready_rng.fwd_seed + C) & (M - 1);
     77                        return kernelTLS.ready_rng.fwd_seed >> D;
     78                }
     79
     80                static inline unsigned __tls_rand_bck() {
     81                        unsigned int r = kernelTLS.ready_rng.bck_seed >> D;
     82                        kernelTLS.ready_rng.bck_seed = AI * (kernelTLS.ready_rng.bck_seed - C) & (M - 1);
     83                        return r;
     84                }
     85
     86                #undef M
     87                #undef A
     88                #undef AI
     89                #undef C
     90                #undef D
     91
     92                static inline void __tls_rand_advance_bck(void) {
     93                        kernelTLS.ready_rng.bck_seed = kernelTLS.ready_rng.fwd_seed;
    6094                }
    6195        }
  • libcfa/src/concurrency/kernel/startup.cfa

    r67ca73e re67a82d  
    7878static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info);
    7979
     80#if defined(__CFA_WITH_VERIFY__)
     81        static bool verify_fwd_bck_rng(void);
     82#endif
     83
    8084//-----------------------------------------------------------------------------
    8185// Forward Declarations for other modules
     
    8791//-----------------------------------------------------------------------------
    8892// Other Forward Declarations
    89 extern bool __wake_proc(processor *);
     93extern void __wake_proc(processor *);
    9094
    9195//-----------------------------------------------------------------------------
     
    158162        __cfa_dbg_global_clusters.list{ __get };
    159163        __cfa_dbg_global_clusters.lock{};
     164
     165        /* paranoid */ verify( verify_fwd_bck_rng() );
    160166
    161167        // Initialize the global scheduler lock
     
    475481        #endif
    476482
    477         int target = __atomic_add_fetch( &cltr->nprocessors, 1u, __ATOMIC_SEQ_CST );
     483        lock( this.cltr->idles );
     484                int target = this.cltr->idles.total += 1u;
     485        unlock( this.cltr->idles );
    478486
    479487        id = doregister((__processor_id_t*)&this);
     
    493501// Not a ctor, it just preps the destruction but should not destroy members
    494502static void deinit(processor & this) {
    495 
    496         int target = __atomic_sub_fetch( &this.cltr->nprocessors, 1u, __ATOMIC_SEQ_CST );
     503        lock( this.cltr->idles );
     504                int target = this.cltr->idles.total -= 1u;
     505        unlock( this.cltr->idles );
    497506
    498507        // Lock the RWlock so no-one pushes/pops while we are changing the queue
     
    501510                // Adjust the ready queue size
    502511                ready_queue_shrink( this.cltr, target );
    503 
    504                 // Make sure we aren't on the idle queue
    505                 unsafe_remove( this.cltr->idles, &this );
    506512
    507513        // Unlock the RWlock
     
    516522        ( this.terminated ){ 0 };
    517523        ( this.runner ){};
    518         init( this, name, _cltr );
     524
     525        disable_interrupts();
     526                init( this, name, _cltr );
     527        enable_interrupts( __cfaabi_dbg_ctx );
    519528
    520529        __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this);
     
    540549        free( this.stack );
    541550
    542         deinit( this );
     551        disable_interrupts();
     552                deinit( this );
     553        enable_interrupts( __cfaabi_dbg_ctx );
    543554}
    544555
    545556//-----------------------------------------------------------------------------
    546557// Cluster
     558static void ?{}(__cluster_idles & this) {
     559        this.lock  = 0;
     560        this.idle  = 0;
     561        this.total = 0;
     562        (this.list){};
     563}
     564
    547565void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) with( this ) {
    548566        this.name = name;
    549567        this.preemption_rate = preemption_rate;
    550         this.nprocessors = 0;
    551568        ready_queue{};
    552569
     
    666683        return stack;
    667684}
     685
     686#if defined(__CFA_WITH_VERIFY__)
     687static bool verify_fwd_bck_rng(void) {
     688        kernelTLS.ready_rng.fwd_seed = 25214903917_l64u * (rdtscl() ^ (uintptr_t)&verify_fwd_bck_rng);
     689
     690        unsigned values[10];
     691        for(i; 10) {
     692                values[i] = __tls_rand_fwd();
     693        }
     694
     695        __tls_rand_advance_bck();
     696
     697        for ( i; 9 -~= 0 ) {
     698                if(values[i] != __tls_rand_bck()) {
     699                        return false;
     700                }
     701        }
     702
     703        return true;
     704}
     705#endif
  • libcfa/src/concurrency/kernel_private.hfa

    r67ca73e re67a82d  
    121121void     unregister( struct __processor_id_t * proc );
    122122
     123//-----------------------------------------------------------------------
     124// Cluster idle lock/unlock
     125static inline void lock(__cluster_idles & this) {
     126        for() {
     127                uint64_t l = this.lock;
     128                if(
     129                        (0 == (l % 2))
     130                        && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
     131                ) return;
     132                Pause();
     133        }
     134}
     135
     136static inline void unlock(__cluster_idles & this) {
     137        /* paranoid */ verify( 1 == (this.lock % 2) );
     138        __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
     139}
     140
    123141//=======================================================================
    124142// Reader-writer lock implementation
     
    248266// pop thread from the ready queue of a cluster
    249267// returns 0p if empty
     268// May return 0p spuriously
    250269__attribute__((hot)) struct $thread * pop(struct cluster * cltr);
     270
     271//-----------------------------------------------------------------------
     272// pop thread from the ready queue of a cluster
     273// returns 0p if empty
     274// guaranteed to find any threads added before this call
     275__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr);
    251276
    252277//-----------------------------------------------------------------------
  • libcfa/src/concurrency/ready_queue.cfa

    r67ca73e re67a82d  
    1717// #define __CFA_DEBUG_PRINT_READY_QUEUE__
    1818
     19// #define USE_SNZI
     20
    1921#include "bits/defs.hfa"
    2022#include "kernel_private.hfa"
     
    148150//  queues or removing them.
    149151uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
     152        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     153
    150154        // Step 1 : lock global lock
    151155        // It is needed to avoid processors that register mid Critical-Section
     
    162166        }
    163167
     168        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    164169        return s;
    165170}
    166171
    167172void ready_mutate_unlock( uint_fast32_t last_s ) with(*__scheduler_lock) {
     173        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
     174
    168175        // Step 1 : release local locks
    169176        // This must be done while the global lock is held to avoid
     
    180187        /*paranoid*/ assert(true == lock);
    181188        __atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE);
     189
     190        /* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
    182191}
    183192
     
    192201void ^?{}(__ready_queue_t & this) with (this) {
    193202        verify( 1 == lanes.count );
    194         verify( !query( snzi ) );
     203        #ifdef USE_SNZI
     204                verify( !query( snzi ) );
     205        #endif
    195206        free(lanes.data);
    196207}
     
    198209//-----------------------------------------------------------------------
    199210__attribute__((hot)) bool query(struct cluster * cltr) {
    200         return query(cltr->ready_queue.snzi);
     211        #ifdef USE_SNZI
     212                return query(cltr->ready_queue.snzi);
     213        #endif
     214        return true;
    201215}
    202216
     
    262276        bool lane_first = push(lanes.data[i], thrd);
    263277
    264         // If this lane used to be empty we need to do more
    265         if(lane_first) {
    266                 // Check if the entire queue used to be empty
    267                 first = !query(snzi);
    268 
    269                 // Update the snzi
    270                 arrive( snzi, i );
    271         }
     278        #ifdef USE_SNZI
     279                // If this lane used to be empty we need to do more
     280                if(lane_first) {
     281                        // Check if the entire queue used to be empty
     282                        first = !query(snzi);
     283
     284                        // Update the snzi
     285                        arrive( snzi, i );
     286                }
     287        #endif
    272288
    273289        // Unlock and return
     
    294310__attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) {
    295311        /* paranoid */ verify( lanes.count > 0 );
     312        unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    296313        #if defined(BIAS)
    297314                // Don't bother trying locally too much
     
    300317
    301318        // As long as the list is not empty, try finding a lane that isn't empty and pop from it
    302         while( query(snzi) ) {
     319        #ifdef USE_SNZI
     320                while( query(snzi) ) {
     321        #else
     322                for(25) {
     323        #endif
    303324                // Pick two lists at random
    304325                unsigned i,j;
     
    336357                #endif
    337358
    338                 i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    339                 j %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     359                i %= count;
     360                j %= count;
    340361
    341362                // try popping from the 2 picked lists
     
    353374}
    354375
     376__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
     377        /* paranoid */ verify( lanes.count > 0 );
     378        unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     379        unsigned offset = __tls_rand();
     380        for(i; count) {
     381                unsigned idx = (offset + i) % count;
     382                struct $thread * thrd = try_pop(cltr, idx);
     383                if(thrd) {
     384                        return thrd;
     385                }
     386        }
     387
     388        // All lanes where empty return 0p
     389        return 0p;
     390}
     391
     392
    355393//-----------------------------------------------------------------------
    356394// Given 2 indexes, pick the list with the oldest push an try to pop from it
     
    388426        // Actually pop the list
    389427        struct $thread * thrd;
    390         bool emptied;
    391         [thrd, emptied] = pop(lane);
     428        thrd = pop(lane);
    392429
    393430        /* paranoid */ verify(thrd);
    394431        /* paranoid */ verify(lane.lock);
    395432
    396         // If this was the last element in the lane
    397         if(emptied) {
    398                 depart( snzi, w );
    399         }
     433        #ifdef USE_SNZI
     434                // If this was the last element in the lane
     435                if(emptied) {
     436                        depart( snzi, w );
     437                }
     438        #endif
    400439
    401440        // Unlock and return
     
    424463                        if(head(lane)->link.next == thrd) {
    425464                                $thread * pthrd;
    426                                 bool emptied;
    427                                 [pthrd, emptied] = pop(lane);
     465                                pthrd = pop(lane);
    428466
    429467                                /* paranoid */ verify( pthrd == thrd );
    430468
    431469                                removed = true;
    432                                 if(emptied) {
    433                                         depart( snzi, i );
    434                                 }
     470                                #ifdef USE_SNZI
     471                                        if(emptied) {
     472                                                depart( snzi, i );
     473                                        }
     474                                #endif
    435475                        }
    436476                __atomic_unlock(&lane.lock);
     
    494534        // grow the ready queue
    495535        with( cltr->ready_queue ) {
    496                 ^(snzi){};
     536                #ifdef USE_SNZI
     537                        ^(snzi){};
     538                #endif
    497539
    498540                // Find new count
     
    516558                lanes.count = ncount;
    517559
    518                 // Re-create the snzi
    519                 snzi{ log2( lanes.count / 8 ) };
    520                 for( idx; (size_t)lanes.count ) {
    521                         if( !is_empty(lanes.data[idx]) ) {
    522                                 arrive(snzi, idx);
    523                         }
    524                 }
     560                #ifdef USE_SNZI
     561                        // Re-create the snzi
     562                        snzi{ log2( lanes.count / 8 ) };
     563                        for( idx; (size_t)lanes.count ) {
     564                                if( !is_empty(lanes.data[idx]) ) {
     565                                        arrive(snzi, idx);
     566                                }
     567                        }
     568                #endif
    525569        }
    526570
     
    542586
    543587        with( cltr->ready_queue ) {
    544                 ^(snzi){};
     588                #ifdef USE_SNZI
     589                        ^(snzi){};
     590                #endif
    545591
    546592                // Remember old count
     
    567613                        while(!is_empty(lanes.data[idx])) {
    568614                                struct $thread * thrd;
    569                                 __attribute__((unused)) bool _;
    570                                 [thrd, _] = pop(lanes.data[idx]);
     615                                thrd = pop(lanes.data[idx]);
    571616
    572617                                push(cltr, thrd);
     
    596641                }
    597642
    598                 // Re-create the snzi
    599                 snzi{ log2( lanes.count / 8 ) };
    600                 for( idx; (size_t)lanes.count ) {
    601                         if( !is_empty(lanes.data[idx]) ) {
    602                                 arrive(snzi, idx);
    603                         }
    604                 }
     643                #ifdef USE_SNZI
     644                        // Re-create the snzi
     645                        snzi{ log2( lanes.count / 8 ) };
     646                        for( idx; (size_t)lanes.count ) {
     647                                if( !is_empty(lanes.data[idx]) ) {
     648                                        arrive(snzi, idx);
     649                                }
     650                        }
     651                #endif
    605652        }
    606653
  • libcfa/src/concurrency/ready_subqueue.hfa

    r67ca73e re67a82d  
    144144// returns popped
    145145// returns true of lane was empty before push, false otherwise
    146 [$thread *, bool] pop(__intrusive_lane_t & this) {
     146$thread * pop(__intrusive_lane_t & this) {
    147147        /* paranoid */ verify(this.lock);
    148148        /* paranoid */ verify(this.before.link.ts != 0ul);
     
    162162        head->link.next = next;
    163163        next->link.prev = head;
    164         node->link.[next, prev] = 0p;
     164        node->link.next = 0p;
     165        node->link.prev = 0p;
    165166
    166167        // Update head time stamp
     
    180181                /* paranoid */ verify(tail(this)->link.prev == head(this));
    181182                /* paranoid */ verify(head(this)->link.next == tail(this));
    182                 return [node, true];
     183                return node;
    183184        }
    184185        else {
     
    187188                /* paranoid */ verify(head(this)->link.next != tail(this));
    188189                /* paranoid */ verify(this.before.link.ts != 0);
    189                 return [node, false];
     190                return node;
    190191        }
    191192}
  • libcfa/src/concurrency/stats.cfa

    r67ca73e re67a82d  
    3838                        stats->io.submit_q.busy   = 0;
    3939                        stats->io.complete_q.completed_avg.val = 0;
    40                         stats->io.complete_q.completed_avg.slow_cnt = 0;
    41                         stats->io.complete_q.completed_avg.fast_cnt = 0;
     40                        stats->io.complete_q.completed_avg.cnt = 0;
     41                        stats->io.complete_q.blocks = 0;
    4242                #endif
    4343        }
     
    6060
    6161                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    62                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.rdy          , proc->io.submit_q.submit_avg.rdy          , __ATOMIC_SEQ_CST );
    63                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.csm          , proc->io.submit_q.submit_avg.csm          , __ATOMIC_SEQ_CST );
    64                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.avl          , proc->io.submit_q.submit_avg.avl          , __ATOMIC_SEQ_CST );
    65                         __atomic_fetch_add( &cltr->io.submit_q.submit_avg.cnt          , proc->io.submit_q.submit_avg.cnt          , __ATOMIC_SEQ_CST );
    66                         __atomic_fetch_add( &cltr->io.submit_q.look_avg.val            , proc->io.submit_q.look_avg.val            , __ATOMIC_SEQ_CST );
    67                         __atomic_fetch_add( &cltr->io.submit_q.look_avg.cnt            , proc->io.submit_q.look_avg.cnt            , __ATOMIC_SEQ_CST );
    68                         __atomic_fetch_add( &cltr->io.submit_q.look_avg.block          , proc->io.submit_q.look_avg.block          , __ATOMIC_SEQ_CST );
    69                         __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.val           , proc->io.submit_q.alloc_avg.val           , __ATOMIC_SEQ_CST );
    70                         __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.cnt           , proc->io.submit_q.alloc_avg.cnt           , __ATOMIC_SEQ_CST );
    71                         __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.block         , proc->io.submit_q.alloc_avg.block         , __ATOMIC_SEQ_CST );
    72                         __atomic_fetch_add( &cltr->io.submit_q.helped                  , proc->io.submit_q.helped                  , __ATOMIC_SEQ_CST );
    73                         __atomic_fetch_add( &cltr->io.submit_q.leader                  , proc->io.submit_q.leader                  , __ATOMIC_SEQ_CST );
    74                         __atomic_fetch_add( &cltr->io.submit_q.busy                    , proc->io.submit_q.busy                    , __ATOMIC_SEQ_CST );
    75                         __atomic_fetch_add( &cltr->io.complete_q.completed_avg.val     , proc->io.complete_q.completed_avg.val     , __ATOMIC_SEQ_CST );
    76                         __atomic_fetch_add( &cltr->io.complete_q.completed_avg.slow_cnt, proc->io.complete_q.completed_avg.slow_cnt, __ATOMIC_SEQ_CST );
    77                         __atomic_fetch_add( &cltr->io.complete_q.completed_avg.fast_cnt, proc->io.complete_q.completed_avg.fast_cnt, __ATOMIC_SEQ_CST );
     62                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.rdy     , proc->io.submit_q.submit_avg.rdy     , __ATOMIC_SEQ_CST );
     63                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.csm     , proc->io.submit_q.submit_avg.csm     , __ATOMIC_SEQ_CST );
     64                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.avl     , proc->io.submit_q.submit_avg.avl     , __ATOMIC_SEQ_CST );
     65                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.cnt     , proc->io.submit_q.submit_avg.cnt     , __ATOMIC_SEQ_CST );
     66                        __atomic_fetch_add( &cltr->io.submit_q.look_avg.val       , proc->io.submit_q.look_avg.val       , __ATOMIC_SEQ_CST );
     67                        __atomic_fetch_add( &cltr->io.submit_q.look_avg.cnt       , proc->io.submit_q.look_avg.cnt       , __ATOMIC_SEQ_CST );
     68                        __atomic_fetch_add( &cltr->io.submit_q.look_avg.block     , proc->io.submit_q.look_avg.block     , __ATOMIC_SEQ_CST );
     69                        __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.val      , proc->io.submit_q.alloc_avg.val      , __ATOMIC_SEQ_CST );
     70                        __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.cnt      , proc->io.submit_q.alloc_avg.cnt      , __ATOMIC_SEQ_CST );
     71                        __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.block    , proc->io.submit_q.alloc_avg.block    , __ATOMIC_SEQ_CST );
     72                        __atomic_fetch_add( &cltr->io.submit_q.helped             , proc->io.submit_q.helped             , __ATOMIC_SEQ_CST );
     73                        __atomic_fetch_add( &cltr->io.submit_q.leader             , proc->io.submit_q.leader             , __ATOMIC_SEQ_CST );
     74                        __atomic_fetch_add( &cltr->io.submit_q.busy               , proc->io.submit_q.busy               , __ATOMIC_SEQ_CST );
     75                        __atomic_fetch_add( &cltr->io.complete_q.completed_avg.val, proc->io.complete_q.completed_avg.val, __ATOMIC_SEQ_CST );
     76                        __atomic_fetch_add( &cltr->io.complete_q.completed_avg.cnt, proc->io.complete_q.completed_avg.cnt, __ATOMIC_SEQ_CST );
     77                        __atomic_fetch_add( &cltr->io.complete_q.blocks           , proc->io.complete_q.blocks           , __ATOMIC_SEQ_CST );
    7878                #endif
    7979        }
     
    154154                                        "- avg alloc search len   : %'18.2lf\n"
    155155                                        "- avg alloc search block : %'18.2lf\n"
    156                                         "- total wait calls       : %'15" PRIu64 "   (%'" PRIu64 " slow, %'" PRIu64 " fast)\n"
     156                                        "- total wait calls       : %'15" PRIu64 "\n"
    157157                                        "- avg completion/wait    : %'18.2lf\n"
     158                                        "- total completion blocks: %'15" PRIu64 "\n"
    158159                                        "\n"
    159160                                        , cluster ? "Cluster" : "Processor",  name, id
     
    165166                                        , io.submit_q.alloc_avg.cnt
    166167                                        , aavgv, aavgb
    167                                         , io.complete_q.completed_avg.slow_cnt + io.complete_q.completed_avg.fast_cnt
    168                                         , io.complete_q.completed_avg.slow_cnt,  io.complete_q.completed_avg.fast_cnt
    169                                         , ((double)io.complete_q.completed_avg.val) / (io.complete_q.completed_avg.slow_cnt + io.complete_q.completed_avg.fast_cnt)
     168                                        , io.complete_q.completed_avg.cnt
     169                                        , ((double)io.complete_q.completed_avg.val) / io.complete_q.completed_avg.cnt
     170                                        , io.complete_q.blocks
    170171                                );
    171172                        }
  • libcfa/src/concurrency/stats.hfa

    r67ca73e re67a82d  
    9090                                struct {
    9191                                        volatile uint64_t val;
    92                                         volatile uint64_t slow_cnt;
    93                                         volatile uint64_t fast_cnt;
     92                                        volatile uint64_t cnt;
    9493                                } completed_avg;
     94                                volatile uint64_t blocks;
    9595                        } complete_q;
    9696                };
  • libcfa/src/containers/list.hfa

    r67ca73e re67a82d  
    1313// Update Count     : 1
    1414//
     15
     16#pragma once
    1517
    1618#include <assert.h>
  • libcfa/src/exception.c

    r67ca73e re67a82d  
    1010// Created On       : Mon Jun 26 15:13:00 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Aug 15 07:17:19 2020
    13 // Update Count     : 26
     12// Last Modified On : Thu Aug 20 23:45:45 2020
     13// Update Count     : 27
    1414//
    1515
     
    3131#include <unwind.h>
    3232#include <bits/debug.hfa>
     33#include "concurrency/invoke.h"
    3334#include "stdhdr/assert.h"
    3435
     
    6162
    6263
    63 // Temperary global exception context. Does not work with concurency.
    64 struct exception_context_t {
    65         struct __cfaehm_try_resume_node * top_resume;
    66 
    67         exception_t * current_exception;
    68         int current_handler_index;
    69 } static shared_stack = {NULL, NULL, 0};
    70 
    7164// Get the current exception context.
    7265// There can be a single global until multithreading occurs, then each stack
    73 // needs its own. It will have to be updated to handle that.
    74 struct exception_context_t * this_exception_context() {
     66// needs its own. We get this from libcfathreads (no weak attribute).
     67__attribute__((weak)) struct exception_context_t * this_exception_context() {
     68        static struct exception_context_t shared_stack = {NULL, NULL};
    7569        return &shared_stack;
    7670}
     
    125119
    126120// MEMORY MANAGEMENT =========================================================
     121
     122struct __cfaehm_node {
     123        struct _Unwind_Exception unwind_exception;
     124        struct __cfaehm_node * next;
     125        int handler_index;
     126};
     127
     128#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
     129#define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
     130#define UNWIND_TO_NODE(unwind) ((struct __cfaehm_node *)(unwind))
     131#define NULL_MAP(map, ptr) ((ptr) ? (map(ptr)) : NULL)
    127132
    128133// How to clean up an exception in various situations.
     
    140145}
    141146
    142 // We need a piece of storage to raise the exception, for now its a single
    143 // piece.
    144 static struct _Unwind_Exception this_exception_storage;
    145 
    146 struct __cfaehm_node {
    147         struct __cfaehm_node * next;
    148 };
    149 
    150 #define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
    151 #define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
    152 
    153147// Creates a copy of the indicated exception and sets current_exception to it.
    154148static void __cfaehm_allocate_exception( exception_t * except ) {
     
    164158        }
    165159
     160        // Initialize the node:
     161        exception_t * except_store = NODE_TO_EXCEPT(store);
     162        store->unwind_exception.exception_class = __cfaehm_exception_class;
     163        store->unwind_exception.exception_cleanup = __cfaehm_exception_cleanup;
     164        store->handler_index = 0;
     165        except->virtual_table->copy( except_store, except );
     166
    166167        // Add the node to the list:
    167         store->next = EXCEPT_TO_NODE(context->current_exception);
    168         context->current_exception = NODE_TO_EXCEPT(store);
    169 
    170         // Copy the exception to storage.
    171         except->virtual_table->copy( context->current_exception, except );
    172 
    173         // Set up the exception storage.
    174         this_exception_storage.exception_class = __cfaehm_exception_class;
    175         this_exception_storage.exception_cleanup = __cfaehm_exception_cleanup;
     168        store->next = NULL_MAP(EXCEPT_TO_NODE, context->current_exception);
     169        context->current_exception = except_store;
    176170}
    177171
     
    188182        if ( context->current_exception == except ) {
    189183                node = to_free->next;
    190                 context->current_exception = (node) ? NODE_TO_EXCEPT(node) : 0;
     184                context->current_exception = NULL_MAP(NODE_TO_EXCEPT, node);
    191185        } else {
    192186                node = EXCEPT_TO_NODE(context->current_exception);
     
    216210        // Verify actions follow the rules we expect.
    217211        verify((actions & _UA_CLEANUP_PHASE) && (actions & _UA_FORCE_UNWIND));
    218         verify(!(actions & (_UA_SEARCH_PHASE | _UA_HANDER_FRAME)));
     212        verify(!(actions & (_UA_SEARCH_PHASE | _UA_HANDLER_FRAME)));
    219213
    220214        if ( actions & _UA_END_OF_STACK ) {
     
    225219}
    226220
     221static struct _Unwind_Exception cancel_exception_storage;
     222
    227223// Cancel the current stack, prefroming approprate clean-up and messaging.
    228224void __cfaehm_cancel_stack( exception_t * exception ) {
    229225        // TODO: Detect current stack and pick a particular stop-function.
    230226        _Unwind_Reason_Code ret;
    231         ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
     227        ret = _Unwind_ForcedUnwind( &cancel_exception_storage, _Stop_Fn, (void*)0x22 );
    232228        printf("UNWIND ERROR %d after force unwind\n", ret);
    233229        abort();
     
    250246static void __cfaehm_begin_unwind(void(*defaultHandler)(exception_t *)) {
    251247        struct exception_context_t * context = this_exception_context();
    252         struct _Unwind_Exception * storage = &this_exception_storage;
    253248        if ( NULL == context->current_exception ) {
    254249                printf("UNWIND ERROR missing exception in begin unwind\n");
    255250                abort();
    256251        }
     252        struct _Unwind_Exception * storage =
     253                &EXCEPT_TO_NODE(context->current_exception)->unwind_exception;
    257254
    258255        // Call stdlibc to raise the exception
     
    426423                                _Unwind_Reason_Code ret = (0 == index)
    427424                                        ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
    428                                 context->current_handler_index = index;
     425                                UNWIND_TO_NODE(unwind_exception)->handler_index = index;
    429426
    430427                                // Based on the return value, check if we matched the exception
     
    432429                                        __cfadbg_print_safe(exception, " handler found\n");
    433430                                } else {
     431                                        // TODO: Continue the search if there is more in the table.
    434432                                        __cfadbg_print_safe(exception, " no handler\n");
    435433                                }
     
    523521        // Exception handler
    524522        // Note: Saving the exception context on the stack breaks termination exceptions.
    525         catch_block( this_exception_context()->current_handler_index,
     523        catch_block( EXCEPT_TO_NODE( this_exception_context()->current_exception )->handler_index,
    526524                     this_exception_context()->current_exception );
    527525}
  • libcfa/src/heap.cfa

    r67ca73e re67a82d  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Aug  9 12:23:20 2020
    13 // Update Count     : 894
     12// Last Modified On : Wed Aug 12 16:43:38 2020
     13// Update Count     : 902
    1414//
    1515
     
    650650                for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
    651651                #else
    652                 for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
     652                // for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
     653                for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
     654                        typeof(p) temp = (( p )`next)->top;                     // FIX ME: direct assignent fails, initialization works
     655                        p = temp;
    653656                #endif // BUCKETLOCK
    654657                        total += size;
     
    11621165                choose( option ) {
    11631166                  case M_TOP_PAD:
    1164                         heapExpand = ceiling( value, pageSize ); return 1;
     1167                        heapExpand = ceiling2( value, pageSize ); return 1;
    11651168                  case M_MMAP_THRESHOLD:
    11661169                        if ( setMmapStart( value ) ) return 1;
  • libcfa/src/iostream.cfa

    r67ca73e re67a82d  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Aug 10 09:32:14 2020
    13 // Update Count     : 1126
     12// Last Modified On : Tue Aug 11 22:16:33 2020
     13// Update Count     : 1128
    1414//
    1515
     
    3737
    3838forall( dtype ostype | ostream( ostype ) ) {
    39         ostype & ?|?( ostype & os, zero_t ) {
    40                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    41                 fmt( os, "%d", 0n );
    42                 return os;
    43         } // ?|?
    44         void ?|?( ostype & os, zero_t z ) {
    45                 (ostype &)(os | z); ends( os );
    46         } // ?|?
    47 
    48         ostype & ?|?( ostype & os, one_t ) {
    49                 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    50                 fmt( os, "%d", 1n );
    51                 return os;
    52         } // ?|?
    53         void ?|?( ostype & os, one_t o ) {
    54                 (ostype &)(os | o); ends( os );
    55         } // ?|?
    56 
    5739        ostype & ?|?( ostype & os, bool b ) {
    5840                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
  • libcfa/src/iostream.hfa

    r67ca73e re67a82d  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 16 07:43:32 2020
    13 // Update Count     : 348
     12// Last Modified On : Tue Aug 11 22:16:14 2020
     13// Update Count     : 350
    1414//
    1515
     
    6767
    6868forall( dtype ostype | ostream( ostype ) ) {
    69         ostype & ?|?( ostype &, zero_t );
    70         void ?|?( ostype &, zero_t );
    71         ostype & ?|?( ostype &, one_t );
    72         void ?|?( ostype &, one_t );
    73 
    7469        ostype & ?|?( ostype &, bool );
    7570        void ?|?( ostype &, bool );
  • libcfa/src/parseargs.cfa

    r67ca73e re67a82d  
    11#include "parseargs.hfa"
    22
    3 // #include <stdio.h>
    4 // #include <stdlib.h>
     3#include <stdint.h>
     4#include <string.h>
    55#include <errno.h>
    6 #include <string.h>
    76#include <unistd.h>
    87extern "C" {
     
    2019        extern          long long int strtoll (const char* str, char** endptr, int base);
    2120        extern unsigned long long int strtoull(const char* str, char** endptr, int base);
    22 }
    23 
    24 #include <common.hfa>
    25 #include <limits.hfa>
    26 
    27 void printopt(FILE * out, int width, int max, char sn, const char * ln, const char * help) {
    28         int hwidth = max - (11 + width);
    29         if(hwidth <= 0) hwidth = max;
    30 
    31         fprintf(out, "  -%c, --%-*s   %.*s\n", sn, width, ln, hwidth, help);
    32         for() {
    33                 help += min(strlen(help), hwidth);
    34                 if('\0' == *help) break;
    35                 fprintf(out, "%*s%.*s\n", width + 11, "", hwidth, help);
    36         }
    37 }
    38 
     21        extern                 double strtod  (const char* str, char** endptr);
     22}
     23
     24#include "common.hfa"
     25#include "limits.hfa"
     26
     27extern int cfa_args_argc;
     28extern char ** cfa_args_argv;
     29extern char ** cfa_args_envp;
     30
     31static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * usage, FILE * out)  __attribute__ ((noreturn));
     32
     33void parse_args( cfa_option options[], size_t opt_count, const char * usage, char ** & left ) {
     34        parse_args(cfa_args_argc, cfa_args_argv, options, opt_count, usage, left );
     35}
     36
     37//-----------------------------------------------------------------------------
     38// getopt_long wrapping
    3939void parse_args(
    4040        int argc,
     
    4646) {
    4747        struct option optarr[opt_count + 2];
    48         int width = 0;
    49         int max_width = 1_000_000;
    5048        {
    5149                int idx = 0;
     
    6260                                }
    6361                                idx++;
    64 
    65                                 int w = strlen(options[i].long_name);
    66                                 if(w > width) width = w;
    6762                        }
    6863                }
    69                 optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0p, 'h'];
    70                 optarr[idx+1].[name, has_arg, flag, val] = [0p, no_argument, 0p, 0];
     64                optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0, 'h'];
     65                optarr[idx+1].[name, has_arg, flag, val] = [0, no_argument, 0, 0];
    7166        }
    7267
     
    9994                                out = stdout;
    10095                        case '?':
    101                                 goto USAGE;
     96                                usage(argv[0], options, opt_count, usage, out);
    10297                        default:
    10398                                for(i; opt_count) {
     
    108103
    109104                                                fprintf(out, "Argument '%s' for option %c could not be parsed\n\n", arg, (char)opt);
    110                                                 goto USAGE;
     105                                                usage(argv[0], options, opt_count, usage, out);
    111106                                        }
    112107                                }
     
    115110
    116111        }
    117 
    118         USAGE:;
     112}
     113
     114//-----------------------------------------------------------------------------
     115// Print usage
     116static void printopt(FILE * out, int width, int max, char sn, const char * ln, const char * help) {
     117        int hwidth = max - (11 + width);
     118        if(hwidth <= 0) hwidth = max;
     119
     120        fprintf(out, "  -%c, --%-*s   %.*s\n", sn, width, ln, hwidth, help);
     121        for() {
     122                help += min(strlen(help), hwidth);
     123                if('\0' == *help) break;
     124                fprintf(out, "%*s%.*s\n", width + 11, "", hwidth, help);
     125        }
     126}
     127
     128void print_args_usage(cfa_option options[], size_t opt_count, const char * usage, bool error)  __attribute__ ((noreturn)) {
     129        usage(cfa_args_argv[0], options, opt_count, usage, error ? stderr : stdout);
     130}
     131
     132void print_args_usage(int , char * argv[], cfa_option options[], size_t opt_count, const char * usage, bool error)  __attribute__ ((noreturn)) {
     133        usage(argv[0], options, opt_count, usage, error ? stderr : stdout);
     134}
     135
     136static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * help, FILE * out) __attribute__((noreturn)) {
     137        int width = 0;
     138        {
     139                for(i; opt_count) {
     140                        if(options[i].long_name) {
     141                                int w = strlen(options[i].long_name);
     142                                if(w > width) width = w;
     143                        }
     144                }
     145        }
     146
     147        int max_width = 1_000_000;
    119148        int outfd = fileno(out);
    120149        if(isatty(outfd)) {
     
    125154        }
    126155
    127         fprintf(out, "Usage:\n  %s %s\n", argv[0], usage);
     156        fprintf(out, "Usage:\n  %s %s\n", cmd, help);
    128157
    129158        for(i; opt_count) {
     
    134163}
    135164
     165//-----------------------------------------------------------------------------
     166// Typed argument parsing
    136167bool parse_yesno(const char * arg, bool & value ) {
    137168        if(strcmp(arg, "yes") == 0) {
     
    163194}
    164195
     196bool parse(const char * arg, int & value) {
     197        char * end;
     198        int r = strtoll(arg, &end, 10);
     199        if(*end != '\0') return false;
     200
     201        value = r;
     202        return true;
     203}
     204
    165205bool parse(const char * arg, unsigned & value) {
    166206        char * end;
     
    173213}
    174214
    175 bool parse(const char * arg, size_t & value) {
     215bool parse(const char * arg, unsigned long & value) {
    176216        char * end;
    177217        unsigned long long int r = strtoull(arg, &end, 10);
    178218        if(*end != '\0') return false;
    179         if(r > (size_t)MAX) return false;
    180 
    181         value = r;
    182         return true;
    183 }
    184 
    185 bool parse(const char * arg, int & value) {
    186         char * end;
    187         int r = strtoll(arg, &end, 10);
    188         if(*end != '\0') return false;
    189 
    190         value = r;
    191         return true;
    192 }
     219        if(r > (unsigned long)MAX) return false;
     220
     221        value = r;
     222        return true;
     223}
     224
     225bool parse(const char * arg, unsigned long long & value) {
     226        char * end;
     227        unsigned long long int r = strtoull(arg, &end, 10);
     228        if(*end != '\0') return false;
     229        if(r > (unsigned long long)MAX) return false;
     230
     231        value = r;
     232        return true;
     233}
     234
     235bool parse(const char * arg, double & value) {
     236        char * end;
     237        double r = strtod(arg, &end);
     238        if(*end != '\0') return false;
     239
     240        value = r;
     241        return true;
     242}
  • libcfa/src/parseargs.hfa

    r67ca73e re67a82d  
    3131}
    3232
     33void parse_args( cfa_option options[], size_t opt_count, const char * usage, char ** & left );
    3334void parse_args( int argc, char * argv[], cfa_option options[], size_t opt_count, const char * usage, char ** & left );
     35
     36void print_args_usage(cfa_option options[], size_t opt_count, const char * usage, bool error)  __attribute__ ((noreturn));
     37void print_args_usage(int argc, char * argv[], cfa_option options[], size_t opt_count, const char * usage, bool error)  __attribute__ ((noreturn));
    3438
    3539bool parse_yesno   (const char *, bool & );
     
    3842
    3943bool parse(const char *, const char * & );
     44bool parse(const char *, int & );
    4045bool parse(const char *, unsigned & );
    41 bool parse(const char *, size_t & );
    42 bool parse(const char *, int & );
     46bool parse(const char *, unsigned long & );
     47bool parse(const char *, unsigned long long & );
     48bool parse(const char *, double & );
  • libcfa/src/stdlib.hfa

    r67ca73e re67a82d  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Jul 30 16:14:58 2020
    13 // Update Count     : 490
     12// Last Modified On : Fri Aug 14 23:38:50 2020
     13// Update Count     : 504
    1414//
    1515
     
    3939//---------------------------------------
    4040
     41#include "common.hfa"
     42
     43//---------------------------------------
     44
    4145// Macro because of returns
    4246#define $VAR_ALLOC( allocation, alignment ) \
     
    136140        T * alloc_set( char fill ) {
    137141                return (T *)memset( (T *)alloc(), (int)fill, sizeof(T) ); // initialize with fill value
    138         } // alloc
    139 
    140         T * alloc_set( T fill ) {
     142        } // alloc_set
     143
     144        T * alloc_set( const T & fill ) {
    141145                return (T *)memcpy( (T *)alloc(), &fill, sizeof(T) ); // initialize with fill value
    142         } // alloc
     146        } // alloc_set
    143147
    144148        T * alloc_set( size_t dim, char fill ) {
    145149                return (T *)memset( (T *)alloc( dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value
    146         } // alloc
    147 
    148         T * alloc_set( size_t dim, T fill ) {
     150        } // alloc_set
     151
     152        T * alloc_set( size_t dim, const T & fill ) {
    149153                T * r = (T *)alloc( dim );
    150154                for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value
    151155                return r;
    152         } // alloc
    153 
    154         T * alloc_set( size_t dim, const T fill[] ) {
    155                 return (T *)memcpy( (T *)alloc( dim ), fill, dim * sizeof(T) ); // initialize with fill value
    156         } // alloc
     156        } // alloc_set
     157
     158        T * alloc_set( size_t dimNew, const T fill[], size_t dimOld ) {
     159                return (T *)memcpy( (T *)alloc( dimNew ), fill, min( dimNew, dimOld ) * sizeof(T) ); // initialize with fill value
     160        } // alloc_set
    157161
    158162        T * alloc_set( T ptr[], size_t dim, char fill ) {       // realloc array with fill
     
    166170        } // alloc_set
    167171
    168         T * alloc_set( T ptr[], size_t dim, T & fill ) {        // realloc array with fill
     172        T * alloc_set( T ptr[], size_t dim, const T & fill ) {  // realloc array with fill
    169173                size_t odim = malloc_size( ptr ) / sizeof(T);   // current dimension
    170174                size_t nsize = dim * sizeof(T);                                 // new allocation
     
    177181                } // if
    178182                return nptr;
    179         } // alloc_align_set
     183        } // alloc_set
    180184} // distribution
    181185
     
    204208        T * alloc_align_set( size_t align, char fill ) {
    205209                return (T *)memset( (T *)alloc_align( align ), (int)fill, sizeof(T) ); // initialize with fill value
    206         } // alloc_align
    207 
    208         T * alloc_align_set( size_t align, T fill ) {
     210        } // alloc_align_set
     211
     212        T * alloc_align_set( size_t align, const T & fill ) {
    209213                return (T *)memcpy( (T *)alloc_align( align ), &fill, sizeof(T) ); // initialize with fill value
    210         } // alloc_align
     214        } // alloc_align_set
    211215
    212216        T * alloc_align_set( size_t align, size_t dim, char fill ) {
    213217                return (T *)memset( (T *)alloc_align( align, dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value
    214         } // alloc_align
    215 
    216         T * alloc_align_set( size_t align, size_t dim, T fill ) {
     218        } // alloc_align_set
     219
     220        T * alloc_align_set( size_t align, size_t dim, const T & fill ) {
    217221                T * r = (T *)alloc_align( align, dim );
    218222                for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value
    219223                return r;
    220         } // alloc_align
    221 
    222         T * alloc_align_set( size_t align, size_t dim, const T fill[] ) {
    223                 return (T *)memcpy( (T *)alloc_align( align, dim ), fill, dim * sizeof(T) );
    224         } // alloc_align
     224        } // alloc_align_set
     225
     226        T * alloc_align_set( size_t align, size_t dimNew, const T fill[], size_t dimOld ) {
     227                return (T *)memcpy( (T *)alloc_align( align, dimNew ), fill, min( dimNew, dimOld ) * sizeof(T) );
     228        } // alloc_align_set
    225229
    226230        T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ) {
     
    234238        } // alloc_align_set
    235239
    236         T * alloc_align_set( T ptr[], size_t align, size_t dim, T & fill ) {
     240        T * alloc_align_set( T ptr[], size_t align, size_t dim, const T & fill ) {
    237241                size_t odim = malloc_size( ptr ) / sizeof(T);   // current dimension
    238242                size_t nsize = dim * sizeof(T);                                 // new allocation
     
    374378//---------------------------------------
    375379
    376 #include "common.hfa"
    377 
    378 //---------------------------------------
    379 
    380380extern bool threading_enabled(void) OPTIONAL_THREAD;
    381381
  • src/AST/Attribute.hpp

    r67ca73e re67a82d  
    5151        template<typename node_t>
    5252        friend node_t * mutate(const node_t * node);
     53        template<typename node_t>
     54    friend node_t * shallowCopy(const node_t * node);
    5355};
    5456
  • src/AST/CVQualifiers.hpp

    r67ca73e re67a82d  
    2727                Restrict = 1 << 1,
    2828                Volatile = 1 << 2,
    29                 Lvalue   = 1 << 3,
    30                 Mutex    = 1 << 4,
    31                 Atomic   = 1 << 5,
    32                 NumQualifiers = 6
     29                Mutex    = 1 << 3,
     30                Atomic   = 1 << 4,
     31                NumQualifiers = 5
    3332        };
    3433
    3534        /// Mask for equivalence-preserving qualfiers
    36         enum { EquivQualifiers = ~(Restrict | Lvalue) };
     35        enum { EquivQualifiers = ~Restrict };
    3736
    3837        /// Underlying data for qualifiers
     
    4443                                bool is_restrict : 1;
    4544                                bool is_volatile : 1;
    46                                 bool is_lvalue   : 1;
    4745                                bool is_mutex    : 1;
    4846                                bool is_atomic   : 1;
  • src/AST/Convert.cpp

    r67ca73e re67a82d  
    2020
    2121#include "AST/Attribute.hpp"
     22#include "AST/Copy.hpp"
    2223#include "AST/Decl.hpp"
    2324#include "AST/Expr.hpp"
     
    166167                        LinkageSpec::Spec( node->linkage.val ),
    167168                        bfwd,
    168                         type,
     169                        type->clone(),
    169170                        init,
    170171                        attr,
     
    587588                assert( tgtResnSlots.empty() );
    588589
    589                 if ( srcInferred.mode == ast::Expr::InferUnion::Params ) {
     590                if ( srcInferred.data.inferParams ) {
    590591                        const ast::InferredParams &srcParams = srcInferred.inferParams();
    591592                        for (auto & srcParam : srcParams) {
     
    593594                                        srcParam.second.decl,
    594595                                        get<Declaration>().accept1(srcParam.second.declptr),
    595                                         get<Type>().accept1(srcParam.second.actualType),
    596                                         get<Type>().accept1(srcParam.second.formalType),
    597                                         get<Expression>().accept1(srcParam.second.expr)
     596                                        get<Type>().accept1(srcParam.second.actualType)->clone(),
     597                                        get<Type>().accept1(srcParam.second.formalType)->clone(),
     598                                        get<Expression>().accept1(srcParam.second.expr)->clone()
    598599                                ));
    599600                                assert(res.second);
    600601                        }
    601                 } else if ( srcInferred.mode == ast::Expr::InferUnion::Slots  ) {
     602                }
     603                if ( srcInferred.data.resnSlots ) {
    602604                        const ast::ResnSlots &srcSlots = srcInferred.resnSlots();
    603605                        for (auto srcSlot : srcSlots) {
     
    620622
    621623                tgt->result = get<Type>().accept1(src->result);
     624                // Unconditionally use a clone of the result type.
     625                // We know this will leak some objects: much of the immediate conversion result.
     626                // In some cases, using the conversion result directly gives unintended object sharing.
     627                // A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache.
     628                // But tgt->result must be fully owned privately by tgt.
     629                // Applying these conservative copies here means
     630                // - weak references point at the declaration's copy, not these expr.result copies (good)
     631                // - we copy more objects than really needed (bad, tolerated)
     632                if (tgt->result) {
     633                        tgt->result = tgt->result->clone();
     634                }
    622635                return visitBaseExpr_skipResultType(src, tgt);
    623636        }
     
    979992
    980993        const ast::Expr * visit( const ast::StmtExpr * node ) override final {
     994                auto stmts = node->stmts;
     995                // disable sharing between multiple StmtExprs explicitly.
     996                if (inCache(stmts)) {
     997                        stmts = ast::deepCopy(stmts.get());
     998                }
    981999                auto rslt = new StmtExpr(
    982                         get<CompoundStmt>().accept1(node->stmts)
     1000                        get<CompoundStmt>().accept1(stmts)
    9831001                );
    9841002
     
    19862004
    19872005                assert( oldInferParams.empty() || oldResnSlots.empty() );
    1988                 assert( newInferred.mode == ast::Expr::InferUnion::Empty );
     2006                // assert( newInferred.mode == ast::Expr::InferUnion::Empty );
    19892007
    19902008                if ( !oldInferParams.empty() ) {
     
    21172135                                old->location,
    21182136                                GET_ACCEPT_1(member, DeclWithType),
    2119                                 GET_ACCEPT_1(aggregate, Expr)
     2137                                GET_ACCEPT_1(aggregate, Expr),
     2138                                ast::MemberExpr::NoOpConstructionChosen
    21202139                        )
    21212140                );
  • src/AST/Decl.cpp

    r67ca73e re67a82d  
    5050
    5151const Type * FunctionDecl::get_type() const { return type.get(); }
    52 void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); }
     52void FunctionDecl::set_type( const Type * t ) {
     53        type = strict_dynamic_cast< const FunctionType * >( t );
     54}
    5355
    5456// --- TypeDecl
  • src/AST/Decl.hpp

    r67ca73e re67a82d  
    3333
    3434// Must be included in *all* AST classes; should be #undef'd at the end of the file
    35 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     35#define MUTATE_FRIEND \
     36    template<typename node_t> friend node_t * mutate(const node_t * node); \
     37        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3638
    3739namespace ast {
     
    8890        virtual const Type * get_type() const = 0;
    8991        /// Set type of this declaration. May be verified by subclass
    90         virtual void set_type(Type *) = 0;
     92        virtual void set_type( const Type * ) = 0;
    9193
    9294        const DeclWithType * accept( Visitor & v ) const override = 0;
     
    111113
    112114        const Type* get_type() const override { return type; }
    113         void set_type( Type * ty ) override { type = ty; }
     115        void set_type( const Type * ty ) override { type = ty; }
    114116
    115117        const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
     
    133135
    134136        const Type * get_type() const override;
    135         void set_type(Type * t) override;
     137        void set_type( const Type * t ) override;
    136138
    137139        bool has_body() const { return stmts; }
     
    150152        std::vector<ptr<DeclWithType>> assertions;
    151153
    152         NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
    153                 Type* b, Linkage::Spec spec = Linkage::Cforall )
     154        NamedTypeDecl(
     155                const CodeLocation & loc, const std::string & name, Storage::Classes storage,
     156                const Type * b, Linkage::Spec spec = Linkage::Cforall )
    154157        : Decl( loc, name, storage, spec ), base( b ), params(), assertions() {}
    155158
     
    186189        };
    187190
    188         TypeDecl( const CodeLocation & loc, const std::string & name, Storage::Classes storage, Type * b,
    189                           Kind k, bool s, Type * i = nullptr )
    190                 : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == Ttype || s ),
    191                 init( i ) {}
     191        TypeDecl(
     192                const CodeLocation & loc, const std::string & name, Storage::Classes storage,
     193                const Type * b, TypeDecl::Kind k, bool s, const Type * i = nullptr )
     194        : NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeDecl::Ttype || s ),
     195          init( i ) {}
    192196
    193197        const char * typeString() const override;
  • src/AST/Expr.cpp

    r67ca73e re67a82d  
    2020#include <vector>
    2121
     22#include "Copy.hpp"                // for shallowCopy
     23#include "Eval.hpp"                // for call
    2224#include "GenericSubstitution.hpp"
     25#include "LinkageSpec.hpp"
    2326#include "Stmt.hpp"
    2427#include "Type.hpp"
     
    2730#include "Common/SemanticError.h"
    2831#include "GenPoly/Lvalue.h"        // for referencesPermissable
    29 #include "InitTweak/InitTweak.h"   // for getPointerBase
     32#include "InitTweak/InitTweak.h"   // for getFunction, getPointerBase
    3033#include "ResolvExpr/typeops.h"    // for extractResultType
    3134#include "Tuples/Tuples.h"         // for makeTupleType
    3235
    3336namespace ast {
     37
     38namespace {
     39        std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"};
     40}
     41
     42// --- Expr
     43bool Expr::get_lvalue() const {
     44        return false;
     45}
    3446
    3547// --- ApplicationExpr
     
    4658}
    4759
     60bool ApplicationExpr::get_lvalue() const {
     61        if ( const DeclWithType * func = InitTweak::getFunction( this ) ) {
     62                return func->linkage == Linkage::Intrinsic && lvalueFunctionNames.count( func->name );
     63        }
     64        return false;
     65}
     66
    4867// --- UntypedExpr
    4968
     
    5170        assert( arg );
    5271
    53         UntypedExpr * ret = new UntypedExpr{
    54                 loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } }
    55         };
     72        UntypedExpr * ret = call( loc, "*?", arg );
    5673        if ( const Type * ty = arg->result ) {
    5774                const Type * base = InitTweak::getPointerBase( ty );
     
    6582                        // base type
    6683                        ret->result = base;
    67                         add_qualifiers( ret->result, CV::Lvalue );
    6884                }
    6985        }
    7086        return ret;
     87}
     88
     89bool UntypedExpr::get_lvalue() const {
     90        std::string fname = InitTweak::getFunctionName( this );
     91        return lvalueFunctionNames.count( fname );
    7192}
    7293
     
    7495        assert( lhs && rhs );
    7596
    76         UntypedExpr * ret = new UntypedExpr{
    77                 loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } }
    78         };
     97        UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
    7998        if ( lhs->result && rhs->result ) {
    8099                // if both expressions are typed, assumes that this assignment is a C bitwise assignment,
     
    108127AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) {
    109128        if ( arg->result ) {
    110                 if ( arg->result->is_lvalue() ) {
     129                if ( arg->get_lvalue() ) {
    111130                        // lvalue, retains all levels of reference, and gains a pointer inside the references
    112131                        Type * res = addrType( arg->result );
    113                         res->set_lvalue( false ); // result of & is never an lvalue
    114132                        result = res;
    115133                } else {
     
    118136                                        dynamic_cast< const ReferenceType * >( arg->result.get() ) ) {
    119137                                Type * res = addrType( refType->base );
    120                                 res->set_lvalue( false ); // result of & is never an lvalue
    121138                                result = res;
    122139                        } else {
     
    139156: Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}
    140157
     158bool CastExpr::get_lvalue() const {
     159        // This is actually wrong by C, but it works with our current set-up.
     160        return arg->get_lvalue();
     161}
     162
    141163// --- KeywordCastExpr
    142164
    143165const char * KeywordCastExpr::targetString() const {
    144166        return AggregateDecl::aggrString( target );
     167}
     168
     169// --- UntypedMemberExpr
     170
     171bool UntypedMemberExpr::get_lvalue() const {
     172        return aggregate->get_lvalue();
    145173}
    146174
     
    153181        assert( aggregate->result );
    154182
    155         // take ownership of member type
    156         result = mem->get_type();
     183        // Deep copy on result type avoids mutation on transitively multiply referenced object.
     184        //
     185        // Example, adapted from parts of builtins and bootloader:
     186        //
     187        // forall(dtype T)
     188        // struct __Destructor {
     189        //   T * object;
     190        //   void (*dtor)(T *);
     191        // };
     192        //
     193        // forall(dtype S)
     194        // void foo(__Destructor(S) &d) {
     195        //   if (d.dtor) {  // here
     196        //   }
     197        // }
     198        //
     199        // Let e be the "d.dtor" guard espression, which is MemberExpr after resolve.  Let d be the
     200        // declaration of member __Destructor.dtor (an ObjectDecl), as accessed via the top-level
     201        // declaration of __Destructor.  Consider the types e.result and d.type.  In the old AST, one
     202        // is a clone of the other.  Ordinary new-AST use would set them up as a multiply-referenced
     203        // object.
     204        //
     205        // e.result: PointerType
     206        // .base: FunctionType
     207        // .params.front(): ObjectDecl, the anonymous parameter of type T*
     208        // .type: PointerType
     209        // .base: TypeInstType
     210        // let x = that
     211        // let y = similar, except start from d.type
     212        //
     213        // Consider two code lines down, genericSubstitution(...).apply(result).
     214        //
     215        // Applying this chosen-candidate's type substitution means modifying x, substituting
     216        // S for T.  This mutation should affect x and not y.
     217
     218        result = deepCopy(mem->get_type());
     219
    157220        // substitute aggregate generic parameters into member type
    158221        genericSubstitution( aggregate->result ).apply( result );
    159         // ensure lvalue and appropriate restrictions from aggregate type
    160         add_qualifiers( result, aggregate->result->qualifiers | CV::Lvalue );
     222        // ensure appropriate restrictions from aggregate type
     223        add_qualifiers( result, aggregate->result->qualifiers );
     224}
     225
     226MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
     227    MemberExpr::NoOpConstruction overloadSelector )
     228: Expr( loc ), member( mem ), aggregate( agg ) {
     229        assert( member );
     230        assert( aggregate );
     231        assert( aggregate->result );
     232        (void) overloadSelector;
     233}
     234
     235bool MemberExpr::get_lvalue() const {
     236        // This is actually wrong by C, but it works with our current set-up.
     237        return true;
    161238}
    162239
     
    170247        assert( var );
    171248        assert( var->get_type() );
    172         result = var->get_type();
    173         add_qualifiers( result, CV::Lvalue );
     249        result = shallowCopy( var->get_type() );
     250}
     251
     252bool VariableExpr::get_lvalue() const {
     253        // It isn't always an lvalue, but it is never an rvalue.
     254        return true;
    174255}
    175256
     
    258339: Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
    259340
     341// --- CommaExpr
     342bool CommaExpr::get_lvalue() const {
     343        // This is wrong by C, but the current implementation uses it.
     344        // (ex: Specialize, Lvalue and Box)
     345        return arg2->get_lvalue();
     346}
     347
    260348// --- ConstructorExpr
    261349
     
    276364        assert( t && i );
    277365        result = t;
    278         add_qualifiers( result, CV::Lvalue );
     366}
     367
     368bool CompoundLiteralExpr::get_lvalue() const {
     369        return true;
    279370}
    280371
     
    293384        // like MemberExpr, TupleIndexExpr is always an lvalue
    294385        result = type->types[ index ];
    295         add_qualifiers( result, CV::Lvalue );
     386}
     387
     388bool TupleIndexExpr::get_lvalue() const {
     389        return tuple->get_lvalue();
    296390}
    297391
  • src/AST/Expr.hpp

    r67ca73e re67a82d  
    3131
    3232// Must be included in *all* AST classes; should be #undef'd at the end of the file
    33 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     33#define MUTATE_FRIEND \
     34    template<typename node_t> friend node_t * mutate(const node_t * node); \
     35        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
     36
    3437
    3538class ConverterOldToNew;
     
    4245struct ParamEntry {
    4346        UniqueId decl;
    44         ptr<Decl> declptr;
     47        readonly<Decl> declptr;
    4548        ptr<Type> actualType;
    4649        ptr<Type> formalType;
     
    6265class Expr : public ParseNode {
    6366public:
    64         /// Saves space (~16 bytes) by combining ResnSlots and InferredParams
     67        /*
     68         * NOTE: the union approach is incorrect until the case of
     69         * partial resolution in InferMatcher is eliminated.
     70         * it is reverted to allow unresolved and resolved parameters
     71         * to coexist in an expression node.
     72         */
    6573        struct InferUnion {
     74                // mode is now unused
    6675                enum { Empty, Slots, Params } mode;
    67                 union data_t {
    68                         char def;
    69                         ResnSlots resnSlots;
    70                         InferredParams inferParams;
    71 
    72                         data_t() : def('\0') {}
    73                         ~data_t() {}
     76                struct data_t {
     77                        // char def;
     78                        ResnSlots * resnSlots;
     79                        InferredParams * inferParams;
     80
     81                        data_t(): resnSlots(nullptr), inferParams(nullptr) {}
     82                        data_t(const data_t &other) = delete;
     83                        ~data_t() {
     84                                delete resnSlots;
     85                                delete inferParams;
     86                        }
    7487                } data;
    7588
    7689                /// initializes from other InferUnion
    7790                void init_from( const InferUnion& o ) {
    78                         switch ( o.mode ) {
    79                         case Empty:  return;
    80                         case Slots:  new(&data.resnSlots) ResnSlots{ o.data.resnSlots }; return;
    81                         case Params: new(&data.inferParams) InferredParams{ o.data.inferParams }; return;
     91                        if (o.data.resnSlots) {
     92                                data.resnSlots = new ResnSlots(*o.data.resnSlots);
     93                        }
     94                        if (o.data.inferParams) {
     95                                data.inferParams = new InferredParams(*o.data.inferParams);
    8296                        }
    8397                }
     
    8599                /// initializes from other InferUnion (move semantics)
    86100                void init_from( InferUnion&& o ) {
    87                         switch ( o.mode ) {
    88                         case Empty:  return;
    89                         case Slots:  new(&data.resnSlots) ResnSlots{ std::move(o.data.resnSlots) }; return;
    90                         case Params:
    91                                 new(&data.inferParams) InferredParams{ std::move(o.data.inferParams) }; return;
    92                         }
    93                 }
    94 
    95                 /// clears variant fields
    96                 void reset() {
    97                         switch( mode ) {
    98                         case Empty:  return;
    99                         case Slots:  data.resnSlots.~ResnSlots(); return;
    100                         case Params: data.inferParams.~InferredParams(); return;
    101                         }
     101                        data.resnSlots = o.data.resnSlots;
     102                        data.inferParams = o.data.inferParams;
     103                        o.data.resnSlots = nullptr;
     104                        o.data.inferParams = nullptr;
    102105                }
    103106
     
    107110                InferUnion& operator= ( const InferUnion& ) = delete;
    108111                InferUnion& operator= ( InferUnion&& ) = delete;
    109                 ~InferUnion() { reset(); }
     112
     113                bool hasSlots() const { return data.resnSlots; }
    110114
    111115                ResnSlots& resnSlots() {
    112                         switch (mode) {
    113                         case Empty: new(&data.resnSlots) ResnSlots{}; mode = Slots; // fallthrough
    114                         case Slots: return data.resnSlots;
    115                         case Params: assertf(false, "Cannot return to resnSlots from Params"); abort();
     116                        if (!data.resnSlots) {
     117                                data.resnSlots = new ResnSlots();
    116118                        }
    117                         assertf(false, "unreachable");
     119                        return *data.resnSlots;
    118120                }
    119121
    120122                const ResnSlots& resnSlots() const {
    121                         if (mode == Slots) {
    122                                 return data.resnSlots;
     123                        if (data.resnSlots) {
     124                                return *data.resnSlots;
    123125                        }
    124126                        assertf(false, "Mode was not already resnSlots");
     
    127129
    128130                InferredParams& inferParams() {
    129                         switch (mode) {
    130                         case Slots: data.resnSlots.~ResnSlots(); // fallthrough
    131                         case Empty: new(&data.inferParams) InferredParams{}; mode = Params; // fallthrough
    132                         case Params: return data.inferParams;
     131                        if (!data.inferParams) {
     132                                data.inferParams = new InferredParams();
    133133                        }
    134                         assertf(false, "unreachable");
     134                        return *data.inferParams;
    135135                }
    136136
    137137                const InferredParams& inferParams() const {
    138                         if (mode == Params) {
    139                                 return data.inferParams;
     138                        if (data.inferParams) {
     139                                return *data.inferParams;
    140140                        }
    141141                        assertf(false, "Mode was not already Params");
     
    143143                }
    144144
    145                 void set_inferParams( InferredParams && ps ) {
    146                         switch(mode) {
    147                         case Slots:
    148                                 data.resnSlots.~ResnSlots();
    149                                 // fallthrough
    150                         case Empty:
    151                                 new(&data.inferParams) InferredParams{ std::move( ps ) };
    152                                 mode = Params;
    153                                 break;
    154                         case Params:
    155                                 data.inferParams = std::move( ps );
    156                                 break;
    157                         }
     145                void set_inferParams( InferredParams * ps ) {
     146                        delete data.resnSlots;
     147                        data.resnSlots = nullptr;
     148                        delete data.inferParams;
     149                        data.inferParams = ps;
    158150                }
    159151
     
    161153                /// and the other is in `Params`.
    162154                void splice( InferUnion && o ) {
    163                         if ( o.mode == Empty ) return;
    164                         if ( mode == Empty ) { init_from( o ); return; }
    165                         assert( mode == o.mode && "attempt to splice incompatible InferUnion" );
    166 
    167                         if ( mode == Slots ){
    168                                 data.resnSlots.insert(
    169                                         data.resnSlots.end(), o.data.resnSlots.begin(), o.data.resnSlots.end() );
    170                         } else if ( mode == Params ) {
    171                                 for ( const auto & p : o.data.inferParams ) {
    172                                         data.inferParams[p.first] = std::move(p.second);
     155                        if (o.data.resnSlots) {
     156                                if (data.resnSlots) {
     157                                        data.resnSlots->insert(
     158                                                data.resnSlots->end(), o.data.resnSlots->begin(), o.data.resnSlots->end() );
     159                                        delete o.data.resnSlots;
    173160                                }
    174                         } else assertf(false, "invalid mode");
     161                                else {
     162                                        data.resnSlots = o.data.resnSlots;
     163                                }
     164                                o.data.resnSlots = nullptr;
     165                        }
     166
     167                        if (o.data.inferParams) {
     168                                if (data.inferParams) {
     169                                        for ( const auto & p : *o.data.inferParams ) {
     170                                                (*data.inferParams)[p.first] = std::move(p.second);
     171                                        }
     172                                        delete o.data.inferParams;
     173                                }
     174                                else {
     175                                        data.inferParams = o.data.inferParams;
     176                                }
     177                                o.data.inferParams = nullptr;
     178                        }
    175179                }
    176180        };
     
    185189
    186190        Expr * set_extension( bool ex ) { extension = ex; return this; }
     191        virtual bool get_lvalue() const;
    187192
    188193        virtual const Expr * accept( Visitor & v ) const override = 0;
     
    201206        ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} );
    202207
     208        bool get_lvalue() const final;
     209
    203210        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    204211private:
     
    215222        UntypedExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} )
    216223        : Expr( loc ), func( f ), args( std::move(as) ) {}
     224
     225        bool get_lvalue() const final;
    217226
    218227        /// Creates a new dereference expression
     
    291300        CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {}
    292301
     302        bool get_lvalue() const final;
     303
    293304        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    294305private:
     
    338349        : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); }
    339350
     351        bool get_lvalue() const final;
     352
    340353        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    341354private:
     
    352365        MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg );
    353366
     367        bool get_lvalue() const final;
     368
    354369        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    355370private:
    356371        MemberExpr * clone() const override { return new MemberExpr{ *this }; }
    357372        MUTATE_FRIEND
     373
     374        // Custructor overload meant only for AST conversion
     375        enum NoOpConstruction { NoOpConstructionChosen };
     376        MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
     377            NoOpConstruction overloadSelector );
     378        friend class ::ConverterOldToNew;
     379        friend class ::ConverterNewToOld;
    358380};
    359381
     
    365387        VariableExpr( const CodeLocation & loc );
    366388        VariableExpr( const CodeLocation & loc, const DeclWithType * v );
     389
     390        bool get_lvalue() const final;
    367391
    368392        /// generates a function pointer for a given function
     
    532556
    533557        CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 )
    534         : Expr( loc ), arg1( a1 ), arg2( a2 ) {}
     558        : Expr( loc ), arg1( a1 ), arg2( a2 ) {
     559                this->result = a2->result;
     560        }
     561
     562        bool get_lvalue() const final;
    535563
    536564        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
     
    605633        CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i );
    606634
     635        bool get_lvalue() const final;
     636
    607637        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
    608638private:
     
    660690
    661691        TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i );
     692
     693        bool get_lvalue() const final;
    662694
    663695        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Fwd.hpp

    r67ca73e re67a82d  
    1010// Created On       : Wed May  8 16:05:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun 24 09:48:00 2019
    13 // Update Count     : 1
     12// Last Modified On : Thr Jul 23 14:15:00 2020
     13// Update Count     : 2
    1414//
    1515
     
    108108class FunctionType;
    109109class ReferenceToType;
    110 class StructInstType;
    111 class UnionInstType;
    112 class EnumInstType;
     110template<typename decl_t> class SueInstType;
     111using StructInstType = SueInstType<StructDecl>;
     112using UnionInstType = SueInstType<UnionDecl>;
     113using EnumInstType = SueInstType<EnumDecl>;
    113114class TraitInstType;
    114115class TypeInstType;
  • src/AST/GenericSubstitution.cpp

    r67ca73e re67a82d  
    6262        Pass<GenericSubstitutionBuilder> builder;
    6363        maybe_accept( ty, builder );
    64         return std::move(builder.pass.sub);
     64        return std::move(builder.core.sub);
    6565}
    6666
  • src/AST/Init.hpp

    r67ca73e re67a82d  
    2525
    2626// Must be included in *all* AST classes; should be #undef'd at the end of the file
    27 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     27#define MUTATE_FRIEND \
     28    template<typename node_t> friend node_t * mutate(const node_t * node); \
     29        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    2830
    2931namespace ast {
  • src/AST/Node.cpp

    r67ca73e re67a82d  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 16 14:16:00 2019
    11 // Last Modified By :
    12 // Last Modified On :
    13 // Update Count     :
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Jun  5 10:21:00 2020
     13// Update Count     : 1
    1414//
    1515
     
    1717#include "Fwd.hpp"
    1818
     19#include <csignal>  // MEMORY DEBUG -- for raise
    1920#include <iostream>
    2021
     
    2930#include "Print.hpp"
    3031
    31 template< typename node_t, enum ast::Node::ref_type ref_t >
    32 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); }
    33 
    34 template< typename node_t, enum ast::Node::ref_type ref_t >
    35 void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
    36 
    37 template< typename node_t, enum ast::Node::ref_type ref_t >
    38 void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); }
     32/// MEMORY DEBUG -- allows breaking on ref-count changes of dynamically chosen object.
     33/// Process to use in GDB:
     34///   break ast::Node::_trap()
     35///   run
     36///   set variable MEM_TRAP_OBJ = <target>
     37///   disable <first breakpoint>
     38///   continue
     39void * MEM_TRAP_OBJ = nullptr;
     40
     41void _trap( const void * node ) {
     42        if ( node == MEM_TRAP_OBJ ) std::raise(SIGTRAP);
     43}
     44
     45[[noreturn]] static inline void strict_fail(const ast::Node * node) {
     46        assertf(node, "strict_as had nullptr input.");
     47        const ast::ParseNode * parse = dynamic_cast<const ast::ParseNode *>( node );
     48        if ( nullptr == parse ) {
     49                assertf(nullptr, "%s (no location)", toString(node).c_str());
     50        } else if ( parse->location.isUnset() ) {
     51                assertf(nullptr, "%s (unset location)", toString(node).c_str());
     52        } else {
     53                assertf(nullptr, "%s (at %s:%d)", toString(node).c_str(),
     54                        parse->location.filename.c_str(), parse->location.first_line);
     55        }
     56}
     57
     58template< typename node_t, enum ast::Node::ref_type ref_t >
     59void ast::ptr_base<node_t, ref_t>::_strict_fail() const {
     60        strict_fail(node);
     61}
     62
     63template< typename node_t, enum ast::Node::ref_type ref_t >
     64void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) {
     65        node->increment(ref_t);
     66        _trap( node );
     67}
     68
     69template< typename node_t, enum ast::Node::ref_type ref_t >
     70void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) {
     71        _trap( node );
     72        node->decrement( ref_t, do_delete );
     73}
     74
     75template< typename node_t, enum ast::Node::ref_type ref_t >
     76void ast::ptr_base<node_t, ref_t>::_check() const {
     77        // if(node) assert(node->was_ever_strong == false || node->strong_count > 0);
     78}
    3979
    4080template< typename node_t, enum ast::Node::ref_type ref_t >
  • src/AST/Node.hpp

    r67ca73e re67a82d  
    1010// Created On       : Wed May 8 10:27:04 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Jun  3 13:26:00 2019
    13 // Update Count     : 5
     12// Last Modified On : Fri Jun 5 9:47:00 2020
     13// Update Count     : 6
    1414//
    1515
     
    3838        Node& operator= (const Node&) = delete;
    3939        Node& operator= (Node&&) = delete;
    40         virtual ~Node() = default;
     40        virtual ~Node() {}
    4141
    4242        virtual const Node * accept( Visitor & v ) const = 0;
     
    5757        template<typename node_t>
    5858        friend node_t * mutate(const node_t * node);
     59        template<typename node_t>
     60        friend node_t * shallowCopy(const node_t * node);
    5961
    6062        mutable size_t strong_count = 0;
     
    6971        }
    7072
    71         void decrement(ast::Node::ref_type ref) const {
     73        void decrement(ast::Node::ref_type ref, bool do_delete = true) const {
    7274                switch (ref) {
    7375                        case ref_type::strong: strong_count--; break;
     
    7577                }
    7678
    77                 if(!strong_count && !weak_count) {
     79                if( do_delete && !strong_count && !weak_count) {
    7880                        delete this;
    7981                }
     
    9496        assertf(
    9597                node->weak_count == 0,
    96                 "Error: mutating node with weak references to it will invalided some references"
     98                "Error: mutating node with weak references to it will invalidate some references"
    9799        );
    98100        return node->clone();
     
    104106        // skip mutate if equivalent
    105107        if ( node->*field == val ) return node;
    106        
     108
    107109        // mutate and return
    108110        node_t * ret = mutate( node );
     
    123125        (ret->*field)[i] = std::forward< field_t >( val );
    124126        return ret;
     127}
     128
     129/// Mutate an entire indexed collection by cloning to accepted value
     130template<typename node_t, typename parent_t, typename coll_t>
     131const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) {
     132        for ( unsigned i = 0; i < (node->*field).size(); ++i ) {
     133                node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) );
     134        }
     135        return node;
    125136}
    126137
     
    219230        operator const node_t * () const { _check(); return node; }
    220231
     232        const node_t * release() {
     233                const node_t * ret = node;
     234                if ( node ) {
     235                        _dec(node, false);
     236                        node = nullptr;
     237                }
     238                return ret;
     239        }
     240
    221241        /// wrapper for convenient access to dynamic_cast
    222242        template<typename o_node_t>
    223243        const o_node_t * as() const { _check(); return dynamic_cast<const o_node_t *>(node); }
    224244
    225         /// wrapper for convenient access to strict_dynamic_cast
     245        /// Wrapper that makes sure dynamic_cast returns non-null.
    226246        template<typename o_node_t>
    227         const o_node_t * strict_as() const { _check(); return strict_dynamic_cast<const o_node_t *>(node); }
     247        const o_node_t * strict_as() const {
     248                if (const o_node_t * ret = as<o_node_t>()) return ret;
     249                _strict_fail();
     250        }
     251
     252        /// Wrapper that makes sure dynamic_cast does not fail.
     253        template<typename o_node_t, decltype(nullptr) null>
     254        const o_node_t * strict_as() const { return node ? strict_as<o_node_t>() : nullptr; }
    228255
    229256        /// Returns a mutable version of the pointer in this node.
     
    244271
    245272        void _inc( const node_t * other );
    246         void _dec( const node_t * other );
     273        void _dec( const node_t * other, bool do_delete = true );
    247274        void _check() const;
     275        void _strict_fail() const __attribute__((noreturn));
    248276
    249277        const node_t * node;
  • src/AST/Pass.hpp

    r67ca73e re67a82d  
    88//
    99// Author           : Thierry Delisle
    10 // Created On       : Thu May 09 15::37::05 2019
     10// Created On       : Thu May 09 15:37:05 2019
    1111// Last Modified By :
    1212// Last Modified On :
     
    3535#include "AST/SymbolTable.hpp"
    3636
     37#include "AST/ForallSubstitutionTable.hpp"
     38
    3739// Private prelude header, needed for some of the magic tricks this class pulls off
    3840#include "AST/Pass.proto.hpp"
     
    4648//
    4749// Several additional features are available through inheritance
    48 // | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the
    49 //                          current expression
    50 // | WithStmtsToAdd       - provides the ability to insert statements before or after the current
    51 //                          statement by adding new statements into stmtsToAddBefore or
    52 //                          stmtsToAddAfter respectively.
    53 // | WithDeclsToAdd       - provides the ability to insert declarations before or after the current
    54 //                          declarations by adding new DeclStmt into declsToAddBefore or
    55 //                          declsToAddAfter respectively.
    56 // | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
    57 //                          to false in pre{visit,visit} to skip visiting children
    58 // | WithGuards           - provides the ability to save/restore data like a LIFO stack; to save,
    59 //                          call GuardValue with the variable to save, the variable will
    60 //                          automatically be restored to its previous value after the corresponding
    61 //                          postvisit/postmutate teminates.
    62 // | WithVisitorRef       - provides an pointer to the templated visitor wrapper
    63 // | WithSymbolTable      - provides symbol table functionality
     50// | WithTypeSubstitution  - provides polymorphic const TypeSubstitution * env for the
     51//                           current expression
     52// | WithStmtsToAdd        - provides the ability to insert statements before or after the current
     53//                           statement by adding new statements into stmtsToAddBefore or
     54//                           stmtsToAddAfter respectively.
     55// | WithDeclsToAdd        - provides the ability to insert declarations before or after the
     56//                           current declarations by adding new DeclStmt into declsToAddBefore or
     57//                           declsToAddAfter respectively.
     58// | WithShortCircuiting   - provides the ability to skip visiting child nodes; set visit_children
     59//                           to false in pre{visit,visit} to skip visiting children
     60// | WithGuards            - provides the ability to save/restore data like a LIFO stack; to save,
     61//                           call GuardValue with the variable to save, the variable will
     62//                           automatically be restored to its previous value after the
     63//                           corresponding postvisit/postmutate teminates.
     64// | WithVisitorRef        - provides an pointer to the templated visitor wrapper
     65// | WithSymbolTable       - provides symbol table functionality
     66// | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation
    6467//-------------------------------------------------------------------------------------------------
    65 template< typename pass_t >
     68template< typename core_t >
    6669class Pass final : public ast::Visitor {
    6770public:
     71        using core_type = core_t;
     72        using type = Pass<core_t>;
     73
    6874        /// Forward any arguments to the pass constructor
    6975        /// Propagate 'this' if necessary
    7076        template< typename... Args >
    7177        Pass( Args &&... args)
    72                 : pass( std::forward<Args>( args )... )
     78                : core( std::forward<Args>( args )... )
    7379        {
    7480                // After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
    75                 typedef Pass<pass_t> this_t;
    76                 this_t * const * visitor = __pass::visitor(pass, 0);
     81                type * const * visitor = __pass::visitor(core, 0);
    7782                if(visitor) {
    78                         *const_cast<this_t **>( visitor ) = this;
     83                        *const_cast<type **>( visitor ) = this;
    7984                }
    8085        }
     
    8287        virtual ~Pass() = default;
    8388
     89        /// Construct and run a pass on a translation unit.
     90        template< typename... Args >
     91        static void run( std::list< ptr<Decl> > & decls, Args &&... args ) {
     92                Pass<core_t> visitor( std::forward<Args>( args )... );
     93                accept_all( decls, visitor );
     94        }
     95
     96        template< typename... Args >
     97        static void run( std::list< ptr<Decl> > & decls ) {
     98                Pass<core_t> visitor;
     99                accept_all( decls, visitor );
     100        }
     101
    84102        /// Storage for the actual pass
    85         pass_t pass;
     103        core_t core;
    86104
    87105        /// Visit function declarations
     
    179197        const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
    180198
    181         template<typename pass_type>
    182         friend void accept_all( std::list< ptr<Decl> > & decls, Pass<pass_type>& visitor );
     199        template<typename core_type>
     200        friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor );
    183201private:
    184202
    185         bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(pass, 0); return ptr ? *ptr : true; }
     203        bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(core, 0); return ptr ? *ptr : true; }
    186204
    187205private:
     
    202220        container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
    203221
     222        /// Mutate forall-list, accounting for presence of type substitution map
     223        template<typename node_t>
     224        void mutate_forall( const node_t *& );
     225
    204226public:
    205227        /// Logic to call the accept and mutate the parent if needed, delegates call to accept
     
    210232        /// Internal RAII guard for symbol table features
    211233        struct guard_symtab {
    212                 guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass, 0); }
    213                 ~guard_symtab()                                   { __pass::symtab::leave(pass, 0); }
    214                 Pass<pass_t> & pass;
     234                guard_symtab( Pass<core_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.core, 0); }
     235                ~guard_symtab()                                   { __pass::symtab::leave(pass.core, 0); }
     236                Pass<core_t> & pass;
    215237        };
    216238
    217239        /// Internal RAII guard for scope features
    218240        struct guard_scope {
    219                 guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); }
    220                 ~guard_scope()                                   { __pass::scope::leave(pass, 0); }
    221                 Pass<pass_t> & pass;
     241                guard_scope( Pass<core_t> & pass ): pass( pass ) { __pass::scope::enter(pass.core, 0); }
     242                ~guard_scope()                                   { __pass::scope::leave(pass.core, 0); }
     243                Pass<core_t> & pass;
     244        };
     245
     246        /// Internal RAII guard for forall substitutions
     247        struct guard_forall_subs {
     248                guard_forall_subs( Pass<core_t> & pass, const ParameterizedType * type )
     249                : pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); }
     250                ~guard_forall_subs()         { __pass::forall::leave(pass.core, 0, type ); }
     251                Pass<core_t> & pass;
     252                const ParameterizedType * type;
    222253        };
    223254
     
    227258
    228259/// Apply a pass to an entire translation unit
    229 template<typename pass_t>
    230 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<pass_t> & visitor );
     260template<typename core_t>
     261void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor );
    231262
    232263//-------------------------------------------------------------------------------------------------
     
    268299        };
    269300
    270         template< typename pass_t>
    271         friend auto __pass::at_cleanup( pass_t & pass, int ) -> decltype( &pass.at_cleanup );
     301        template< typename core_t>
     302        friend auto __pass::at_cleanup( core_t & core, int ) -> decltype( &core.at_cleanup );
    272303public:
    273304
     
    305336
    306337/// Used to get a pointer to the pass with its wrapped type
    307 template<typename pass_t>
     338template<typename core_t>
    308339struct WithVisitorRef {
    309         Pass<pass_t> * const visitor = nullptr;
     340        Pass<core_t> * const visitor = nullptr;
    310341};
    311342
     
    314345        SymbolTable symtab;
    315346};
     347
     348/// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl
     349struct WithForallSubstitutor {
     350        ForallSubstitutionTable subs;
     351};
     352
    316353}
    317354
     
    321358extern struct PassVisitorStats {
    322359        size_t depth = 0;
    323         Stats::Counters::MaxCounter<double> * max = nullptr;
    324         Stats::Counters::AverageCounter<double> * avg = nullptr;
     360        Stats::Counters::MaxCounter<double> * max;
     361        Stats::Counters::AverageCounter<double> * avg;
    325362} pass_visitor_stats;
    326363}
  • src/AST/Pass.impl.hpp

    r67ca73e re67a82d  
    2525        using namespace ast; \
    2626        /* back-up the visit children */ \
    27         __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
     27        __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 0) ); \
    2828        /* setup the scope for passes that want to run code at exit */ \
    29         __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (pass, 0) ); \
     29        __attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (core, 0) ); \
     30        /* begin tracing memory allocation if requested by this pass */ \
     31        __pass::beginTrace( core, 0 ); \
    3032        /* call the implementation of the previsit of this pass */ \
    31         __pass::previsit( pass, node, 0 );
     33        __pass::previsit( core, node, 0 );
    3234
    3335#define VISIT( code... ) \
     
    4042#define VISIT_END( type, node ) \
    4143        /* call the implementation of the postvisit of this pass */ \
    42         auto __return = __pass::postvisit( pass, node, 0 ); \
     44        auto __return = __pass::postvisit( core, node, 0 ); \
    4345        assertf(__return, "post visit should never return null"); \
     46        /* end tracing memory allocation if requested by this pass */ \
     47        __pass::endTrace( core, 0 ); \
    4448        return __return;
    4549
     
    119123        }
    120124
    121         template< typename pass_t >
     125        template< typename core_t >
    122126        template< typename node_t >
    123         auto ast::Pass< pass_t >::call_accept( const node_t * node )
     127        auto ast::Pass< core_t >::call_accept( const node_t * node )
    124128                -> typename std::enable_if<
    125129                                !std::is_base_of<ast::Expr, node_t>::value &&
     
    127131                        , decltype( node->accept(*this) )
    128132                >::type
    129 
    130133        {
    131134                __pedantic_pass_assert( __visit_children() );
    132                 __pedantic_pass_assert( expr );
     135                __pedantic_pass_assert( node );
    133136
    134137                static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
     
    138141        }
    139142
    140         template< typename pass_t >
    141         const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {
     143        template< typename core_t >
     144        const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
    142145                __pedantic_pass_assert( __visit_children() );
    143146                __pedantic_pass_assert( expr );
    144147
    145                 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
     148                const ast::TypeSubstitution ** env_ptr = __pass::env( core, 0);
    146149                if ( env_ptr && expr->env ) {
    147150                        *env_ptr = expr->env;
     
    151154        }
    152155
    153         template< typename pass_t >
    154         const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
     156        template< typename core_t >
     157        const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
    155158                __pedantic_pass_assert( __visit_children() );
    156159                __pedantic_pass_assert( stmt );
     
    160163
    161164                // get the stmts/decls that will need to be spliced in
    162                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    163                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
    164                 auto decls_before = __pass::declsToAddBefore( pass, 0);
    165                 auto decls_after  = __pass::declsToAddAfter ( pass, 0);
     165                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     166                auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
     167                auto decls_before = __pass::declsToAddBefore( core, 0);
     168                auto decls_after  = __pass::declsToAddAfter ( core, 0);
    166169
    167170                // These may be modified by subnode but most be restored once we exit this statemnet.
    168                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( pass, 0) );
     171                ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( core, 0) );
    169172                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    170173                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    202205        }
    203206
    204         template< typename pass_t >
     207        template< typename core_t >
    205208        template< template <class...> class container_t >
    206         container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
     209        container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
    207210                __pedantic_pass_assert( __visit_children() );
    208211                if( statements.empty() ) return {};
     
    215218
    216219                // get the stmts/decls that will need to be spliced in
    217                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    218                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
    219                 auto decls_before = __pass::declsToAddBefore( pass, 0);
    220                 auto decls_after  = __pass::declsToAddAfter ( pass, 0);
     220                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     221                auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
     222                auto decls_before = __pass::declsToAddBefore( core, 0);
     223                auto decls_after  = __pass::declsToAddAfter ( core, 0);
    221224
    222225                // These may be modified by subnode but most be restored once we exit this statemnet.
     
    268271        }
    269272
    270         template< typename pass_t >
     273        template< typename core_t >
    271274        template< template <class...> class container_t, typename node_t >
    272         container_t< ast::ptr<node_t> > ast::Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
     275        container_t< ast::ptr<node_t> > ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
    273276                __pedantic_pass_assert( __visit_children() );
    274277                if( container.empty() ) return {};
     
    299302        }
    300303
    301         template< typename pass_t >
     304        template< typename core_t >
    302305        template<typename node_t, typename parent_t, typename child_t>
    303         void ast::Pass< pass_t >::maybe_accept(
     306        void ast::Pass< core_t >::maybe_accept(
    304307                const node_t * & parent,
    305308                child_t parent_t::*child
     
    323326        }
    324327
     328
     329        template< typename core_t >
     330        template< typename node_t >
     331        void ast::Pass< core_t >::mutate_forall( const node_t *& node ) {
     332                if ( auto subs = __pass::forall::subs( core, 0 ) ) {
     333                        // tracking TypeDecl substitution, full clone
     334                        if ( node->forall.empty() ) return;
     335
     336                        node_t * mut = mutate( node );
     337                        mut->forall = subs->clone( node->forall, *this );
     338                        node = mut;
     339                } else {
     340                        // not tracking TypeDecl substitution, just mutate
     341                        maybe_accept( node, &node_t::forall );
     342                }
     343        }
    325344}
    326345
     
    333352//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    334353
    335 template< typename pass_t >
    336 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
     354template< typename core_t >
     355inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< core_t > & visitor ) {
    337356        // We are going to aggregate errors for all these statements
    338357        SemanticErrorException errors;
     
    342361
    343362        // get the stmts/decls that will need to be spliced in
    344         auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
    345         auto decls_after  = __pass::declsToAddAfter ( visitor.pass, 0);
     363        auto decls_before = __pass::declsToAddBefore( visitor.core, 0);
     364        auto decls_after  = __pass::declsToAddAfter ( visitor.core, 0);
    346365
    347366        // update pass statitistics
     
    392411//--------------------------------------------------------------------------
    393412// ObjectDecl
    394 template< typename pass_t >
    395 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
     413template< typename core_t >
     414const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::ObjectDecl * node ) {
    396415        VISIT_START( node );
    397416
     
    406425        )
    407426
    408         __pass::symtab::addId( pass, 0, node );
     427        __pass::symtab::addId( core, 0, node );
    409428
    410429        VISIT_END( DeclWithType, node );
     
    413432//--------------------------------------------------------------------------
    414433// FunctionDecl
    415 template< typename pass_t >
    416 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {
    417         VISIT_START( node );
    418 
    419         __pass::symtab::addId( pass, 0, node );
     434template< typename core_t >
     435const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::FunctionDecl * node ) {
     436        VISIT_START( node );
     437
     438        __pass::symtab::addId( core, 0, node );
    420439
    421440        VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
     
    425444                // shadow with exprs and not the other way around.
    426445                guard_symtab guard { *this };
    427                 __pass::symtab::addWith( pass, 0, node->withExprs, node );
     446                __pass::symtab::addWith( core, 0, node->withExprs, node );
    428447                {
    429448                        guard_symtab guard { *this };
    430449                        // implicit add __func__ identifier as specified in the C manual 6.4.2.2
    431                         static ast::ObjectDecl func(
    432                                 node->location, "__func__",
    433                                 new ast::ArrayType(
    434                                         new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
     450                        static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{
     451                                CodeLocation{}, "__func__",
     452                                new ast::ArrayType{
     453                                        new ast::BasicType{ ast::BasicType::Char, ast::CV::Const },
    435454                                        nullptr, VariableLen, DynamicDim
    436                                 )
    437                         );
    438                         __pass::symtab::addId( pass, 0, &func );
     455                                }
     456                        } };
     457                        __pass::symtab::addId( core, 0, func );
    439458                        VISIT(
    440459                                maybe_accept( node, &FunctionDecl::type );
     
    454473//--------------------------------------------------------------------------
    455474// StructDecl
    456 template< typename pass_t >
    457 const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {
     475template< typename core_t >
     476const ast::Decl * ast::Pass< core_t >::visit( const ast::StructDecl * node ) {
    458477        VISIT_START( node );
    459478
    460479        // make up a forward declaration and add it before processing the members
    461480        // needs to be on the heap because addStruct saves the pointer
    462         __pass::symtab::addStructFwd( pass, 0, node );
     481        __pass::symtab::addStructFwd( core, 0, node );
    463482
    464483        VISIT({
     
    469488
    470489        // this addition replaces the forward declaration
    471         __pass::symtab::addStruct( pass, 0, node );
     490        __pass::symtab::addStruct( core, 0, node );
    472491
    473492        VISIT_END( Decl, node );
     
    476495//--------------------------------------------------------------------------
    477496// UnionDecl
    478 template< typename pass_t >
    479 const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {
     497template< typename core_t >
     498const ast::Decl * ast::Pass< core_t >::visit( const ast::UnionDecl * node ) {
    480499        VISIT_START( node );
    481500
    482501        // make up a forward declaration and add it before processing the members
    483         __pass::symtab::addUnionFwd( pass, 0, node );
     502        __pass::symtab::addUnionFwd( core, 0, node );
    484503
    485504        VISIT({
     
    489508        })
    490509
    491         __pass::symtab::addUnion( pass, 0, node );
     510        __pass::symtab::addUnion( core, 0, node );
    492511
    493512        VISIT_END( Decl, node );
     
    496515//--------------------------------------------------------------------------
    497516// EnumDecl
    498 template< typename pass_t >
    499 const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {
    500         VISIT_START( node );
    501 
    502         __pass::symtab::addEnum( pass, 0, node );
     517template< typename core_t >
     518const ast::Decl * ast::Pass< core_t >::visit( const ast::EnumDecl * node ) {
     519        VISIT_START( node );
     520
     521        __pass::symtab::addEnum( core, 0, node );
    503522
    504523        VISIT(
     
    513532//--------------------------------------------------------------------------
    514533// TraitDecl
    515 template< typename pass_t >
    516 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {
     534template< typename core_t >
     535const ast::Decl * ast::Pass< core_t >::visit( const ast::TraitDecl * node ) {
    517536        VISIT_START( node );
    518537
     
    523542        })
    524543
    525         __pass::symtab::addTrait( pass, 0, node );
     544        __pass::symtab::addTrait( core, 0, node );
    526545
    527546        VISIT_END( Decl, node );
     
    530549//--------------------------------------------------------------------------
    531550// TypeDecl
    532 template< typename pass_t >
    533 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {
     551template< typename core_t >
     552const ast::Decl * ast::Pass< core_t >::visit( const ast::TypeDecl * node ) {
    534553        VISIT_START( node );
    535554
     
    543562        // note that assertions come after the type is added to the symtab, since they are not part of the type proper
    544563        // and may depend on the type itself
    545         __pass::symtab::addType( pass, 0, node );
     564        __pass::symtab::addType( core, 0, node );
    546565
    547566        VISIT(
     
    559578//--------------------------------------------------------------------------
    560579// TypedefDecl
    561 template< typename pass_t >
    562 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {
     580template< typename core_t >
     581const ast::Decl * ast::Pass< core_t >::visit( const ast::TypedefDecl * node ) {
    563582        VISIT_START( node );
    564583
     
    569588        })
    570589
    571         __pass::symtab::addType( pass, 0, node );
     590        __pass::symtab::addType( core, 0, node );
    572591
    573592        VISIT( maybe_accept( node, &TypedefDecl::assertions ); )
     
    578597//--------------------------------------------------------------------------
    579598// AsmDecl
    580 template< typename pass_t >
    581 const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {
     599template< typename core_t >
     600const ast::AsmDecl * ast::Pass< core_t >::visit( const ast::AsmDecl * node ) {
    582601        VISIT_START( node );
    583602
     
    591610//--------------------------------------------------------------------------
    592611// StaticAssertDecl
    593 template< typename pass_t >
    594 const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {
     612template< typename core_t >
     613const ast::StaticAssertDecl * ast::Pass< core_t >::visit( const ast::StaticAssertDecl * node ) {
    595614        VISIT_START( node );
    596615
     
    605624//--------------------------------------------------------------------------
    606625// CompoundStmt
    607 template< typename pass_t >
    608 const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {
     626template< typename core_t >
     627const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
    609628        VISIT_START( node );
    610629        VISIT({
    611630                // do not enter a new scope if inFunction is true - needs to check old state before the assignment
    612                 auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
    613                         if ( ! inFunction ) __pass::symtab::enter(pass, 0);
    614                 }, [this, inFunction = this->inFunction]() {
    615                         if ( ! inFunction ) __pass::symtab::leave(pass, 0);
     631                auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() {
     632                        if ( ! inFunctionCpy ) __pass::symtab::enter(core, 0);
     633                }, [this, inFunctionCpy = this->inFunction]() {
     634                        if ( ! inFunctionCpy ) __pass::symtab::leave(core, 0);
    616635                });
    617636                ValueGuard< bool > guard2( inFunction );
     
    625644//--------------------------------------------------------------------------
    626645// ExprStmt
    627 template< typename pass_t >
    628 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {
     646template< typename core_t >
     647const ast::Stmt * ast::Pass< core_t >::visit( const ast::ExprStmt * node ) {
    629648        VISIT_START( node );
    630649
     
    638657//--------------------------------------------------------------------------
    639658// AsmStmt
    640 template< typename pass_t >
    641 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {
     659template< typename core_t >
     660const ast::Stmt * ast::Pass< core_t >::visit( const ast::AsmStmt * node ) {
    642661        VISIT_START( node )
    643662
     
    654673//--------------------------------------------------------------------------
    655674// DirectiveStmt
    656 template< typename pass_t >
    657 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {
     675template< typename core_t >
     676const ast::Stmt * ast::Pass< core_t >::visit( const ast::DirectiveStmt * node ) {
    658677        VISIT_START( node )
    659678
     
    663682//--------------------------------------------------------------------------
    664683// IfStmt
    665 template< typename pass_t >
    666 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {
     684template< typename core_t >
     685const ast::Stmt * ast::Pass< core_t >::visit( const ast::IfStmt * node ) {
    667686        VISIT_START( node );
    668687
     
    681700//--------------------------------------------------------------------------
    682701// WhileStmt
    683 template< typename pass_t >
    684 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {
     702template< typename core_t >
     703const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) {
    685704        VISIT_START( node );
    686705
     
    698717//--------------------------------------------------------------------------
    699718// ForStmt
    700 template< typename pass_t >
    701 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ForStmt * node ) {
     719template< typename core_t >
     720const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForStmt * node ) {
    702721        VISIT_START( node );
    703722
     
    716735//--------------------------------------------------------------------------
    717736// SwitchStmt
    718 template< typename pass_t >
    719 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SwitchStmt * node ) {
     737template< typename core_t >
     738const ast::Stmt * ast::Pass< core_t >::visit( const ast::SwitchStmt * node ) {
    720739        VISIT_START( node );
    721740
     
    730749//--------------------------------------------------------------------------
    731750// CaseStmt
    732 template< typename pass_t >
    733 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CaseStmt * node ) {
     751template< typename core_t >
     752const ast::Stmt * ast::Pass< core_t >::visit( const ast::CaseStmt * node ) {
    734753        VISIT_START( node );
    735754
     
    744763//--------------------------------------------------------------------------
    745764// BranchStmt
    746 template< typename pass_t >
    747 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::BranchStmt * node ) {
     765template< typename core_t >
     766const ast::Stmt * ast::Pass< core_t >::visit( const ast::BranchStmt * node ) {
    748767        VISIT_START( node );
    749768        VISIT_END( Stmt, node );
     
    752771//--------------------------------------------------------------------------
    753772// ReturnStmt
    754 template< typename pass_t >
    755 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ReturnStmt * node ) {
     773template< typename core_t >
     774const ast::Stmt * ast::Pass< core_t >::visit( const ast::ReturnStmt * node ) {
    756775        VISIT_START( node );
    757776
     
    765784//--------------------------------------------------------------------------
    766785// ThrowStmt
    767 template< typename pass_t >
    768 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ThrowStmt * node ) {
     786template< typename core_t >
     787const ast::Stmt * ast::Pass< core_t >::visit( const ast::ThrowStmt * node ) {
    769788        VISIT_START( node );
    770789
     
    779798//--------------------------------------------------------------------------
    780799// TryStmt
    781 template< typename pass_t >
    782 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::TryStmt * node ) {
     800template< typename core_t >
     801const ast::Stmt * ast::Pass< core_t >::visit( const ast::TryStmt * node ) {
    783802        VISIT_START( node );
    784803
     
    794813//--------------------------------------------------------------------------
    795814// CatchStmt
    796 template< typename pass_t >
    797 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {
     815template< typename core_t >
     816const ast::Stmt * ast::Pass< core_t >::visit( const ast::CatchStmt * node ) {
    798817        VISIT_START( node );
    799818
     
    811830//--------------------------------------------------------------------------
    812831// FinallyStmt
    813 template< typename pass_t >
    814 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {
     832template< typename core_t >
     833const ast::Stmt * ast::Pass< core_t >::visit( const ast::FinallyStmt * node ) {
    815834        VISIT_START( node );
    816835
     
    824843//--------------------------------------------------------------------------
    825844// FinallyStmt
    826 template< typename pass_t >
    827 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SuspendStmt * node ) {
     845template< typename core_t >
     846const ast::Stmt * ast::Pass< core_t >::visit( const ast::SuspendStmt * node ) {
    828847        VISIT_START( node );
    829848
     
    837856//--------------------------------------------------------------------------
    838857// WaitForStmt
    839 template< typename pass_t >
    840 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {
     858template< typename core_t >
     859const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitForStmt * node ) {
    841860        VISIT_START( node );
    842861                // for( auto & clause : node->clauses ) {
     
    906925//--------------------------------------------------------------------------
    907926// WithStmt
    908 template< typename pass_t >
    909 const ast::Decl * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {
     927template< typename core_t >
     928const ast::Decl * ast::Pass< core_t >::visit( const ast::WithStmt * node ) {
    910929        VISIT_START( node );
    911930
     
    915934                        // catch statements introduce a level of scope (for the caught exception)
    916935                        guard_symtab guard { *this };
    917                         __pass::symtab::addWith( pass, 0, node->exprs, node );
     936                        __pass::symtab::addWith( core, 0, node->exprs, node );
    918937                        maybe_accept( node, &WithStmt::stmt );
    919938                }
     
    924943//--------------------------------------------------------------------------
    925944// NullStmt
    926 template< typename pass_t >
    927 const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {
     945template< typename core_t >
     946const ast::NullStmt * ast::Pass< core_t >::visit( const ast::NullStmt * node ) {
    928947        VISIT_START( node );
    929948        VISIT_END( NullStmt, node );
     
    932951//--------------------------------------------------------------------------
    933952// DeclStmt
    934 template< typename pass_t >
    935 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {
     953template< typename core_t >
     954const ast::Stmt * ast::Pass< core_t >::visit( const ast::DeclStmt * node ) {
    936955        VISIT_START( node );
    937956
     
    945964//--------------------------------------------------------------------------
    946965// ImplicitCtorDtorStmt
    947 template< typename pass_t >
    948 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
     966template< typename core_t >
     967const ast::Stmt * ast::Pass< core_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
    949968        VISIT_START( node );
    950969
    951970        // For now this isn't visited, it is unclear if this causes problem
    952971        // if all tests are known to pass, remove this code
    953         // VISIT(
    954         //      maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
    955         // )
     972        VISIT(
     973                maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
     974        )
    956975
    957976        VISIT_END( Stmt, node );
     
    960979//--------------------------------------------------------------------------
    961980// ApplicationExpr
    962 template< typename pass_t >
    963 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {
     981template< typename core_t >
     982const ast::Expr * ast::Pass< core_t >::visit( const ast::ApplicationExpr * node ) {
    964983        VISIT_START( node );
    965984
     
    978997//--------------------------------------------------------------------------
    979998// UntypedExpr
    980 template< typename pass_t >
    981 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {
     999template< typename core_t >
     1000const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedExpr * node ) {
    9821001        VISIT_START( node );
    9831002
     
    9961015//--------------------------------------------------------------------------
    9971016// NameExpr
    998 template< typename pass_t >
    999 const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {
     1017template< typename core_t >
     1018const ast::Expr * ast::Pass< core_t >::visit( const ast::NameExpr * node ) {
    10001019        VISIT_START( node );
    10011020
     
    10101029//--------------------------------------------------------------------------
    10111030// CastExpr
    1012 template< typename pass_t >
    1013 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {
     1031template< typename core_t >
     1032const ast::Expr * ast::Pass< core_t >::visit( const ast::CastExpr * node ) {
    10141033        VISIT_START( node );
    10151034
     
    10261045//--------------------------------------------------------------------------
    10271046// KeywordCastExpr
    1028 template< typename pass_t >
    1029 const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {
     1047template< typename core_t >
     1048const ast::Expr * ast::Pass< core_t >::visit( const ast::KeywordCastExpr * node ) {
    10301049        VISIT_START( node );
    10311050
     
    10421061//--------------------------------------------------------------------------
    10431062// VirtualCastExpr
    1044 template< typename pass_t >
    1045 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {
     1063template< typename core_t >
     1064const ast::Expr * ast::Pass< core_t >::visit( const ast::VirtualCastExpr * node ) {
    10461065        VISIT_START( node );
    10471066
     
    10581077//--------------------------------------------------------------------------
    10591078// AddressExpr
    1060 template< typename pass_t >
    1061 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {
     1079template< typename core_t >
     1080const ast::Expr * ast::Pass< core_t >::visit( const ast::AddressExpr * node ) {
    10621081        VISIT_START( node );
    10631082
     
    10741093//--------------------------------------------------------------------------
    10751094// LabelAddressExpr
    1076 template< typename pass_t >
    1077 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {
     1095template< typename core_t >
     1096const ast::Expr * ast::Pass< core_t >::visit( const ast::LabelAddressExpr * node ) {
    10781097        VISIT_START( node );
    10791098
     
    10881107//--------------------------------------------------------------------------
    10891108// UntypedMemberExpr
    1090 template< typename pass_t >
    1091 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {
     1109template< typename core_t >
     1110const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedMemberExpr * node ) {
    10921111        VISIT_START( node );
    10931112
     
    11051124//--------------------------------------------------------------------------
    11061125// MemberExpr
    1107 template< typename pass_t >
    1108 const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {
     1126template< typename core_t >
     1127const ast::Expr * ast::Pass< core_t >::visit( const ast::MemberExpr * node ) {
    11091128        VISIT_START( node );
    11101129
     
    11211140//--------------------------------------------------------------------------
    11221141// VariableExpr
    1123 template< typename pass_t >
    1124 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {
     1142template< typename core_t >
     1143const ast::Expr * ast::Pass< core_t >::visit( const ast::VariableExpr * node ) {
    11251144        VISIT_START( node );
    11261145
     
    11351154//--------------------------------------------------------------------------
    11361155// ConstantExpr
    1137 template< typename pass_t >
    1138 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {
     1156template< typename core_t >
     1157const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstantExpr * node ) {
    11391158        VISIT_START( node );
    11401159
     
    11491168//--------------------------------------------------------------------------
    11501169// SizeofExpr
    1151 template< typename pass_t >
    1152 const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {
     1170template< typename core_t >
     1171const ast::Expr * ast::Pass< core_t >::visit( const ast::SizeofExpr * node ) {
    11531172        VISIT_START( node );
    11541173
     
    11691188//--------------------------------------------------------------------------
    11701189// AlignofExpr
    1171 template< typename pass_t >
    1172 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {
     1190template< typename core_t >
     1191const ast::Expr * ast::Pass< core_t >::visit( const ast::AlignofExpr * node ) {
    11731192        VISIT_START( node );
    11741193
     
    11891208//--------------------------------------------------------------------------
    11901209// UntypedOffsetofExpr
    1191 template< typename pass_t >
    1192 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {
     1210template< typename core_t >
     1211const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedOffsetofExpr * node ) {
    11931212        VISIT_START( node );
    11941213
     
    12051224//--------------------------------------------------------------------------
    12061225// OffsetofExpr
    1207 template< typename pass_t >
    1208 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {
     1226template< typename core_t >
     1227const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetofExpr * node ) {
    12091228        VISIT_START( node );
    12101229
     
    12211240//--------------------------------------------------------------------------
    12221241// OffsetPackExpr
    1223 template< typename pass_t >
    1224 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {
     1242template< typename core_t >
     1243const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetPackExpr * node ) {
    12251244        VISIT_START( node );
    12261245
     
    12371256//--------------------------------------------------------------------------
    12381257// LogicalExpr
    1239 template< typename pass_t >
    1240 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {
     1258template< typename core_t >
     1259const ast::Expr * ast::Pass< core_t >::visit( const ast::LogicalExpr * node ) {
    12411260        VISIT_START( node );
    12421261
     
    12541273//--------------------------------------------------------------------------
    12551274// ConditionalExpr
    1256 template< typename pass_t >
    1257 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {
     1275template< typename core_t >
     1276const ast::Expr * ast::Pass< core_t >::visit( const ast::ConditionalExpr * node ) {
    12581277        VISIT_START( node );
    12591278
     
    12721291//--------------------------------------------------------------------------
    12731292// CommaExpr
    1274 template< typename pass_t >
    1275 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {
     1293template< typename core_t >
     1294const ast::Expr * ast::Pass< core_t >::visit( const ast::CommaExpr * node ) {
    12761295        VISIT_START( node );
    12771296
     
    12891308//--------------------------------------------------------------------------
    12901309// TypeExpr
    1291 template< typename pass_t >
    1292 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {
     1310template< typename core_t >
     1311const ast::Expr * ast::Pass< core_t >::visit( const ast::TypeExpr * node ) {
    12931312        VISIT_START( node );
    12941313
     
    13051324//--------------------------------------------------------------------------
    13061325// AsmExpr
    1307 template< typename pass_t >
    1308 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {
     1326template< typename core_t >
     1327const ast::Expr * ast::Pass< core_t >::visit( const ast::AsmExpr * node ) {
    13091328        VISIT_START( node );
    13101329
     
    13221341//--------------------------------------------------------------------------
    13231342// ImplicitCopyCtorExpr
    1324 template< typename pass_t >
    1325 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
     1343template< typename core_t >
     1344const ast::Expr * ast::Pass< core_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
    13261345        VISIT_START( node );
    13271346
     
    13381357//--------------------------------------------------------------------------
    13391358// ConstructorExpr
    1340 template< typename pass_t >
    1341 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {
     1359template< typename core_t >
     1360const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstructorExpr * node ) {
    13421361        VISIT_START( node );
    13431362
     
    13541373//--------------------------------------------------------------------------
    13551374// CompoundLiteralExpr
    1356 template< typename pass_t >
    1357 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {
     1375template< typename core_t >
     1376const ast::Expr * ast::Pass< core_t >::visit( const ast::CompoundLiteralExpr * node ) {
    13581377        VISIT_START( node );
    13591378
     
    13701389//--------------------------------------------------------------------------
    13711390// RangeExpr
    1372 template< typename pass_t >
    1373 const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {
     1391template< typename core_t >
     1392const ast::Expr * ast::Pass< core_t >::visit( const ast::RangeExpr * node ) {
    13741393        VISIT_START( node );
    13751394
     
    13871406//--------------------------------------------------------------------------
    13881407// UntypedTupleExpr
    1389 template< typename pass_t >
    1390 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {
     1408template< typename core_t >
     1409const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedTupleExpr * node ) {
    13911410        VISIT_START( node );
    13921411
     
    14031422//--------------------------------------------------------------------------
    14041423// TupleExpr
    1405 template< typename pass_t >
    1406 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {
     1424template< typename core_t >
     1425const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleExpr * node ) {
    14071426        VISIT_START( node );
    14081427
     
    14191438//--------------------------------------------------------------------------
    14201439// TupleIndexExpr
    1421 template< typename pass_t >
    1422 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {
     1440template< typename core_t >
     1441const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleIndexExpr * node ) {
    14231442        VISIT_START( node );
    14241443
     
    14351454//--------------------------------------------------------------------------
    14361455// TupleAssignExpr
    1437 template< typename pass_t >
    1438 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {
     1456template< typename core_t >
     1457const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleAssignExpr * node ) {
    14391458        VISIT_START( node );
    14401459
     
    14511470//--------------------------------------------------------------------------
    14521471// StmtExpr
    1453 template< typename pass_t >
    1454 const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {
     1472template< typename core_t >
     1473const ast::Expr * ast::Pass< core_t >::visit( const ast::StmtExpr * node ) {
    14551474        VISIT_START( node );
    14561475
    14571476        VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr
    14581477                // get the stmts that will need to be spliced in
    1459                 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
    1460                 auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
     1478                auto stmts_before = __pass::stmtsToAddBefore( core, 0);
     1479                auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
    14611480
    14621481                // These may be modified by subnode but most be restored once we exit this statemnet.
    1463                 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( pass, 0) );
     1482                ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( core, 0) );
    14641483                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
    14651484                ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
     
    14791498//--------------------------------------------------------------------------
    14801499// UniqueExpr
    1481 template< typename pass_t >
    1482 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {
     1500template< typename core_t >
     1501const ast::Expr * ast::Pass< core_t >::visit( const ast::UniqueExpr * node ) {
    14831502        VISIT_START( node );
    14841503
     
    14951514//--------------------------------------------------------------------------
    14961515// UntypedInitExpr
    1497 template< typename pass_t >
    1498 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {
     1516template< typename core_t >
     1517const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedInitExpr * node ) {
    14991518        VISIT_START( node );
    15001519
     
    15121531//--------------------------------------------------------------------------
    15131532// InitExpr
    1514 template< typename pass_t >
    1515 const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {
     1533template< typename core_t >
     1534const ast::Expr * ast::Pass< core_t >::visit( const ast::InitExpr * node ) {
    15161535        VISIT_START( node );
    15171536
     
    15291548//--------------------------------------------------------------------------
    15301549// DeletedExpr
    1531 template< typename pass_t >
    1532 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {
     1550template< typename core_t >
     1551const ast::Expr * ast::Pass< core_t >::visit( const ast::DeletedExpr * node ) {
    15331552        VISIT_START( node );
    15341553
     
    15461565//--------------------------------------------------------------------------
    15471566// DefaultArgExpr
    1548 template< typename pass_t >
    1549 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {
     1567template< typename core_t >
     1568const ast::Expr * ast::Pass< core_t >::visit( const ast::DefaultArgExpr * node ) {
    15501569        VISIT_START( node );
    15511570
     
    15621581//--------------------------------------------------------------------------
    15631582// GenericExpr
    1564 template< typename pass_t >
    1565 const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {
     1583template< typename core_t >
     1584const ast::Expr * ast::Pass< core_t >::visit( const ast::GenericExpr * node ) {
    15661585        VISIT_START( node );
    15671586
     
    16021621//--------------------------------------------------------------------------
    16031622// VoidType
    1604 template< typename pass_t >
    1605 const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {
     1623template< typename core_t >
     1624const ast::Type * ast::Pass< core_t >::visit( const ast::VoidType * node ) {
    16061625        VISIT_START( node );
    16071626
     
    16111630//--------------------------------------------------------------------------
    16121631// BasicType
    1613 template< typename pass_t >
    1614 const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {
     1632template< typename core_t >
     1633const ast::Type * ast::Pass< core_t >::visit( const ast::BasicType * node ) {
    16151634        VISIT_START( node );
    16161635
     
    16201639//--------------------------------------------------------------------------
    16211640// PointerType
    1622 template< typename pass_t >
    1623 const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {
     1641template< typename core_t >
     1642const ast::Type * ast::Pass< core_t >::visit( const ast::PointerType * node ) {
    16241643        VISIT_START( node );
    16251644
     
    16341653//--------------------------------------------------------------------------
    16351654// ArrayType
    1636 template< typename pass_t >
    1637 const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {
     1655template< typename core_t >
     1656const ast::Type * ast::Pass< core_t >::visit( const ast::ArrayType * node ) {
    16381657        VISIT_START( node );
    16391658
     
    16481667//--------------------------------------------------------------------------
    16491668// ReferenceType
    1650 template< typename pass_t >
    1651 const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {
     1669template< typename core_t >
     1670const ast::Type * ast::Pass< core_t >::visit( const ast::ReferenceType * node ) {
    16521671        VISIT_START( node );
    16531672
     
    16611680//--------------------------------------------------------------------------
    16621681// QualifiedType
    1663 template< typename pass_t >
    1664 const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {
     1682template< typename core_t >
     1683const ast::Type * ast::Pass< core_t >::visit( const ast::QualifiedType * node ) {
    16651684        VISIT_START( node );
    16661685
     
    16751694//--------------------------------------------------------------------------
    16761695// FunctionType
    1677 template< typename pass_t >
    1678 const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) {
    1679         VISIT_START( node );
    1680 
    1681         VISIT(
    1682                 maybe_accept( node, &FunctionType::forall  );
     1696template< typename core_t >
     1697const ast::Type * ast::Pass< core_t >::visit( const ast::FunctionType * node ) {
     1698        VISIT_START( node );
     1699
     1700        VISIT({
     1701                guard_forall_subs forall_guard { *this, node };
     1702                mutate_forall( node );
    16831703                maybe_accept( node, &FunctionType::returns );
    16841704                maybe_accept( node, &FunctionType::params  );
    1685         )
     1705        })
    16861706
    16871707        VISIT_END( Type, node );
     
    16901710//--------------------------------------------------------------------------
    16911711// StructInstType
    1692 template< typename pass_t >
    1693 const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {
    1694         VISIT_START( node );
    1695 
    1696         __pass::symtab::addStruct( pass, 0, node->name );
     1712template< typename core_t >
     1713const ast::Type * ast::Pass< core_t >::visit( const ast::StructInstType * node ) {
     1714        VISIT_START( node );
     1715
     1716        __pass::symtab::addStruct( core, 0, node->name );
    16971717
    16981718        VISIT({
    16991719                guard_symtab guard { *this };
    1700                 maybe_accept( node, &StructInstType::forall );
     1720                guard_forall_subs forall_guard { *this, node };
     1721                mutate_forall( node );
    17011722                maybe_accept( node, &StructInstType::params );
    17021723        })
     
    17071728//--------------------------------------------------------------------------
    17081729// UnionInstType
    1709 template< typename pass_t >
    1710 const ast::Type * ast::Pass< pass_t >::visit( const ast::UnionInstType * node ) {
    1711         VISIT_START( node );
    1712 
    1713         __pass::symtab::addStruct( pass, 0, node->name );
    1714 
    1715         {
     1730template< typename core_t >
     1731const ast::Type * ast::Pass< core_t >::visit( const ast::UnionInstType * node ) {
     1732        VISIT_START( node );
     1733
     1734        __pass::symtab::addUnion( core, 0, node->name );
     1735
     1736        VISIT({
    17161737                guard_symtab guard { *this };
    1717                 maybe_accept( node, &UnionInstType::forall );
     1738                guard_forall_subs forall_guard { *this, node };
     1739                mutate_forall( node );
    17181740                maybe_accept( node, &UnionInstType::params );
    1719         }
     1741        })
    17201742
    17211743        VISIT_END( Type, node );
     
    17241746//--------------------------------------------------------------------------
    17251747// EnumInstType
    1726 template< typename pass_t >
    1727 const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) {
    1728         VISIT_START( node );
    1729 
    1730         VISIT(
    1731                 maybe_accept( node, &EnumInstType::forall );
     1748template< typename core_t >
     1749const ast::Type * ast::Pass< core_t >::visit( const ast::EnumInstType * node ) {
     1750        VISIT_START( node );
     1751
     1752        VISIT({
     1753                guard_forall_subs forall_guard { *this, node };
     1754                mutate_forall( node );
    17321755                maybe_accept( node, &EnumInstType::params );
    1733         )
     1756        })
    17341757
    17351758        VISIT_END( Type, node );
     
    17381761//--------------------------------------------------------------------------
    17391762// TraitInstType
    1740 template< typename pass_t >
    1741 const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) {
    1742         VISIT_START( node );
    1743 
    1744         VISIT(
    1745                 maybe_accept( node, &TraitInstType::forall );
     1763template< typename core_t >
     1764const ast::Type * ast::Pass< core_t >::visit( const ast::TraitInstType * node ) {
     1765        VISIT_START( node );
     1766
     1767        VISIT({
     1768                guard_forall_subs forall_guard { *this, node };
     1769                mutate_forall( node );
    17461770                maybe_accept( node, &TraitInstType::params );
    1747         )
     1771        })
    17481772
    17491773        VISIT_END( Type, node );
     
    17521776//--------------------------------------------------------------------------
    17531777// TypeInstType
    1754 template< typename pass_t >
    1755 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeInstType * node ) {
    1756         VISIT_START( node );
    1757 
    1758         VISIT(
    1759                 maybe_accept( node, &TypeInstType::forall );
    1760                 maybe_accept( node, &TypeInstType::params );
     1778template< typename core_t >
     1779const ast::Type * ast::Pass< core_t >::visit( const ast::TypeInstType * node ) {
     1780        VISIT_START( node );
     1781
     1782        VISIT(
     1783                {
     1784                        guard_forall_subs forall_guard { *this, node };
     1785                        mutate_forall( node );
     1786                        maybe_accept( node, &TypeInstType::params );
     1787                }
     1788                // ensure that base re-bound if doing substitution
     1789                __pass::forall::replace( core, 0, node );
    17611790        )
    17621791
     
    17661795//--------------------------------------------------------------------------
    17671796// TupleType
    1768 template< typename pass_t >
    1769 const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {
     1797template< typename core_t >
     1798const ast::Type * ast::Pass< core_t >::visit( const ast::TupleType * node ) {
    17701799        VISIT_START( node );
    17711800
     
    17801809//--------------------------------------------------------------------------
    17811810// TypeofType
    1782 template< typename pass_t >
    1783 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {
     1811template< typename core_t >
     1812const ast::Type * ast::Pass< core_t >::visit( const ast::TypeofType * node ) {
    17841813        VISIT_START( node );
    17851814
     
    17931822//--------------------------------------------------------------------------
    17941823// VarArgsType
    1795 template< typename pass_t >
    1796 const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {
     1824template< typename core_t >
     1825const ast::Type * ast::Pass< core_t >::visit( const ast::VarArgsType * node ) {
    17971826        VISIT_START( node );
    17981827
     
    18021831//--------------------------------------------------------------------------
    18031832// ZeroType
    1804 template< typename pass_t >
    1805 const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {
     1833template< typename core_t >
     1834const ast::Type * ast::Pass< core_t >::visit( const ast::ZeroType * node ) {
    18061835        VISIT_START( node );
    18071836
     
    18111840//--------------------------------------------------------------------------
    18121841// OneType
    1813 template< typename pass_t >
    1814 const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {
     1842template< typename core_t >
     1843const ast::Type * ast::Pass< core_t >::visit( const ast::OneType * node ) {
    18151844        VISIT_START( node );
    18161845
     
    18201849//--------------------------------------------------------------------------
    18211850// GlobalScopeType
    1822 template< typename pass_t >
    1823 const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {
     1851template< typename core_t >
     1852const ast::Type * ast::Pass< core_t >::visit( const ast::GlobalScopeType * node ) {
    18241853        VISIT_START( node );
    18251854
     
    18301859//--------------------------------------------------------------------------
    18311860// Designation
    1832 template< typename pass_t >
    1833 const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {
     1861template< typename core_t >
     1862const ast::Designation * ast::Pass< core_t >::visit( const ast::Designation * node ) {
    18341863        VISIT_START( node );
    18351864
     
    18411870//--------------------------------------------------------------------------
    18421871// SingleInit
    1843 template< typename pass_t >
    1844 const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
     1872template< typename core_t >
     1873const ast::Init * ast::Pass< core_t >::visit( const ast::SingleInit * node ) {
    18451874        VISIT_START( node );
    18461875
     
    18541883//--------------------------------------------------------------------------
    18551884// ListInit
    1856 template< typename pass_t >
    1857 const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
     1885template< typename core_t >
     1886const ast::Init * ast::Pass< core_t >::visit( const ast::ListInit * node ) {
    18581887        VISIT_START( node );
    18591888
     
    18681897//--------------------------------------------------------------------------
    18691898// ConstructorInit
    1870 template< typename pass_t >
    1871 const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
     1899template< typename core_t >
     1900const ast::Init * ast::Pass< core_t >::visit( const ast::ConstructorInit * node ) {
    18721901        VISIT_START( node );
    18731902
     
    18831912//--------------------------------------------------------------------------
    18841913// Attribute
    1885 template< typename pass_t >
    1886 const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node  )  {
     1914template< typename core_t >
     1915const ast::Attribute * ast::Pass< core_t >::visit( const ast::Attribute * node  )  {
    18871916        VISIT_START( node );
    18881917
     
    18961925//--------------------------------------------------------------------------
    18971926// TypeSubstitution
    1898 template< typename pass_t >
    1899 const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
     1927template< typename core_t >
     1928const ast::TypeSubstitution * ast::Pass< core_t >::visit( const ast::TypeSubstitution * node ) {
    19001929        VISIT_START( node );
    19011930
     
    19071936                                guard_symtab guard { *this };
    19081937                                auto new_node = p.second->accept( *this );
    1909                                 if (new_node != p.second) mutated = false;
     1938                                if (new_node != p.second) mutated = true;
    19101939                                new_map.insert({ p.first, new_node });
    19111940                        }
     
    19231952                                guard_symtab guard { *this };
    19241953                                auto new_node = p.second->accept( *this );
    1925                                 if (new_node != p.second) mutated = false;
     1954                                if (new_node != p.second) mutated = true;
    19261955                                new_map.insert({ p.first, new_node });
    19271956                        }
  • src/AST/Pass.proto.hpp

    r67ca73e re67a82d  
    1717// IWYU pragma: private, include "Pass.hpp"
    1818
     19#include "Common/Stats/Heap.h"
     20
    1921namespace ast {
    20 template<typename pass_type>
     22template<typename core_t>
    2123class Pass;
    2224
     
    8284                };
    8385
    84                 std::stack< cleanup_t > cleanups;
     86                std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
    8587        };
    8688
     
    111113        /// "Short hand" to check if this is a valid previsit function
    112114        /// Mostly used to make the static_assert look (and print) prettier
    113         template<typename pass_t, typename node_t>
     115        template<typename core_t, typename node_t>
    114116        struct is_valid_previsit {
    115                 using ret_t = decltype( ((pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );
     117                using ret_t = decltype( ((core_t*)nullptr)->previsit( (const node_t *)nullptr ) );
    116118
    117119                static constexpr bool value = std::is_void< ret_t >::value ||
     
    127129        template<>
    128130        struct __assign<true> {
    129                 template<typename pass_t, typename node_t>
    130                 static inline void result( pass_t & pass, const node_t * & node ) {
    131                         pass.previsit( node );
     131                template<typename core_t, typename node_t>
     132                static inline void result( core_t & core, const node_t * & node ) {
     133                        core.previsit( node );
    132134                }
    133135        };
     
    135137        template<>
    136138        struct __assign<false> {
    137                 template<typename pass_t, typename node_t>
    138                 static inline void result( pass_t & pass, const node_t * & node ) {
    139                         node = pass.previsit( node );
     139                template<typename core_t, typename node_t>
     140                static inline void result( core_t & core, const node_t * & node ) {
     141                        node = core.previsit( node );
    140142                        assertf(node, "Previsit must not return NULL");
    141143                }
     
    150152        template<>
    151153        struct __return<true> {
    152                 template<typename pass_t, typename node_t>
    153                 static inline const node_t * result( pass_t & pass, const node_t * & node ) {
    154                         pass.postvisit( node );
     154                template<typename core_t, typename node_t>
     155                static inline const node_t * result( core_t & core, const node_t * & node ) {
     156                        core.postvisit( node );
    155157                        return node;
    156158                }
     
    159161        template<>
    160162        struct __return<false> {
    161                 template<typename pass_t, typename node_t>
    162                 static inline auto result( pass_t & pass, const node_t * & node ) {
    163                         return pass.postvisit( node );
     163                template<typename core_t, typename node_t>
     164                static inline auto result( core_t & core, const node_t * & node ) {
     165                        return core.postvisit( node );
    164166                }
    165167        };
     
    180182        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    181183        // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
    182         template<typename pass_t, typename node_t>
    183         static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
     184        template<typename core_t, typename node_t>
     185        static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) {
    184186                static_assert(
    185                         is_valid_previsit<pass_t, node_t>::value,
     187                        is_valid_previsit<core_t, node_t>::value,
    186188                        "Previsit may not change the type of the node. It must return its paremeter or void."
    187189                );
     
    189191                __assign<
    190192                        std::is_void<
    191                                 decltype( pass.previsit( node ) )
     193                                decltype( core.previsit( node ) )
    192194                        >::value
    193                 >::result( pass, node );
     195                >::result( core, node );
    194196        }
    195197
    196         template<typename pass_t, typename node_t>
    197         static inline auto previsit( pass_t &, const node_t *, long ) {}
     198        template<typename core_t, typename node_t>
     199        static inline auto previsit( core_t &, const node_t *, long ) {}
    198200
    199201        // PostVisit : never mutates the passed pointer but may return a different node
    200         template<typename pass_t, typename node_t>
    201         static inline auto postvisit( pass_t & pass, const node_t * node, int ) ->
    202                 decltype( pass.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
     202        template<typename core_t, typename node_t>
     203        static inline auto postvisit( core_t & core, const node_t * node, int ) ->
     204                decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
    203205        {
    204206                return __return<
    205207                        std::is_void<
    206                                 decltype( pass.postvisit( node ) )
     208                                decltype( core.postvisit( node ) )
    207209                        >::value
    208                 >::result( pass, node );
     210                >::result( core, node );
    209211        }
    210212
    211         template<typename pass_t, typename node_t>
    212         static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
     213        template<typename core_t, typename node_t>
     214        static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; }
    213215
    214216        //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
     
    225227        // The type is not strictly enforced but does match the accessory
    226228        #define FIELD_PTR( name, default_type ) \
    227         template< typename pass_t > \
    228         static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
     229        template< typename core_t > \
     230        static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
    229231        \
    230         template< typename pass_t > \
    231         static inline default_type * name( pass_t &, long ) { return nullptr; }
     232        template< typename core_t > \
     233        static inline default_type * name( core_t &, long ) { return nullptr; }
    232234
    233235        // List of fields and their expected types
     
    239241        FIELD_PTR( visit_children, __pass::bool_ref )
    240242        FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
    241         FIELD_PTR( visitor, ast::Pass<pass_t> * const )
     243        FIELD_PTR( visitor, ast::Pass<core_t> * const )
    242244
    243245        // Remove the macro to make sure we don't clash
    244246        #undef FIELD_PTR
     247
     248        template< typename core_t >
     249        static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     250                // Stats::Heap::stacktrace_push(core_t::traceId);
     251        }
     252
     253        template< typename core_t >
     254        static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
     255                // Stats::Heap::stacktrace_pop();
     256        }
     257
     258        template< typename core_t >
     259        static void beginTrace(core_t &, long) {}
     260
     261        template< typename core_t >
     262        static void endTrace(core_t &, long) {}
    245263
    246264        // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
     
    248266        // detect it using the same strategy
    249267        namespace scope {
    250                 template<typename pass_t>
    251                 static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
    252                         pass.beginScope();
    253                 }
    254 
    255                 template<typename pass_t>
    256                 static inline void enter( pass_t &, long ) {}
    257 
    258                 template<typename pass_t>
    259                 static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
    260                         pass.endScope();
    261                 }
    262 
    263                 template<typename pass_t>
    264                 static inline void leave( pass_t &, long ) {}
    265         };
    266 
    267         // Finally certain pass desire an up to date symbol table automatically
     268                template<typename core_t>
     269                static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) {
     270                        core.beginScope();
     271                }
     272
     273                template<typename core_t>
     274                static inline void enter( core_t &, long ) {}
     275
     276                template<typename core_t>
     277                static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) {
     278                        core.endScope();
     279                }
     280
     281                template<typename core_t>
     282                static inline void leave( core_t &, long ) {}
     283        } // namespace scope
     284
     285        // Certain passes desire an up to date symbol table automatically
    268286        // detect the presence of a member name `symtab` and call all the members appropriately
    269287        namespace symtab {
    270288                // Some simple scoping rules
    271                 template<typename pass_t>
    272                 static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab.enterScope(), void() ) {
    273                         pass.symtab.enterScope();
    274                 }
    275 
    276                 template<typename pass_t>
    277                 static inline auto enter( pass_t &, long ) {}
    278 
    279                 template<typename pass_t>
    280                 static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab.leaveScope(), void() ) {
    281                         pass.symtab.leaveScope();
    282                 }
    283 
    284                 template<typename pass_t>
    285                 static inline auto leave( pass_t &, long ) {}
     289                template<typename core_t>
     290                static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) {
     291                        core.symtab.enterScope();
     292                }
     293
     294                template<typename core_t>
     295                static inline auto enter( core_t &, long ) {}
     296
     297                template<typename core_t>
     298                static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) {
     299                        core.symtab.leaveScope();
     300                }
     301
     302                template<typename core_t>
     303                static inline auto leave( core_t &, long ) {}
    286304
    287305                // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments
    288306                // Create macro to condense these common patterns
    289307                #define SYMTAB_FUNC1( func, type ) \
    290                 template<typename pass_t> \
    291                 static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.symtab.func( arg ), void() ) {\
    292                         pass.symtab.func( arg ); \
     308                template<typename core_t> \
     309                static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\
     310                        core.symtab.func( arg ); \
    293311                } \
    294312                \
    295                 template<typename pass_t> \
    296                 static inline void func( pass_t &, long, type ) {}
     313                template<typename core_t> \
     314                static inline void func( core_t &, long, type ) {}
    297315
    298316                #define SYMTAB_FUNC2( func, type1, type2 ) \
    299                 template<typename pass_t> \
    300                 static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.symtab.func( arg1, arg2 ), void () ) {\
    301                         pass.symtab.func( arg1, arg2 ); \
     317                template<typename core_t> \
     318                static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\
     319                        core.symtab.func( arg1, arg2 ); \
    302320                } \
    303321                        \
    304                 template<typename pass_t> \
    305                 static inline void func( pass_t &, long, type1, type2 ) {}
     322                template<typename core_t> \
     323                static inline void func( core_t &, long, type1, type2 ) {}
    306324
    307325                SYMTAB_FUNC1( addId     , const DeclWithType *  );
     
    311329                SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
    312330                SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
    313                 SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Node * );
     331                SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Decl * );
    314332
    315333                // A few extra functions have more complicated behaviour, they are hand written
    316                 template<typename pass_t>
    317                 static inline auto addStructFwd( pass_t & pass, int, const ast::StructDecl * decl ) -> decltype( pass.symtab.addStruct( decl ), void() ) {
     334                template<typename core_t>
     335                static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
    318336                        ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
    319337                        fwd->params = decl->params;
    320                         pass.symtab.addStruct( fwd );
    321                 }
    322 
    323                 template<typename pass_t>
    324                 static inline void addStructFwd( pass_t &, long, const ast::StructDecl * ) {}
    325 
    326                 template<typename pass_t>
    327                 static inline auto addUnionFwd( pass_t & pass, int, const ast::UnionDecl * decl ) -> decltype( pass.symtab.addUnion( decl ), void() ) {
     338                        core.symtab.addStruct( fwd );
     339                }
     340
     341                template<typename core_t>
     342                static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {}
     343
     344                template<typename core_t>
     345                static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) {
    328346                        UnionDecl * fwd = new UnionDecl( decl->location, decl->name );
    329347                        fwd->params = decl->params;
    330                         pass.symtab.addUnion( fwd );
    331                 }
    332 
    333                 template<typename pass_t>
    334                 static inline void addUnionFwd( pass_t &, long, const ast::UnionDecl * ) {}
    335 
    336                 template<typename pass_t>
    337                 static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addStruct( str ), void() ) {
    338                         if ( ! pass.symtab.lookupStruct( str ) ) {
    339                                 pass.symtab.addStruct( str );
     348                        core.symtab.addUnion( fwd );
     349                }
     350
     351                template<typename core_t>
     352                static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {}
     353
     354                template<typename core_t>
     355                static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {
     356                        if ( ! core.symtab.lookupStruct( str ) ) {
     357                                core.symtab.addStruct( str );
    340358                        }
    341359                }
    342360
    343                 template<typename pass_t>
    344                 static inline void addStruct( pass_t &, long, const std::string & ) {}
    345 
    346                 template<typename pass_t>
    347                 static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addUnion( str ), void() ) {
    348                         if ( ! pass.symtab.lookupUnion( str ) ) {
    349                                 pass.symtab.addUnion( str );
     361                template<typename core_t>
     362                static inline void addStruct( core_t &, long, const std::string & ) {}
     363
     364                template<typename core_t>
     365                static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {
     366                        if ( ! core.symtab.lookupUnion( str ) ) {
     367                                core.symtab.addUnion( str );
    350368                        }
    351369                }
    352370
    353                 template<typename pass_t>
    354                 static inline void addUnion( pass_t &, long, const std::string & ) {}
     371                template<typename core_t>
     372                static inline void addUnion( core_t &, long, const std::string & ) {}
    355373
    356374                #undef SYMTAB_FUNC1
    357375                #undef SYMTAB_FUNC2
    358         };
    359 };
    360 };
     376        } // namespace symtab
     377
     378        // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
     379        // Detect the presence of a member name `subs` and call all members appropriately
     380        namespace forall {
     381                // Some simple scoping rules
     382                template<typename core_t>
     383                static inline auto enter( core_t & core, int, const ast::ParameterizedType * type )
     384                -> decltype( core.subs, void() ) {
     385                        if ( ! type->forall.empty() ) core.subs.beginScope();
     386                }
     387
     388                template<typename core_t>
     389                static inline auto enter( core_t &, long, const ast::ParameterizedType * ) {}
     390
     391                template<typename core_t>
     392                static inline auto leave( core_t & core, int, const ast::ParameterizedType * type )
     393                -> decltype( core.subs, void() ) {
     394                        if ( ! type->forall.empty() ) { core.subs.endScope(); }
     395                }
     396
     397                template<typename core_t>
     398                static inline auto leave( core_t &, long, const ast::ParameterizedType * ) {}
     399
     400                // Get the substitution table, if present
     401                template<typename core_t>
     402                static inline auto subs( core_t & core, int ) -> decltype( &core.subs ) {
     403                        return &core.subs;
     404                }
     405
     406                template<typename core_t>
     407                static inline ast::ForallSubstitutionTable * subs( core_t &, long ) { return nullptr; }
     408
     409                // Replaces a TypeInstType's base TypeDecl according to the table
     410                template<typename core_t>
     411                static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst )
     412                -> decltype( core.subs, void() ) {
     413                        inst = ast::mutate_field(
     414                                inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) );
     415                }
     416
     417                template<typename core_t>
     418                static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {}
     419
     420        } // namespace forall
     421} // namespace __pass
     422} // namespace ast
  • src/AST/Print.cpp

    r67ca73e re67a82d  
    2929
    3030template <typename C, typename... T>
    31 constexpr auto make_array(T&&... values) ->
    32         array<C,sizeof...(T)>
     31constexpr array<C,sizeof...(T)> make_array(T&&... values)
    3332{
    3433        return array<C,sizeof...(T)>{
     
    129128
    130129        void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) {
    131                 switch ( inferred.mode ) {
    132                 case ast::Expr::InferUnion::Empty: return;
    133                 case ast::Expr::InferUnion::Slots: {
    134                         os << indent << "with " << inferred.data.resnSlots.size()
     130                if (inferred.data.resnSlots && !inferred.data.resnSlots->empty()) {
     131                        os << indent << "with " << inferred.data.resnSlots->size()
    135132                           << " pending inference slots" << endl;
    136                         return;
    137                 }
    138                 case ast::Expr::InferUnion::Params: {
     133                }
     134                if (inferred.data.inferParams && !inferred.data.inferParams->empty()) {
    139135                        os << indent << "with inferred parameters " << level << ":" << endl;
    140136                        ++indent;
    141                         for ( const auto & i : inferred.data.inferParams ) {
     137                        for ( const auto & i : *inferred.data.inferParams ) {
    142138                                os << indent;
    143                                 short_print( Decl::fromId( i.second.decl ) );
     139                                short_print( i.second.declptr );
    144140                                os << endl;
    145141                                print( i.second.expr->inferred, level+1 );
    146142                        }
    147143                        --indent;
    148                         return;
    149                 }
    150144                }
    151145        }
     
    233227                }
    234228
    235                 if ( ! short_mode && ! node->assertions.empty() ) {
     229                if ( ! node->assertions.empty() ) {
    236230                        os << endl << indent << "... with assertions" << endl;
    237231                        ++indent;
     
    243237        void postprint( const ast::Expr * node ) {
    244238                print( node->inferred );
     239
     240                if ( node->result ) {
     241                        os << endl << indent << "... with resolved type:" << endl;
     242                        ++indent;
     243                        os << indent;
     244                        node->result->accept( *this );
     245                        --indent;
     246                }
    245247
    246248                if ( node->env ) {
     
    842844        virtual const ast::Expr * visit( const ast::CastExpr * node ) override final {
    843845                ++indent;
    844                 os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;
     846                os << (node->isGenerated ? "Generated" : "Explicit") << " Cast of:" << endl << indent;
    845847                safe_print( node->arg );
    846848                os << endl << indent-1 << "... to:";
  • src/AST/Stmt.hpp

    r67ca73e re67a82d  
    2727
    2828// Must be included in *all* AST classes; should be #undef'd at the end of the file
    29 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     29#define MUTATE_FRIEND \
     30    template<typename node_t> friend node_t * mutate(const node_t * node); \
     31        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3032
    3133namespace ast {
     
    412414class ImplicitCtorDtorStmt final : public Stmt {
    413415public:
    414         readonly<Stmt> callStmt;
     416        ptr<Stmt> callStmt;
    415417
    416418        ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt,
  • src/AST/Type.cpp

    r67ca73e re67a82d  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon May 13 15:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Dec 15 16:56:28 2019
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Jul 23 14:16:00 2020
     13// Update Count     : 5
    1414//
    1515
     
    2121
    2222#include "Decl.hpp"
     23#include "ForallSubstitutor.hpp" // for substituteForall
    2324#include "Init.hpp"
     25#include "Common/utility.h"      // for copy, move
    2426#include "InitTweak/InitTweak.h" // for getPointerBase
    2527#include "Tuples/Tuples.h"       // for isTtype
     
    9092// GENERATED END
    9193
     94// --- ParameterizedType
     95
     96void ParameterizedType::initWithSub(
     97        const ParameterizedType & o, Pass< ForallSubstitutor > & sub
     98) {
     99        forall = sub.core( o.forall );
     100}
     101
    92102// --- FunctionType
     103
     104FunctionType::FunctionType( const FunctionType & o )
     105: ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(),
     106  isVarArgs( o.isVarArgs ) {
     107        Pass< ForallSubstitutor > sub;
     108        initWithSub( o, sub );           // initialize substitution map
     109        returns = sub.core( o.returns ); // apply to return and parameter types
     110        params = sub.core( o.params );
     111}
    93112
    94113namespace {
     
    106125
    107126// --- ReferenceToType
     127
     128void ReferenceToType::initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ) {
     129        ParameterizedType::initWithSub( o, sub ); // initialize substitution
     130        params = sub.core( o.params );            // apply to parameters
     131}
     132
     133ReferenceToType::ReferenceToType( const ReferenceToType & o )
     134: ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ),
     135  hoistType( o.hoistType ) {
     136        Pass< ForallSubstitutor > sub;
     137        initWithSub( o, sub );
     138}
     139
    108140std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const {
    109141        assertf( aggr(), "Must have aggregate to perform lookup" );
     
    116148}
    117149
    118 // --- StructInstType
    119 
    120 StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q,
    121         std::vector<ptr<Attribute>>&& as )
    122 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    123 
    124 bool StructInstType::isComplete() const { return base ? base->body : false; }
    125 
    126 // --- UnionInstType
    127 
    128 UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q,
    129         std::vector<ptr<Attribute>>&& as )
    130 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    131 
    132 bool UnionInstType::isComplete() const { return base ? base->body : false; }
    133 
    134 // --- EnumInstType
    135 
    136 EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q,
    137         std::vector<ptr<Attribute>>&& as )
    138 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
    139 
    140 bool EnumInstType::isComplete() const { return base ? base->body : false; }
     150// --- SueInstType (StructInstType, UnionInstType, EnumInstType)
     151
     152template<typename decl_t>
     153SueInstType<decl_t>::SueInstType(
     154        const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
     155: ReferenceToType( b->name, q, move(as) ), base( b ) {}
     156
     157template<typename decl_t>
     158bool SueInstType<decl_t>::isComplete() const {
     159        return base ? base->body : false;
     160}
     161
     162template class SueInstType<StructDecl>;
     163template class SueInstType<UnionDecl>;
     164template class SueInstType<EnumDecl>;
    141165
    142166// --- TraitInstType
    143167
    144 TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,
    145         std::vector<ptr<Attribute>>&& as )
    146 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
     168TraitInstType::TraitInstType(
     169        const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
     170: ReferenceToType( b->name, q, move(as) ), base( b ) {}
    147171
    148172// --- TypeInstType
     173
     174TypeInstType::TypeInstType( const TypeInstType & o )
     175: ReferenceToType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) {
     176        Pass< ForallSubstitutor > sub;
     177        initWithSub( o, sub );      // initialize substitution
     178        base = sub.core( o.base );  // apply to base type
     179}
    149180
    150181void TypeInstType::set_base( const TypeDecl * b ) {
     
    158189
    159190TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    160 : Type( q ), types( std::move(ts) ), members() {
     191: Type( q ), types( move(ts) ), members() {
    161192        // This constructor is awkward. `TupleType` needs to contain objects so that members can be
    162193        // named, but members without initializer nodes end up getting constructors, which breaks
  • src/AST/Type.hpp

    r67ca73e re67a82d  
    99// Author           : Aaron B. Moss
    1010// Created On       : Thu May 9 10:00:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Dec 11 21:56:46 2019
    13 // Update Count     : 5
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Jul 23 14:15:00 2020
     13// Update Count     : 6
    1414//
    1515
     
    2929
    3030// Must be included in *all* AST classes; should be #undef'd at the end of the file
    31 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
     31#define MUTATE_FRIEND \
     32    template<typename node_t> friend node_t * mutate(const node_t * node); \
     33        template<typename node_t> friend node_t * shallowCopy(const node_t * node);
    3234
    3335namespace ast {
     36
     37template< typename T > class Pass;
     38
     39struct ForallSubstitutor;
    3440
    3541class Type : public Node {
     
    4450        bool is_volatile() const { return qualifiers.is_volatile; }
    4551        bool is_restrict() const { return qualifiers.is_restrict; }
    46         bool is_lvalue() const { return qualifiers.is_lvalue; }
    4752        bool is_mutex() const { return qualifiers.is_mutex; }
    4853        bool is_atomic() const { return qualifiers.is_atomic; }
     
    5156        Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; }
    5257        Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; }
    53         Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }
    5458        Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; }
    5559        Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; }
     
    163167        static const char *typeNames[];
    164168
    165         BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 
     169        BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    166170        : Type(q, std::move(as)), kind(k) {}
    167171
     
    265269/// Base type for potentially forall-qualified types
    266270class ParameterizedType : public Type {
     271protected:
     272        /// initializes forall with substitutor
     273        void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub );
    267274public:
    268275        using ForallList = std::vector<ptr<TypeDecl>>;
     
    276283        ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )
    277284        : Type(q, std::move(as)), forall() {}
     285
     286        // enforce use of ForallSubstitutor to copy parameterized type
     287        ParameterizedType( const ParameterizedType & ) = delete;
     288
     289        ParameterizedType( ParameterizedType && ) = default;
     290
     291        // no need to change destructor, and operator= deleted in Node
    278292
    279293private:
     
    301315        : ParameterizedType(q), returns(), params(), isVarArgs(va) {}
    302316
     317        FunctionType( const FunctionType & o );
     318
    303319        /// true if either the parameters or return values contain a tttype
    304320        bool isTtype() const;
     
    314330/// base class for types that refer to types declared elsewhere (aggregates and typedefs)
    315331class ReferenceToType : public ParameterizedType {
     332protected:
     333        /// Initializes forall and parameters based on substitutor
     334        void initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub );
    316335public:
    317336        std::vector<ptr<Expr>> params;
     
    319338        bool hoistType = false;
    320339
    321         ReferenceToType( const std::string& n, CV::Qualifiers q = {},
    322                 std::vector<ptr<Attribute>> && as = {} )
     340        ReferenceToType(
     341                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    323342        : ParameterizedType(q, std::move(as)), params(), name(n) {}
     343
     344        ReferenceToType( const ReferenceToType & o );
    324345
    325346        /// Gets aggregate declaration this type refers to
     
    333354};
    334355
    335 /// instance of struct type
    336 class StructInstType final : public ReferenceToType {
    337 public:
    338         readonly<StructDecl> base;
    339 
    340         StructInstType( const std::string& n, CV::Qualifiers q = {},
    341                 std::vector<ptr<Attribute>> && as = {} )
     356// Common implementation for the SUE instance types. Not to be used directly.
     357template<typename decl_t>
     358class SueInstType final : public ReferenceToType {
     359public:
     360        using base_type = decl_t;
     361        readonly<decl_t> base;
     362
     363        SueInstType(
     364                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    342365        : ReferenceToType( n, q, std::move(as) ), base() {}
    343         StructInstType( const StructDecl * b, CV::Qualifiers q = {},
    344                 std::vector<ptr<Attribute>> && as = {} );
     366
     367        SueInstType(
     368                const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    345369
    346370        bool isComplete() const override;
    347371
    348         const StructDecl * aggr() const override { return base; }
    349 
    350         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    351 private:
    352         StructInstType * clone() const override { return new StructInstType{ *this }; }
    353         MUTATE_FRIEND
    354 };
    355 
    356 /// instance of union type
    357 class UnionInstType final : public ReferenceToType {
    358 public:
    359         readonly<UnionDecl> base;
    360 
    361         UnionInstType( const std::string& n, CV::Qualifiers q = {},
    362                 std::vector<ptr<Attribute>> && as = {} )
     372        const decl_t * aggr() const override { return base; }
     373
     374        const Type * accept( Visitor & v ) const override { return v.visit( this ); }
     375private:
     376        SueInstType<decl_t> * clone() const override { return new SueInstType<decl_t>{ *this }; }
     377        MUTATE_FRIEND
     378};
     379
     380/// An instance of a struct type.
     381using StructInstType = SueInstType<StructDecl>;
     382
     383/// An instance of a union type.
     384using UnionInstType = SueInstType<UnionDecl>;
     385
     386/// An instance of an enum type.
     387using EnumInstType = SueInstType<EnumDecl>;
     388
     389/// An instance of a trait type.
     390class TraitInstType final : public ReferenceToType {
     391public:
     392        readonly<TraitDecl> base;
     393
     394        TraitInstType(
     395                const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
    363396        : ReferenceToType( n, q, std::move(as) ), base() {}
    364         UnionInstType( const UnionDecl * b, CV::Qualifiers q = {},
    365                 std::vector<ptr<Attribute>> && as = {} );
    366 
    367         bool isComplete() const override;
    368 
    369         const UnionDecl * aggr() const override { return base; }
    370 
    371         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    372 private:
    373         UnionInstType * clone() const override { return new UnionInstType{ *this }; }
    374         MUTATE_FRIEND
    375 };
    376 
    377 /// instance of enum type
    378 class EnumInstType final : public ReferenceToType {
    379 public:
    380         readonly<EnumDecl> base;
    381 
    382         EnumInstType( const std::string& n, CV::Qualifiers q = {},
    383                 std::vector<ptr<Attribute>> && as = {} )
    384         : ReferenceToType( n, q, std::move(as) ), base() {}
    385         EnumInstType( const EnumDecl * b, CV::Qualifiers q = {},
    386                 std::vector<ptr<Attribute>> && as = {} );
    387 
    388         bool isComplete() const override;
    389 
    390         const EnumDecl * aggr() const override { return base; }
    391 
    392         const Type * accept( Visitor & v ) const override { return v.visit( this ); }
    393 private:
    394         EnumInstType * clone() const override { return new EnumInstType{ *this }; }
    395         MUTATE_FRIEND
    396 };
    397 
    398 /// instance of trait type
    399 class TraitInstType final : public ReferenceToType {
    400 public:
    401         readonly<TraitDecl> base;
    402 
    403         TraitInstType( const std::string& n, CV::Qualifiers q = {},
    404                 std::vector<ptr<Attribute>> && as = {} )
    405         : ReferenceToType( n, q, std::move(as) ), base() {}
    406         TraitInstType( const TraitDecl * b, CV::Qualifiers q = {},
    407                 std::vector<ptr<Attribute>> && as = {} );
     397
     398        TraitInstType(
     399                const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
    408400
    409401        // not meaningful for TraitInstType
     
    424416        TypeDecl::Kind kind;
    425417
    426         TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
     418        TypeInstType(
     419                const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
    427420                std::vector<ptr<Attribute>> && as = {} )
    428421        : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
     
    431424        : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
    432425
     426        TypeInstType( const TypeInstType & o );
     427
    433428        /// sets `base`, updating `kind` correctly
    434429        void set_base( const TypeDecl * );
  • src/AST/TypeEnvironment.cpp

    r67ca73e re67a82d  
    5959        std::copy( clz.vars.begin(), clz.vars.end(), std::ostream_iterator< std::string >( out, " " ) );
    6060        out << ")";
    61        
     61
    6262        if ( clz.bound ) {
    6363                out << " -> ";
     
    9292                                }
    9393                        }
    94                        
     94
    9595                        i = next;  // go to next node even if this removed
    9696                }
     
    161161                Pass<Occurs> occur{ var, env };
    162162                maybe_accept( ty, occur );
    163                 return occur.pass.result;
    164         }
    165 }
    166 
    167 bool TypeEnvironment::combine( 
     163                return occur.core.result;
     164        }
     165}
     166
     167bool TypeEnvironment::combine(
    168168                const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) {
    169169        // short-circuit easy cases
     
    199199                                auto st = internal_lookup( *vt );
    200200                                if ( st == env.end() ) {
    201                                         // unbound, safe to add if occurs 
     201                                        // unbound, safe to add if occurs
    202202                                        if ( r.bound && occurs( r.bound, *vt, *this ) ) return false;
    203203                                        r.vars.emplace( *vt );
     
    266266}
    267267
    268 bool TypeEnvironment::bindVar( 
    269                 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
    270                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 
    271                 const SymbolTable & symtab 
     268bool TypeEnvironment::bindVar(
     269                const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
     270                AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen,
     271                const SymbolTable & symtab
    272272) {
    273273        // remove references from bound type, so that type variables can only bind to value types
     
    286286                        ptr<Type> newType = it->bound;
    287287                        reset_qualifiers( newType, typeInst->qualifiers );
    288                         if ( unifyInexact( 
    289                                         newType, target, *this, need, have, open, 
     288                        if ( unifyInexact(
     289                                        newType, target, *this, need, have, open,
    290290                                        widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) {
    291291                                if ( common ) {
     
    300300                }
    301301        } else {
    302                 env.emplace_back( 
     302                env.emplace_back(
    303303                        typeInst->name, target, widen.first && widen.second, data );
    304304        }
     
    306306}
    307307
    308 bool TypeEnvironment::bindVarToVar( 
    309                 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
    310                 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 
    311                 WidenMode widen, const SymbolTable & symtab 
     308bool TypeEnvironment::bindVarToVar(
     309                const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
     310                AssertionSet & need, AssertionSet & have, const OpenVarSet & open,
     311                WidenMode widen, const SymbolTable & symtab
    312312) {
    313313        auto c1 = internal_lookup( var1->name );
    314314        auto c2 = internal_lookup( var2->name );
    315        
     315
    316316        // exit early if variables already bound together
    317317        if ( c1 != env.end() && c1 == c2 ) {
     
    396396}
    397397
    398 bool TypeEnvironment::mergeBound( 
     398bool TypeEnvironment::mergeBound(
    399399                EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) {
    400400        if ( from.bound ) {
     
    406406                        AssertionSet need, have;
    407407
    408                         if ( unifyInexact( 
     408                        if ( unifyInexact(
    409409                                        toType, fromType, *this, need, have, open, widen, symtab, common ) ) {
    410410                                // unifies, set common type if necessary
     
    424424}
    425425
    426 bool TypeEnvironment::mergeClasses( 
     426bool TypeEnvironment::mergeClasses(
    427427        ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab
    428428) {
  • src/AST/TypeEnvironment.hpp

    r67ca73e re67a82d  
    3737/// Adding this comparison operator significantly improves assertion satisfaction run time for
    3838/// some cases. The current satisfaction algorithm's speed partially depends on the order of
    39 /// assertions. Assertions which have fewer possible matches should appear before assertions 
    40 /// which have more possible matches. This seems to imply that this could be further improved 
    41 /// by providing an indexer as an additional argument and ordering based on the number of 
     39/// assertions. Assertions which have fewer possible matches should appear before assertions
     40/// which have more possible matches. This seems to imply that this could be further improved
     41/// by providing an indexer as an additional argument and ordering based on the number of
    4242/// matches of the same kind (object, function) for the names of the declarations.
    4343///
    44 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 
     44/// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this
    4545/// comparator.
    4646///
    47 /// Note: since this compares pointers for position, minor changes in the source file that 
    48 /// affect memory layout can alter compilation time in unpredictable ways. For example, the 
    49 /// placement of a line directive can reorder type pointers with respect to each other so that 
    50 /// assertions are seen in different orders, causing a potentially different number of 
    51 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 
    52 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so 
    53 /// that assertions compare more consistently. I've tried to modify this to compare on mangle 
    54 /// name instead of type as the second comparator, but this causes some assertions to never be 
     47/// Note: since this compares pointers for position, minor changes in the source file that
     48/// affect memory layout can alter compilation time in unpredictable ways. For example, the
     49/// placement of a line directive can reorder type pointers with respect to each other so that
     50/// assertions are seen in different orders, causing a potentially different number of
     51/// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27
     52/// seconds by reordering line directives alone, so it would be nice to fix this comparison so
     53/// that assertions compare more consistently. I've tried to modify this to compare on mangle
     54/// name instead of type as the second comparator, but this causes some assertions to never be
    5555/// recorded. More investigation is needed.
    5656struct AssertCompare {
     
    8686void print( std::ostream &, const OpenVarSet &, Indenter indent = {} );
    8787
    88 /// Represents an equivalence class of bound type variables, optionally with the concrete type 
     88/// Represents an equivalence class of bound type variables, optionally with the concrete type
    8989/// they bind to.
    9090struct EqvClass {
     
    9595
    9696        EqvClass() : vars(), bound(), allowWidening( true ), data() {}
    97        
     97
    9898        /// Copy-with-bound constructor
    99         EqvClass( const EqvClass & o, const Type * b ) 
     99        EqvClass( const EqvClass & o, const Type * b )
    100100        : vars( o.vars ), bound( b ), allowWidening( o.allowWidening ), data( o.data ) {}
    101101
     
    142142        void writeToSubstitution( TypeSubstitution & sub ) const;
    143143
    144         template< typename node_t, enum Node::ref_type ref_t >
    145         int apply( ptr_base< node_t, ref_t > & type ) const {
     144        template< typename node_t >
     145        auto apply( node_t && type ) const {
    146146                TypeSubstitution sub;
    147147                writeToSubstitution( sub );
    148                 return sub.apply( type );
    149         }
    150 
    151         template< typename node_t, enum Node::ref_type ref_t >
    152         int applyFree( ptr_base< node_t, ref_t > & type ) const {
     148                return sub.apply( std::forward<node_t>(type) );
     149        }
     150
     151        template< typename node_t >
     152        auto applyFree( node_t && type ) const {
    153153                TypeSubstitution sub;
    154154                writeToSubstitution( sub );
    155                 return sub.applyFree( type );
     155                return sub.applyFree( std::forward<node_t>(type) );
    156156        }
    157157
     
    172172        void addActual( const TypeEnvironment & actualEnv, OpenVarSet & openVars );
    173173
    174         /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 
     174        /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if
    175175        /// needed. Returns false on failure.
    176         bool bindVar( 
    177                 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
    178                 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
     176        bool bindVar(
     177                const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
     178                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
    179179                ResolvExpr::WidenMode widen, const SymbolTable & symtab );
    180        
    181         /// Binds the type classes represented by `var1` and `var2` together; will add one or both 
     180
     181        /// Binds the type classes represented by `var1` and `var2` together; will add one or both
    182182        /// classes if needed. Returns false on failure.
    183         bool bindVarToVar( 
    184                 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
    185                 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
     183        bool bindVarToVar(
     184                const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
     185                AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
    186186                ResolvExpr::WidenMode widen, const SymbolTable & symtab );
    187187
     
    198198
    199199        /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails
    200         bool mergeBound( 
     200        bool mergeBound(
    201201                EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab );
    202202
    203203        /// Merges two type classes from local environment, returning false if fails
    204         bool mergeClasses( 
    205                 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 
     204        bool mergeClasses(
     205                ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars,
    206206                const SymbolTable & symtab );
    207207
  • src/AST/TypeSubstitution.cpp

    r67ca73e re67a82d  
    1818
    1919namespace ast {
     20
     21
     22// size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
    2023
    2124TypeSubstitution::TypeSubstitution() {
     
    9295namespace {
    9396        struct EnvTrimmer {
    94                 ptr<TypeSubstitution> env;
     97                const TypeSubstitution * env;
    9598                TypeSubstitution * newEnv;
    9699                EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
     
    108111        if ( env ) {
    109112                TypeSubstitution * newEnv = new TypeSubstitution();
    110 #if TIME_TO_CONVERT_PASSES
    111113                Pass<EnvTrimmer> trimmer( env, newEnv );
    112114                expr->accept( trimmer );
    113 #else
    114                 (void)expr;
    115                 (void)env;
    116 #endif
    117115                return newEnv;
    118116        }
     
    121119
    122120void TypeSubstitution::normalize() {
    123 #if TIME_TO_CONVERT_PASSES
    124         PassVisitor<Substituter> sub( *this, true );
     121        Pass<Substituter> sub( *this, true );
    125122        do {
    126                 sub.pass.subCount = 0;
    127                 sub.pass.freeOnly = true;
     123                sub.core.subCount = 0;
     124                sub.core.freeOnly = true;
    128125                for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) {
    129                         i->second = i->second->acceptMutator( sub );
    130                 }
    131         } while ( sub.pass.subCount );
    132 #endif
    133 }
    134 
    135 #if TIME_TO_CONVERT_PASSES
    136 
    137 Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) {
     126                        i->second = i->second->accept( sub );
     127                }
     128        } while ( sub.core.subCount );
     129}
     130
     131const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
    138132        BoundVarsType::const_iterator bound = boundVars.find( inst->name );
    139133        if ( bound != boundVars.end() ) return inst;
     
    146140                // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here.
    147141                // TODO: investigate preventing type variables from being bound to themselves in the first place.
    148                 if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {
     142                if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
    149143                        if ( inst->name == replacement->name ) {
    150144                                return inst;
     
    153147                // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl;
    154148                subCount++;
    155                 Type * newtype = i->second->clone();
    156                 newtype->get_qualifiers() |= inst->get_qualifiers();
    157                 delete inst;
    158                 // Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
    159                 return newtype->acceptMutator( *visitor );
    160         } // if
    161 }
    162 
    163 Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) {
     149                ptr<Type> newType = i->second; // force clone if needed
     150                add_qualifiers( newType, inst->qualifiers );
     151                // Note: need to recursively apply substitution to the new type because normalize does not
     152                // substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
     153                newType = newType->accept( *visitor );
     154                return newType.release();
     155        } // if
     156}
     157
     158const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) {
    164159        VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
    165160        if ( i == sub.varEnv.end() ) {
     
    167162        } else {
    168163                subCount++;
    169                 delete nameExpr;
    170                 return i->second->clone();
    171         } // if
    172 }
    173 
    174 void TypeSubstitution::Substituter::premutate( Type * type ) {
     164                return i->second;
     165        } // if
     166}
     167
     168void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) {
    175169        GuardValue( boundVars );
    176170        // bind type variables from forall-qualifiers
    177171        if ( freeOnly ) {
    178                 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
    179                         boundVars.insert( (*tyvar)->name );
     172                for ( const TypeDecl * tyvar : ptype->forall ) {
     173                                boundVars.insert( tyvar->name );
    180174                } // for
    181175        } // if
    182176}
    183177
    184 template< typename TypeClass >
    185 void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) {
     178void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) {
    186179        GuardValue( boundVars );
    187180        // bind type variables from forall-qualifiers
    188181        if ( freeOnly ) {
    189                 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
    190                         boundVars.insert( (*tyvar)->name );
     182                for ( const TypeDecl * tyvar : type->forall ) {
     183                        boundVars.insert( tyvar->name );
    191184                } // for
    192185                // bind type variables from generic type instantiations
    193                 std::list< TypeDecl* > *baseParameters = type->get_baseParameters();
    194                 if ( baseParameters && ! type->parameters.empty() ) {
    195                         for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) {
    196                                 boundVars.insert( (*tyvar)->name );
    197                         } // for
    198                 } // if
    199         } // if
    200 }
    201 
    202 void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) {
     186                if ( auto decl = type->aggr() ) {
     187                        if ( ! type->params.empty() ) {
     188                                for ( const TypeDecl * tyvar : decl->params ) {
     189                                        boundVars.insert( tyvar->name );
     190                                } // for
     191                        } // if
     192                }
     193        } // if
     194}
     195
     196void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) {
    203197        handleAggregateType( aggregateUseType );
    204198}
    205199
    206 void TypeSubstitution::Substituter::premutate( UnionInstType *aggregateUseType ) {
     200void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) {
    207201        handleAggregateType( aggregateUseType );
    208202}
    209 
    210 #endif
    211203
    212204} // namespace ast
  • src/AST/TypeSubstitution.hpp

    r67ca73e re67a82d  
    4444        TypeSubstitution &operator=( const TypeSubstitution &other );
    4545
    46         template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const;
    47         template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const;
     46        template< typename SynTreeClass >
     47        struct ApplyResult {
     48                // const SynTreeClass * node;
     49                ast::ptr<SynTreeClass> node;
     50                int count;
     51        };
     52
     53        template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const;
     54        template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const;
    4855
    4956        template< typename node_t, enum Node::ref_type ref_t >
    5057        int apply( ptr_base< node_t, ref_t > & input ) const {
    5158                const node_t * p = input.get();
    52                 int ret = apply(p);
    53                 input = p;
    54                 return ret;
     59                auto ret = apply(p);
     60                input = ret.node;
     61                return ret.count;
    5562        }
    5663
     
    5865        int applyFree( ptr_base< node_t, ref_t > & input ) const {
    5966                const node_t * p = input.get();
    60                 int ret = applyFree(p);
    61                 input = p;
    62                 return ret;
     67                auto ret = applyFree(p);
     68                input = ret.node;
     69                return ret.count;
    6370        }
    6471
     
    9299        void initialize( const TypeSubstitution &src, TypeSubstitution &dest );
    93100
    94         template<typename pass_type>
     101        template<typename core_t>
    95102        friend class Pass;
    96103
     
    147154// PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals.
    148155#include "Pass.hpp"
     156#include "Copy.hpp"
    149157
    150158namespace ast {
     
    152160// definitition must happen after PassVisitor is included so that WithGuards can be used
    153161struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
     162                static size_t traceId;
    154163
    155164                Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
    156165
    157 #if TIME_TO_CONVERT_PASSES
    158 
    159                 Type * postmutate( TypeInstType * aggregateUseType );
    160                 Expression * postmutate( NameExpr * nameExpr );
     166                const Type * postvisit( const TypeInstType * aggregateUseType );
     167                const Expr * postvisit( const NameExpr * nameExpr );
    161168
    162169                /// Records type variable bindings from forall-statements
    163                 void premutate( Type * type );
     170                void previsit( const ParameterizedType * type );
    164171                /// Records type variable bindings from forall-statements and instantiations of generic types
    165                 template< typename TypeClass > void handleAggregateType( TypeClass * type );
    166 
    167                 void premutate( StructInstType * aggregateUseType );
    168                 void premutate( UnionInstType * aggregateUseType );
    169 
    170 #endif
     172                void handleAggregateType( const ReferenceToType * type );
     173
     174                void previsit( const StructInstType * aggregateUseType );
     175                void previsit( const UnionInstType * aggregateUseType );
    171176
    172177                const TypeSubstitution & sub;
     
    179184
    180185template< typename SynTreeClass >
    181 int TypeSubstitution::apply( const SynTreeClass *& input ) const {
     186TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const {
    182187        assert( input );
    183188        Pass<Substituter> sub( *this, false );
    184         input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
    185 ///     std::cerr << "substitution result is: ";
    186 ///     newType->print( std::cerr );
    187 ///     std::cerr << std::endl;
    188         return sub.pass.subCount;
     189        input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
     190        return { input, sub.core.subCount };
    189191}
    190192
    191193template< typename SynTreeClass >
    192 int TypeSubstitution::applyFree( const SynTreeClass *& input ) const {
     194TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const {
    193195        assert( input );
    194196        Pass<Substituter> sub( *this, true );
    195         input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
    196 ///     std::cerr << "substitution result is: ";
    197 ///     newType->print( std::cerr );
    198 ///     std::cerr << std::endl;
    199         return sub.pass.subCount;
     197        input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
     198        return { input, sub.core.subCount };
    200199}
    201200
  • src/AST/module.mk

    r67ca73e re67a82d  
    2222        AST/DeclReplacer.cpp \
    2323        AST/Expr.cpp \
     24        AST/ForallSubstitutionTable.cpp \
    2425        AST/GenericSubstitution.cpp \
    2526        AST/Init.cpp \
  • src/AST/porting.md

    r67ca73e re67a82d  
    4747      template<typename node_t>
    4848      friend node_t * mutate(const node_t * node);
     49      template<typename node_t>
     50      friend node_t * shallowCopy(const node_t * node);
     51    or equilant.
     52* You should use the `mutate` function where possible as it avoids extra copies.
     53  * If you must copy use `shallowCopy` or `deepCopy` as required.
    4954
    5055All leaves of the `Node` inheritance tree are now declared `final`
  • src/Common/Eval.cc

    r67ca73e re67a82d  
    168168        if (expr) {
    169169                expr->accept(ev);
    170                 return std::make_pair(ev.pass.value, ev.pass.valid);
     170                return std::make_pair(ev.core.value, ev.core.valid);
    171171        } else {
    172172                return std::make_pair(0, false);
  • src/Common/ScopedMap.h

    r67ca73e re67a82d  
    249249
    250250        /// Gets the note at the given scope
     251        Note& getNote() { return scopes.back().note; }
     252        const Note& getNote() const { return scopes.back().note; }
    251253        Note& getNote( size_type i ) { return scopes[i].note; }
    252254        const Note& getNote( size_type i ) const { return scopes[i].note; }
  • src/Common/Stats/Heap.cc

    r67ca73e re67a82d  
    5353                const size_t passes_size = sizeof(passes) / sizeof(passes[0]);
    5454                size_t       passes_cnt = 1;
     55
     56                StatBlock    stacktrace_stats[100];
     57                size_t       stacktrace_stats_count = 0;
     58                bool         stacktrace_stats_enabled = true;
     59
     60                size_t       trace[1000];
     61                const size_t stacktrace_max_depth = sizeof(trace) / sizeof(size_t);
     62                size_t       stacktrace_depth;
     63
     64                size_t new_stacktrace_id(const char * const name) {
     65                        stacktrace_stats[stacktrace_stats_count].name = name;
     66                        return stacktrace_stats_count++;
     67                }
     68
     69                void stacktrace_push(size_t id) {
     70                        ++stacktrace_depth;
     71                        assertf(stacktrace_depth < stacktrace_max_depth, "Stack trace too deep: increase size of array in Heap.cc");
     72                        trace[stacktrace_depth] = id;
     73                }
     74
     75                void stacktrace_pop() {
     76                        assertf(stacktrace_depth > 0, "Invalid stack tracing operation: trace is empty");
     77                        --stacktrace_depth;
     78                }
    5579
    5680                void newPass( const char * const name ) {
     
    116140                        for(size_t i = 0; i < passes_cnt; i++) {
    117141                                print(passes[i], nc, total_mallocs, total_frees, overall_peak);
     142                        }
     143
     144                        print('-', nct);
     145                        std::cerr << std::setw(nc) << "Trace";
     146                        std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
     147
     148                        print('-', nct);
     149                        for (size_t i = 0; i < stacktrace_stats_count; i++) {
     150                                print(stacktrace_stats[i], nc, total_mallocs, total_frees, overall_peak);
    118151                        }
    119152                        print('-', nct);
     
    188221                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    189222                                }
     223
     224                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     225                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     226                                }
    190227                                return __malloc( size );
    191228                        }
     
    196233                                        passes[passes_cnt - 1].frees++;
    197234                                        passes[passes_cnt - 1].n_allocs--;
     235                                }
     236                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     237                                        stacktrace_stats[trace[stacktrace_depth]].frees++;
    198238                                }
    199239                                return __free( ptr );
     
    208248                                                = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
    209249                                }
     250                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     251                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     252                                }
    210253                                return __calloc( nelem, size );
    211254                        }
     
    218261                                        passes[passes_cnt - 1].frees++;
    219262                                } // if
     263                                if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
     264                                        stacktrace_stats[trace[stacktrace_depth]].mallocs++;
     265                                        stacktrace_stats[trace[stacktrace_depth]].frees++;
     266                                }
    220267                                return s;
    221268                        }
  • src/Common/Stats/Heap.h

    r67ca73e re67a82d  
    2020                void newPass( const char * const name );
    2121                void print();
     22
     23                size_t new_stacktrace_id(const char * const name);
     24                void stacktrace_push(size_t id);
     25                void stacktrace_pop();
    2226        }
    2327}
  • src/CompilationState.cc

    r67ca73e re67a82d  
    1414//
    1515
     16#include "config.h"
     17
    1618int
    1719        astp = false,
     
    2830        genproto = false,
    2931        deterministic_output = false,
     32        useNewAST = CFA_USE_NEW_AST,
    3033        nomainp = false,
    3134        parsep = false,
  • src/CompilationState.h

    r67ca73e re67a82d  
    2929        genproto,
    3030        deterministic_output,
     31        useNewAST,
    3132        nomainp,
    3233        parsep,
  • src/InitTweak/InitTweak.cc

    r67ca73e re67a82d  
    127127        ast::Pass< InitFlattener_new > flattener;
    128128        maybe_accept( init, flattener );
    129         return std::move( flattener.pass.argList );
     129        return std::move( flattener.core.argList );
    130130}
    131131
     
    561561                ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
    562562                maybe_accept( stmt, finder );
    563                 return std::move( finder.pass.matches );
     563                return std::move( finder.core.matches );
    564564        }
    565565
  • src/Parser/ExpressionNode.cc

    r67ca73e re67a82d  
    1010// Created On       : Sat May 16 13:17:07 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Jul 15 08:24:08 2020
    13 // Update Count     : 1046
     12// Last Modified On : Thu Aug 20 14:01:46 2020
     13// Update Count     : 1076
    1414//
    1515
     
    6565
    6666void lnthSuffix( string & str, int & type, int & ltype ) {
     67        // 'u' can appear before or after length suffix
    6768        string::size_type posn = str.find_last_of( "lL" );
    6869
    6970        if ( posn == string::npos ) return;                                     // no suffix
    70         if ( posn == str.length() - 1 ) { type = 3; return; } // no length => long
    71 
     71        size_t end = str.length() - 1;
     72        if ( posn == end ) { type = 3; return; }                        // no length after 'l' => long
     73       
    7274        string::size_type next = posn + 1;                                      // advance to length
    7375        if ( str[next] == '3' ) {                                                       // 32
     
    8486                } // if
    8587        } // if
    86         // remove "lL" for these cases because it may not imply long
    87         str.erase( posn );                                                                      // remove length suffix and "uU"
     88
     89        char fix = '\0';
     90        if ( str[end] == 'u' || str[end] == 'U' ) fix = str[end]; // ends with 'uU' ?
     91        str.erase( posn );                                                                      // remove length suffix and possibly uU
     92        if ( type == 5 ) {                                                                      // L128 does not need uU
     93                end = str.length() - 1;
     94                if ( str[end] == 'u' || str[end] == 'U' ) str.erase( end ); // ends with 'uU' ? remove
     95        } else if ( fix != '\0' ) str += fix;                           // put 'uU' back if removed
    8896} // lnthSuffix
    8997
     
    156164        if ( isdigit( str[str.length() - 1] ) ) {                       // no suffix ?
    157165                lnthSuffix( str, type, ltype );                                 // could have length suffix
    158                 if ( type == 5 && Unsigned ) str.erase( str.length() - 1 ); // L128 and terminating "uU" ?
    159166        } else {
    160167                // At least one digit in integer constant, so safe to backup while looking for suffix.
     
    195202                        if ( type < 5 ) {                                                       // not L128 ?
    196203                                sscanf( (char *)str.c_str(), "%llx", &v );
     204#if defined(__SIZEOF_INT128__)
    197205                        } else {                                                                        // hex int128 constant
    198206                                unsigned int len = str.length();
     
    204212                          FHEX1: ;
    205213                                sscanf( (char *)str.c_str(), "%llx", &v );
     214#endif // __SIZEOF_INT128__
    206215                        } // if
    207216                        //printf( "%llx %llu\n", v, v );
    208217                } else if ( checkB( str[1] ) ) {                                // binary constant ?
     218#if defined(__SIZEOF_INT128__)
    209219                        unsigned int len = str.length();
    210220                        if ( type == 5 && len > 2 + 64 ) {
     
    214224                                scanbin( str2, v2 );
    215225                        } // if
     226#endif // __SIZEOF_INT128__
    216227                        scanbin( str, v );
    217228                        //printf( "%#llx %llu\n", v, v );
     
    223234                                unsigned int len = str.length();
    224235                                if ( len > 1 + 43 || (len == 1 + 43 && str[0] > '3') ) SemanticError( yylloc, "128-bit octal constant to large " + str );
     236                                char buf[32];
    225237                                if ( len <= 1 + 21 ) {                                  // value < 21 octal digitis
    226                                         sscanf( (char *)str.c_str(), "%llo", &v ); // leave value in octal
     238                                        sscanf( (char *)str.c_str(), "%llo", &v );
    227239                                } else {
    228240                                        sscanf( &str[len - 21], "%llo", &v );
     
    237249                                        } // if
    238250                                        v = val >> 64; v2 = (uint64_t)val;      // replace octal constant with 2 hex constants
    239                                         char buf[32];
    240251                                        sprintf( buf, "%#llx", v2 );
    241252                                        str2 = buf;
    242                                         sprintf( buf, "%#llx", v );
    243                                         str = buf;
    244253                                } // if
     254                                sprintf( buf, "%#llx", v );
     255                                str = buf;
    245256#endif // __SIZEOF_INT128__
    246257                        } // if
     
    256267                        if ( str.length() == 39 && str > (Unsigned ? "340282366920938463463374607431768211455" : "170141183460469231731687303715884105727") )
    257268                                SemanticError( yylloc, "128-bit decimal constant to large " + str );
     269                        char buf[32];
    258270                        if ( len <= 19 ) {                                                      // value < 19 decimal digitis
    259                                 sscanf( (char *)str.c_str(), "%llu", &v ); // leave value in decimal
     271                                sscanf( (char *)str.c_str(), "%llu", &v );
    260272                        } else {
    261273                                sscanf( &str[len - 19], "%llu", &v );
     
    270282                                } // if
    271283                                v = val >> 64; v2 = (uint64_t)val;              // replace decimal constant with 2 hex constants
    272                                 char buf[32];
    273284                                sprintf( buf, "%#llx", v2 );
    274285                                str2 = buf;
    275                                 sprintf( buf, "%#llx", v );
    276                                 str = buf;
    277286                        } // if
     287                        sprintf( buf, "%#llx", v );
     288                        str = buf;
    278289#endif // __SIZEOF_INT128__
    279290                } // if
  • src/ResolvExpr/AdjustExprType.cc

    r67ca73e re67a82d  
    100100
    101101namespace {
    102         struct AdjustExprType_new final : public ast::WithShortCircuiting {
     102        class AdjustExprType_new final : public ast::WithShortCircuiting {
     103                const ast::SymbolTable & symtab;
     104        public:
    103105                const ast::TypeEnvironment & tenv;
    104                 const ast::SymbolTable & symtab;
    105106
    106107                AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
    107                 : tenv( e ), symtab( syms ) {}
     108                : symtab( syms ), tenv( e ) {}
    108109
    109                 void premutate( const ast::VoidType * ) { visit_children = false; }
    110                 void premutate( const ast::BasicType * ) { visit_children = false; }
    111                 void premutate( const ast::PointerType * ) { visit_children = false; }
    112                 void premutate( const ast::ArrayType * ) { visit_children = false; }
    113                 void premutate( const ast::FunctionType * ) { visit_children = false; }
    114                 void premutate( const ast::StructInstType * ) { visit_children = false; }
    115                 void premutate( const ast::UnionInstType * ) { visit_children = false; }
    116                 void premutate( const ast::EnumInstType * ) { visit_children = false; }
    117                 void premutate( const ast::TraitInstType * ) { visit_children = false; }
    118                 void premutate( const ast::TypeInstType * ) { visit_children = false; }
    119                 void premutate( const ast::TupleType * ) { visit_children = false; }
    120                 void premutate( const ast::VarArgsType * ) { visit_children = false; }
    121                 void premutate( const ast::ZeroType * ) { visit_children = false; }
    122                 void premutate( const ast::OneType * ) { visit_children = false; }
     110                void previsit( const ast::VoidType * ) { visit_children = false; }
     111                void previsit( const ast::BasicType * ) { visit_children = false; }
     112                void previsit( const ast::PointerType * ) { visit_children = false; }
     113                void previsit( const ast::ArrayType * ) { visit_children = false; }
     114                void previsit( const ast::FunctionType * ) { visit_children = false; }
     115                void previsit( const ast::StructInstType * ) { visit_children = false; }
     116                void previsit( const ast::UnionInstType * ) { visit_children = false; }
     117                void previsit( const ast::EnumInstType * ) { visit_children = false; }
     118                void previsit( const ast::TraitInstType * ) { visit_children = false; }
     119                void previsit( const ast::TypeInstType * ) { visit_children = false; }
     120                void previsit( const ast::TupleType * ) { visit_children = false; }
     121                void previsit( const ast::VarArgsType * ) { visit_children = false; }
     122                void previsit( const ast::ZeroType * ) { visit_children = false; }
     123                void previsit( const ast::OneType * ) { visit_children = false; }
    123124
    124                 const ast::Type * postmutate( const ast::ArrayType * at ) {
     125                const ast::Type * postvisit( const ast::ArrayType * at ) {
    125126                        return new ast::PointerType{ at->base, at->qualifiers };
    126127                }
    127128
    128                 const ast::Type * postmutate( const ast::FunctionType * ft ) {
     129                const ast::Type * postvisit( const ast::FunctionType * ft ) {
    129130                        return new ast::PointerType{ ft };
    130131                }
    131132
    132                 const ast::Type * postmutate( const ast::TypeInstType * inst ) {
     133                const ast::Type * postvisit( const ast::TypeInstType * inst ) {
    133134                        // replace known function-type-variables with pointer-to-function
    134135                        if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
  • src/ResolvExpr/Candidate.hpp

    r67ca73e re67a82d  
    5151
    5252        Candidate( const ast::Expr * x, const ast::TypeEnvironment & e )
    53         : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {}
     53        : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {
     54                assert(x->result);
     55        }
    5456
    5557        Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero )
    5658        : expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ),
    57           need( o.need ) {}
     59          need( o.need ) {
     60                assert(x->result);
     61        }
    5862
    5963        Candidate(
    60                 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 
     64                const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o,
    6165                const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero )
    62         : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {}
     66        : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {
     67                assert(x->result);
     68        }
    6369
    6470        Candidate(
     
    6672                ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero )
    6773        : expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ),
    68           need( n.begin(), n.end() ) {}
     74          need( n.begin(), n.end() ) {
     75                assert(x->result);
     76        }
    6977};
    7078
  • src/ResolvExpr/CandidateFinder.cpp

    r67ca73e re67a82d  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed Jun 5 14:30:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Wed Jun 5 14:30:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct  1 14:55:00 2019
     13// Update Count     : 2
    1414//
    1515
     
    5454                return new ast::CastExpr{ expr, expr->result->stripReferences() };
    5555        }
    56        
     56
    5757        return expr;
    5858}
     
    6161UniqueId globalResnSlot = 0;
    6262
    63 Cost computeConversionCost( 
    64         const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,
    65         const ast::TypeEnvironment & env
     63Cost computeConversionCost(
     64        const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
     65        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    6666) {
    6767        PRINT(
     
    7474                std::cerr << std::endl;
    7575        )
    76         Cost convCost = conversionCost( argType, paramType, symtab, env );
     76        Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env );
    7777        PRINT(
    7878                std::cerr << std::endl << "cost is " << convCost << std::endl;
     
    107107
    108108        /// Computes conversion cost for a given expression to a given type
    109         const ast::Expr * computeExpressionConversionCost( 
    110                 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 
     109        const ast::Expr * computeExpressionConversionCost(
     110                const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
    111111        ) {
    112                 Cost convCost = computeConversionCost( arg->result, paramType, symtab, env );
     112                Cost convCost = computeConversionCost(
     113                                arg->result, paramType, arg->get_lvalue(), symtab, env );
    113114                outCost += convCost;
    114115
    115                 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 
    116                 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 
     116                // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
     117                // conversion. Ignore poly cost for now, since this requires resolution of the cast to
    117118                // infer parameters and this does not currently work for the reason stated below
    118119                Cost tmpCost = convCost;
     
    123124                        return new ast::CastExpr{ arg, newType };
    124125
    125                         // xxx - *should* be able to resolve this cast, but at the moment pointers are not 
    126                         // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 
     126                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not
     127                        // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
    127128                        // once this is fixed it should be possible to resolve the cast.
    128                         // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 
    129                         // but it shouldn't be because this makes the conversion from DT* to DT* since 
     129                        // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
     130                        // but it shouldn't be because this makes the conversion from DT* to DT* since
    130131                        // commontype(zero_t, DT*) is DT*, rather than nothing
    131132
    132133                        // CandidateFinder finder{ symtab, env };
    133134                        // finder.find( arg, ResolvMode::withAdjustment() );
    134                         // assertf( finder.candidates.size() > 0, 
     135                        // assertf( finder.candidates.size() > 0,
    135136                        //      "Somehow castable expression failed to find alternatives." );
    136                         // assertf( finder.candidates.size() == 1, 
     137                        // assertf( finder.candidates.size() == 1,
    137138                        //      "Somehow got multiple alternatives for known cast expression." );
    138139                        // return finder.candidates.front()->expr;
     
    143144
    144145        /// Computes conversion cost for a given candidate
    145         Cost computeApplicationConversionCost( 
    146                 CandidateRef cand, const ast::SymbolTable & symtab 
     146        Cost computeApplicationConversionCost(
     147                CandidateRef cand, const ast::SymbolTable & symtab
    147148        ) {
    148149                auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
     
    167168                                if ( function->isVarArgs ) {
    168169                                        convCost.incUnsafe();
    169                                         PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 
     170                                        PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
    170171                                                << convCost << std::endl; ; )
    171172                                        // convert reference-typed expressions into value-typed expressions
    172                                         cand->expr = ast::mutate_field_index( 
    173                                                 appExpr, &ast::ApplicationExpr::args, i, 
     173                                        cand->expr = ast::mutate_field_index(
     174                                                appExpr, &ast::ApplicationExpr::args, i,
    174175                                                referenceToRvalueConversion( args[i], convCost ) );
    175176                                        continue;
     
    180181                                // Default arguments should be free - don't include conversion cost.
    181182                                // Unwrap them here because they are not relevant to the rest of the system
    182                                 cand->expr = ast::mutate_field_index( 
     183                                cand->expr = ast::mutate_field_index(
    183184                                        appExpr, &ast::ApplicationExpr::args, i, def->expr );
    184185                                ++param;
     
    188189                        // mark conversion cost and also specialization cost of param type
    189190                        const ast::Type * paramType = (*param)->get_type();
    190                         cand->expr = ast::mutate_field_index( 
    191                                 appExpr, &ast::ApplicationExpr::args, i, 
    192                                 computeExpressionConversionCost( 
     191                        cand->expr = ast::mutate_field_index(
     192                                appExpr, &ast::ApplicationExpr::args, i,
     193                                computeExpressionConversionCost(
    193194                                        args[i], paramType, symtab, cand->env, convCost ) );
    194195                        convCost.decSpec( specCost( paramType ) );
     
    198199                if ( param != params.end() ) return Cost::infinity;
    199200
    200                 // specialization cost of return types can't be accounted for directly, it disables 
     201                // specialization cost of return types can't be accounted for directly, it disables
    201202                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    202203                //
     
    215216        }
    216217
    217         void makeUnifiableVars( 
    218                 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 
    219                 ast::AssertionSet & need 
     218        void makeUnifiableVars(
     219                const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars,
     220                ast::AssertionSet & need
    220221        ) {
    221222                for ( const ast::TypeDecl * tyvar : type->forall ) {
     
    254255
    255256                ArgPack()
    256                 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 
     257                : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
    257258                  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    258                
    259                 ArgPack( 
    260                         const ast::TypeEnvironment & env, const ast::AssertionSet & need, 
     259
     260                ArgPack(
     261                        const ast::TypeEnvironment & env, const ast::AssertionSet & need,
    261262                        const ast::AssertionSet & have, const ast::OpenVarSet & open )
    262                 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 
     263                : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
    263264                  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    264                
     265
    265266                ArgPack(
    266                         std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 
    267                         ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 
    268                         unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 
     267                        std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
     268                        ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
     269                        unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
    269270                        unsigned nextExpl = 0, unsigned explAlt = 0 )
    270271                : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ),
    271272                  have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
    272273                  nextExpl( nextExpl ), explAlt( explAlt ) {}
    273                
     274
    274275                ArgPack(
    275                         const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 
     276                        const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
    276277                        ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
    277                 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 
    278                   need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 
     278                : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ),
     279                  need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ),
    279280                  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
    280                
     281
    281282                /// true if this pack is in the middle of an exploded argument
    282283                bool hasExpl() const { return nextExpl > 0; }
     
    286287                        return args[ nextArg-1 ][ explAlt ];
    287288                }
    288                
     289
    289290                /// Ends a tuple expression, consolidating the appropriate args
    290291                void endTuple( const std::vector< ArgPack > & packs ) {
     
    307308
    308309        /// Instantiates an argument to match a parameter, returns false if no matching results left
    309         bool instantiateArgument( 
    310                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 
    311                 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 
    312                 unsigned nTuples = 0 
     310        bool instantiateArgument(
     311                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
     312                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
     313                unsigned nTuples = 0
    313314        ) {
    314315                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
     
    318319                                // xxx - dropping initializer changes behaviour from previous, but seems correct
    319320                                // ^^^ need to handle the case where a tuple has a default argument
    320                                 if ( ! instantiateArgument( 
     321                                if ( ! instantiateArgument(
    321322                                        type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
    322323                                nTuples = 0;
     
    329330                } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
    330331                        // paramType is a ttype, consumes all remaining arguments
    331                        
     332
    332333                        // completed tuples; will be spliced to end of results to finish
    333334                        std::vector< ArgPack > finalResults{};
     
    342343                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
    343344                                        unsigned nextArg = results[i].nextArg;
    344                                        
     345
    345346                                        // use next element of exploded tuple if present
    346347                                        if ( results[i].hasExpl() ) {
     
    352353                                                results.emplace_back(
    353354                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    354                                                         copy( results[i].need ), copy( results[i].have ), 
     355                                                        copy( results[i].need ), copy( results[i].have ),
    355356                                                        copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
    356357                                                        results[i].explAlt );
     
    370371                                                        // push empty tuple expression
    371372                                                        newResult.parent = i;
    372                                                         std::vector< ast::ptr< ast::Expr > > emptyList;
    373                                                         newResult.expr =
    374                                                                 new ast::TupleExpr{ CodeLocation{}, move( emptyList ) };
     373                                                        newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
    375374                                                        argType = newResult.expr->result;
    376375                                                } else {
     
    400399
    401400                                                // check unification for ttype before adding to final
    402                                                 if ( 
    403                                                         unify( 
     401                                                if (
     402                                                        unify(
    404403                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
    405                                                                 newResult.open, symtab ) 
     404                                                                newResult.open, symtab )
    406405                                                ) {
    407406                                                        finalResults.emplace_back( move( newResult ) );
     
    424423                                                if ( expl.exprs.empty() ) {
    425424                                                        results.emplace_back(
    426                                                                 results[i], move( env ), copy( results[i].need ), 
     425                                                                results[i], move( env ), copy( results[i].need ),
    427426                                                                copy( results[i].have ), move( open ), nextArg + 1, expl.cost );
    428                                                        
     427
    429428                                                        continue;
    430429                                                }
     
    432431                                                // add new result
    433432                                                results.emplace_back(
    434                                                         i, expl.exprs.front(), move( env ), copy( results[i].need ), 
    435                                                         copy( results[i].have ), move( open ), nextArg + 1, nTuples, 
     433                                                        i, expl.exprs.front(), move( env ), copy( results[i].need ),
     434                                                        copy( results[i].have ), move( open ), nextArg + 1, nTuples,
    436435                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    437436                                        }
     
    479478
    480479                                        results.emplace_back(
    481                                                 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 
     480                                                i, expr, move( env ), move( need ), move( have ), move( open ), nextArg,
    482481                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
    483482                                }
     
    495494                                        if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
    496495                                                results.emplace_back(
    497                                                         i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 
     496                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ),
    498497                                                        move( need ), move( have ), move( open ), nextArg, nTuples );
    499498                                        }
     
    517516                                if ( expl.exprs.empty() ) {
    518517                                        results.emplace_back(
    519                                                 results[i], move( env ), move( need ), move( have ), move( open ), 
     518                                                results[i], move( env ), move( need ), move( have ), move( open ),
    520519                                                nextArg + 1, expl.cost );
    521                                        
     520
    522521                                        continue;
    523522                                }
     
    539538                                        // add new result
    540539                                        results.emplace_back(
    541                                                 i, expr, move( env ), move( need ), move( have ), move( open ), 
     540                                                i, expr, move( env ), move( need ), move( have ), move( open ),
    542541                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    543542                                }
     
    548547                genStart = genEnd;
    549548
    550                 return genEnd != results.size();
     549                return genEnd != results.size();  // were any new results added?
    551550        }
    552551
    553552        /// Generate a cast expression from `arg` to `toType`
    554         const ast::Expr * restructureCast( 
     553        const ast::Expr * restructureCast(
    555554                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
    556555        ) {
    557                 if ( 
    558                         arg->result->size() > 1 
    559                         && ! toType->isVoid() 
    560                         && ! dynamic_cast< const ast::ReferenceType * >( toType ) 
     556                if (
     557                        arg->result->size() > 1
     558                        && ! toType->isVoid()
     559                        && ! dynamic_cast< const ast::ReferenceType * >( toType )
    561560                ) {
    562                         // Argument is a tuple and the target type is neither void nor a reference. Cast each 
    563                         // member of the tuple to its corresponding target type, producing the tuple of those 
    564                         // cast expressions. If there are more components of the tuple than components in the 
    565                         // target type, then excess components do not come out in the result expression (but 
     561                        // Argument is a tuple and the target type is neither void nor a reference. Cast each
     562                        // member of the tuple to its corresponding target type, producing the tuple of those
     563                        // cast expressions. If there are more components of the tuple than components in the
     564                        // target type, then excess components do not come out in the result expression (but
    566565                        // UniqueExpr ensures that the side effects will still be produced)
    567566                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    568                                 // expressions which may contain side effects require a single unique instance of 
     567                                // expressions which may contain side effects require a single unique instance of
    569568                                // the expression
    570569                                arg = new ast::UniqueExpr{ arg->location, arg };
     
    574573                                // cast each component
    575574                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
    576                                 components.emplace_back( 
     575                                components.emplace_back(
    577576                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
    578577                        }
     
    594593
    595594        /// Actually visits expressions to find their candidate interpretations
    596         struct Finder final : public ast::WithShortCircuiting {
     595        class Finder final : public ast::WithShortCircuiting {
     596                const ast::SymbolTable & symtab;
     597        public:
     598                static size_t traceId;
    597599                CandidateFinder & selfFinder;
    598                 const ast::SymbolTable & symtab;
    599600                CandidateList & candidates;
    600601                const ast::TypeEnvironment & tenv;
    601602                ast::ptr< ast::Type > & targetType;
    602603
     604                enum Errors {
     605                        NotFound,
     606                        NoMatch,
     607                        ArgsToFew,
     608                        ArgsToMany,
     609                        RetsToFew,
     610                        RetsToMany,
     611                        NoReason
     612                };
     613
     614                struct {
     615                        Errors code = NotFound;
     616                } reason;
     617
    603618                Finder( CandidateFinder & f )
    604                 : selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),
     619                : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ),
    605620                  targetType( f.targetType ) {}
    606                
     621
    607622                void previsit( const ast::Node * ) { visit_children = false; }
    608623
     
    611626                void addCandidate( Args &&... args ) {
    612627                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
     628                        reason.code = NoReason;
    613629                }
    614630
     
    639655
    640656                /// Completes a function candidate with arguments located
    641                 void validateFunctionCandidate( 
    642                         const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 
    643                         CandidateList & out 
     657                void validateFunctionCandidate(
     658                        const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
     659                        CandidateList & out
    644660                ) {
    645                         ast::ApplicationExpr * appExpr = 
     661                        ast::ApplicationExpr * appExpr =
    646662                                new ast::ApplicationExpr{ func->expr->location, func->expr };
    647663                        // sum cost and accumulate arguments
     
    657673                        appExpr->args = move( vargs );
    658674                        // build and validate new candidate
    659                         auto newCand = 
     675                        auto newCand =
    660676                                std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
    661677                        PRINT(
     
    669685                /// Builds a list of candidates for a function, storing them in out
    670686                void makeFunctionCandidates(
    671                         const CandidateRef & func, const ast::FunctionType * funcType, 
     687                        const CandidateRef & func, const ast::FunctionType * funcType,
    672688                        const ExplodedArgs_new & args, CandidateList & out
    673689                ) {
     
    676692                        ast::TypeEnvironment funcEnv{ func->env };
    677693                        makeUnifiableVars( funcType, funcOpen, funcNeed );
    678                         // add all type variables as open variables now so that those not used in the parameter
    679                         // list are still considered open
     694                        // add all type variables as open variables now so that those not used in the
     695                        // parameter list are still considered open
    680696                        funcEnv.add( funcType->forall );
    681697
     
    683699                                // attempt to narrow based on expected target type
    684700                                const ast::Type * returnType = funcType->returns.front()->get_type();
    685                                 if ( ! unify( 
    686                                         returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 
     701                                if ( ! unify(
     702                                        returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
    687703                                ) {
    688704                                        // unification failed, do not pursue this candidate
     
    698714                        for ( const ast::DeclWithType * param : funcType->params ) {
    699715                                auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param );
    700                                 // Try adding the arguments corresponding to the current parameter to the existing 
     716                                // Try adding the arguments corresponding to the current parameter to the existing
    701717                                // matches
    702                                 if ( ! instantiateArgument( 
     718                                if ( ! instantiateArgument(
    703719                                        obj->type, obj->init, args, results, genStart, symtab ) ) return;
    704720                        }
     
    750766                                                        if ( expl.exprs.empty() ) {
    751767                                                                results.emplace_back(
    752                                                                         results[i], move( env ), copy( results[i].need ), 
    753                                                                         copy( results[i].have ), move( open ), nextArg + 1, 
     768                                                                        results[i], move( env ), copy( results[i].need ),
     769                                                                        copy( results[i].have ), move( open ), nextArg + 1,
    754770                                                                        expl.cost );
    755771
     
    760776                                                        results.emplace_back(
    761777                                                                i, expl.exprs.front(), move( env ), copy( results[i].need ),
    762                                                                 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 
     778                                                                copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost,
    763779                                                                expl.exprs.size() == 1 ? 0 : 1, j );
    764780                                                }
     
    780796                /// Adds implicit struct-conversions to the alternative list
    781797                void addAnonConversions( const CandidateRef & cand ) {
    782                         // adds anonymous member interpretations whenever an aggregate value type is seen. 
    783                         // it's okay for the aggregate expression to have reference type -- cast it to the 
     798                        // adds anonymous member interpretations whenever an aggregate value type is seen.
     799                        // it's okay for the aggregate expression to have reference type -- cast it to the
    784800                        // base type to treat the aggregate as the referenced value
    785801                        ast::ptr< ast::Expr > aggrExpr( cand->expr );
    786802                        ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
    787803                        cand->env.apply( aggrType );
    788                        
     804
    789805                        if ( aggrType.as< ast::ReferenceType >() ) {
    790806                                aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
     
    799815
    800816                /// Adds aggregate member interpretations
    801                 void addAggMembers( 
    802                         const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 
    803                         const Candidate & cand, const Cost & addedCost, const std::string & name 
     817                void addAggMembers(
     818                        const ast::ReferenceToType * aggrInst, const ast::Expr * expr,
     819                        const Candidate & cand, const Cost & addedCost, const std::string & name
    804820                ) {
    805821                        for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
    806822                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
    807                                 CandidateRef newCand = std::make_shared<Candidate>( 
     823                                CandidateRef newCand = std::make_shared<Candidate>(
    808824                                        cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
    809                                 // add anonymous member interpretations whenever an aggregate value type is seen 
     825                                // add anonymous member interpretations whenever an aggregate value type is seen
    810826                                // as a member expression
    811827                                addAnonConversions( newCand );
     
    815831
    816832                /// Adds tuple member interpretations
    817                 void addTupleMembers( 
    818                         const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 
    819                         const Cost & addedCost, const ast::Expr * member 
     833                void addTupleMembers(
     834                        const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
     835                        const Cost & addedCost, const ast::Expr * member
    820836                ) {
    821837                        if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
    822                                 // get the value of the constant expression as an int, must be between 0 and the 
     838                                // get the value of the constant expression as an int, must be between 0 and the
    823839                                // length of the tuple to have meaning
    824840                                long long val = constantExpr->intValue();
    825841                                if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    826842                                        addCandidate(
    827                                                 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 
     843                                                cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
    828844                                                addedCost );
    829845                                }
     
    837853                        if ( funcFinder.candidates.empty() ) return;
    838854
    839                         std::vector< CandidateFinder > argCandidates =
     855                        reason.code = NoMatch;
     856
     857                        std::vector< CandidateFinder > argCandidates =
    840858                                selfFinder.findSubExprs( untypedExpr->args );
    841                        
     859
    842860                        // take care of possible tuple assignments
    843861                        // if not tuple assignment, handled as normal function call
     
    877895                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    878896                                                        CandidateRef newFunc{ new Candidate{ *func } };
    879                                                         newFunc->expr = 
     897                                                        newFunc->expr =
    880898                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    881899                                                        makeFunctionCandidates( newFunc, function, argExpansions, found );
    882900                                                }
    883                                         } else if ( 
    884                                                 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 
     901                                        } else if (
     902                                                auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
    885903                                        ) {
    886904                                                if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
    887905                                                        if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    888906                                                                CandidateRef newFunc{ new Candidate{ *func } };
    889                                                                 newFunc->expr = 
     907                                                                newFunc->expr =
    890908                                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    891909                                                                makeFunctionCandidates( newFunc, function, argExpansions, found );
     
    901919                                std::vector< ExplodedArg > funcE;
    902920                                funcE.reserve( funcFinder.candidates.size() );
    903                                 for ( const CandidateRef & func : funcFinder ) { 
     921                                for ( const CandidateRef & func : funcFinder ) {
    904922                                        funcE.emplace_back( *func, symtab );
    905923                                }
     
    913931                                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    914932                                                                CandidateRef newOp{ new Candidate{ *op} };
    915                                                                 newOp->expr = 
     933                                                                newOp->expr =
    916934                                                                        referenceToRvalueConversion( newOp->expr, newOp->cost );
    917935                                                                makeFunctionCandidates( newOp, function, argExpansions, found );
     
    922940                        }
    923941
    924                         // Implement SFINAE; resolution errors are only errors if there aren't any non-error 
     942                        // Implement SFINAE; resolution errors are only errors if there aren't any non-error
    925943                        // candidates
    926944                        if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     
    934952                                        auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    935953                                        auto function = pointer->base.strict_as< ast::FunctionType >();
    936                                        
     954
    937955                                        std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
    938956                                        std::cerr << "parameters are:" << std::endl;
     
    957975                        promoteCvtCost( winners );
    958976
    959                         // function may return a struct/union value, in which case we need to add candidates 
    960                         // for implicit conversions to each of the anonymous members, which must happen after 
     977                        // function may return a struct/union value, in which case we need to add candidates
     978                        // for implicit conversions to each of the anonymous members, which must happen after
    961979                        // `findMinCost`, since anon conversions are never the cheapest
    962980                        for ( const CandidateRef & c : winners ) {
     
    966984
    967985                        if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
    968                                 // If resolution is unsuccessful with a target type, try again without, since it 
     986                                // If resolution is unsuccessful with a target type, try again without, since it
    969987                                // will sometimes succeed when it wouldn't with a target type binding.
    970988                                // For example:
     
    9831001                /// true if expression is an lvalue
    9841002                static bool isLvalue( const ast::Expr * x ) {
    985                         return x->result && ( x->result->is_lvalue() || x->result.as< ast::ReferenceType >() );
     1003                        return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
    9861004                }
    9871005
     
    9891007                        CandidateFinder finder{ symtab, tenv };
    9901008                        finder.find( addressExpr->arg );
     1009
     1010                        if( finder.candidates.empty() ) return;
     1011
     1012                        reason.code = NoMatch;
     1013
    9911014                        for ( CandidateRef & r : finder.candidates ) {
    9921015                                if ( ! isLvalue( r->expr ) ) continue;
     
    10091032                        finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    10101033
     1034                        if( !finder.candidates.empty() ) reason.code = NoMatch;
     1035
    10111036                        CandidateList matches;
    10121037                        for ( CandidateRef & cand : finder.candidates ) {
     
    10161041                                cand->env.extractOpenVars( open );
    10171042
    1018                                 // It is possible that a cast can throw away some values in a multiply-valued 
    1019                                 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 
    1020                                 // subexpression results that are cast directly. The candidate is invalid if it 
     1043                                // It is possible that a cast can throw away some values in a multiply-valued
     1044                                // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
     1045                                // subexpression results that are cast directly. The candidate is invalid if it
    10211046                                // has fewer results than there are types to cast to.
    10221047                                int discardedValues = cand->expr->result->size() - toType->size();
     
    10251050                                // unification run for side-effects
    10261051                                unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
    1027                                 Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env );
     1052                                Cost thisCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1053                                                symtab, cand->env );
    10281054                                PRINT(
    10291055                                        std::cerr << "working on cast with result: " << toType << std::endl;
     
    10371063                                        // count one safe conversion for each value that is thrown away
    10381064                                        thisCost.incSafe( discardedValues );
    1039                                         CandidateRef newCand = std::make_shared<Candidate>( 
    1040                                                 restructureCast( cand->expr, toType, castExpr->isGenerated ), 
    1041                                                 copy( cand->env ), move( open ), move( need ), cand->cost, 
     1065                                        CandidateRef newCand = std::make_shared<Candidate>(
     1066                                                restructureCast( cand->expr, toType, castExpr->isGenerated ),
     1067                                                copy( cand->env ), move( open ), move( need ), cand->cost,
    10421068                                                cand->cost + thisCost );
    10431069                                        inferParameters( newCand, matches );
     
    10571083                        finder.find( castExpr->arg, ResolvMode::withoutPrune() );
    10581084                        for ( CandidateRef & r : finder.candidates ) {
    1059                                 addCandidate( 
    1060                                         *r, 
     1085                                addCandidate(
     1086                                        *r,
    10611087                                        new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
    10621088                        }
     
    10671093                        aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
    10681094                        for ( CandidateRef & agg : aggFinder.candidates ) {
    1069                                 // it's okay for the aggregate expression to have reference type -- cast it to the 
     1095                                // it's okay for the aggregate expression to have reference type -- cast it to the
    10701096                                // base type to treat the aggregate as the referenced value
    10711097                                Cost addedCost = Cost::zero;
     
    10741100                                // find member of the given type
    10751101                                if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
    1076                                         addAggMembers( 
     1102                                        addAggMembers(
    10771103                                                structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    10781104                                } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
    1079                                         addAggMembers( 
     1105                                        addAggMembers(
    10801106                                                unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    10811107                                } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
     
    10921118                        std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name );
    10931119                        PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
     1120                        if( declList.empty() ) return;
     1121
     1122                        reason.code = NoMatch;
     1123
    10941124                        for ( auto & data : declList ) {
    10951125                                Cost cost = Cost::zero;
     
    10971127
    10981128                                CandidateRef newCand = std::make_shared<Candidate>(
    1099                                         newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 
     1129                                        newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
    11001130                                        cost );
    11011131                                PRINT(
     
    11071137                                        std::cerr << std::endl;
    11081138                                )
    1109                                 newCand->expr = ast::mutate_field( 
    1110                                         newCand->expr.get(), &ast::Expr::result, 
     1139                                newCand->expr = ast::mutate_field(
     1140                                        newCand->expr.get(), &ast::Expr::result,
    11111141                                        renameTyVars( newCand->expr->result ) );
    1112                                 // add anonymous member interpretations whenever an aggregate value type is seen 
     1142                                // add anonymous member interpretations whenever an aggregate value type is seen
    11131143                                // as a name expression
    11141144                                addAnonConversions( newCand );
     
    11201150                        // not sufficient to just pass `variableExpr` here, type might have changed since
    11211151                        // creation
    1122                         addCandidate( 
     1152                        addCandidate(
    11231153                                new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
    11241154                }
     
    11301160                void postvisit( const ast::SizeofExpr * sizeofExpr ) {
    11311161                        if ( sizeofExpr->type ) {
    1132                                 addCandidate( 
    1133                                         new ast::SizeofExpr{ 
    1134                                                 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 
     1162                                addCandidate(
     1163                                        new ast::SizeofExpr{
     1164                                                sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) },
    11351165                                        tenv );
    11361166                        } else {
     
    11411171                                CandidateList winners = findMinCost( finder.candidates );
    11421172                                if ( winners.size() != 1 ) {
    1143                                         SemanticError( 
     1173                                        SemanticError(
    11441174                                                sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
    11451175                                }
     
    11541184                void postvisit( const ast::AlignofExpr * alignofExpr ) {
    11551185                        if ( alignofExpr->type ) {
    1156                                 addCandidate( 
    1157                                         new ast::AlignofExpr{ 
    1158                                                 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 
     1186                                addCandidate(
     1187                                        new ast::AlignofExpr{
     1188                                                alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) },
    11591189                                        tenv );
    11601190                        } else {
     
    11651195                                CandidateList winners = findMinCost( finder.candidates );
    11661196                                if ( winners.size() != 1 ) {
    1167                                         SemanticError( 
     1197                                        SemanticError(
    11681198                                                alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
    11691199                                }
     
    11721202                                choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    11731203                                choice->cost = Cost::zero;
    1174                                 addCandidate( 
     1204                                addCandidate(
    11751205                                        *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
    11761206                        }
     
    11851215                        for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
    11861216                                auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
    1187                                 addCandidate( 
     1217                                addCandidate(
    11881218                                        new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
    11891219                        }
     
    12061236                        finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
    12071237                        if ( finder2.candidates.empty() ) return;
     1238
     1239                        reason.code = NoMatch;
    12081240
    12091241                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    12181250
    12191251                                        addCandidate(
    1220                                                 new ast::LogicalExpr{ 
     1252                                                new ast::LogicalExpr{
    12211253                                                        logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
    12221254                                                move( env ), move( open ), move( need ), r1->cost + r2->cost );
     
    12401272                        finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    12411273                        if ( finder3.candidates.empty() ) return;
     1274
     1275                        reason.code = NoMatch;
    12421276
    12431277                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    12561290                                                ast::AssertionSet have;
    12571291
    1258                                                 // unify true and false results, then infer parameters to produce new 
     1292                                                // unify true and false results, then infer parameters to produce new
    12591293                                                // candidates
    12601294                                                ast::ptr< ast::Type > common;
    1261                                                 if ( 
    1262                                                         unify( 
    1263                                                                 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 
    1264                                                                 common ) 
     1295                                                if (
     1296                                                        unify(
     1297                                                                r2->expr->result, r3->expr->result, env, need, have, open, symtab,
     1298                                                                common )
    12651299                                                ) {
    12661300                                                        // generate typed expression
    1267                                                         ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 
     1301                                                        ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
    12681302                                                                conditionalExpr->location, r1->expr, r2->expr, r3->expr };
    12691303                                                        newExpr->result = common ? common : r2->expr->result;
    12701304                                                        // convert both options to result type
    12711305                                                        Cost cost = r1->cost + r2->cost + r3->cost;
    1272                                                         newExpr->arg2 = computeExpressionConversionCost( 
     1306                                                        newExpr->arg2 = computeExpressionConversionCost(
    12731307                                                                newExpr->arg2, newExpr->result, symtab, env, cost );
    12741308                                                        newExpr->arg3 = computeExpressionConversionCost(
     
    12871321                        ast::TypeEnvironment env{ tenv };
    12881322                        ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env );
    1289                        
     1323
    12901324                        CandidateFinder finder2{ symtab, env };
    12911325                        finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
     
    13171351                        finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
    13181352                        if ( finder2.candidates.empty() ) return;
     1353
     1354                        reason.code = NoMatch;
    13191355
    13201356                        for ( const CandidateRef & r1 : finder1.candidates ) {
     
    13301366
    13311367                                        ast::ptr< ast::Type > common;
    1332                                         if ( 
    1333                                                 unify( 
    1334                                                         r1->expr->result, r2->expr->result, env, need, have, open, symtab, 
    1335                                                         common ) 
     1368                                        if (
     1369                                                unify(
     1370                                                        r1->expr->result, r2->expr->result, env, need, have, open, symtab,
     1371                                                        common )
    13361372                                        ) {
    13371373                                                // generate new expression
    1338                                                 ast::RangeExpr * newExpr = 
     1374                                                ast::RangeExpr * newExpr =
    13391375                                                        new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
    13401376                                                newExpr->result = common ? common : r1->expr->result;
    13411377                                                // add candidate
    13421378                                                CandidateRef newCand = std::make_shared<Candidate>(
    1343                                                         newExpr, move( env ), move( open ), move( need ), 
     1379                                                        newExpr, move( env ), move( open ), move( need ),
    13441380                                                        r1->cost + r2->cost );
    13451381                                                inferParameters( newCand, candidates );
     
    13501386
    13511387                void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
    1352                         std::vector< CandidateFinder > subCandidates = 
     1388                        std::vector< CandidateFinder > subCandidates =
    13531389                                selfFinder.findSubExprs( tupleExpr->exprs );
    13541390                        std::vector< CandidateList > possibilities;
     
    13701406
    13711407                                addCandidate(
    1372                                         new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 
     1408                                        new ast::TupleExpr{ tupleExpr->location, move( exprs ) },
    13731409                                        move( env ), move( open ), move( need ), sumCost( subs ) );
    13741410                        }
     
    14121448                                toType = SymTab::validateType( initExpr->location, toType, symtab );
    14131449                                toType = adjustExprType( toType, tenv, symtab );
    1414                                 // The call to find must occur inside this loop, otherwise polymorphic return 
    1415                                 // types are not bound to the initialization type, since return type variables are 
    1416                                 // only open for the duration of resolving the UntypedExpr. 
     1450                                // The call to find must occur inside this loop, otherwise polymorphic return
     1451                                // types are not bound to the initialization type, since return type variables are
     1452                                // only open for the duration of resolving the UntypedExpr.
    14171453                                CandidateFinder finder{ symtab, tenv, toType };
    14181454                                finder.find( initExpr->expr, ResolvMode::withAdjustment() );
    14191455                                for ( CandidateRef & cand : finder.candidates ) {
     1456                                        if(reason.code == NotFound) reason.code = NoMatch;
     1457
    14201458                                        ast::TypeEnvironment env{ cand->env };
    14211459                                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     
    14261464                                        )
    14271465
    1428                                         // It is possible that a cast can throw away some values in a multiply-valued 
    1429                                         // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 
    1430                                         // the subexpression results that are cast directly. The candidate is invalid 
     1466                                        // It is possible that a cast can throw away some values in a multiply-valued
     1467                                        // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
     1468                                        // the subexpression results that are cast directly. The candidate is invalid
    14311469                                        // if it has fewer results than there are types to cast to.
    14321470                                        int discardedValues = cand->expr->result->size() - toType->size();
     
    14351473                                        // unification run for side-effects
    14361474                                        unify( toType, cand->expr->result, env, need, have, open, symtab );
    1437                                         Cost thisCost = castCost( cand->expr->result, toType, symtab, env );
    1438                                        
     1475                                        Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1476                                                        symtab, env );
     1477
    14391478                                        if ( thisCost != Cost::infinity ) {
    14401479                                                // count one safe conversion for each value that is thrown away
    14411480                                                thisCost.incSafe( discardedValues );
    1442                                                 CandidateRef newCand = std::make_shared<Candidate>( 
    1443                                                         new ast::InitExpr{ 
    1444                                                                 initExpr->location, restructureCast( cand->expr, toType ), 
    1445                                                                 initAlt.designation }, 
    1446                                                         copy( cand->env ), move( open ), move( need ), cand->cost, thisCost );
     1481                                                CandidateRef newCand = std::make_shared<Candidate>(
     1482                                                        new ast::InitExpr{
     1483                                                                initExpr->location, restructureCast( cand->expr, toType ),
     1484                                                                initAlt.designation },
     1485                                                        move(env), move( open ), move( need ), cand->cost, thisCost );
    14471486                                                inferParameters( newCand, matches );
    14481487                                        }
     
    14691508        };
    14701509
    1471         /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
     1510        // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
     1511        /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
    14721512        /// return type. Skips ambiguous candidates.
    14731513        CandidateList pruneCandidates( CandidateList & candidates ) {
     
    14861526                        {
    14871527                                ast::ptr< ast::Type > newType = candidate->expr->result;
     1528                                assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
    14881529                                candidate->env.apply( newType );
    14891530                                mangleName = Mangle::mangle( newType );
     
    14941535                                if ( candidate->cost < found->second.candidate->cost ) {
    14951536                                        PRINT(
    1496                                                 std::cerr << "cost " << candidate->cost << " beats " 
     1537                                                std::cerr << "cost " << candidate->cost << " beats "
    14971538                                                        << found->second.candidate->cost << std::endl;
    14981539                                        )
     
    15001541                                        found->second = PruneStruct{ candidate };
    15011542                                } else if ( candidate->cost == found->second.candidate->cost ) {
    1502                                         // if one of the candidates contains a deleted identifier, can pick the other, 
    1503                                         // since deleted expressions should not be ambiguous if there is another option 
     1543                                        // if one of the candidates contains a deleted identifier, can pick the other,
     1544                                        // since deleted expressions should not be ambiguous if there is another option
    15041545                                        // that is at least as good
    15051546                                        if ( findDeletedExpr( candidate->expr ) ) {
     
    15151556                                } else {
    15161557                                        PRINT(
    1517                                                 std::cerr << "cost " << candidate->cost << " loses to " 
     1558                                                std::cerr << "cost " << candidate->cost << " loses to "
    15181559                                                        << found->second.candidate->cost << std::endl;
    15191560                                        )
     
    15301571
    15311572                        CandidateRef cand = target.second.candidate;
    1532                        
     1573
    15331574                        ast::ptr< ast::Type > newResult = cand->expr->result;
    15341575                        cand->env.applyFree( newResult );
    15351576                        cand->expr = ast::mutate_field(
    15361577                                cand->expr.get(), &ast::Expr::result, move( newResult ) );
    1537                        
     1578
    15381579                        out.emplace_back( cand );
    15391580                }
     
    15491590
    15501591        if ( mode.failFast && candidates.empty() ) {
    1551                 SemanticError( expr, "No reasonable alternatives for expression " );
     1592                switch(finder.core.reason.code) {
     1593                case Finder::NotFound:
     1594                        { SemanticError( expr, "No alternatives for expression " ); break; }
     1595                case Finder::NoMatch:
     1596                        { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
     1597                case Finder::ArgsToFew:
     1598                case Finder::ArgsToMany:
     1599                case Finder::RetsToFew:
     1600                case Finder::RetsToMany:
     1601                case Finder::NoReason:
     1602                default:
     1603                        { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
     1604                }
    15521605        }
    15531606
     
    15581611                std::vector< std::string > errors;
    15591612                for ( CandidateRef & candidate : candidates ) {
    1560                         satisfyAssertions( candidate, symtab, satisfied, errors );
     1613                        satisfyAssertions( candidate, localSyms, satisfied, errors );
    15611614                }
    15621615
     
    15831636
    15841637                CandidateList pruned = pruneCandidates( candidates );
    1585                
     1638
    15861639                if ( mode.failFast && pruned.empty() ) {
    15871640                        std::ostringstream stream;
     
    16021655                )
    16031656                PRINT(
    1604                         std::cerr << "there are " << candidates.size() << " alternatives after elimination" 
     1657                        std::cerr << "there are " << candidates.size() << " alternatives after elimination"
    16051658                                << std::endl;
    16061659                )
    16071660        }
    16081661
    1609         // adjust types after pruning so that types substituted by pruneAlternatives are correctly 
     1662        // adjust types after pruning so that types substituted by pruneAlternatives are correctly
    16101663        // adjusted
    16111664        if ( mode.adjust ) {
    16121665                for ( CandidateRef & r : candidates ) {
    1613                         r->expr = ast::mutate_field( 
    1614                                 r->expr.get(), &ast::Expr::result, 
    1615                                 adjustExprType( r->expr->result, r->env, symtab ) );
     1666                        r->expr = ast::mutate_field(
     1667                                r->expr.get(), &ast::Expr::result,
     1668                                adjustExprType( r->expr->result, r->env, localSyms ) );
    16161669                }
    16171670        }
     
    16251678}
    16261679
    1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 
    1628         const std::vector< ast::ptr< ast::Expr > > & xs 
     1680std::vector< CandidateFinder > CandidateFinder::findSubExprs(
     1681        const std::vector< ast::ptr< ast::Expr > > & xs
    16291682) {
    16301683        std::vector< CandidateFinder > out;
    16311684
    16321685        for ( const auto & x : xs ) {
    1633                 out.emplace_back( symtab, env );
     1686                out.emplace_back( localSyms, env );
    16341687                out.back().find( x, ResolvMode::withAdjustment() );
    1635                
     1688
    16361689                PRINT(
    16371690                        std::cerr << "findSubExprs" << std::endl;
  • src/ResolvExpr/CandidateFinder.hpp

    r67ca73e re67a82d  
    99// Author           : Aaron B. Moss
    1010// Created On       : Wed Jun 5 14:30:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Wed Jun 5 14:30:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct  1  9:51:00 2019
     13// Update Count     : 2
    1414//
    1515
     
    2828struct CandidateFinder {
    2929        CandidateList candidates;          ///< List of candidate resolutions
    30         const ast::SymbolTable & symtab;   ///< Symbol table to lookup candidates
     30        const ast::SymbolTable & localSyms;   ///< Symbol table to lookup candidates
    3131        const ast::TypeEnvironment & env;  ///< Substitutions performed in this resolution
    3232        ast::ptr< ast::Type > targetType;  ///< Target type for resolution
    3333
    34         CandidateFinder( 
    35                 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
     34        CandidateFinder(
     35                const ast::SymbolTable & syms, const ast::TypeEnvironment & env,
    3636                const ast::Type * tt = nullptr )
    37         : candidates(), symtab( symtab ), env( env ), targetType( tt ) {}
     37        : candidates(), localSyms( syms ), env( env ), targetType( tt ) {}
    3838
    3939        /// Fill candidates with feasible resolutions for `expr`
     
    4949        iterator begin() { return candidates.begin(); }
    5050        const_iterator begin() const { return candidates.begin(); }
    51        
     51
    5252        iterator end() { return candidates.end(); }
    5353        const_iterator end() const { return candidates.end(); }
     
    5555
    5656/// Computes conversion cost between two types
    57 Cost computeConversionCost( 
    58         const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,
    59         const ast::TypeEnvironment & env );
     57Cost computeConversionCost(
     58        const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
     59        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
    6060
    6161} // namespace ResolvExpr
  • src/ResolvExpr/CastCost.cc

    r67ca73e re67a82d  
    1010// Created On       : Sun May 17 06:57:43 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Aug  8 16:12:00 2019
    13 // Update Count     : 8
     12// Last Modified On : Tue Oct  4 15:00:00 2019
     13// Update Count     : 9
    1414//
    1515
     
    142142
    143143                CastCost_new(
    144                         const ast::Type * dst, const ast::SymbolTable & symtab,
     144                        const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
    145145                        const ast::TypeEnvironment & env, CostCalculation costFunc )
    146                 : ConversionCost_new( dst, symtab, env, costFunc ) {}
     146                : ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {}
    147147
    148148                void postvisit( const ast::BasicType * basicType ) {
     
    152152                                cost = Cost::unsafe;
    153153                        } else {
    154                                 cost = conversionCost( basicType, dst, symtab, env );
     154                                cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env );
    155155                        }
    156156                }
     
    183183                }
    184184        };
     185
     186        #warning For overload resolution between the two versions.
     187        int localPtrsCastable(const ast::Type * t1, const ast::Type * t2,
     188                        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) {
     189                return ptrsCastable( t1, t2, symtab, env );
     190        }
     191        Cost localCastCost(
     192                const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     193                const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     194        ) { return castCost( src, dst, srcIsLvalue, symtab, env ); }
    185195} // anonymous namespace
    186196
     197
     198
    187199Cost castCost(
    188         const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    189         const ast::TypeEnvironment & env
     200        const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     201        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    190202) {
    191203        if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
     
    193205                        // check cast cost against bound type, if present
    194206                        if ( eqvClass->bound ) {
    195                                 return castCost( src, eqvClass->bound, symtab, env );
     207                                return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env );
    196208                        } else {
    197209                                return Cost::infinity;
     
    201213                        auto type = strict_dynamic_cast< const ast::TypeDecl * >( named );
    202214                        if ( type->base ) {
    203                                 return castCost( src, type->base, symtab, env ) + Cost::safe;
     215                                return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
    204216                        }
    205217                }
     
    224236                #warning cast on ptrsCastable artifact of having two functions, remove when port done
    225237                return convertToReferenceCost(
    226                         src, refType, symtab, env,
    227                         ( int (*)(
    228                                 const ast::Type *, const ast::Type *, const ast::SymbolTable &,
    229                                 const ast::TypeEnvironment & )
    230                         ) ptrsCastable );
     238                        src, refType, srcIsLvalue, symtab, env, localPtrsCastable );
    231239        } else {
    232240                #warning cast on castCost artifact of having two functions, remove when port done
    233                 ast::Pass< CastCost_new > converter{
    234                         dst, symtab, env,
    235                         ( Cost (*)(
    236                                 const ast::Type *, const ast::Type *, const ast::SymbolTable &,
    237                                 const ast::TypeEnvironment & )
    238                         ) castCost };
     241                ast::Pass< CastCost_new > converter(
     242                        dst, srcIsLvalue, symtab, env, localCastCost );
    239243                src->accept( converter );
    240                 return converter.pass.cost;
     244                return converter.core.cost;
    241245        }
    242246}
  • src/ResolvExpr/CommonType.cc

    r67ca73e re67a82d  
    666666                const ast::OpenVarSet & open;
    667667        public:
     668                static size_t traceId;
    668669                ast::ptr< ast::Type > result;
    669670
     
    893894        };
    894895
     896        // size_t CommonType_new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new");
    895897        namespace {
    896898                ast::ptr< ast::Type > handleReference(
     
    939941                        ast::ptr< ast::Type > result;
    940942                        const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >();
    941                         const ast::ReferenceType * ref2 = type1.as< ast::ReferenceType >();
     943                        const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >();
    942944
    943945                        if ( depth1 > depth2 ) {
     
    966968                ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open };
    967969                type1->accept( visitor );
    968                 ast::ptr< ast::Type > result = visitor.pass.result;
     970                ast::ptr< ast::Type > result = visitor.core.result;
    969971
    970972                // handling for opaque type declarations (?)
  • src/ResolvExpr/ConversionCost.cc

    r67ca73e re67a82d  
    481481        }
    482482
    483 static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
    484                 const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
    485         return ptrsAssignable( t1, t2, env );
    486 }
    487 
    488 // TODO: This is used for overload resolution. It might be able to be dropped once the old system
    489 // is removed.
    490 static Cost localConversionCost(
    491         const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    492         const ast::TypeEnvironment & env
    493 ) { return conversionCost( src, dst, symtab, env ); }
     483namespace {
     484        # warning For overload resolution between the two versions.
     485        int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
     486                        const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
     487                return ptrsAssignable( t1, t2, env );
     488        }
     489        Cost localConversionCost(
     490                const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     491                const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     492        ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); }
     493}
    494494
    495495Cost conversionCost(
    496         const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    497         const ast::TypeEnvironment & env
     496        const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     497        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
    498498) {
    499499        if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
    500500                if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) {
    501501                        if ( eqv->bound ) {
    502                                 return conversionCost(src, eqv->bound, symtab, env );
     502                                return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env );
    503503                        } else {
    504504                                return Cost::infinity;
     
    508508                        assertf( type, "Unexpected typedef." );
    509509                        if ( type->base ) {
    510                                 return conversionCost( src, type->base, symtab, env ) + Cost::safe;
     510                                return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
    511511                        }
    512512                }
     
    518518        } else if ( const ast::ReferenceType * refType =
    519519                         dynamic_cast< const ast::ReferenceType * >( dst ) ) {
    520                 return convertToReferenceCost( src, refType, symtab, env, localPtrsAssignable );
     520                return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable );
    521521        } else {
    522                 ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
     522                ast::Pass<ConversionCost_new> converter( dst, srcIsLvalue, symtab, env, localConversionCost );
    523523                src->accept( converter );
    524                 return converter.pass.cost;
    525         }
    526 }
    527 
    528 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst,
     524                return converter.core.cost;
     525        }
     526}
     527
     528static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    529529                int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
    530                 NumCostCalculation func ) {
     530                PtrsCalculation func ) {
    531531        if ( 0 < diff ) {
    532532                Cost cost = convertToReferenceCost(
    533                         strict_dynamic_cast< const ast::ReferenceType * >( src )->base,
    534                         dst, (diff - 1), symtab, env, func );
     533                        strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst,
     534                        srcIsLvalue, (diff - 1), symtab, env, func );
    535535                cost.incReference();
    536536                return cost;
     
    538538                Cost cost = convertToReferenceCost(
    539539                        src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base,
    540                         (diff + 1), symtab, env, func );
     540                        srcIsLvalue, (diff + 1), symtab, env, func );
    541541                cost.incReference();
    542542                return cost;
     
    563563                        }
    564564                } else {
    565                         ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
     565                        ast::Pass<ConversionCost_new> converter( dst, srcIsLvalue, symtab, env, localConversionCost );
    566566                        src->accept( converter );
    567                         return converter.pass.cost;
     567                        return converter.core.cost;
    568568                }
    569569        } else {
     
    572572                assert( dstAsRef );
    573573                if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) {
    574                         if ( src->is_lvalue() ) {
     574                        if ( srcIsLvalue ) {
    575575                                if ( src->qualifiers == dstAsRef->base->qualifiers ) {
    576576                                        return Cost::reference;
     
    591591
    592592Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst,
    593             const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
    594                 NumCostCalculation func ) {
     593                bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
     594                PtrsCalculation func ) {
    595595        int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth();
    596         return convertToReferenceCost( src, dst, sdepth - ddepth, symtab, env, func );
     596        return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func );
    597597}
    598598
     
    651651        assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) );
    652652
    653         cost = costCalc( refType->base, dst, symtab, env );
     653        cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env );
    654654        if ( refType->base->qualifiers == dst->qualifiers ) {
    655655                cost.incReference();
     
    667667void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) {
    668668        (void)enumInstType;
    669         static const ast::BasicType integer( ast::BasicType::SignedInt );
    670         cost = costCalc( &integer, dst, symtab, env );
     669        static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
     670        cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
    671671        if ( cost < Cost::unsafe ) {
    672672                cost.incSafe();
     
    680680void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
    681681        if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
    682                 cost = costCalc( eqv->bound, dst, symtab, env );
     682                cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
    683683        } else if ( const ast::TypeInstType * dstAsInst =
    684684                        dynamic_cast< const ast::TypeInstType * >( dst ) ) {
     
    690690                assertf( type, "Unexpected typedef.");
    691691                if ( type->base ) {
    692                         cost = costCalc( type->base, dst, symtab, env ) + Cost::safe;
     692                        cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe;
    693693                }
    694694        }
     
    703703                auto dstEnd = dstAsTuple->types.end();
    704704                while ( srcIt != srcEnd && dstIt != dstEnd ) {
    705                         Cost newCost = costCalc( * srcIt++, * dstIt++, symtab, env );
     705                        Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env );
    706706                        if ( newCost == Cost::infinity ) {
    707707                                return;
     
    738738                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    739739                }
     740        } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
     741                cost = Cost::zero;
     742                // +1 for zero_t ->, +1 for disambiguation
     743                cost.incSafe( maxIntCost + 2 );
    740744        }
    741745}
     
    755759                        cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
    756760                }
    757         } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
    758                 cost = Cost::zero;
    759                 cost.incSafe( maxIntCost + 2 );
    760         }
    761 }
    762 
     761        }
     762}
     763// size_t ConversionCost_new::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
    763764
    764765} // namespace ResolvExpr
  • src/ResolvExpr/ConversionCost.h

    r67ca73e re67a82d  
    7272
    7373// Some function pointer types, differ in return type.
    74 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *,
     74using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool,
    7575        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
    76 using NumCostCalculation = std::function<int(const ast::Type *, const ast::Type *,
     76using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *,
    7777        const ast::SymbolTable &, const ast::TypeEnvironment &)>;
    7878
     
    8181protected:
    8282        const ast::Type * dst;
     83        bool srcIsLvalue;
    8384        const ast::SymbolTable & symtab;
    8485        const ast::TypeEnvironment & env;
    8586        CostCalculation costCalc;
    8687public:
     88        static size_t traceId;
    8789        Cost cost;
    8890
    89         ConversionCost_new( const ast::Type * dst, const ast::SymbolTable & symtab,
     91        ConversionCost_new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
    9092                        const ast::TypeEnvironment & env, CostCalculation costCalc ) :
    91                 dst( dst ), symtab( symtab ), env( env ), costCalc( costCalc ), cost( Cost::infinity )
     93                dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ),
     94                costCalc( costCalc ), cost( Cost::infinity )
    9295        {}
    9396
     
    110113
    111114Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest,
    112         const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, NumCostCalculation func );
     115        bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env,
     116        PtrsCalculation func );
    113117
    114118} // namespace ResolvExpr
  • src/ResolvExpr/CurrentObject.cc

    r67ca73e re67a82d  
    2121#include <string>                      // for string, operator<<, allocator
    2222
     23#include "AST/Copy.hpp"                // for shallowCopy
    2324#include "AST/Expr.hpp"                // for InitAlternative
    2425#include "AST/GenericSubstitution.hpp" // for genericSubstitution
    2526#include "AST/Init.hpp"                // for Designation
    2627#include "AST/Node.hpp"                // for readonly
     28#include "AST/Print.hpp"                // for readonly
    2729#include "AST/Type.hpp"
    2830#include "Common/Indenter.h"           // for Indenter, operator<<
     
    596598                SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
    597599
    598                 void setPosition( 
    599                         std::deque< ptr< Expr > >::const_iterator begin, 
     600                void setPosition(
     601                        std::deque< ptr< Expr > >::const_iterator begin,
    600602                        std::deque< ptr< Expr > >::const_iterator end
    601603                ) override {
     
    637639                        auto res = eval(expr);
    638640                        if ( ! res.second ) {
    639                                 SemanticError( location, 
     641                                SemanticError( location,
    640642                                        toString("Array designator must be a constant expression: ", expr ) );
    641643                        }
     
    644646
    645647        public:
    646                 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 
     648                ArrayIterator( const CodeLocation & loc, const ArrayType * at )
    647649                : location( loc ), array( at ), base( at->base ) {
    648650                        PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
     
    655657
    656658                void setPosition( const Expr * expr ) {
    657                         // need to permit integer-constant-expressions, including: integer constants, 
    658                         // enumeration constants, character constants, sizeof expressions, alignof expressions, 
     659                        // need to permit integer-constant-expressions, including: integer constants,
     660                        // enumeration constants, character constants, sizeof expressions, alignof expressions,
    659661                        // cast expressions
    660662                        if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     
    662664                                        index = constExpr->intValue();
    663665                                } catch ( SemanticErrorException & ) {
    664                                         SemanticError( expr, 
     666                                        SemanticError( expr,
    665667                                                "Constant expression of non-integral type in array designator: " );
    666668                                }
    667669                        } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
    668670                                setPosition( castExpr->arg );
    669                         } else if ( 
    670                                 dynamic_cast< const SizeofExpr * >( expr ) 
    671                                 || dynamic_cast< const AlignofExpr * >( expr ) 
     671                        } else if (
     672                                dynamic_cast< const SizeofExpr * >( expr )
     673                                || dynamic_cast< const AlignofExpr * >( expr )
    672674                        ) {
    673675                                index = 0;
    674676                        } else {
    675                                 assertf( false, 
     677                                assertf( false,
    676678                                        "bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
    677679                        }
    678680                }
    679681
    680                 void setPosition( 
    681                         std::deque< ptr< Expr > >::const_iterator begin, 
     682                void setPosition(
     683                        std::deque< ptr< Expr > >::const_iterator begin,
    682684                        std::deque< ptr< Expr > >::const_iterator end
    683685                ) override {
     
    758760                }
    759761
    760                 AggregateIterator( 
    761                         const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 
     762                AggregateIterator(
     763                        const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
    762764                        const MemberList & ms )
    763                 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 
     765                : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
    764766                  sub( genericSubstitution( i ) ) {
    765767                        PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
     
    768770
    769771        public:
    770                 void setPosition( 
    771                         std::deque< ptr< Expr > >::const_iterator begin, 
     772                void setPosition(
     773                        std::deque< ptr< Expr > >::const_iterator begin,
    772774                        std::deque< ptr< Expr > >::const_iterator end
    773775                ) final {
     
    786788                                        return;
    787789                                }
    788                                 assertf( false, 
     790                                assertf( false,
    789791                                        "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
    790792                        } else {
    791                                 assertf( false, 
     793                                assertf( false,
    792794                                        "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
    793795                        }
     
    803805                                                new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
    804806                                        // need to substitute for generic types so that casts are to concrete types
     807                                        alt.type = shallowCopy(alt.type.get());
    805808                                        PRINT( std::cerr << "  type is: " << alt.type; )
    806809                                        sub.apply( alt.type ); // also apply to designation??
     
    842845                                for ( InitAlternative & alt : ret ) {
    843846                                        PRINT( std::cerr << "iterating and adding designators" << std::endl; )
    844                                         alt.designation.get_and_mutate()->designators.emplace_front( 
     847                                        alt.designation.get_and_mutate()->designators.emplace_front(
    845848                                                new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
    846849                                }
     
    897900        class TupleIterator final : public AggregateIterator {
    898901        public:
    899                 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 
    900                 : AggregateIterator( 
    901                         loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 
     902                TupleIterator( const CodeLocation & loc, const TupleType * inst )
     903                : AggregateIterator(
     904                        loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members
    902905                ) {}
    903906
     
    926929                                return new UnionIterator{ loc, uit };
    927930                        } else {
    928                                 assertf( 
    929                                         dynamic_cast< const EnumInstType * >( aggr )
    930                                                 || dynamic_cast< const TypeInstType * >( aggr ),
     931                                assertf(
     932                                        dynamic_cast< const EnumInstType * >( type )
     933                                                || dynamic_cast< const TypeInstType * >( type ),
    931934                                        "Encountered unhandled ReferenceToType in createMemberIterator: %s",
    932935                                                toString( type ).c_str() );
     
    949952                using DesignatorChain = std::deque< ptr< Expr > >;
    950953                PRINT( std::cerr << "___findNext" << std::endl; )
    951                
     954
    952955                // find all the d's
    953956                std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
     
    10131016                // set new designators
    10141017                assertf( ! objStack.empty(), "empty object stack when setting designation" );
    1015                 Designation * actualDesignation = 
     1018                Designation * actualDesignation =
    10161019                        new Designation{ designation->location, DesignatorChain{d} };
    10171020                objStack.back()->setPosition( d ); // destroys d
  • src/ResolvExpr/PolyCost.cc

    r67ca73e re67a82d  
    5858
    5959// TODO: When the old PolyCost is torn out get rid of the _new suffix.
    60 struct PolyCost_new {
     60class PolyCost_new {
     61        const ast::SymbolTable &symtab;
     62public:
    6163        int result;
    62         const ast::SymbolTable &symtab;
    6364        const ast::TypeEnvironment &env_;
    6465
    65         PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :
    66                 result( 0 ), symtab( symtab ), env_( env ) {}
     66        PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env )
     67        : symtab( symtab ), result( 0 ), env_( env ) {}
    6768
    6869        void previsit( const ast::TypeInstType * type ) {
     
    8687        ast::Pass<PolyCost_new> costing( symtab, env );
    8788        type->accept( costing );
    88         return costing.pass.result;
     89        return costing.core.result;
    8990}
    9091
  • src/ResolvExpr/PtrsAssignable.cc

    r67ca73e re67a82d  
    155155                ast::Pass<PtrsAssignable_new> visitor( dst, env );
    156156                src->accept( visitor );
    157                 return visitor.pass.result;
     157                return visitor.core.result;
    158158        }
    159159
  • src/ResolvExpr/PtrsCastable.cc

    r67ca73e re67a82d  
    293293                ast::Pass< PtrsCastable_new > ptrs{ dst, env, symtab };
    294294                src->accept( ptrs );
    295                 return ptrs.pass.result;
     295                return ptrs.core.result;
    296296        }
    297297}
  • src/ResolvExpr/RenameVars.cc

    r67ca73e re67a82d  
    1919#include <utility>                 // for pair
    2020
     21#include "AST/ForallSubstitutionTable.hpp"
    2122#include "AST/Pass.hpp"
    2223#include "AST/Type.hpp"
     
    3031#include "SynTree/Visitor.h"       // for acceptAll, maybeAccept
    3132
     33#include "AST/Copy.hpp"
     34
    3235namespace ResolvExpr {
    3336
     
    3740                int resetCount = 0;
    3841                ScopedMap< std::string, std::string > nameMap;
     42        public:
     43                ast::ForallSubstitutionTable subs;
    3944
    40         public:
    4145                void reset() {
    4246                        level = 0;
     
    4448                }
    4549
    46                 using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;
    47 
    4850                void rename( TypeInstType * type ) {
    49                         mapConstIterator it = nameMap.find( type->name );
     51                        auto it = nameMap.find( type->name );
    5052                        if ( it != nameMap.end() ) {
    5153                                type->name = it->second;
     
    6567                                        // ditto for assertion names, the next level in
    6668                                        level++;
    67                                         // acceptAll( td->assertions, *this );
    68                                 } // for
    69                         } // if
     69                                }
     70                        }
    7071                }
    7172
     
    7778
    7879                const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
    79                         mapConstIterator it = nameMap.find( type->name );
     80                        // re-linking of base type handled by WithForallSubstitutor
     81
     82                        // rename
     83                        auto it = nameMap.find( type->name );
    8084                        if ( it != nameMap.end() ) {
    81                                 ast::TypeInstType * mutType = ast::mutate( type );
    82                                 mutType->name = it->second;
    83                     type = mutType;
     85                                // unconditionally mutate because map will *always* have different name,
     86                                // if this mutates, will *always* have been mutated by ForallSubstitutor above
     87                                ast::TypeInstType * mut = ast::mutate( type );
     88                                mut->name = it->second;
     89                    type = mut;
    8490                        }
     91
    8592                        return type;
    8693                }
     
    8895                template<typename NodeT>
    8996                const NodeT * openLevel( const NodeT * type ) {
    90                         if ( !type->forall.empty() ) {
    91                                 nameMap.beginScope();
    92                                 // Load new names from this forall clause and perform renaming.
    93                                 NodeT * mutType = ast::mutate( type );
    94                                 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
    95                                         std::ostringstream output;
    96                                         output << "_" << resetCount << "_" << level << "_" << td->name;
    97                                         std::string newname( output.str() );
    98                                         nameMap[ td->name ] = newname;
    99                                         ++level;
     97                        if ( type->forall.empty() ) return type;
    10098
    101                                         ast::TypeDecl * decl = ast::mutate( td.get() );
    102                                         decl->name = newname;
    103                                         td = decl;
    104                                 }
     99                        nameMap.beginScope();
     100
     101                        // Load new names from this forall clause and perform renaming.
     102                        NodeT * mutType = ast::mutate( type );
     103                        assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
     104                        for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
     105                                std::ostringstream output;
     106                                output << "_" << resetCount << "_" << level << "_" << td->name;
     107                                std::string newname =  output.str();
     108                                nameMap[ td->name ] = newname;
     109                                ++level;
     110
     111                                ast::TypeDecl * mutDecl = ast::mutate( td.get() );
     112                                assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
     113                                mutDecl->name = newname;
     114                                // assertion above means `td = mutDecl;` is unnecessary
    105115                        }
     116                        // assertion above means `type = mutType;` is unnecessary
     117
    106118                        return type;
    107119                }
    108120
    109                 template<typename NodeT>
    110                 const NodeT * closeLevel( const NodeT * type ) {
    111                         if ( !type->forall.empty() ) {
    112                                 nameMap.endScope();
    113                         }
    114                         return type;
     121                void closeLevel( const ast::ParameterizedType * type ) {
     122                        if ( type->forall.empty() ) return;
     123
     124                        nameMap.endScope();
    115125                }
    116126        };
     
    119129        RenamingData renaming;
    120130
    121         struct RenameVars {
     131        struct RenameVars_old {
    122132                void previsit( TypeInstType * instType ) {
    123133                        renaming.openLevel( (Type*)instType );
     
    130140                        renaming.closeLevel( type );
    131141                }
     142        };
     143
     144        struct RenameVars_new /*: public ast::WithForallSubstitutor*/ {
     145                #warning when old RenameVars goes away, replace hack below with global pass inheriting from WithForallSubstitutor
     146                ast::ForallSubstitutionTable & subs = renaming.subs;
    132147
    133148                const ast::FunctionType * previsit( const ast::FunctionType * type ) {
     
    146161                        return renaming.rename( renaming.openLevel( type ) );
    147162                }
    148                 const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) {
    149                         return renaming.closeLevel( type );
     163                void postvisit( const ast::ParameterizedType * type ) {
     164                        renaming.closeLevel( type );
    150165                }
    151166        };
     
    154169
    155170void renameTyVars( Type * t ) {
    156         PassVisitor<RenameVars> renamer;
     171        PassVisitor<RenameVars_old> renamer;
    157172        t->accept( renamer );
    158173}
    159174
    160175const ast::Type * renameTyVars( const ast::Type * t ) {
    161         ast::Pass<RenameVars> renamer;
    162         return t->accept( renamer );
     176        ast::Type *tc = ast::deepCopy(t);
     177        ast::Pass<RenameVars_new> renamer;
     178//      return t->accept( renamer );
     179        return tc->accept( renamer );
    163180}
    164181
  • src/ResolvExpr/ResolveTypeof.cc

    r67ca73e re67a82d  
    9999                        // replace basetypeof(<enum>) by int
    100100                        if ( dynamic_cast<EnumInstType*>(newType) ) {
    101                                 Type* newerType = 
    102                                         new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 
     101                                Type* newerType =
     102                                        new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,
    103103                                        newType->attributes };
    104104                                delete newType;
    105105                                newType = newerType;
    106106                        }
    107                         newType->get_qualifiers().val 
     107                        newType->get_qualifiers().val
    108108                                = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;
    109109                } else {
    110110                        newType->get_qualifiers().val |= oldQuals;
    111111                }
    112                
     112
    113113                return newType;
    114114        }
     
    120120                ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {}
    121121
    122                 void premutate( const ast::TypeofType * ) { visit_children = false; }
     122                void previsit( const ast::TypeofType * ) { visit_children = false; }
    123123
    124                 const ast::Type * postmutate( const ast::TypeofType * typeofType ) {
     124                const ast::Type * postvisit( const ast::TypeofType * typeofType ) {
    125125                        // pass on null expression
    126126                        if ( ! typeofType->expr ) return typeofType;
     
    133133                                // typeof wrapping expression
    134134                                ast::TypeEnvironment dummy;
    135                                 ast::ptr< ast::Expr > newExpr = 
     135                                ast::ptr< ast::Expr > newExpr =
    136136                                        resolveInVoidContext( typeofType->expr, localSymtab, dummy );
    137137                                assert( newExpr->result && ! newExpr->result->isVoid() );
     
    143143                                // replace basetypeof(<enum>) by int
    144144                                if ( newType.as< ast::EnumInstType >() ) {
    145                                         newType = new ast::BasicType{ 
     145                                        newType = new ast::BasicType{
    146146                                                ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) };
    147147                                }
    148                                 reset_qualifiers( 
    149                                         newType, 
     148                                reset_qualifiers(
     149                                        newType,
    150150                                        ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
    151151                        } else {
     
    153153                        }
    154154
    155                         return newType;
     155                        return newType.release();
    156156                }
    157157        };
  • src/ResolvExpr/Resolver.cc

    r67ca73e re67a82d  
    982982                ast::Pass<DeleteFinder_new> finder;
    983983                expr->accept( finder );
    984                 return finder.pass.delExpr;
     984                return finder.core.delExpr;
    985985        }
    986986
     
    10721072                /// Strips extraneous casts out of an expression
    10731073                struct StripCasts_new final {
    1074                         const ast::Expr * postmutate( const ast::CastExpr * castExpr ) {
     1074                        const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
    10751075                                if (
    1076                                         castExpr->isGenerated
     1076                                        castExpr->isGenerated == ast::GeneratedCast
    10771077                                        && typesCompatible( castExpr->arg->result, castExpr->result )
    10781078                                ) {
     
    11281128
    11291129                // set up and resolve expression cast to void
    1130                 ast::CastExpr * untyped = new ast::CastExpr{ expr };
     1130                ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
    11311131                CandidateRef choice = findUnfinishedKindExpression(
    11321132                        untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
     
    12361236
    12371237        public:
     1238                static size_t traceId;
    12381239                Resolver_new() = default;
    12391240                Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; }
     
    12661267                const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
    12671268        };
    1268 
    1269         void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit ) {
    1270                 ast::Pass< Resolver_new > resolver;
    1271                 accept_all( translationUnit, resolver );
     1269        // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver");
     1270
     1271        void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) {
     1272                ast::Pass< Resolver_new >::run( translationUnit );
    12721273        }
    12731274
     
    12991300                // default value expressions have an environment which shouldn't be there and trips up
    13001301                // later passes.
    1301                 ast::ptr< ast::FunctionDecl > ret = functionDecl;
    1302                 for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {
    1303                         const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i];
    1304 
    1305                         if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {
     1302                assert( functionDecl->unique() );
     1303                ast::FunctionType * mutType = mutate( functionDecl->type.get() );
     1304
     1305                for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
     1306                        if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
    13061307                                if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
    13071308                                        if ( init->value->env == nullptr ) continue;
    13081309                                        // clone initializer minus the initializer environment
    1309                                         ast::chain_mutate( ret )
    1310                                                 ( &ast::FunctionDecl::type )
    1311                                                         ( &ast::FunctionType::params )[i]
    1312                                                                 ( &ast::ObjectDecl::init )
    1313                                                                         ( &ast::SingleInit::value )->env = nullptr;
    1314 
    1315                                         assert( functionDecl != ret.get() || functionDecl->unique() );
    1316                                         assert( ! ret->type->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env );
     1310                                        auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
     1311                                        auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
     1312                                        auto mutValue = mutate( mutInit->value.get() );
     1313
     1314                                        mutValue->env = nullptr;
     1315                                        mutInit->value = mutValue;
     1316                                        mutParam->init = mutInit;
     1317                                        mutType->params[i] = mutParam;
     1318
     1319                                        assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
    13171320                                }
    13181321                        }
    13191322                }
    1320                 return ret.get();
     1323                mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
     1324                return functionDecl;
    13211325        }
    13221326
     
    13411345                // in case we decide to allow nested enums
    13421346                GuardValue( inEnumDecl );
    1343                 inEnumDecl = false;
     1347                inEnumDecl = true;
    13441348        }
    13451349
  • src/ResolvExpr/SatisfyAssertions.cpp

    r67ca73e re67a82d  
    99// Author           : Aaron B. Moss
    1010// Created On       : Mon Jun 10 17:45:00 2019
    11 // Last Modified By : Aaron B. Moss
    12 // Last Modified On : Mon Jun 10 17:45:00 2019
    13 // Update Count     : 1
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct  1 13:56:00 2019
     13// Update Count     : 2
    1414//
    1515
     
    188188
    189189                                matches.emplace_back(
    190                                         cdata, adjType, std::move( newEnv ), std::move( newNeed ), std::move( have ),
     190                                        cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
    191191                                        std::move( newOpen ), crntResnSlot );
    192192                        }
     
    229229                InferMatcher( InferCache & inferred ) : inferred( inferred ) {}
    230230
    231                 const ast::Expr * postmutate( const ast::Expr * expr ) {
     231                const ast::Expr * postvisit( const ast::Expr * expr ) {
    232232                        // Skip if no slots to find
    233                         if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
    234 
     233                        if ( !expr->inferred.hasSlots() ) return expr;
     234                        // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
     235                        std::vector<UniqueId> missingSlots;
    235236                        // find inferred parameters for resolution slots
    236                         ast::InferredParams newInferred;
     237                        ast::InferredParams * newInferred = new ast::InferredParams();
    237238                        for ( UniqueId slot : expr->inferred.resnSlots() ) {
    238239                                // fail if no matching assertions found
    239240                                auto it = inferred.find( slot );
    240241                                if ( it == inferred.end() ) {
    241                                         assert(!"missing assertion");
     242                                        std::cerr << "missing assertion " << slot << std::endl;
     243                                        missingSlots.push_back(slot);
     244                                        continue;
    242245                                }
    243246
     
    245248                                for ( auto & entry : it->second ) {
    246249                                        // recurse on inferParams of resolved expressions
    247                                         entry.second.expr = postmutate( entry.second.expr );
    248                                         auto res = newInferred.emplace( entry );
     250                                        entry.second.expr = postvisit( entry.second.expr );
     251                                        auto res = newInferred->emplace( entry );
    249252                                        assert( res.second && "all assertions newly placed" );
    250253                                }
     
    252255
    253256                        ast::Expr * ret = mutate( expr );
    254                         ret->inferred.set_inferParams( std::move( newInferred ) );
     257                        ret->inferred.set_inferParams( newInferred );
     258                        if (!missingSlots.empty()) ret->inferred.resnSlots() = missingSlots;
    255259                        return ret;
    256260                }
     
    299303                        Cost cost;
    300304
    301                         OutType( 
    302                                 const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 
     305                        OutType(
     306                                const ast::TypeEnvironment & e, const ast::OpenVarSet & o,
    303307                                const std::vector< DeferRef > & as, const ast::SymbolTable & symtab )
    304308                        : env( e ), open( o ), assns( as ), cost( Cost::zero ) {
     
    306310                                for ( const DeferRef & assn : assns ) {
    307311                                        // compute conversion cost from satisfying decl to assertion
    308                                         cost += computeConversionCost( 
    309                                                 assn.match.adjType, assn.decl->get_type(), symtab, env );
    310                                        
     312                                        cost += computeConversionCost(
     313                                                assn.match.adjType, assn.decl->get_type(), false, symtab, env );
     314
    311315                                        // mark vars+specialization on function-type assertions
    312                                         const ast::FunctionType * func = 
     316                                        const ast::FunctionType * func =
    313317                                                GenPoly::getFunctionType( assn.match.cdata.id->get_type() );
    314318                                        if ( ! func ) continue;
     
    317321                                                cost.decSpec( specCost( param->get_type() ) );
    318322                                        }
    319                                        
     323
    320324                                        cost.incVar( func->forall.size() );
    321                                        
     325
    322326                                        for ( const ast::TypeDecl * td : func->forall ) {
    323327                                                cost.decSpec( td->assertions.size() );
     
    329333                };
    330334
    331                 CandidateEnvMerger( 
    332                         const ast::TypeEnvironment & env, const ast::OpenVarSet & open, 
     335                CandidateEnvMerger(
     336                        const ast::TypeEnvironment & env, const ast::OpenVarSet & open,
    333337                        const ast::SymbolTable & syms )
    334338                : crnt(), envs{ env }, opens{ open }, symtab( syms ) {}
  • src/ResolvExpr/SatisfyAssertions.hpp

    r67ca73e re67a82d  
    2828
    2929/// Recursively satisfies all assertions provided in a candidate; returns true if succeeds
    30 void satisfyAssertions( 
    31         CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 
     30void satisfyAssertions(
     31        CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out,
    3232        std::vector<std::string> & errors );
    3333
  • src/ResolvExpr/SpecCost.cc

    r67ca73e re67a82d  
    1010// Created On       : Tue Oct 02 15:50:00 2018
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Jun 19 10:43:00 2019
    13 // Update Count     : 2
    14 //
    15 
     12// Last Modified On : Wed Jul  3 11:07:00 2019
     13// Update Count     : 3
     14//
     15
     16#include <cassert>
    1617#include <limits>
    1718#include <list>
     
    129130                        typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
    130131
     132                #warning Should use a standard maybe_accept
     133                void maybe_accept( ast::Type const * type ) {
     134                        if ( type ) {
     135                                auto node = type->accept( *visitor );
     136                                assert( node == nullptr || node == type );
     137                        }
     138                }
     139
    131140                // Update the minimum to the new lowest non-none value.
    132141                template<typename T>
     
    134143                        for ( const auto & node : list ) {
    135144                                count = -1;
    136                                 mapper( node )->accept( *visitor );
     145                                maybe_accept( mapper( node ) );
    137146                                if ( count != -1 && count < minimum ) minimum = count;
    138147                        }
     
    208217        }
    209218        ast::Pass<SpecCounter> counter;
    210         type->accept( *counter.pass.visitor );
    211         return counter.pass.get_count();
     219        type->accept( counter );
     220        return counter.core.get_count();
    212221}
    213222
  • src/ResolvExpr/Unify.cc

    r67ca73e re67a82d  
    2525#include <vector>
    2626
     27#include "AST/Copy.hpp"
    2728#include "AST/Decl.hpp"
    2829#include "AST/Node.hpp"
    2930#include "AST/Pass.hpp"
     31#include "AST/Print.hpp"
    3032#include "AST/Type.hpp"
    3133#include "AST/TypeEnvironment.hpp"
     
    135137                findOpenVars( newSecond, open, closed, need, have, FirstOpen );
    136138
    137                 return unifyExact(
    138                         newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
     139                return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
    139140        }
    140141
     
    148149                newFirst->get_qualifiers() = Type::Qualifiers();
    149150                newSecond->get_qualifiers() = Type::Qualifiers();
    150 ///   std::cerr << "first is ";
    151 ///   first->print( std::cerr );
    152 ///   std::cerr << std::endl << "second is ";
    153 ///   second->print( std::cerr );
    154 ///   std::cerr << std::endl << "newFirst is ";
    155 ///   newFirst->print( std::cerr );
    156 ///   std::cerr << std::endl << "newSecond is ";
    157 ///   newSecond->print( std::cerr );
    158 ///   std::cerr << std::endl;
     151
    159152                bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
    160153                delete newFirst;
     
    170163                ast::AssertionSet need, have;
    171164
    172                 ast::ptr<ast::Type> newFirst{ first }, newSecond{ second };
    173                 env.apply( newFirst );
    174                 env.apply( newSecond );
    175                 reset_qualifiers( newFirst );
    176                 reset_qualifiers( newSecond );
     165                ast::Type * newFirst  = shallowCopy( first  );
     166                ast::Type * newSecond = shallowCopy( second );
     167                newFirst ->qualifiers = {};
     168                newSecond->qualifiers = {};
     169                ast::ptr< ast::Type > t1_(newFirst );
     170                ast::ptr< ast::Type > t2_(newSecond);
     171
     172                ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
     173                ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
    177174
    178175                return unifyExact(
    179                         newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
     176                        subFirst,
     177                        subSecond,
     178                        newEnv, need, have, open, noWiden(), symtab );
    180179        }
    181180
     
    326325
    327326        void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
    328 ///   std::cerr << "assertion set is" << std::endl;
    329 ///   printAssertionSet( assertions, std::cerr, 8 );
    330 ///   std::cerr << "looking for ";
    331 ///   assert->print( std::cerr );
    332 ///   std::cerr << std::endl;
    333327                AssertionSet::iterator i = assertions.find( assert );
    334328                if ( i != assertions.end() ) {
    335 ///     std::cerr << "found it!" << std::endl;
    336329                        i->second.isUsed = true;
    337330                } // if
     
    709702                const ast::SymbolTable & symtab;
    710703        public:
     704                static size_t traceId;
    711705                bool result;
    712706
     
    797791                        for ( const ast::DeclWithType * d : src ) {
    798792                                ast::Pass<TtypeExpander_new> expander{ env };
    799                                 d = d->accept( expander );
    800                                 auto types = flatten( d->get_type() );
     793                                // TtypeExpander pass is impure (may mutate nodes in place)
     794                                // need to make nodes shared to prevent accidental mutation
     795                                ast::ptr<ast::DeclWithType> dc = d;
     796                                dc = dc->accept( expander );
     797                                auto types = flatten( dc->get_type() );
    801798                                for ( ast::ptr< ast::Type > & t : types ) {
    802799                                        // outermost const, volatile, _Atomic qualifiers in parameters should not play
     
    807804                                        // requirements than a non-mutex function
    808805                                        remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
    809                                         dst.emplace_back( new ast::ObjectDecl{ d->location, "", t } );
     806                                        dst.emplace_back( new ast::ObjectDecl{ dc->location, "", t } );
    810807                                }
    811808                        }
     
    943940
    944941        private:
    945                 template< typename RefType >
    946                 const RefType * handleRefType( const RefType * inst, const ast::Type * other ) {
     942                // Returns: other, cast as XInstType
     943                // Assigns this->result: whether types are compatible (up to generic parameters)
     944                template< typename XInstType >
     945                const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
    947946                        // check that the other type is compatible and named the same
    948                         auto otherInst = dynamic_cast< const RefType * >( other );
    949                         result = otherInst && inst->name == otherInst->name;
     947                        auto otherInst = dynamic_cast< const XInstType * >( other );
     948                        this->result = otherInst && inst->name == otherInst->name;
    950949                        return otherInst;
    951950                }
     
    968967                }
    969968
    970                 template< typename RefType >
    971                 void handleGenericRefType( const RefType * inst, const ast::Type * other ) {
     969                template< typename XInstType >
     970                void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
    972971                        // check that other type is compatible and named the same
    973                         const RefType * inst2 = handleRefType( inst, other );
    974                         if ( ! inst2 ) return;
     972                        const XInstType * otherInst = handleRefType( inst, other );
     973                        if ( ! this->result ) return;
    975974
    976975                        // check that parameters of types unify, if any
    977976                        const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
    978                         const std::vector< ast::ptr< ast::Expr > > & params2 = inst2->params;
     977                        const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
    979978
    980979                        auto it = params.begin();
     
    11141113
    11151114                        ast::Pass<TtypeExpander_new> expander{ tenv };
    1116                         const ast::Type * flat = tuple->accept( expander );
    1117                         const ast::Type * flat2 = tuple2->accept( expander );
     1115
     1116                        ast::ptr<ast::TupleType> tuplec = tuple;
     1117                        ast::ptr<ast::TupleType> tuple2c = tuple2;
     1118                        const ast::Type * flat = tuplec->accept( expander );
     1119                        const ast::Type * flat2 = tuple2c->accept( expander );
    11181120
    11191121                        auto types = flatten( flat );
     
    11401142        };
    11411143
     1144        // size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new");
    11421145        bool unify(
    11431146                        const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
     
    11881191                        ast::Pass<Unify_new> comparator{ type2, env, need, have, open, widen, symtab };
    11891192                        type1->accept( comparator );
    1190                         return comparator.pass.result;
     1193                        return comparator.core.result;
    11911194                }
    11921195        }
     
    12021205                // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
    12031206                // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
    1204                 ast::ptr<ast::Type> t1{ type1 }, t2{ type2 };
    1205                 reset_qualifiers( t1 );
    1206                 reset_qualifiers( t2 );
     1207                ast::Type * t1 = shallowCopy(type1.get());
     1208                ast::Type * t2 = shallowCopy(type2.get());
     1209                t1->qualifiers = {};
     1210                t2->qualifiers = {};
     1211                ast::ptr< ast::Type > t1_(t1);
     1212                ast::ptr< ast::Type > t2_(t2);
    12071213
    12081214                if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) {
    1209                         t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
    1210 
    12111215                        // if exact unification on unqualified types, try to merge qualifiers
    12121216                        if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
    1213                                 common = type1;
    1214                                 reset_qualifiers( common, q1 | q2 );
     1217                                t1->qualifiers = q1 | q2;
     1218                                common = t1;
    12151219                                return true;
    12161220                        } else {
     
    12191223
    12201224                } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) {
    1221                         t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
    1222 
    12231225                        // no exact unification, but common type
    1224                         reset_qualifiers( common, q1 | q2 );
     1226                        auto c = shallowCopy(common.get());
     1227                        c->qualifiers = q1 | q2;
     1228                        common = c;
    12251229                        return true;
    12261230                } else {
  • src/ResolvExpr/typeops.h

    r67ca73e re67a82d  
    1010// Created On       : Sun May 17 07:28:22 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Aug  8 16:36:00 2019
    13 // Update Count     : 5
     12// Last Modified On : Tue Oct  1 09:45:00 2019
     13// Update Count     : 6
    1414//
    1515
     
    8383                const SymTab::Indexer & indexer, const TypeEnvironment & env );
    8484        Cost castCost(
    85                 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    86                 const ast::TypeEnvironment & env );
     85                const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     86                const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
    8787
    8888        // in ConversionCost.cc
     
    9090                const SymTab::Indexer & indexer, const TypeEnvironment & env );
    9191        Cost conversionCost(
    92                 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
    93                 const ast::TypeEnvironment & env );
     92                const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     93                const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
    9494
    9595        // in AlternativeFinder.cc
  • src/SymTab/Autogen.h

    r67ca73e re67a82d  
    2121
    2222#include "AST/Decl.hpp"
     23#include "AST/Eval.hpp"
    2324#include "AST/Expr.hpp"
    2425#include "AST/Init.hpp"
     
    265266                }
    266267
    267                 ast::ptr< ast::Expr > begin, end, cmp, update;
     268                ast::ptr< ast::Expr > begin, end;
     269                std::string cmp, update;
    268270
    269271                if ( forward ) {
     
    271273                        begin = ast::ConstantExpr::from_int( loc, 0 );
    272274                        end = array->dimension;
    273                         cmp = new ast::NameExpr{ loc, "?<?" };
    274                         update = new ast::NameExpr{ loc, "++?" };
     275                        cmp = "?<?";
     276                        update = "++?";
    275277                } else {
    276278                        // generate: for ( int i = N-1; i >= 0; --i )
    277                         begin = new ast::UntypedExpr{
    278                                 loc, new ast::NameExpr{ loc, "?-?" },
    279                                 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } };
     279                        begin = ast::call(
     280                                loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) );
    280281                        end = ast::ConstantExpr::from_int( loc, 0 );
    281                         cmp = new ast::NameExpr{ loc, "?>=?" };
    282                         update = new ast::NameExpr{ loc, "--?" };
     282                        cmp = "?>=?";
     283                        update = "--?";
    283284                }
    284285
     
    286287                        loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },
    287288                        new ast::SingleInit{ loc, begin } };
    288                
    289                 ast::ptr< ast::Expr > cond = new ast::UntypedExpr{
    290                         loc, cmp, { new ast::VariableExpr{ loc, index }, end } };
    291                
    292                 ast::ptr< ast::Expr > inc = new ast::UntypedExpr{
    293                         loc, update, { new ast::VariableExpr{ loc, index } } };
    294                
    295                 ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{
    296                         loc, new ast::NameExpr{ loc, "?[?]" },
    297                         { dstParam, new ast::VariableExpr{ loc, index } } };
     289                ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
     290               
     291                ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end );
     292               
     293                ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar );
     294               
     295                ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar );
    298296               
    299297                // srcParam must keep track of the array indices to build the source parameter and/or
    300298                // array list initializer
    301                 srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );
     299                srcParam.addArrayIndex( indexVar, array->dimension );
    302300
    303301                // for stmt's body, eventually containing call
     
    385383                if ( isUnnamedBitfield( obj ) ) return {};
    386384
    387                 ast::ptr< ast::Type > addCast = nullptr;
     385                ast::ptr< ast::Type > addCast;
    388386                if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
    389387                        assert( dstParam->result );
  • src/SymTab/FixFunction.cc

    r67ca73e re67a82d  
    106106                bool isVoid = false;
    107107
    108                 void premutate( const ast::FunctionDecl * ) { visit_children = false; }
     108                void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    109109
    110                 const ast::DeclWithType * postmutate( const ast::FunctionDecl * func ) {
     110                const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) {
    111111                        return new ast::ObjectDecl{
    112112                                func->location, func->name, new ast::PointerType{ func->type }, nullptr,
     
    114114                }
    115115
    116                 void premutate( const ast::ArrayType * ) { visit_children = false; }
     116                void previsit( const ast::ArrayType * ) { visit_children = false; }
    117117
    118                 const ast::Type * postmutate( const ast::ArrayType * array ) {
     118                const ast::Type * postvisit( const ast::ArrayType * array ) {
    119119                        return new ast::PointerType{
    120120                                array->base, array->dimension, array->isVarLen, array->isStatic,
     
    122122                }
    123123
    124                 void premutate( const ast::VoidType * ) { isVoid = true; }
     124                void previsit( const ast::VoidType * ) { isVoid = true; }
    125125
    126                 void premutate( const ast::BasicType * ) { visit_children = false; }
    127                 void premutate( const ast::PointerType * ) { visit_children = false; }
    128                 void premutate( const ast::StructInstType * ) { visit_children = false; }
    129                 void premutate( const ast::UnionInstType * ) { visit_children = false; }
    130                 void premutate( const ast::EnumInstType * ) { visit_children = false; }
    131                 void premutate( const ast::TraitInstType * ) { visit_children = false; }
    132                 void premutate( const ast::TypeInstType * ) { visit_children = false; }
    133                 void premutate( const ast::TupleType * ) { visit_children = false; }
    134                 void premutate( const ast::VarArgsType * ) { visit_children = false; }
    135                 void premutate( const ast::ZeroType * ) { visit_children = false; }
    136                 void premutate( const ast::OneType * ) { visit_children = false; }
     126                void previsit( const ast::BasicType * ) { visit_children = false; }
     127                void previsit( const ast::PointerType * ) { visit_children = false; }
     128                void previsit( const ast::StructInstType * ) { visit_children = false; }
     129                void previsit( const ast::UnionInstType * ) { visit_children = false; }
     130                void previsit( const ast::EnumInstType * ) { visit_children = false; }
     131                void previsit( const ast::TraitInstType * ) { visit_children = false; }
     132                void previsit( const ast::TypeInstType * ) { visit_children = false; }
     133                void previsit( const ast::TupleType * ) { visit_children = false; }
     134                void previsit( const ast::VarArgsType * ) { visit_children = false; }
     135                void previsit( const ast::ZeroType * ) { visit_children = false; }
     136                void previsit( const ast::OneType * ) { visit_children = false; }
    137137        };
    138138} // anonymous namespace
     
    141141        ast::Pass< FixFunction_new > fixer;
    142142        dwt = dwt->accept( fixer );
    143         isVoid |= fixer.pass.isVoid;
     143        isVoid |= fixer.core.isVoid;
    144144        return dwt;
    145145}
  • src/SymTab/Mangler.cc

    r67ca73e re67a82d  
    447447                ast::Pass<Mangler_new> mangler( mode );
    448448                maybeAccept( decl, mangler );
    449                 return mangler.pass.get_mangleName();
     449                return mangler.core.get_mangleName();
    450450        }
    451451
     
    691691                                                                mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
    692692                                                        assert->accept( sub_mangler );
    693                                                         assertionNames.push_back( sub_mangler.pass.get_mangleName() );
     693                                                        assertionNames.push_back( sub_mangler.core.get_mangleName() );
    694694                                                        acount++;
    695695                                                } // for
  • src/SynTree/ApplicationExpr.cc

    r67ca73e re67a82d  
    3434
    3535ParamEntry::ParamEntry( const ParamEntry &other ) :
    36                 decl( other.decl ), declptr( maybeClone( other.declptr ) ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
     36                decl( other.decl ), declptr( other.declptr ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
    3737}
    3838
    3939ParamEntry::~ParamEntry() {
    40         delete declptr;
     40        // delete declptr;
    4141        delete actualType;
    4242        delete formalType;
  • src/SynTree/Expression.cc

    r67ca73e re67a82d  
    6969void Expression::print( std::ostream & os, Indenter indent ) const {
    7070        printInferParams( inferParams, os, indent+1, 0 );
     71
     72        if ( result ) {
     73                os << std::endl << indent << "with resolved type:" << std::endl;
     74                os << (indent+1);
     75                result->print( os, indent+1 );
     76        }
    7177
    7278        if ( env ) {
  • src/SynTree/Statement.h

    r67ca73e re67a82d  
    518518class ImplicitCtorDtorStmt : public Statement {
    519519  public:
    520         // Non-owned pointer to the constructor/destructor statement
     520        // the constructor/destructor call statement; owned here for a while, eventually transferred elsewhere
    521521        Statement * callStmt;
    522522
  • src/Tuples/Explode.cc

    r67ca73e re67a82d  
    129129                        for ( const ast::Expr * expr : tupleExpr->exprs ) {
    130130                                exprs.emplace_back( applyCast( expr, false ) );
    131                                 //exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );
    132131                        }
    133132                        if ( first ) {
     
    148147        }
    149148
    150         const ast::Expr * postmutate( const ast::UniqueExpr * node ) {
     149        const ast::Expr * postvisit( const ast::UniqueExpr * node ) {
    151150                // move cast into unique expr so that the unique expr has type T& rather than
    152151                // type T. In particular, this transformation helps with generating the
     
    162161                        castAdded = false;
    163162                        const ast::Type * newType = getReferenceBase( newNode->result );
    164                         return new ast::CastExpr{ newNode->location, node, newType };
     163                        return new ast::CastExpr{ newNode->location, newNode, newType };
    165164                }
    166165                return newNode;
    167166        }
    168167
    169         const ast::Expr * postmutate( const ast::TupleIndexExpr * tupleExpr ) {
     168        const ast::Expr * postvisit( const ast::TupleIndexExpr * tupleExpr ) {
    170169                // tuple index expr needs to be rebuilt to ensure that the type of the
    171170                // field is consistent with the type of the tuple expr, since the field
     
    180179        ast::Pass<CastExploderCore> exploder;
    181180        expr = expr->accept( exploder );
    182         if ( ! exploder.pass.foundUniqueExpr ) {
     181        if ( ! exploder.core.foundUniqueExpr ) {
    183182                expr = new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } };
    184183        }
  • src/Tuples/Explode.h

    r67ca73e re67a82d  
    210210                        }
    211211                        // Cast a reference away to a value-type to allow further explosion.
    212                         if ( dynamic_cast< const ast::ReferenceType *>( local->result.get() ) ) {
     212                        if ( local->result.as< ast::ReferenceType >() ) {
    213213                                local = new ast::CastExpr{ local, tupleType };
    214214                        }
     
    220220                                // delete idx;
    221221                        }
    222                         // delete local;
    223222                }
    224223        } else {
  • src/Tuples/TupleAssignment.cc

    r67ca73e re67a82d  
    465465                                        // resolve ctor/dtor for the new object
    466466                                        ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
    467                                                         InitTweak::genCtorInit( location, ret ), spotter.crntFinder.symtab );
     467                                                        InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms );
    468468                                        // remove environments from subexpressions of stmtExpr
    469469                                        ast::Pass< EnvRemover > rm{ env };
     
    504504
    505505                        std::vector< ast::ptr< ast::Expr > > match() override {
    506                                 static UniqueName lhsNamer( "__massassign_L" );
    507                                 static UniqueName rhsNamer( "__massassign_R" );
     506                                // temporary workaround for new and old ast to coexist and avoid name collision
     507                                static UniqueName lhsNamer( "__massassign_Ln" );
     508                                static UniqueName rhsNamer( "__massassign_Rn" );
    508509                                // empty tuple case falls into this matcher
    509510                                assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
     
    534535
    535536                        std::vector< ast::ptr< ast::Expr > > match() override {
    536                                 static UniqueName lhsNamer( "__multassign_L" );
    537                                 static UniqueName rhsNamer( "__multassign_R" );
     537                                // temporary workaround for new and old ast to coexist and avoid name collision
     538                                static UniqueName lhsNamer( "__multassign_Ln" );
     539                                static UniqueName rhsNamer( "__multassign_Rn" );
    538540
    539541                                if ( lhs.size() != rhs.size() ) return {};
     
    560562                                        // resolve the cast expression so that rhsCand return type is bound by the cast
    561563                                        // type as needed, and transfer the resulting environment
    562                                         ResolvExpr::CandidateFinder finder{ spotter.crntFinder.symtab, env };
     564                                        ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env };
    563565                                        finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
    564566                                        assert( finder.candidates.size() == 1 );
     
    609611                                        // explode the LHS so that each field of a tuple-valued expr is assigned
    610612                                        ResolvExpr::CandidateList lhs;
    611                                         explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true );
     613                                        explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true );
    612614                                        for ( ResolvExpr::CandidateRef & cand : lhs ) {
    613615                                                // each LHS value must be a reference - some come in with a cast, if not
     
    629631                                                        if ( isTuple( rhsCand->expr ) ) {
    630632                                                                // multiple assignment
    631                                                                 explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true );
     633                                                                explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
    632634                                                                matcher.reset(
    633635                                                                        new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     
    648650                                                        // multiple assignment
    649651                                                        ResolvExpr::CandidateList rhs;
    650                                                         explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true );
     652                                                        explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
    651653                                                        matcher.reset(
    652654                                                                new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
     
    678680                                )
    679681
    680                                 ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env };
     682                                ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env };
    681683
    682684                                try {
  • src/Tuples/TupleExpansion.cc

    r67ca73e re67a82d  
    323323                std::vector<ast::ptr<ast::Type>> types;
    324324                ast::CV::Qualifiers quals{
    325                         ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |
     325                        ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict |
    326326                        ast::CV::Atomic | ast::CV::Mutex };
    327327
  • src/Tuples/Tuples.cc

    r67ca73e re67a82d  
    4343        };
    4444        struct ImpurityDetectorIgnoreUnique : public ImpurityDetector {
     45                using ImpurityDetector::previsit;
    4546                void previsit( ast::UniqueExpr const * ) {
    4647                        visit_children = false;
     
    5253                ast::Pass<Detector> detector;
    5354                expr->accept( detector );
    54                 return detector.pass.maybeImpure;
     55                return detector.core.maybeImpure;
    5556        }
    5657} // namespace
  • src/config.h.in

    r67ca73e re67a82d  
    2727/* Location of cfa install. */
    2828#undef CFA_PREFIX
     29
     30/* Sets whether or not to use the new-ast, this is adefault value and can be
     31   overrided by --old-ast and --new-ast */
     32#undef CFA_USE_NEW_AST
    2933
    3034/* Major.Minor */
  • src/main.cc

    r67ca73e re67a82d  
    3131using namespace std;
    3232
    33 
     33#include "AST/Convert.hpp"
    3434#include "CompilationState.h"
    3535#include "../config.h"                      // for CFA_LIBDIR
     
    340340                } // if
    341341
    342                 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
     342                if( useNewAST) {
     343                        auto transUnit = convert( move( translationUnit ) );
     344                        PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
     345                        translationUnit = convert( move( transUnit ) );
     346                } else {
     347                        PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
     348                }
     349
    343350                if ( exprp ) {
    344351                        dump( translationUnit );
     
    458465        { "prototypes", no_argument, nullptr, 'p' },
    459466        { "deterministic-out", no_argument, nullptr, 'd' },
     467        { "old-ast", no_argument, nullptr, 'O'},
     468        { "new-ast", no_argument, nullptr, 'A'},
    460469        { "print", required_argument, nullptr, 'P' },
    461470        { "prelude-dir", required_argument, nullptr, PreludeDir },
     
    479488        "generate prototypes for prelude functions",            // -p
    480489        "don't print output that isn't deterministic",        // -d
     490        "Use the old-ast",                                    // -O
     491        "Use the new-ast",                                    // -A
    481492        "print",                                              // -P
    482493        "<directory> prelude directory for debug/nodebug",      // no flag
     
    584595                        break;
    585596                  case 'd':                                     // don't print non-deterministic output
    586                     deterministic_output = true;
     597                        deterministic_output = true;
     598                        break;
     599                  case 'O':                                     // don't print non-deterministic output
     600                        useNewAST = false;
     601                        break;
     602                  case 'A':                                     // don't print non-deterministic output
     603                        useNewAST = true;
    587604                        break;
    588605                  case 'P':                                                                             // print options
  • tests/.expect/alloc-ERROR.txt

    r67ca73e re67a82d  
    1616          Name: stp
    1717
     18      with resolved type:
     19        unsigned long int
    1820
    1921
     
    2830    Name: stp
    2931    constant expression (10 10: signed int)
     32    with resolved type:
     33      signed int
    3034
    3135
  • tests/.expect/castError.txt

    r67ca73e re67a82d  
    33  Name: f
    44... to:
     5  char
     6with resolved type:
    57  char Alternatives are:
    68Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
     
    911      ... returning nothing
    1012
     13      with resolved type:
     14        pointer to function
     15          accepting unspecified arguments
     16        ... returning nothing
     17
    1118    ... to:
     19      char
     20    with resolved type:
    1221      char
    1322  (types:
     
    1827Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    1928      Variable Expression: f: double
     29      with resolved type:
     30        double
    2031    ... to:
     32      char
     33    with resolved type:
    2134      char
    2235  (types:
     
    2740Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    2841      Variable Expression: f: signed int
     42      with resolved type:
     43        signed int
    2944    ... to:
     45      char
     46    with resolved type:
    3047      char
    3148  (types:
     
    3956  Comma Expression:
    4057    constant expression (3 3: signed int)
     58    with resolved type:
     59      signed int
    4160    Name: v
    42 ... to: nothing Alternatives are:
     61... to: nothing
     62with resolved type:
     63  void  Alternatives are:
    4364Cost ( 0, 0, 2, 0, 0, 0, 0 ): Generated Cast of:
    4465      Comma Expression:
    4566        constant expression (3 3: signed int)
     67        with resolved type:
     68          signed int
    4669        Variable Expression: v: unsigned char
     70        with resolved type:
     71          unsigned char
     72      with resolved type:
     73        unsigned char
    4774    ... to: nothing
     75    with resolved type:
     76      void
    4877  (types:
    4978    void
     
    5483      Comma Expression:
    5584        constant expression (3 3: signed int)
     85        with resolved type:
     86          signed int
    5687        Variable Expression: v: signed short int
     88        with resolved type:
     89          signed short int
     90      with resolved type:
     91        signed short int
    5792    ... to: nothing
     93    with resolved type:
     94      void
    5895  (types:
    5996    void
     
    69106    char
    70107
     108with resolved type:
     109  instance of struct S with body 1
     110  ... with parameters
     111    char
     112
  • tests/.expect/declarationSpecifier.x64.txt

    r67ca73e re67a82d  
    11291129static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    11301130static inline signed int invoke_main(signed int argc, char **argv, char **envp);
     1131signed int _X13cfa_args_argci_1;
     1132char **_X13cfa_args_argvPPc_1;
     1133char **_X13cfa_args_envpPPc_1;
    11311134signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    11321135    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11331136    {
     1137        ((void)(_X13cfa_args_argci_1=_X4argci_1));
     1138    }
     1139
     1140    {
     1141        ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
     1142    }
     1143
     1144    {
     1145        ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
     1146    }
     1147
     1148    {
    11341149        signed int _tmp_cp_ret4;
    11351150        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/declarationSpecifier.x86.txt

    r67ca73e re67a82d  
    11291129static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    11301130static inline signed int invoke_main(signed int argc, char **argv, char **envp);
     1131signed int _X13cfa_args_argci_1;
     1132char **_X13cfa_args_argvPPc_1;
     1133char **_X13cfa_args_envpPPc_1;
    11311134signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    11321135    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    11331136    {
     1137        ((void)(_X13cfa_args_argci_1=_X4argci_1));
     1138    }
     1139
     1140    {
     1141        ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
     1142    }
     1143
     1144    {
     1145        ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
     1146    }
     1147
     1148    {
    11341149        signed int _tmp_cp_ret4;
    11351150        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/gccExtensions.x64.txt

    r67ca73e re67a82d  
    321321static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    322322static inline signed int invoke_main(signed int argc, char **argv, char **envp);
     323signed int _X13cfa_args_argci_1;
     324char **_X13cfa_args_argvPPc_1;
     325char **_X13cfa_args_envpPPc_1;
    323326signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    324327    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    325328    {
     329        ((void)(_X13cfa_args_argci_1=_X4argci_1));
     330    }
     331
     332    {
     333        ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
     334    }
     335
     336    {
     337        ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
     338    }
     339
     340    {
    326341        signed int _tmp_cp_ret4;
    327342        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/gccExtensions.x86.txt

    r67ca73e re67a82d  
    299299static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
    300300static inline signed int invoke_main(signed int argc, char **argv, char **envp);
     301signed int _X13cfa_args_argci_1;
     302char **_X13cfa_args_argvPPc_1;
     303char **_X13cfa_args_envpPPc_1;
    301304signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
    302305    __attribute__ ((unused)) signed int _X12_retval_maini_1;
    303306    {
     307        ((void)(_X13cfa_args_argci_1=_X4argci_1));
     308    }
     309
     310    {
     311        ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
     312    }
     313
     314    {
     315        ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
     316    }
     317
     318    {
    304319        signed int _tmp_cp_ret4;
    305320        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
  • tests/.expect/init1.txt

    r67ca73e re67a82d  
    1111... to:
    1212  reference to signed int
     13with resolved type:
     14  reference to signed int
    1315init1.cfa:97:1 error: No reasonable alternatives for expression Applying untyped:
    1416  Name: ?{}
     
    1618  Generated Cast of:
    1719    Variable Expression: _retval_f_py: pointer to signed int
     20    with resolved type:
     21      pointer to signed int
    1822  ... to:
     23    reference to pointer to signed int
     24  with resolved type:
    1925    reference to pointer to signed int
    2026  Name: px
     
    2430... to:
    2531  reference to float
     32with resolved type:
     33  reference to float
    2634init1.cfa:107:1 error: No reasonable alternatives for expression Applying untyped:
    2735  Name: ?{}
     
    2937  Generated Cast of:
    3038    Variable Expression: _retval_f_py2: pointer to float
     39    with resolved type:
     40      pointer to float
    3141  ... to:
     42    reference to pointer to float
     43  with resolved type:
    3244    reference to pointer to float
    3345  Name: cpx
     
    3749... to:
    3850  reference to instance of type T (not function type)
     51with resolved type:
     52  reference to instance of type T (not function type)
    3953init1.cfa:118:1 error: No reasonable alternatives for expression Applying untyped:
    4054  Name: ?{}
     
    4256  Generated Cast of:
    4357    Variable Expression: _retval_anycvt: pointer to instance of type T (not function type)
     58    with resolved type:
     59      pointer to instance of type T (not function type)
    4460  ... to:
     61    reference to pointer to instance of type T (not function type)
     62  with resolved type:
    4563    reference to pointer to instance of type T (not function type)
    4664  Name: s
  • tests/.expect/minmax.txt

    r67ca73e re67a82d  
    11char                    z a     min a
    2 signed int              4 3     min 3
     2signed int              4 -3    min -3
    33unsigned int            4 3     min 3
    4 signed long int         4 3     min 3
     4signed long int         4 -3    min -3
    55unsigned long int       4 3     min 3
    6 signed long long int    4 3     min 3
     6signed long long int    4 -3    min -3
    77unsigned long long int  4 3     min 3
    88float                   4. 3.1  min 3.1
     
    1111
    1212char                    z a     max z
    13 signed int              4 3     max 4
     13signed int              4 -3    max 4
    1414unsigned int            4 3     max 4
    15 signed long int         4 3     max 4
     15signed long int         4 -3    max 4
    1616unsigned long int       4 3     max 4
    17 signed long long int    4 3     max 4
     17signed long long int    4 -3    max 4
    1818unsigned long long int  4 3     max 4
    1919float                   4. 3.1  max 4.
  • tests/Makefile.am

    r67ca73e re67a82d  
    163163        $(CFACOMPILETEST) -DERR2 -c -fsyntax-only -o $(abspath ${@})
    164164
     165# Exception Tests
     166# Test with libcfathread; it changes how storage works.
     167
     168exceptions/%-threads : exceptions/%.cfa $(CFACCBIN)
     169        $(CFACOMPILETEST) -include exceptions/with-threads.hfa -c -o $(abspath ${@}).o
     170        $(CFACCLOCAL) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g')) $(abspath ${@}).o -o $(abspath ${@})
     171
    165172#------------------------------------------------------------------------------
    166173# Other targets
  • tests/alloc.cfa

    r67ca73e re67a82d  
    1010// Created On       : Wed Feb  3 07:56:22 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr  6 21:08:23 2020
    13 // Update Count     : 428
     12// Last Modified On : Fri Aug 14 16:59:59 2020
     13// Update Count     : 430
    1414//
    1515
     
    9090        // do not free
    9191
    92         ip1 = alloc_set( 2 * dim, ip );                                         // CFA array alloc, fill
     92        ip1 = alloc_set( 2 * dim, ip, 2 * dim );                                // CFA array alloc, fill
    9393        printf( "CFA array alloc, fill from array\n" );
    9494        for ( i; 2 * dim ) { printf( "%#x %#x, ", ip[i], ip1[i] ); }
     
    288288        // do not free
    289289
    290         stp1 = alloc_align_set( Alignment, dim, stp );          // CFA array memalign, fill
     290        stp1 = alloc_align_set( Alignment, dim, stp, dim );     // CFA array memalign, fill
    291291        assert( (uintptr_t)stp % Alignment == 0 );
    292292        printf( "CFA array alloc_align, fill array\n" );
  • tests/errors/.expect/completeType.x64.txt

    r67ca73e re67a82d  
    66    Name: x
    77
    8 ... to: nothing Alternatives are:
     8... to: nothing
     9with resolved type:
     10  void  Alternatives are:
    911Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
    1012      Application of
     
    2022
    2123
     24        with resolved type:
     25          pointer to forall
     26            _90_4_DT: data type
     27            function
     28          ... with parameters
     29            intrinsic pointer to instance of type _90_4_DT (not function type)
     30          ... returning
     31            _retval__operator_deref: reference to instance of type _90_4_DT (not function type)
     32            ... with attributes:
     33              Attribute with name: unused
     34
     35
    2236      ... to arguments
    2337        Variable Expression: x: pointer to instance of struct A with body 0
    24 
     38        with resolved type:
     39          pointer to instance of struct A with body 0
     40
     41      with resolved type:
     42        reference to instance of struct A with body 0
    2543    ... to: nothing
     44    with resolved type:
     45      void
    2646  (types:
    2747    void
     
    4363
    4464
     65        with resolved type:
     66          pointer to forall
     67            _90_4_DT: data type
     68            function
     69          ... with parameters
     70            intrinsic pointer to instance of type _90_4_DT (not function type)
     71          ... returning
     72            _retval__operator_deref: reference to instance of type _90_4_DT (not function type)
     73            ... with attributes:
     74              Attribute with name: unused
     75
     76
    4577      ... to arguments
    4678        Variable Expression: x: pointer to instance of struct B with body 1
    47 
     79        with resolved type:
     80          pointer to instance of struct B with body 1
     81
     82      with resolved type:
     83        reference to instance of struct B with body 1
    4884    ... to: nothing
     85    with resolved type:
     86      void
    4987  (types:
    5088    void
     
    121159            ... returning nothing
    122160
     161            with resolved type:
     162              pointer to forall
     163                _109_0_T: sized data type
     164                ... with assertions
     165                  ?=?: pointer to function
     166                  ... with parameters
     167                    reference to instance of type _109_0_T (not function type)
     168                    instance of type _109_0_T (not function type)
     169                  ... returning
     170                    _retval__operator_assign: instance of type _109_0_T (not function type)
     171                    ... with attributes:
     172                      Attribute with name: unused
     173
     174
     175                  ?{}: pointer to function
     176                  ... with parameters
     177                    reference to instance of type _109_0_T (not function type)
     178                  ... returning nothing
     179
     180                  ?{}: pointer to function
     181                  ... with parameters
     182                    reference to instance of type _109_0_T (not function type)
     183                    instance of type _109_0_T (not function type)
     184                  ... returning nothing
     185
     186                  ^?{}: pointer to function
     187                  ... with parameters
     188                    reference to instance of type _109_0_T (not function type)
     189                  ... returning nothing
     190
     191
     192                function
     193              ... with parameters
     194                pointer to instance of type _109_0_T (not function type)
     195              ... returning nothing
     196
    123197          ... to arguments
    124198            Variable Expression: z: pointer to instance of type T (not function type)
    125 
     199            with resolved type:
     200              pointer to instance of type T (not function type)
     201
     202          with resolved type:
     203            void
    126204        (types:
    127205          void
  • tests/errors/.expect/completeType.x86.txt

    r67ca73e re67a82d  
    66    Name: x
    77
    8 ... to: nothing Alternatives are:
     8... to: nothing
     9with resolved type:
     10  void  Alternatives are:
    911Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
    1012      Application of
     
    2022
    2123
     24        with resolved type:
     25          pointer to forall
     26            _89_4_DT: data type
     27            function
     28          ... with parameters
     29            intrinsic pointer to instance of type _89_4_DT (not function type)
     30          ... returning
     31            _retval__operator_deref: reference to instance of type _89_4_DT (not function type)
     32            ... with attributes:
     33              Attribute with name: unused
     34
     35
    2236      ... to arguments
    2337        Variable Expression: x: pointer to instance of struct A with body 0
    24 
     38        with resolved type:
     39          pointer to instance of struct A with body 0
     40
     41      with resolved type:
     42        reference to instance of struct A with body 0
    2543    ... to: nothing
     44    with resolved type:
     45      void
    2646  (types:
    2747    void
     
    4363
    4464
     65        with resolved type:
     66          pointer to forall
     67            _89_4_DT: data type
     68            function
     69          ... with parameters
     70            intrinsic pointer to instance of type _89_4_DT (not function type)
     71          ... returning
     72            _retval__operator_deref: reference to instance of type _89_4_DT (not function type)
     73            ... with attributes:
     74              Attribute with name: unused
     75
     76
    4577      ... to arguments
    4678        Variable Expression: x: pointer to instance of struct B with body 1
    47 
     79        with resolved type:
     80          pointer to instance of struct B with body 1
     81
     82      with resolved type:
     83        reference to instance of struct B with body 1
    4884    ... to: nothing
     85    with resolved type:
     86      void
    4987  (types:
    5088    void
     
    121159            ... returning nothing
    122160
     161            with resolved type:
     162              pointer to forall
     163                _108_0_T: sized data type
     164                ... with assertions
     165                  ?=?: pointer to function
     166                  ... with parameters
     167                    reference to instance of type _108_0_T (not function type)
     168                    instance of type _108_0_T (not function type)
     169                  ... returning
     170                    _retval__operator_assign: instance of type _108_0_T (not function type)
     171                    ... with attributes:
     172                      Attribute with name: unused
     173
     174
     175                  ?{}: pointer to function
     176                  ... with parameters
     177                    reference to instance of type _108_0_T (not function type)
     178                  ... returning nothing
     179
     180                  ?{}: pointer to function
     181                  ... with parameters
     182                    reference to instance of type _108_0_T (not function type)
     183                    instance of type _108_0_T (not function type)
     184                  ... returning nothing
     185
     186                  ^?{}: pointer to function
     187                  ... with parameters
     188                    reference to instance of type _108_0_T (not function type)
     189                  ... returning nothing
     190
     191
     192                function
     193              ... with parameters
     194                pointer to instance of type _108_0_T (not function type)
     195              ... returning nothing
     196
    123197          ... to arguments
    124198            Variable Expression: z: pointer to instance of type T (not function type)
    125 
     199            with resolved type:
     200              pointer to instance of type T (not function type)
     201
     202          with resolved type:
     203            void
    126204        (types:
    127205          void
  • tests/exceptions/terminate.cfa

    r67ca73e re67a82d  
    142142        }
    143143}
    144 
  • tests/heap.cfa

    r67ca73e re67a82d  
    1010// Created On       : Tue Nov  6 17:54:56 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Aug  4 06:36:17 2020
    13 // Update Count     : 56
     12// Last Modified On : Sun Aug  9 08:05:16 2020
     13// Update Count     : 57
    1414//
    1515
     
    232232                size_t s = i + default_mmap_start();                    // cross over point
    233233                char * area = (char *)calloc( 1, s );
    234 //              if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    235234                if ( area[0] != '\0' || area[s - 1] != '\0' ||
    236235                         area[malloc_size( area ) - 1] != '\0' ||
    237                          ! malloc_zero_fill( area ) ) //abort( "calloc/realloc/free corrupt storage3" );
    238                         printf( "C %zd %d %d %d %d\n", s, area[0] != '\0', area[s - 1] != '\0', area[malloc_size( area ) - 1] != '\0', ! malloc_zero_fill( area ) );
     236                         ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage3" );
    239237
    240238                // Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
    241239                for ( r; i ~ 256 * 1024 ~ 26 ) {                                // start at initial memory request
    242240                        area = (char *)realloc( area, r );                      // attempt to reuse storage
    243 //                      if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
    244241                        if ( area[0] != '\0' || area[r - 1] != '\0' ||
    245242                                 area[malloc_size( area ) - 1] != '\0' ||
     
    255252                // initial N byte allocation
    256253                char * area = (char *)memalign( a, amount );    // aligned N-byte allocation
    257 //              if ( area == 0p ) abort( "memalign/realloc/free out of memory" ); // no storage ?
    258254                //sout | alignments[a] | area;
    259255                if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
  • tests/linking/withthreads.cfa

    r67ca73e re67a82d  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // nothreads.cfa --
     7// withthreads.cfa --
    88//
    99// Author           : Thierry Delisle
  • tests/literals.cfa

    r67ca73e re67a82d  
    1010// Created On       : Sat Sep  9 16:34:38 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 12 08:07:39 2019
    13 // Update Count     : 224
     12// Last Modified On : Thu Aug 20 13:51:12 2020
     13// Update Count     : 225
    1414//
    1515
     
    214214        -01234567_l8;  -01234567_l16;  -01234567_l32;  -01234567_l64;  -01234567_l8u;  -01234567_ul16;  -01234567_l32u;  -01234567_ul64;
    215215
    216 #ifdef __LP64__ // 64-bit processor
     216#if defined( __SIZEOF_INT128__ )
    217217        01234567_l128;   01234567_ul128;
    218218        +01234567_l128;  +01234567_ul128;
    219219        -01234567_l128;  -01234567_ul128;
    220 #endif // __LP64__
     220#endif // __SIZEOF_INT128__
    221221
    222222        // decimal
     
    225225        -1234567890L8;  -1234567890L16;  -1234567890l32;  -1234567890l64;  -1234567890UL8;  -1234567890L16U;  -1234567890Ul32;  -1234567890l64u;
    226226
    227 #ifdef __LP64__ // 64-bit processor
     227#if defined( __SIZEOF_INT128__ )
    228228        1234567890l128;   1234567890l128u;
    229229        +1234567890l128;  +1234567890l128u;
    230230        -1234567890l128;  -1234567890l128u;
    231 #endif // __LP64__
     231    1234567890123456789_L128u; 1234567890123456789_L128u;
     232        18446708753438544741_l64u; 18446708753438544741_Ul64;
     233#endif // __SIZEOF_INT128__
    232234
    233235        // hexadecimal
  • tests/minmax.cfa

    r67ca73e re67a82d  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec  4 21:45:31 2018
    13 // Update Count     : 52
     12// Last Modified On : Sat Aug 15 08:28:01 2020
     13// Update Count     : 54
    1414//
    1515
     
    2323
    2424        sout | "char\t\t\t"                                     | 'z' | ' ' | 'a' | "\tmin " | min( 'z', 'a' );
    25         sout | "signed int\t\t"                         | 4 | 3 | "\tmin" | min( 4, 3 );
     25        sout | "signed int\t\t"                         | 4 | -3 | "\tmin" | min( 4, -3 );
    2626        sout | "unsigned int\t\t"                       | 4u | 3u | "\tmin" | min( 4u, 3u );
    27         sout | "signed long int\t\t"            | 4l | 3l | "\tmin" | min( 4l, 3l );
     27        sout | "signed long int\t\t"            | 4l | -3l | "\tmin" | min( 4l, -3l );
    2828        sout | "unsigned long int\t"            | 4ul | 3ul | "\tmin" | min( 4ul, 3ul );
    29         sout | "signed long long int\t"         | 4ll | 3ll | "\tmin" | min( 4ll, 3ll );
     29        sout | "signed long long int\t"         | 4ll | -3ll | "\tmin" | min( 4ll, -3ll );
    3030        sout | "unsigned long long int\t"       | 4ull | 3ull | "\tmin" | min( 4ull, 3ull );
    3131        sout | "float\t\t\t"                            | 4.0f | 3.1f | "\tmin" | min( 4.0f, 3.1f );
     
    3636
    3737        sout | "char\t\t\t"                                     | 'z' | ' ' | 'a' | "\tmax " | max( 'z', 'a' );
    38         sout | "signed int\t\t"                         | 4 | 3 | "\tmax" | max( 4, 3 );
     38        sout | "signed int\t\t"                         | 4 | -3 | "\tmax" | max( 4, -3 );
    3939        sout | "unsigned int\t\t"                       | 4u | 3u | "\tmax" | max( 4u, 3u );
    40         sout | "signed long int\t\t"            | 4l | 3l | "\tmax" | max( 4l, 3l );
     40        sout | "signed long int\t\t"            | 4l | -3l | "\tmax" | max( 4l, -3l );
    4141        sout | "unsigned long int\t"            | 4ul | 3ul | "\tmax" | max( 4ul, 3ul );
    42         sout | "signed long long int\t"         | 4ll | 3ll | "\tmax" | max( 4ll, 3ll );
     42        sout | "signed long long int\t"         | 4ll | -3ll | "\tmax" | max( 4ll, -3ll );
    4343        sout | "unsigned long long int\t"       | 4ull | 3ull | "\tmax" | max( 4ull, 3ull );
    4444        sout | "float\t\t\t"                            | 4.0f | 3.1f | "\tmax" | max( 4.0f, 3.1f );
  • tests/pybin/tools.py

    r67ca73e re67a82d  
    246246# transform path to canonical form
    247247def canonical_path(path):
    248         abspath = os.path.abspath(__main__.__file__)
     248        abspath = os.path.abspath(os.path.realpath(__main__.__file__))
    249249        dname = os.path.dirname(abspath)
    250250        return os.path.join(dname, os.path.normpath(path) )
  • tests/raii/.expect/ctor-autogen-ERR1.txt

    r67ca73e re67a82d  
    77        x: signed int
    88      ... returning nothing
     9
     10      with resolved type:
     11        function
     12        ... with parameters
     13          _dst: reference to instance of struct Managed with body 1
     14          x: signed int
     15        ... returning nothing
    916
    1017      ... deleted by: ?{}: function
     
    2633
    2734
     35              with resolved type:
     36                pointer to function
     37                ... with parameters
     38                  intrinsic reference to signed int
     39                  intrinsic signed int
     40                ... returning
     41                  _retval__operator_assign: signed int
     42                  ... with attributes:
     43                    Attribute with name: unused
     44
     45
    2846            ... to arguments
    2947              Generated Cast of:
     
    3351                  Generated Cast of:
    3452                    Variable Expression: m: reference to instance of struct Managed with body 1
     53                    with resolved type:
     54                      reference to instance of struct Managed with body 1
    3555                  ... to:
    3656                    instance of struct Managed with body 1
     57                  with resolved type:
     58                    instance of struct Managed with body 1
     59                with resolved type:
     60                  signed int
    3761              ... to:
     62                reference to signed int
     63              with resolved type:
    3864                reference to signed int
    3965              Generated Cast of:
    4066                constant expression (0 0: zero_t)
     67                with resolved type:
     68                  zero_t
    4169              ... to:
    4270                signed int
     71              with resolved type:
     72                signed int
    4373
     74            with resolved type:
     75              signed int
    4476            ... with environment:
    4577              Types:
     
    5082    Generated Cast of:
    5183      Variable Expression: x: instance of struct Managed with body 1
     84      with resolved type:
     85        instance of struct Managed with body 1
    5286    ... to:
    5387      reference to instance of struct Managed with body 1
     88    with resolved type:
     89      reference to instance of struct Managed with body 1
    5490    constant expression (123 123: signed int)
     91    with resolved type:
     92      signed int
    5593
     94  with resolved type:
     95    void
    5696... to: nothing
     97with resolved type:
     98  void
  • tests/warnings/.expect/self-assignment.txt

    r67ca73e re67a82d  
    11warnings/self-assignment.cfa:29:1 warning: self assignment of expression: Generated Cast of:
    22  Variable Expression: j: signed int
     3  with resolved type:
     4    signed int
    35... to:
     6  reference to signed int
     7with resolved type:
    48  reference to signed int
    59warnings/self-assignment.cfa:30:1 warning: self assignment of expression: Generated Cast of:
    610  Variable Expression: s: instance of struct S with body 1
     11  with resolved type:
     12    instance of struct S with body 1
    713... to:
     14  reference to instance of struct S with body 1
     15with resolved type:
    816  reference to instance of struct S with body 1
    917warnings/self-assignment.cfa:31:1 warning: self assignment of expression: Generated Cast of:
     
    1220  ... from aggregate:
    1321    Variable Expression: s: instance of struct S with body 1
     22    with resolved type:
     23      instance of struct S with body 1
     24  with resolved type:
     25    signed int
    1426... to:
     27  reference to signed int
     28with resolved type:
    1529  reference to signed int
    1630warnings/self-assignment.cfa:32:1 warning: self assignment of expression: Generated Cast of:
     
    2236    ... from aggregate:
    2337      Variable Expression: t: instance of struct T with body 1
     38      with resolved type:
     39        instance of struct T with body 1
     40    with resolved type:
     41      instance of struct S with body 1
     42  with resolved type:
     43    signed int
    2444... to:
    2545  reference to signed int
     46with resolved type:
     47  reference to signed int
Note: See TracChangeset for help on using the changeset viewer.