Changeset e67a82d


Ignore:
Timestamp:
Aug 20, 2020, 11:48:15 PM (16 months ago)
Author:
Peter A. Buhr <pabuhr@…>
Branches:
arm-eh, jacob/cs343-translation, master, new-ast-unique-expr
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>