Changeset e67a82d
- Timestamp:
- Aug 20, 2020, 11:48:15 PM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- d685cb0
- Parents:
- 67ca73e (diff), 013b028 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 19 added
- 120 edited
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
benchmark/benchcltr.hfa
r67ca73e re67a82d 1 1 #pragma once 2 #include <assert.h> 3 #include <stdint.h> 2 4 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 13 enum { TIMEGRAN = 1000000000LL }; // nanosecond granularity, except for timeval 14 #endif 7 15 8 16 #define BENCH_OPT_SHORT "d:p:t:SPV" … … 14 22 {"procstat", no_argument , 0, 'P'}, \ 15 23 {"viewhalts", no_argument , 0, 'V'}, 16 17 #define BENCH_DECL \18 double duration = 5; \19 int nprocs = 1; \20 int nthreads = 1;21 24 22 25 #define BENCH_OPT_CASE \ … … 52 55 break; 53 56 57 double duration = 5; 58 int nprocs = 1; 59 int nthreads = 1; 54 60 bool silent = false; 61 bool continuous = false; 55 62 bool procstats = false; 56 63 bool 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 57 77 struct cluster * the_benchmark_cluster = 0p; 58 78 struct BenchCluster { … … 60 80 }; 61 81 62 void ?{}( BenchCluster & this, int flags, int stats ) {63 (this.self){ "Benchmark Cluster", flags };82 void ?{}( BenchCluster & this, int num_io, const io_context_params & io_params, int stats ) { 83 (this.self){ "Benchmark Cluster", num_io, io_params }; 64 84 65 85 assert( the_benchmark_cluster == 0p ); … … 105 125 } 106 126 } 127 #else 128 uint64_t getTimeNsec() { 129 timespec curr; 130 clock_gettime( CLOCK_REALTIME, &curr ); 131 return (int64_t)curr.tv_sec * TIMEGRAN + curr.tv_nsec; 132 } 133 134 uint64_t to_miliseconds( uint64_t durtn ) { return durtn / (TIMEGRAN / 1000LL); } 135 double to_fseconds(uint64_t durtn ) { return durtn / (double)TIMEGRAN; } 136 uint64_t from_fseconds(double sec) { return sec * TIMEGRAN; } 137 138 139 void 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 107 155 108 156 void bench_usage( char * argv [] ) { -
benchmark/io/http/options.cfa
r67ca73e re67a82d 10 10 11 11 #include <kernel.hfa> 12 13 #include "parseargs.hfa" 14 12 #include <parseargs.hfa> 15 13 16 14 Options options @= { -
benchmark/io/readv.cfa
r67ca73e re67a82d 40 40 int do_read(int fd, struct iovec * iov) { 41 41 // 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 ; 43 49 if(fixed_file) { 44 50 sflags |= CFA_IO_FIXED_FD1; … … 63 69 64 70 int main(int argc, char * argv[]) { 65 BENCH_DECL71 int file_flags = 0; 66 72 unsigned num_io = 1; 67 io_context_params params;68 int file_flags = 0;69 73 unsigned sublen = 16; 74 unsigned nentries = 0; 70 75 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; 85 81 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); 88 96 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); 139 104 } 140 105 } 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; 141 121 142 122 int lfd = open(__FILE__, file_flags); -
benchmark/readyQ/yield.cfa
r67ca73e re67a82d 43 43 44 44 int main(int argc, char * argv[]) { 45 BENCH_DECL 45 unsigned num_io = 1; 46 io_context_params params; 46 47 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); 52 52 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 ); 70 55 71 56 { … … 73 58 74 59 Time start, end; 75 BenchCluster cl = { 0, CFA_STATS_READY_Q };60 BenchCluster cl = { num_io, params, CFA_STATS_READY_Q }; 76 61 { 77 62 BenchProc procs[nprocs]; -
configure.ac
r67ca73e re67a82d 24 24 #Trasforming cc1 will break compilation 25 25 M4CFA_PROGRAM_NAME 26 27 #============================================================================== 28 # New AST toggling support 29 AH_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]) 30 AC_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]) 37 AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast) 26 38 27 39 #============================================================================== -
driver/cc1.cc
r67ca73e re67a82d 10 10 // Created On : Fri Aug 26 14:23:51 2005 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S at May 30 18:09:05202013 // Update Count : 4 0412 // Last Modified On : Sun Aug 16 21:03:02 2020 13 // Update Count : 413 14 14 // 15 15 … … 24 24 #include <unistd.h> // execvp, fork, unlink 25 25 #include <sys/wait.h> // wait 26 #include <fcntl.h> 26 #include <fcntl.h> // creat 27 27 28 28 … … 59 59 60 60 61 static string __CFA_FLAGPREFIX__( "__CFA_FLAG" ); // " N__=" suffix61 static string __CFA_FLAGPREFIX__( "__CFA_FLAG" ); // "__CFA_FLAG__=" suffix 62 62 63 63 static void checkEnv1( const char * args[], int & nargs ) { // stage 1 … … 111 111 } // checkEnv2 112 112 113 114 static char tmpname[] = P_tmpdir "/CFAXXXXXX.ifa"; 113 #define CFA_SUFFIX ".ifa" 114 115 static char tmpname[] = P_tmpdir "/CFAXXXXXX" CFA_SUFFIX; 115 116 static int tmpfilefd = -1; 116 117 static bool startrm = false; … … 170 171 if ( arg == "-quiet" ) { 171 172 } else if ( arg == "-imultilib" || arg == "-imultiarch" ) { 172 i += 1; // and theargument173 i += 1; // and argument 173 174 } else if ( prefix( arg, "-A" ) ) { 174 175 } else if ( prefix( arg, "-D__GNU" ) ) { … … 177 178 //******** 178 179 } else if ( arg == "-D" && prefix( argv[i + 1], "__GNU" ) ) { 179 i += 1; // and theargument180 i += 1; // and argument 180 181 181 182 // strip flags controlling cpp step … … 184 185 cpp_flag = true; 185 186 } else if ( arg == "-D" && string( argv[i + 1] ) == "__CPP__" ) { 186 i += 1; // and theargument187 i += 1; // and argument 187 188 cpp_flag = true; 188 189 … … 194 195 cpp_out = argv[i]; 195 196 } else { 196 args[nargs++] = argv[i]; // pass theflag along197 args[nargs++] = argv[i]; // pass flag along 197 198 // CPP flags with an argument 198 199 if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" || … … 200 201 arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) { 201 202 i += 1; 202 args[nargs++] = argv[i]; // pass theargument along203 args[nargs++] = argv[i]; // pass argument along 203 204 #ifdef __DEBUG_H__ 204 205 cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl; 205 206 #endif // __DEBUG_H__ 206 207 } 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. 207 210 args[nargs++] = "-MF"; // insert before file 208 211 i += 1; 209 args[nargs++] = argv[i]; // pass theargument along212 args[nargs++] = argv[i]; // pass argument along 210 213 #ifdef __DEBUG_H__ 211 214 cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl; … … 279 282 // Run the C preprocessor and save the output in the given file. 280 283 281 if ( fork() == 0 ) { 284 if ( fork() == 0 ) { // child process ? 282 285 // -o xxx.ii cannot be used to write the output file from cpp because no output file is created if cpp detects 283 286 // an error (e.g., cannot find include file). Whereas, output is always generated, even when there is an error, … … 319 322 320 323 if ( WIFSIGNALED(code) ) { // child failed ? 324 rmtmpfile(); // remove tmpname 321 325 cerr << "CC1 Translator error: stage 1, child failed " << WTERMSIG(code) << endl; 322 326 exit( EXIT_FAILURE ); 323 327 } // if 324 328 325 exit( WEXITSTATUS( code) );// bad cpp result stops top-level gcc329 exit( WEXITSTATUS( code ) ); // bad cpp result stops top-level gcc 326 330 } // Stage1 327 331 … … 371 375 } else if ( arg == "-fno-diagnostics-color" ) { 372 376 color_arg = Color_Auto; 373 } 377 } // if 374 378 375 379 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" ) ) { 378 382 379 383 // strip inappropriate flags with an argument … … 388 392 389 393 } else { 390 args[nargs++] = argv[i]; // pass theflag along394 args[nargs++] = argv[i]; // pass flag along 391 395 if ( arg == "-o" ) { 392 396 i += 1; 393 397 cpp_out = argv[i]; 394 args[nargs++] = argv[i]; // pass theargument along398 args[nargs++] = argv[i]; // pass argument along 395 399 #ifdef __DEBUG_H__ 396 400 cerr << "arg:\"" << argv[i] << "\"" << endl; … … 439 443 } // if 440 444 441 cfa_cpp_out = cfa_cpp_out.substr( 0, dot ) + ".ifa";445 cfa_cpp_out = cfa_cpp_out.substr( 0, dot ) + CFA_SUFFIX; 442 446 if ( creat( cfa_cpp_out.c_str(), 0666 ) == -1 ) { 443 447 perror( "CC1 Translator error: stage 2, creat" ); … … 460 464 // output. Otherwise, run the cfa-cpp preprocessor on the temporary file and save the result into the output file. 461 465 462 if ( fork() == 0 ) { // child runs CFA 466 if ( fork() == 0 ) { // child runs CFA preprocessor 463 467 cargs[0] = ( *new string( bprefix + "cfa-cpp" ) ).c_str(); 464 468 cargs[ncargs++] = cpp_in; … … 518 522 #endif // __DEBUG_H__ 519 523 520 if ( fork() == 0 ) { // child runs CFA524 if ( fork() == 0 ) { // child runs gcc 521 525 args[0] = compiler_path.c_str(); 522 526 args[nargs++] = "-S"; // only compile and put assembler output in specified file -
driver/cfa.cc
r67ca73e re67a82d 10 10 // Created On : Tue Aug 20 13:44:49 2002 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Aug 18 16:40:22202013 // Update Count : 43 512 // Last Modified On : Thu Aug 20 23:43:59 2020 13 // Update Count : 436 14 14 // 15 15 16 16 #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 25 24 #include <sys/types.h> 26 25 #include <sys/stat.h> … … 34 33 using std::to_string; 35 34 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 40 static string __CFA_FLAGPREFIX__( "__CFA_FLAG" ); // "__CFA_FLAG__=" suffix 41 42 static void Putenv( char * argv[], string arg ) { 42 43 // environment variables must have unique names 43 44 static int flags = 0; … … 49 50 } // Putenv 50 51 51 // check if string has prefix 52 bool prefix( const string & arg, const string & pre ) { 52 static bool prefix( const string & arg, const string & pre ) { // check if string has prefix 53 53 return arg.substr( 0, pre.size() ) == pre; 54 54 } // prefix 55 55 56 inline bool ends_with(const string & str, const string & sfix) {56 static inline bool ends_with(const string & str, const string & sfix) { 57 57 if (sfix.size() > str.size()) return false; 58 58 return std::equal(str.rbegin(), str.rbegin() + sfix.size(), sfix.rbegin(), sfix.rend()); … … 60 60 61 61 // check if string has suffix 62 bool suffix( const string & arg ) {62 static bool suffix( const string & arg ) { 63 63 enum { NumSuffixes = 3 }; 64 64 static const string suffixes[NumSuffixes] = { "cfa", "hfa", "ifa" }; … … 70 70 } // suffix 71 71 72 73 72 static inline bool dirExists( const string & path ) { // check if directory exists 74 73 struct stat info; … … 79 78 static inline string dir(const string & path) { 80 79 return path.substr(0, path.find_last_of('/')); 81 } 80 } // dir 82 81 83 82 // Different path modes … … 118 117 } 119 118 120 121 #define xstr(s) str(s)122 #define str(s) #s123 119 124 120 int main( int argc, char * argv[] ) { … … 158 154 PathMode path = FromProc(); 159 155 160 const char * args[argc + 100]; // cfa command line values, plus some space for additional flags156 const char * args[argc + 100]; // cfa command line values, plus some space for additional flags 161 157 int sargs = 1; // starting location for arguments in args list 162 158 int nargs = sargs; // number of arguments in args list; 0 => command name 163 159 164 const char * libs[argc + 20]; // non-user libraries must come separately, plus some added libraries and flags160 const char * libs[argc + 20]; // non-user libraries must come separately, plus some added libraries and flags 165 161 int nlibs = 0; 166 162 … … 180 176 181 177 if ( arg == "-Xlinker" || arg == "-o" ) { 182 args[nargs++] = argv[i]; // pass argumentalong178 args[nargs++] = argv[i]; // pass flag along 183 179 i += 1; 184 180 if ( i == argc ) continue; // next argument available ? 185 181 args[nargs++] = argv[i]; // pass argument along 186 182 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 ) { 189 188 i += 1; 190 if ( i == argc ) continue; 189 if ( i == argc ) continue; // next argument available ? 191 190 Putenv( argv, argv[i] ); 192 193 // CFA specific arguments 194 } 195 else if(arg[5] == ',') { 191 } else if ( arg[5] == ',' ) { // CFA specific arguments 196 192 Putenv( argv, argv[i] + 6 ); 197 198 // CFA specific arguments 199 } 200 else { 193 } else { // CFA specific arguments 201 194 args[nargs++] = argv[i]; 202 } 203 195 } // if 204 196 } else if ( arg == "-CFA" ) { 205 197 CFA_flag = true; // strip the -CFA flag … … 210 202 } else if ( arg == "-nodebug" ) { 211 203 debug = false; // strip the nodebug flag 212 } else if ( arg == "-nolib" ) {213 nolib = true; // strip the nodebug flag214 204 } else if ( arg == "-quiet" ) { 215 205 quiet = true; // strip the quiet flag 216 206 } else if ( arg == "-noquiet" ) { 217 207 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 218 212 } else if ( arg == "-help" ) { 219 213 help = true; // strip the help flag 220 214 } else if ( arg == "-nohelp" ) { 221 215 help = false; // strip the nohelp flag 222 } else if ( arg == "-no-include-stdhdr" ) {223 noincstd_flag = true; // strip the no-include-stdhdr flag224 216 } else if ( arg == "-cfalib") { 225 217 compiling_libs = true; … … 235 227 } else if ( arg == "-v" ) { 236 228 verbose = true; // verbosity required 237 args[nargs++] = argv[i]; // pass argumentalong229 args[nargs++] = argv[i]; // pass flag along 238 230 } else if ( arg == "-g" ) { 239 231 debugging = true; // symbolic debugging required 240 args[nargs++] = argv[i]; // pass argumentalong232 args[nargs++] = argv[i]; // pass flag along 241 233 } else if ( arg == "-save-temps" ) { 242 args[nargs++] = argv[i]; // pass argumentalong234 args[nargs++] = argv[i]; // pass flag along 243 235 Putenv( argv, arg ); // save cfa-cpp output 244 236 } else if ( prefix( arg, "-x" ) ) { // file suffix ? 245 237 string lang; 246 args[nargs++] = argv[i]; // pass argumentalong238 args[nargs++] = argv[i]; // pass flag along 247 239 if ( arg.length() == 2 ) { // separate argument ? 248 240 i += 1; … … 261 253 } else if ( prefix( arg, "-std=" ) || prefix( arg, "--std=" ) ) { 262 254 std_flag = true; // -std=XX provided 263 args[nargs++] = argv[i]; // pass argumentalong255 args[nargs++] = argv[i]; // pass flag along 264 256 } else if ( arg == "-w" ) { 265 args[nargs++] = argv[i]; // pass argumentalong257 args[nargs++] = argv[i]; // pass flag along 266 258 Putenv( argv, arg ); 267 259 } else if ( prefix( arg, "-W" ) ) { // check before next tests 268 260 if ( arg == "-Werror" || arg == "-Wall" ) { 269 args[nargs++] = argv[i]; // pass argumentalong261 args[nargs++] = argv[i]; // pass flag along 270 262 Putenv( argv, argv[i] ); 271 263 } else { … … 281 273 bprefix = arg.substr(2); // strip the -B flag 282 274 } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) { 283 args[nargs++] = argv[i]; // pass argumentalong275 args[nargs++] = argv[i]; // pass flag along 284 276 if ( arg == "-E" || arg == "-M" || arg == "-MM" ) { 285 277 cpp_flag = true; // cpp only 286 278 } // if 287 279 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 288 286 } else if ( arg[1] == 'l' ) { 289 287 // if the user specifies a library, load it after user code … … 337 335 string libbase; 338 336 switch(path) { 339 case Installed:337 case Installed: 340 338 args[nargs++] = "-I" CFA_INCDIR; 341 339 // do not use during build … … 347 345 libbase = CFA_LIBDIR; 348 346 break; 349 case BuildTree:350 case Distributed:347 case BuildTree: 348 case Distributed: 351 349 args[nargs++] = "-I" TOP_SRCDIR "libcfa/src"; 352 350 // do not use during build … … 382 380 string libdir = libbase + arch + "-" + config; 383 381 384 if ( path != Distributed) {382 if ( path != Distributed ) { 385 383 if ( ! nolib && ! dirExists( libdir ) ) { 386 384 cerr << argv[0] << " internal error, configuration " << config << " not installed." << endl; … … 402 400 string preludedir; 403 401 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 408 406 409 407 Putenv( argv, "--prelude-dir=" + preludedir ); … … 477 475 if ( bprefix.length() == 0 ) { 478 476 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 } // if477 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 ); 486 484 487 485 args[nargs++] = "-Xlinker"; // used by backtrace … … 505 503 args[nargs++] = "-Wno-cast-function-type"; 506 504 #endif // HAVE_CAST_FUNCTION_TYPE 507 if ( ! std_flag ) { // default c11, if none specified508 args[nargs++] = "-std=gnu11"; 505 if ( ! std_flag && ! x_flag ) { 506 args[nargs++] = "-std=gnu11"; // default c11, if none specified 509 507 } // if 510 508 args[nargs++] = "-fgnu89-inline"; … … 556 554 // execute the command and return the result 557 555 558 execvp( args[0], (char * const *)args );// should not return556 execvp( args[0], (char * const *)args ); // should not return 559 557 perror( "CFA Translator error: execvp" ); 560 558 exit( EXIT_FAILURE ); -
libcfa/prelude/bootloader.cf
r67ca73e re67a82d 1 1 extern "C" { static inline int invoke_main(int argc, char* argv[], char* envp[]); } 2 int cfa_args_argc; 3 char ** cfa_args_argv; 4 char ** cfa_args_envp; 2 5 3 6 int main(int argc, char* argv[], char* envp[]) { 7 cfa_args_argc = argc; 8 cfa_args_argv = argv; 9 cfa_args_envp = envp; 4 10 return invoke_main(argc, argv, envp); 5 11 } -
libcfa/src/Makefile.am
r67ca73e re67a82d 44 44 45 45 headers = 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 \ 47 47 containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa 48 48 -
libcfa/src/bits/locks.hfa
r67ca73e re67a82d 217 217 } 218 218 } 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 } 219 253 #endif -
libcfa/src/common.hfa
r67ca73e re67a82d 10 10 // Created On : Wed Jul 11 17:54:36 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 12 08:02:18 201813 // Update Count : 512 // Last Modified On : Sat Aug 15 08:51:29 2020 13 // Update Count : 14 14 14 // 15 15 … … 67 67 68 68 static 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 69 72 forall( otype T | { int ?<?( T, T ); } ) 70 73 T min( T t1, T t2 ) { return t1 < t2 ? t1 : t2; } 71 74 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 72 78 forall( otype T | { int ?>?( T, T ); } ) 73 79 T max( T t1, T t2 ) { return t1 > t2 ? t1 : t2; } -
libcfa/src/concurrency/alarm.hfa
r67ca73e re67a82d 23 23 #include "time.hfa" 24 24 25 #include <containers/list.hfa>25 #include "containers/list.hfa" 26 26 27 27 struct $thread; -
libcfa/src/concurrency/coroutine.cfa
r67ca73e re67a82d 215 215 return cor; 216 216 } 217 218 struct $coroutine * __cfactx_cor_active(void) { 219 return active_coroutine(); 220 } 217 221 } 218 222 -
libcfa/src/concurrency/invoke.c
r67ca73e re67a82d 10 10 // Created On : Tue Jan 17 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Aug 20 18:54:34202013 // Update Count : 3 012 // Last Modified On : Thu Aug 20 23:43:23 2020 13 // Update Count : 31 14 14 // 15 15 … … 29 29 // Called from the kernel when starting a coroutine or task so must switch back to user mode. 30 30 31 extern struct $coroutine * __cfactx_cor_active(void); 31 32 extern struct $coroutine * __cfactx_cor_finish(void); 32 33 extern void __cfactx_cor_leave ( struct $coroutine * ); … … 35 36 extern void disable_interrupts() OPTIONAL_THREAD; 36 37 extern void enable_interrupts( __cfaabi_dbg_ctx_param ); 38 39 struct exception_context_t * this_exception_context() { 40 return &__get_stack( __cfactx_cor_active() )->exception_context; 41 } 37 42 38 43 void __cfactx_invoke_coroutine( … … 146 151 147 152 #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 149 162 struct FakeStack { 150 163 float fpRegs[16]; // floating point registers -
libcfa/src/concurrency/invoke.h
r67ca73e re67a82d 26 26 #ifndef _INVOKE_H_ 27 27 #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 }; 28 35 29 36 struct __stack_context_t { … … 51 58 // base of stack 52 59 void * base; 60 61 // Information for exception handling. 62 struct exception_context_t exception_context; 53 63 }; 54 64 … … 84 94 }; 85 95 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(); 87 101 88 102 // struct which calls the monitor is accepting -
libcfa/src/concurrency/io.cfa
r67ca73e re67a82d 41 41 #include "kernel/fwd.hfa" 42 42 #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 } 43 106 44 107 //============================================================================================= … … 93 156 //============================================================================================= 94 157 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 ); 96 159 97 160 static inline void process(struct io_uring_cqe & cqe ) { … … 100 163 101 164 data->result = cqe.res; 102 unpark( data->thrd __cfaabi_dbg_ctx2);165 post( data->sem ); 103 166 } 104 167 … … 136 199 unsigned head = *ring.completion_q.head; 137 200 unsigned tail = *ring.completion_q.tail; 138 const uint32_tmask = *ring.completion_q.mask;201 const __u32 mask = *ring.completion_q.mask; 139 202 140 203 // Nothing was new return 0 … … 143 206 } 144 207 145 uint32_tcount = tail - head;208 __u32 count = tail - head; 146 209 /* paranoid */ verify( count != 0 ); 147 210 for(i; count) { … … 182 245 __STATS__( true, 183 246 io.complete_q.completed_avg.val += count; 184 io.complete_q.completed_avg. fast_cnt += 1;247 io.complete_q.completed_avg.cnt += 1; 185 248 ) 186 249 enable_interrupts( __cfaabi_dbg_ctx ); … … 192 255 // We didn't get anything baton pass to the slow poller 193 256 else { 257 __STATS__( false, 258 io.complete_q.blocks += 1; 259 ) 194 260 __cfadbg_print_safe(io_core, "Kernel I/O : Parking io poller %p\n", &this.self); 195 261 reset = 0; … … 224 290 // 225 291 226 [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_tdata ) {292 [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ) { 227 293 /* paranoid */ verify( data != 0 ); 228 294 … … 230 296 __attribute((unused)) int len = 0; 231 297 __attribute((unused)) int block = 0; 232 uint32_tcnt = *ring.submit_q.num;233 uint32_tmask = *ring.submit_q.mask;298 __u32 cnt = *ring.submit_q.num; 299 __u32 mask = *ring.submit_q.mask; 234 300 235 301 disable_interrupts(); 236 uint32_toff = __tls_rand();302 __u32 off = __tls_rand(); 237 303 enable_interrupts( __cfaabi_dbg_ctx ); 238 304 … … 241 307 // Look through the list starting at some offset 242 308 for(i; cnt) { 243 uint64_texpected = 0;244 uint32_tidx = (i + off) & mask;309 __u64 expected = 0; 310 __u32 idx = (i + off) & mask; 245 311 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; 247 313 248 314 if( *udata == expected && … … 270 336 } 271 337 272 static inline uint32_t __submit_to_ready_array( struct __io_data & ring, uint32_t idx, const uint32_tmask ) {338 static inline __u32 __submit_to_ready_array( struct __io_data & ring, __u32 idx, const __u32 mask ) { 273 339 /* paranoid */ verify( idx <= mask ); 274 340 /* paranoid */ verify( idx != -1ul32 ); … … 277 343 __attribute((unused)) int len = 0; 278 344 __attribute((unused)) int block = 0; 279 uint32_tready_mask = ring.submit_q.ready_cnt - 1;345 __u32 ready_mask = ring.submit_q.ready_cnt - 1; 280 346 281 347 disable_interrupts(); 282 uint32_toff = __tls_rand();348 __u32 off = __tls_rand(); 283 349 enable_interrupts( __cfaabi_dbg_ctx ); 284 350 285 uint32_tpicked;351 __u32 picked; 286 352 LOOKING: for() { 287 353 for(i; ring.submit_q.ready_cnt) { 288 354 picked = (i + off) & ready_mask; 289 uint32_texpected = -1ul32;355 __u32 expected = -1ul32; 290 356 if( __atomic_compare_exchange_n( &ring.submit_q.ready[picked], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) { 291 357 break LOOKING; … … 297 363 298 364 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 ) { 304 368 yield(); 305 369 } … … 316 380 } 317 381 318 void __submit( struct io_context * ctx, uint32_tidx ) __attribute__((nonnull (1))) {382 void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1))) { 319 383 __io_data & ring = *ctx->thrd.ring; 320 384 // Get now the data we definetely need 321 volatile uint32_t* const tail = ring.submit_q.tail;322 const uint32_tmask = *ring.submit_q.mask;385 volatile __u32 * const tail = ring.submit_q.tail; 386 const __u32 mask = *ring.submit_q.mask; 323 387 324 388 // There are 2 submission schemes, check which one we are using … … 332 396 } 333 397 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) ) { 342 402 __STATS__( false, 343 403 io.submit_q.helped += 1; … … 345 405 return; 346 406 } 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 349 431 __STATS__( false, 350 io.submit_q. leader+= 1;432 io.submit_q.busy += 1; 351 433 ) 352 break; 353 } 354 355 __STATS__( false, 356 io.submit_q.busy += 1; 357 ) 358 } 434 } 435 #endif 359 436 360 437 // We got the lock 438 // Collect the submissions 361 439 unsigned to_submit = __collect_submitions( ring ); 440 441 // Actually submit 362 442 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; 369 451 370 452 // Release the consumed SQEs … … 372 454 373 455 // update statistics 374 __STATS__( true,456 __STATS__( false, 375 457 io.submit_q.submit_avg.rdy += to_submit; 376 458 io.submit_q.submit_avg.csm += ret; 377 459 io.submit_q.submit_avg.cnt += 1; 378 460 ) 379 380 unlock(ring.submit_q.lock);381 461 } 382 462 else { 383 463 // 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 385 469 386 470 /* paranoid */ verifyf( ring.submit_q.sqes[ idx ].user_data != 0, … … 420 504 __release_consumed_submission( ring ); 421 505 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 423 511 424 512 __cfadbg_print_safe( io, "Kernel I/O : Performed io_submit for %p, returned %d\n", active_thread(), ret ); … … 426 514 } 427 515 516 // #define PARTIAL_SUBMIT 32 428 517 static unsigned __collect_submitions( struct __io_data & ring ) { 429 518 /* paranoid */ verify( ring.submit_q.ready != 0p ); … … 431 520 432 521 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 435 535 436 536 // 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 438 540 // replace any submission with the sentinel, to consume it. 439 uint32_tidx = __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); 440 542 441 543 // If it was already the sentinel, then we are done … … 453 555 } 454 556 455 static uint32_t__release_consumed_submission( struct __io_data & ring ) {456 const uint32_tsmask = *ring.submit_q.mask;557 static __u32 __release_consumed_submission( struct __io_data & ring ) { 558 const __u32 smask = *ring.submit_q.mask; 457 559 458 560 if( !try_lock(ring.submit_q.release_lock __cfaabi_dbg_ctx2) ) return 0; 459 uint32_tchead = *ring.submit_q.head;460 uint32_tphead = ring.submit_q.prev_head;561 __u32 chead = *ring.submit_q.head; 562 __u32 phead = ring.submit_q.prev_head; 461 563 ring.submit_q.prev_head = chead; 462 564 unlock(ring.submit_q.release_lock); 463 565 464 uint32_tcount = chead - phead;566 __u32 count = chead - phead; 465 567 for( i; count ) { 466 uint32_tidx = ring.submit_q.array[ (phead + i) & smask ];568 __u32 idx = ring.submit_q.array[ (phead + i) & smask ]; 467 569 ring.submit_q.sqes[ idx ].user_data = 0; 468 570 } -
libcfa/src/concurrency/io/setup.cfa
r67ca73e re67a82d 228 228 if( cluster_context ) { 229 229 cluster & cltr = *thrd.curr_cluster; 230 /* paranoid */ verify( cltr. nprocessors== 0 || &cltr == mainCluster );230 /* paranoid */ verify( cltr.idles.total == 0 || &cltr == mainCluster ); 231 231 /* paranoid */ verify( !ready_mutate_islocked() ); 232 232 … … 298 298 if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL; 299 299 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 } 301 307 302 308 int fd = syscall(__NR_io_uring_setup, nentries, ¶ms ); … … 356 362 // Get the pointers from the kernel to fill the structure 357 363 // 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); 365 371 sq.prev_head = *sq.head; 366 372 367 373 { 368 const uint32_tnum = *sq.num;374 const __u32 num = *sq.num; 369 375 for( i; num ) { 370 376 sq.sqes[i].user_data = 0ul64; … … 372 378 } 373 379 374 (sq. lock){};380 (sq.submit_lock){}; 375 381 (sq.release_lock){}; 376 382 … … 382 388 sq.ready[i] = -1ul32; 383 389 } 390 sq.prev_ready = 0; 384 391 } 385 392 else { 386 393 sq.ready_cnt = 0; 387 394 sq.ready = 0p; 395 sq.prev_ready = 0; 388 396 } 389 397 390 398 // 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 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); 397 405 398 406 // some paranoid checks … … 442 450 void __ioctx_register($io_ctx_thread & ctx, struct epoll_event & ev) { 443 451 ev.events = EPOLLIN | EPOLLONESHOT; 444 ev.data.u64 = ( uint64_t)&ctx;452 ev.data.u64 = (__u64)&ctx; 445 453 int ret = epoll_ctl(iopoll.epollfd, EPOLL_CTL_ADD, ctx.ring->fd, &ev); 446 454 if (ret < 0) { -
libcfa/src/concurrency/io/types.hfa
r67ca73e re67a82d 17 17 18 18 #if defined(CFA_HAVE_LINUX_IO_URING_H) 19 extern "C" { 20 #include <linux/types.h> 21 } 22 19 23 #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; } 20 31 21 32 //----------------------------------------------------------------------- … … 23 34 struct __submition_data { 24 35 // Head and tail of the ring (associated with array) 25 volatile uint32_t* head;26 volatile uint32_t* tail;27 volatile uint32_tprev_head;36 volatile __u32 * head; 37 volatile __u32 * tail; 38 volatile __u32 prev_head; 28 39 29 40 // The actual kernel ring which uses head/tail 30 41 // indexes into the sqes arrays 31 uint32_t* array;42 __u32 * array; 32 43 33 44 // 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; 36 47 37 48 // Submission flags (Not sure what for) 38 uint32_t* flags;49 __u32 * flags; 39 50 40 51 // number of sqes not submitted (whatever that means) 41 uint32_t* dropped;52 __u32 * dropped; 42 53 43 54 // 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; 46 58 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; 49 65 50 66 // A buffer of sqes (not the actual ring) … … 58 74 struct __completion_data { 59 75 // Head and tail of the ring 60 volatile uint32_t* head;61 volatile uint32_t* tail;76 volatile __u32 * head; 77 volatile __u32 * tail; 62 78 63 79 // 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; 66 82 67 83 // number of cqes not submitted (whatever that means) 68 uint32_t* overflow;84 __u32 * overflow; 69 85 70 86 // the kernel ring … … 79 95 struct __submition_data submit_q; 80 96 struct __completion_data completion_q; 81 uint32_tring_flags;97 __u32 ring_flags; 82 98 int fd; 83 99 bool eager_submits:1; … … 89 105 // IO user data 90 106 struct __io_user_data_t { 91 int32_tresult;92 $thread * thrd;107 __s32 result; 108 oneshot sem; 93 109 }; 94 110 -
libcfa/src/concurrency/iocall.cfa
r67ca73e re67a82d 32 32 #include "io/types.hfa" 33 33 34 extern [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_tdata );35 extern void __submit( struct io_context * ctx, uint32_tidx ) __attribute__((nonnull (1)));36 37 static inline void ?{}(struct io_uring_sqe & this, uint8_topcode, 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) { 38 38 this.opcode = opcode; 39 39 #if !defined(IOSQE_ASYNC) … … 51 51 } 52 52 53 static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd, void * addr, uint32_t len, uint64_toff ) {53 static inline void ?{}(struct io_uring_sqe & this, __u8 opcode, int fd, void * addr, __u32 len, __u64 off ) { 54 54 (this){ opcode, fd }; 55 55 this.off = off; 56 this.addr = ( uint64_t)(uintptr_t)addr;56 this.addr = (__u64)(uintptr_t)addr; 57 57 this.len = len; 58 58 } … … 101 101 #endif 102 102 103 104 103 #define __submit_prelude \ 105 104 if( 0 != (submit_flags & LINK_FLAGS) ) { errno = ENOTSUP; return -1; } \ 106 105 (void)timeout; (void)cancellation; \ 107 106 if( !context ) context = __get_io_context(); \ 108 __io_user_data_t data = { 0 , active_thread()}; \107 __io_user_data_t data = { 0 }; \ 109 108 struct __io_data & ring = *context->thrd.ring; \ 110 109 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; 114 114 115 115 #define __submit_wait \ 116 116 /*__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 ); \ 118 118 __submit( context, idx ); \ 119 park( __cfaabi_dbg_ctx); \119 wait( data.sem ); \ 120 120 if( data.result < 0 ) { \ 121 121 errno = -data.result; \ … … 149 149 150 150 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); 152 159 153 160 struct msghdr; … … 160 167 extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 161 168 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); 164 171 extern int madvise(void *addr, size_t length, int advice); 165 172 … … 186 193 __submit_prelude 187 194 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; 189 203 190 204 __submit_wait … … 200 214 __submit_prelude 201 215 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; 203 224 204 225 __submit_wait … … 213 234 __submit_prelude 214 235 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 249 int 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) { 222 250 #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_SYNC_FILE_RANGE) 223 251 return sync_file_range(fd, offset, nbytes, flags); … … 268 296 269 297 (*sqe){ IORING_OP_SEND, sockfd }; 270 sqe->addr = ( uint64_t)buf;298 sqe->addr = (__u64)buf; 271 299 sqe->len = len; 272 300 sqe->msg_flags = flags; … … 283 311 284 312 (*sqe){ IORING_OP_RECV, sockfd }; 285 sqe->addr = ( uint64_t)buf;313 sqe->addr = (__u64)buf; 286 314 sqe->len = len; 287 315 sqe->msg_flags = flags; … … 298 326 299 327 (*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; 302 330 sqe->accept_flags = flags; 303 331 … … 313 341 314 342 (*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 350 int cfa_fallocate(int fd, int mode, off_t offset, off_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) { 323 351 #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_FALLOCATE) 324 352 return fallocate( fd, mode, offset, len ); … … 337 365 } 338 366 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) {367 int cfa_fadvise(int fd, off_t offset, off_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) { 340 368 #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_FADVISE) 341 369 return posix_fadvise( fd, offset, len, advice ); … … 344 372 345 373 (*sqe){ IORING_OP_FADVISE, fd }; 346 sqe->off = ( uint64_t)offset;374 sqe->off = (__u64)offset; 347 375 sqe->len = len; 348 376 sqe->fadvise_advice = advice; … … 359 387 360 388 (*sqe){ IORING_OP_MADVISE, 0 }; 361 sqe->addr = ( uint64_t)addr;389 sqe->addr = (__u64)addr; 362 390 sqe->len = length; 363 391 sqe->fadvise_advice = advice; … … 374 402 375 403 (*sqe){ IORING_OP_OPENAT, dirfd }; 376 sqe->addr = ( uint64_t)pathname;404 sqe->addr = (__u64)pathname; 377 405 sqe->open_flags = flags; 378 406 sqe->len = mode; … … 407 435 __submit_prelude 408 436 409 (*sqe){ IORING_OP_STATX, dirfd, pathname, mask, ( uint64_t)statxbuf };437 (*sqe){ IORING_OP_STATX, dirfd, pathname, mask, (__u64)statxbuf }; 410 438 sqe->statx_flags = flags; 411 439 … … 449 477 } 450 478 else { 451 sqe->off = ( uint64_t)-1;479 sqe->off = (__u64)-1; 452 480 } 453 481 sqe->len = len; … … 457 485 } 458 486 else { 459 sqe->splice_off_in = ( uint64_t)-1;487 sqe->splice_off_in = (__u64)-1; 460 488 } 461 489 sqe->splice_flags = flags | (SPLICE_FLAGS & submit_flags); -
libcfa/src/concurrency/kernel.cfa
r67ca73e re67a82d 102 102 // Kernel Scheduling logic 103 103 static $thread * __next_thread(cluster * this); 104 static bool __has_next_thread(cluster * this);104 static $thread * __next_thread_slow(cluster * this); 105 105 static 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 *); 106 static void __wake_one(struct __processor_id_t * id, cluster * cltr); 107 108 static void push (__cluster_idles & idles, processor & proc); 109 static void remove(__cluster_idles & idles, processor & proc); 110 static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles ); 111 109 112 110 113 //============================================================================================= … … 116 119 // Do it here 117 120 kernelTLS.rand_seed ^= rdtscl(); 121 kernelTLS.ready_rng.fwd_seed = 25214903917_l64u * (rdtscl() ^ (uintptr_t)&runner); 122 __tls_rand_advance_bck(); 118 123 119 124 processor * this = runner.proc; … … 134 139 135 140 $thread * readyThread = 0p; 136 for( unsigned int spin_count = 0;; spin_count++ ) { 141 MAIN_LOOP: 142 for() { 137 143 // Try to get the next thread 138 144 readyThread = __next_thread( this->cltr ); 139 145 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 ); 151 148 } 152 149 153 if(__atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST)) break; 154 150 HALT: 155 151 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; 158 195 } 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; 159 204 } 160 205 … … 181 226 // from the processor coroutine to the target thread 182 227 static 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 183 233 $coroutine * proc_cor = get_coroutine(this->runner); 184 234 … … 260 310 proc_cor->state = Active; 261 311 kernelTLS.this_thread = 0p; 312 313 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 262 314 } 263 315 … … 316 368 ready_schedule_lock ( id ); 317 369 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); 327 371 ready_schedule_unlock( id ); 328 372 … … 331 375 332 376 // KERNEL ONLY 333 static $thread * __next_thread(cluster * this) with( *this ) {377 static inline $thread * __next_thread(cluster * this) with( *this ) { 334 378 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 335 379 336 380 ready_schedule_lock ( (__processor_id_t*)kernelTLS.this_processor ); 337 $thread * head = pop( this );381 $thread * thrd = pop( this ); 338 382 ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor ); 339 383 340 384 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 341 return head;385 return thrd; 342 386 } 343 387 344 388 // KERNEL ONLY 345 static bool __has_next_thread(cluster * this) with( *this ) {389 static inline $thread * __next_thread_slow(cluster * this) with( *this ) { 346 390 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 347 391 348 392 ready_schedule_lock ( (__processor_id_t*)kernelTLS.this_processor ); 349 bool not_empty = query( this );393 $thread * thrd = pop_slow( this ); 350 394 ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor ); 351 395 352 396 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 353 return not_empty;397 return thrd; 354 398 } 355 399 … … 441 485 //============================================================================================= 442 486 // Wake a thread from the front if there are any 443 static bool __wake_one(struct __processor_id_t * id, cluster * this) { 487 static void __wake_one(struct __processor_id_t * id, cluster * this) { 488 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 444 489 /* paranoid */ verify( ready_schedule_islocked( id ) ); 445 490 446 491 // 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); 448 496 449 497 // If no one is sleeping, we are done 450 if( 0p == p ) return false;498 if( idle == 0 ) return; 451 499 452 500 // We found a processor, wake it up 453 501 post( p->idle ); 454 502 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; 456 511 } 457 512 458 513 // Unconditionnaly wake a thread 459 bool__wake_proc(processor * this) {514 void __wake_proc(processor * this) { 460 515 __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this); 461 516 … … 464 519 bool ret = post( this->idle ); 465 520 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 523 static 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 534 static 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 545 static [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 } 504 557 } 505 558 -
libcfa/src/concurrency/kernel.hfa
r67ca73e re67a82d 20 20 #include "coroutine.hfa" 21 21 22 #include "containers/ stackLockFree.hfa"22 #include "containers/list.hfa" 23 23 24 24 extern "C" { … … 99 99 100 100 // Link lists fields 101 Link(processor) link;101 DLISTED_MGD_IMPL_IN(processor) 102 102 103 103 #if !defined(__CFA_NO_STATISTICS__) … … 119 119 static inline void ?{}(processor & this, const char name[]) { this{name, *mainCluster }; } 120 120 121 static inline Link(processor) * ?`next( processor * this ) { return &this->link; } 121 DLISTED_MGD_IMPL_OUT(processor) 122 122 123 123 //----------------------------------------------------------------------------- … … 206 206 void ^?{}(__ready_queue_t & this); 207 207 208 // Idle Sleep 209 struct __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 208 223 //----------------------------------------------------------------------------- 209 224 // Cluster … … 219 234 220 235 // List of idle processors 221 StackLF(processor) idles; 222 volatile unsigned int nprocessors; 236 __cluster_idles idles; 223 237 224 238 // List of threads -
libcfa/src/concurrency/kernel/fwd.hfa
r67ca73e re67a82d 50 50 uint64_t rand_seed; 51 51 #endif 52 struct { 53 uint64_t fwd_seed; 54 uint64_t bck_seed; 55 } ready_rng; 52 56 } kernelTLS __attribute__ ((tls_model ( "initial-exec" ))); 57 58 53 59 54 60 static inline uint64_t __tls_rand() { … … 58 64 return __xorshift64( kernelTLS.rand_seed ); 59 65 #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; 60 94 } 61 95 } -
libcfa/src/concurrency/kernel/startup.cfa
r67ca73e re67a82d 78 78 static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info); 79 79 80 #if defined(__CFA_WITH_VERIFY__) 81 static bool verify_fwd_bck_rng(void); 82 #endif 83 80 84 //----------------------------------------------------------------------------- 81 85 // Forward Declarations for other modules … … 87 91 //----------------------------------------------------------------------------- 88 92 // Other Forward Declarations 89 extern bool__wake_proc(processor *);93 extern void __wake_proc(processor *); 90 94 91 95 //----------------------------------------------------------------------------- … … 158 162 __cfa_dbg_global_clusters.list{ __get }; 159 163 __cfa_dbg_global_clusters.lock{}; 164 165 /* paranoid */ verify( verify_fwd_bck_rng() ); 160 166 161 167 // Initialize the global scheduler lock … … 475 481 #endif 476 482 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 ); 478 486 479 487 id = doregister((__processor_id_t*)&this); … … 493 501 // Not a ctor, it just preps the destruction but should not destroy members 494 502 static 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 ); 497 506 498 507 // Lock the RWlock so no-one pushes/pops while we are changing the queue … … 501 510 // Adjust the ready queue size 502 511 ready_queue_shrink( this.cltr, target ); 503 504 // Make sure we aren't on the idle queue505 unsafe_remove( this.cltr->idles, &this );506 512 507 513 // Unlock the RWlock … … 516 522 ( this.terminated ){ 0 }; 517 523 ( this.runner ){}; 518 init( this, name, _cltr ); 524 525 disable_interrupts(); 526 init( this, name, _cltr ); 527 enable_interrupts( __cfaabi_dbg_ctx ); 519 528 520 529 __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this); … … 540 549 free( this.stack ); 541 550 542 deinit( this ); 551 disable_interrupts(); 552 deinit( this ); 553 enable_interrupts( __cfaabi_dbg_ctx ); 543 554 } 544 555 545 556 //----------------------------------------------------------------------------- 546 557 // Cluster 558 static void ?{}(__cluster_idles & this) { 559 this.lock = 0; 560 this.idle = 0; 561 this.total = 0; 562 (this.list){}; 563 } 564 547 565 void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) with( this ) { 548 566 this.name = name; 549 567 this.preemption_rate = preemption_rate; 550 this.nprocessors = 0;551 568 ready_queue{}; 552 569 … … 666 683 return stack; 667 684 } 685 686 #if defined(__CFA_WITH_VERIFY__) 687 static 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 121 121 void unregister( struct __processor_id_t * proc ); 122 122 123 //----------------------------------------------------------------------- 124 // Cluster idle lock/unlock 125 static 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 136 static 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 123 141 //======================================================================= 124 142 // Reader-writer lock implementation … … 248 266 // pop thread from the ready queue of a cluster 249 267 // returns 0p if empty 268 // May return 0p spuriously 250 269 __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); 251 276 252 277 //----------------------------------------------------------------------- -
libcfa/src/concurrency/ready_queue.cfa
r67ca73e re67a82d 17 17 // #define __CFA_DEBUG_PRINT_READY_QUEUE__ 18 18 19 // #define USE_SNZI 20 19 21 #include "bits/defs.hfa" 20 22 #include "kernel_private.hfa" … … 148 150 // queues or removing them. 149 151 uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) { 152 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 153 150 154 // Step 1 : lock global lock 151 155 // It is needed to avoid processors that register mid Critical-Section … … 162 166 } 163 167 168 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 164 169 return s; 165 170 } 166 171 167 172 void ready_mutate_unlock( uint_fast32_t last_s ) with(*__scheduler_lock) { 173 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 174 168 175 // Step 1 : release local locks 169 176 // This must be done while the global lock is held to avoid … … 180 187 /*paranoid*/ assert(true == lock); 181 188 __atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE); 189 190 /* paranoid */ verify( ! kernelTLS.preemption_state.enabled ); 182 191 } 183 192 … … 192 201 void ^?{}(__ready_queue_t & this) with (this) { 193 202 verify( 1 == lanes.count ); 194 verify( !query( snzi ) ); 203 #ifdef USE_SNZI 204 verify( !query( snzi ) ); 205 #endif 195 206 free(lanes.data); 196 207 } … … 198 209 //----------------------------------------------------------------------- 199 210 __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; 201 215 } 202 216 … … 262 276 bool lane_first = push(lanes.data[i], thrd); 263 277 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 272 288 273 289 // Unlock and return … … 294 310 __attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) { 295 311 /* paranoid */ verify( lanes.count > 0 ); 312 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED ); 296 313 #if defined(BIAS) 297 314 // Don't bother trying locally too much … … 300 317 301 318 // 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 303 324 // Pick two lists at random 304 325 unsigned i,j; … … 336 357 #endif 337 358 338 i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );339 j %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );359 i %= count; 360 j %= count; 340 361 341 362 // try popping from the 2 picked lists … … 353 374 } 354 375 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 355 393 //----------------------------------------------------------------------- 356 394 // Given 2 indexes, pick the list with the oldest push an try to pop from it … … 388 426 // Actually pop the list 389 427 struct $thread * thrd; 390 bool emptied; 391 [thrd, emptied] = pop(lane); 428 thrd = pop(lane); 392 429 393 430 /* paranoid */ verify(thrd); 394 431 /* paranoid */ verify(lane.lock); 395 432 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 400 439 401 440 // Unlock and return … … 424 463 if(head(lane)->link.next == thrd) { 425 464 $thread * pthrd; 426 bool emptied; 427 [pthrd, emptied] = pop(lane); 465 pthrd = pop(lane); 428 466 429 467 /* paranoid */ verify( pthrd == thrd ); 430 468 431 469 removed = true; 432 if(emptied) { 433 depart( snzi, i ); 434 } 470 #ifdef USE_SNZI 471 if(emptied) { 472 depart( snzi, i ); 473 } 474 #endif 435 475 } 436 476 __atomic_unlock(&lane.lock); … … 494 534 // grow the ready queue 495 535 with( cltr->ready_queue ) { 496 ^(snzi){}; 536 #ifdef USE_SNZI 537 ^(snzi){}; 538 #endif 497 539 498 540 // Find new count … … 516 558 lanes.count = ncount; 517 559 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 525 569 } 526 570 … … 542 586 543 587 with( cltr->ready_queue ) { 544 ^(snzi){}; 588 #ifdef USE_SNZI 589 ^(snzi){}; 590 #endif 545 591 546 592 // Remember old count … … 567 613 while(!is_empty(lanes.data[idx])) { 568 614 struct $thread * thrd; 569 __attribute__((unused)) bool _; 570 [thrd, _] = pop(lanes.data[idx]); 615 thrd = pop(lanes.data[idx]); 571 616 572 617 push(cltr, thrd); … … 596 641 } 597 642 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 605 652 } 606 653 -
libcfa/src/concurrency/ready_subqueue.hfa
r67ca73e re67a82d 144 144 // returns popped 145 145 // 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) { 147 147 /* paranoid */ verify(this.lock); 148 148 /* paranoid */ verify(this.before.link.ts != 0ul); … … 162 162 head->link.next = next; 163 163 next->link.prev = head; 164 node->link.[next, prev] = 0p; 164 node->link.next = 0p; 165 node->link.prev = 0p; 165 166 166 167 // Update head time stamp … … 180 181 /* paranoid */ verify(tail(this)->link.prev == head(this)); 181 182 /* paranoid */ verify(head(this)->link.next == tail(this)); 182 return [node, true];183 return node; 183 184 } 184 185 else { … … 187 188 /* paranoid */ verify(head(this)->link.next != tail(this)); 188 189 /* paranoid */ verify(this.before.link.ts != 0); 189 return [node, false];190 return node; 190 191 } 191 192 } -
libcfa/src/concurrency/stats.cfa
r67ca73e re67a82d 38 38 stats->io.submit_q.busy = 0; 39 39 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; 42 42 #endif 43 43 } … … 60 60 61 61 #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 ); 78 78 #endif 79 79 } … … 154 154 "- avg alloc search len : %'18.2lf\n" 155 155 "- 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" 157 157 "- avg completion/wait : %'18.2lf\n" 158 "- total completion blocks: %'15" PRIu64 "\n" 158 159 "\n" 159 160 , cluster ? "Cluster" : "Processor", name, id … … 165 166 , io.submit_q.alloc_avg.cnt 166 167 , aavgv, aavgb 167 , io.complete_q.completed_avg. slow_cnt + io.complete_q.completed_avg.fast_cnt168 , io.complete_q.completed_avg.slow_cnt, io.complete_q.completed_avg.fast_cnt169 , ((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 170 171 ); 171 172 } -
libcfa/src/concurrency/stats.hfa
r67ca73e re67a82d 90 90 struct { 91 91 volatile uint64_t val; 92 volatile uint64_t slow_cnt; 93 volatile uint64_t fast_cnt; 92 volatile uint64_t cnt; 94 93 } completed_avg; 94 volatile uint64_t blocks; 95 95 } complete_q; 96 96 }; -
libcfa/src/containers/list.hfa
r67ca73e re67a82d 13 13 // Update Count : 1 14 14 // 15 16 #pragma once 15 17 16 18 #include <assert.h> -
libcfa/src/exception.c
r67ca73e re67a82d 10 10 // Created On : Mon Jun 26 15:13:00 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Aug 15 07:17:19202013 // Update Count : 2 612 // Last Modified On : Thu Aug 20 23:45:45 2020 13 // Update Count : 27 14 14 // 15 15 … … 31 31 #include <unwind.h> 32 32 #include <bits/debug.hfa> 33 #include "concurrency/invoke.h" 33 34 #include "stdhdr/assert.h" 34 35 … … 61 62 62 63 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 71 64 // Get the current exception context. 72 65 // 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}; 75 69 return &shared_stack; 76 70 } … … 125 119 126 120 // MEMORY MANAGEMENT ========================================================= 121 122 struct __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) 127 132 128 133 // How to clean up an exception in various situations. … … 140 145 } 141 146 142 // We need a piece of storage to raise the exception, for now its a single143 // 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 153 147 // Creates a copy of the indicated exception and sets current_exception to it. 154 148 static void __cfaehm_allocate_exception( exception_t * except ) { … … 164 158 } 165 159 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 166 167 // 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; 176 170 } 177 171 … … 188 182 if ( context->current_exception == except ) { 189 183 node = to_free->next; 190 context->current_exception = (node) ? NODE_TO_EXCEPT(node) : 0;184 context->current_exception = NULL_MAP(NODE_TO_EXCEPT, node); 191 185 } else { 192 186 node = EXCEPT_TO_NODE(context->current_exception); … … 216 210 // Verify actions follow the rules we expect. 217 211 verify((actions & _UA_CLEANUP_PHASE) && (actions & _UA_FORCE_UNWIND)); 218 verify(!(actions & (_UA_SEARCH_PHASE | _UA_HAND ER_FRAME)));212 verify(!(actions & (_UA_SEARCH_PHASE | _UA_HANDLER_FRAME))); 219 213 220 214 if ( actions & _UA_END_OF_STACK ) { … … 225 219 } 226 220 221 static struct _Unwind_Exception cancel_exception_storage; 222 227 223 // Cancel the current stack, prefroming approprate clean-up and messaging. 228 224 void __cfaehm_cancel_stack( exception_t * exception ) { 229 225 // TODO: Detect current stack and pick a particular stop-function. 230 226 _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 ); 232 228 printf("UNWIND ERROR %d after force unwind\n", ret); 233 229 abort(); … … 250 246 static void __cfaehm_begin_unwind(void(*defaultHandler)(exception_t *)) { 251 247 struct exception_context_t * context = this_exception_context(); 252 struct _Unwind_Exception * storage = &this_exception_storage;253 248 if ( NULL == context->current_exception ) { 254 249 printf("UNWIND ERROR missing exception in begin unwind\n"); 255 250 abort(); 256 251 } 252 struct _Unwind_Exception * storage = 253 &EXCEPT_TO_NODE(context->current_exception)->unwind_exception; 257 254 258 255 // Call stdlibc to raise the exception … … 426 423 _Unwind_Reason_Code ret = (0 == index) 427 424 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND; 428 context->current_handler_index = index;425 UNWIND_TO_NODE(unwind_exception)->handler_index = index; 429 426 430 427 // Based on the return value, check if we matched the exception … … 432 429 __cfadbg_print_safe(exception, " handler found\n"); 433 430 } else { 431 // TODO: Continue the search if there is more in the table. 434 432 __cfadbg_print_safe(exception, " no handler\n"); 435 433 } … … 523 521 // Exception handler 524 522 // 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, 526 524 this_exception_context()->current_exception ); 527 525 } -
libcfa/src/heap.cfa
r67ca73e re67a82d 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sun Aug 9 12:23:20202013 // Update Count : 89412 // Last Modified On : Wed Aug 12 16:43:38 2020 13 // Update Count : 902 14 14 // 15 15 … … 650 650 for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) { 651 651 #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; 653 656 #endif // BUCKETLOCK 654 657 total += size; … … 1162 1165 choose( option ) { 1163 1166 case M_TOP_PAD: 1164 heapExpand = ceiling ( value, pageSize ); return 1;1167 heapExpand = ceiling2( value, pageSize ); return 1; 1165 1168 case M_MMAP_THRESHOLD: 1166 1169 if ( setMmapStart( value ) ) return 1; -
libcfa/src/iostream.cfa
r67ca73e re67a82d 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Aug 10 09:32:14202013 // Update Count : 112 612 // Last Modified On : Tue Aug 11 22:16:33 2020 13 // Update Count : 1128 14 14 // 15 15 … … 37 37 38 38 forall( 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 57 39 ostype & ?|?( ostype & os, bool b ) { 58 40 if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); -
libcfa/src/iostream.hfa
r67ca73e re67a82d 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Jul 16 07:43:32202013 // Update Count : 3 4812 // Last Modified On : Tue Aug 11 22:16:14 2020 13 // Update Count : 350 14 14 // 15 15 … … 67 67 68 68 forall( 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 74 69 ostype & ?|?( ostype &, bool ); 75 70 void ?|?( ostype &, bool ); -
libcfa/src/parseargs.cfa
r67ca73e re67a82d 1 1 #include "parseargs.hfa" 2 2 3 // #include <stdio.h>4 // #include <stdlib.h>3 #include <stdint.h> 4 #include <string.h> 5 5 #include <errno.h> 6 #include <string.h>7 6 #include <unistd.h> 8 7 extern "C" { … … 20 19 extern long long int strtoll (const char* str, char** endptr, int base); 21 20 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 27 extern int cfa_args_argc; 28 extern char ** cfa_args_argv; 29 extern char ** cfa_args_envp; 30 31 static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * usage, FILE * out) __attribute__ ((noreturn)); 32 33 void 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 39 39 void parse_args( 40 40 int argc, … … 46 46 ) { 47 47 struct option optarr[opt_count + 2]; 48 int width = 0;49 int max_width = 1_000_000;50 48 { 51 49 int idx = 0; … … 62 60 } 63 61 idx++; 64 65 int w = strlen(options[i].long_name);66 if(w > width) width = w;67 62 } 68 63 } 69 optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0 p, 'h'];70 optarr[idx+1].[name, has_arg, flag, val] = [0 p, 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]; 71 66 } 72 67 … … 99 94 out = stdout; 100 95 case '?': 101 goto USAGE;96 usage(argv[0], options, opt_count, usage, out); 102 97 default: 103 98 for(i; opt_count) { … … 108 103 109 104 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); 111 106 } 112 107 } … … 115 110 116 111 } 117 118 USAGE:; 112 } 113 114 //----------------------------------------------------------------------------- 115 // Print usage 116 static 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 128 void 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 132 void 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 136 static 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; 119 148 int outfd = fileno(out); 120 149 if(isatty(outfd)) { … … 125 154 } 126 155 127 fprintf(out, "Usage:\n %s %s\n", argv[0], usage);156 fprintf(out, "Usage:\n %s %s\n", cmd, help); 128 157 129 158 for(i; opt_count) { … … 134 163 } 135 164 165 //----------------------------------------------------------------------------- 166 // Typed argument parsing 136 167 bool parse_yesno(const char * arg, bool & value ) { 137 168 if(strcmp(arg, "yes") == 0) { … … 163 194 } 164 195 196 bool 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 165 205 bool parse(const char * arg, unsigned & value) { 166 206 char * end; … … 173 213 } 174 214 175 bool parse(const char * arg, size_t& value) {215 bool parse(const char * arg, unsigned long & value) { 176 216 char * end; 177 217 unsigned long long int r = strtoull(arg, &end, 10); 178 218 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 225 bool 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 235 bool 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 31 31 } 32 32 33 void parse_args( cfa_option options[], size_t opt_count, const char * usage, char ** & left ); 33 34 void parse_args( int argc, char * argv[], cfa_option options[], size_t opt_count, const char * usage, char ** & left ); 35 36 void print_args_usage(cfa_option options[], size_t opt_count, const char * usage, bool error) __attribute__ ((noreturn)); 37 void print_args_usage(int argc, char * argv[], cfa_option options[], size_t opt_count, const char * usage, bool error) __attribute__ ((noreturn)); 34 38 35 39 bool parse_yesno (const char *, bool & ); … … 38 42 39 43 bool parse(const char *, const char * & ); 44 bool parse(const char *, int & ); 40 45 bool parse(const char *, unsigned & ); 41 bool parse(const char *, size_t & ); 42 bool parse(const char *, int & ); 46 bool parse(const char *, unsigned long & ); 47 bool parse(const char *, unsigned long long & ); 48 bool parse(const char *, double & ); -
libcfa/src/stdlib.hfa
r67ca73e re67a82d 10 10 // Created On : Thu Jan 28 17:12:35 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 30 16:14:58202013 // Update Count : 49012 // Last Modified On : Fri Aug 14 23:38:50 2020 13 // Update Count : 504 14 14 // 15 15 … … 39 39 //--------------------------------------- 40 40 41 #include "common.hfa" 42 43 //--------------------------------------- 44 41 45 // Macro because of returns 42 46 #define $VAR_ALLOC( allocation, alignment ) \ … … 136 140 T * alloc_set( char fill ) { 137 141 return (T *)memset( (T *)alloc(), (int)fill, sizeof(T) ); // initialize with fill value 138 } // alloc 139 140 T * alloc_set( Tfill ) {142 } // alloc_set 143 144 T * alloc_set( const T & fill ) { 141 145 return (T *)memcpy( (T *)alloc(), &fill, sizeof(T) ); // initialize with fill value 142 } // alloc 146 } // alloc_set 143 147 144 148 T * alloc_set( size_t dim, char fill ) { 145 149 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, Tfill ) {150 } // alloc_set 151 152 T * alloc_set( size_t dim, const T & fill ) { 149 153 T * r = (T *)alloc( dim ); 150 154 for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value 151 155 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 value156 } // 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 157 161 158 162 T * alloc_set( T ptr[], size_t dim, char fill ) { // realloc array with fill … … 166 170 } // alloc_set 167 171 168 T * alloc_set( T ptr[], size_t dim, T & fill ) { // realloc array with fill172 T * alloc_set( T ptr[], size_t dim, const T & fill ) { // realloc array with fill 169 173 size_t odim = malloc_size( ptr ) / sizeof(T); // current dimension 170 174 size_t nsize = dim * sizeof(T); // new allocation … … 177 181 } // if 178 182 return nptr; 179 } // alloc_ align_set183 } // alloc_set 180 184 } // distribution 181 185 … … 204 208 T * alloc_align_set( size_t align, char fill ) { 205 209 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, Tfill ) {210 } // alloc_align_set 211 212 T * alloc_align_set( size_t align, const T & fill ) { 209 213 return (T *)memcpy( (T *)alloc_align( align ), &fill, sizeof(T) ); // initialize with fill value 210 } // alloc_align 214 } // alloc_align_set 211 215 212 216 T * alloc_align_set( size_t align, size_t dim, char fill ) { 213 217 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, Tfill ) {218 } // alloc_align_set 219 220 T * alloc_align_set( size_t align, size_t dim, const T & fill ) { 217 221 T * r = (T *)alloc_align( align, dim ); 218 222 for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value 219 223 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 225 229 226 230 T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ) { … … 234 238 } // alloc_align_set 235 239 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 ) { 237 241 size_t odim = malloc_size( ptr ) / sizeof(T); // current dimension 238 242 size_t nsize = dim * sizeof(T); // new allocation … … 374 378 //--------------------------------------- 375 379 376 #include "common.hfa"377 378 //---------------------------------------379 380 380 extern bool threading_enabled(void) OPTIONAL_THREAD; 381 381 -
src/AST/Attribute.hpp
r67ca73e re67a82d 51 51 template<typename node_t> 52 52 friend node_t * mutate(const node_t * node); 53 template<typename node_t> 54 friend node_t * shallowCopy(const node_t * node); 53 55 }; 54 56 -
src/AST/CVQualifiers.hpp
r67ca73e re67a82d 27 27 Restrict = 1 << 1, 28 28 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 33 32 }; 34 33 35 34 /// Mask for equivalence-preserving qualfiers 36 enum { EquivQualifiers = ~ (Restrict | Lvalue)};35 enum { EquivQualifiers = ~Restrict }; 37 36 38 37 /// Underlying data for qualifiers … … 44 43 bool is_restrict : 1; 45 44 bool is_volatile : 1; 46 bool is_lvalue : 1;47 45 bool is_mutex : 1; 48 46 bool is_atomic : 1; -
src/AST/Convert.cpp
r67ca73e re67a82d 20 20 21 21 #include "AST/Attribute.hpp" 22 #include "AST/Copy.hpp" 22 23 #include "AST/Decl.hpp" 23 24 #include "AST/Expr.hpp" … … 166 167 LinkageSpec::Spec( node->linkage.val ), 167 168 bfwd, 168 type ,169 type->clone(), 169 170 init, 170 171 attr, … … 587 588 assert( tgtResnSlots.empty() ); 588 589 589 if ( srcInferred. mode == ast::Expr::InferUnion::Params ) {590 if ( srcInferred.data.inferParams ) { 590 591 const ast::InferredParams &srcParams = srcInferred.inferParams(); 591 592 for (auto & srcParam : srcParams) { … … 593 594 srcParam.second.decl, 594 595 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() 598 599 )); 599 600 assert(res.second); 600 601 } 601 } else if ( srcInferred.mode == ast::Expr::InferUnion::Slots ) { 602 } 603 if ( srcInferred.data.resnSlots ) { 602 604 const ast::ResnSlots &srcSlots = srcInferred.resnSlots(); 603 605 for (auto srcSlot : srcSlots) { … … 620 622 621 623 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 } 622 635 return visitBaseExpr_skipResultType(src, tgt); 623 636 } … … 979 992 980 993 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 } 981 999 auto rslt = new StmtExpr( 982 get<CompoundStmt>().accept1( node->stmts)1000 get<CompoundStmt>().accept1(stmts) 983 1001 ); 984 1002 … … 1986 2004 1987 2005 assert( oldInferParams.empty() || oldResnSlots.empty() ); 1988 assert( newInferred.mode == ast::Expr::InferUnion::Empty );2006 // assert( newInferred.mode == ast::Expr::InferUnion::Empty ); 1989 2007 1990 2008 if ( !oldInferParams.empty() ) { … … 2117 2135 old->location, 2118 2136 GET_ACCEPT_1(member, DeclWithType), 2119 GET_ACCEPT_1(aggregate, Expr) 2137 GET_ACCEPT_1(aggregate, Expr), 2138 ast::MemberExpr::NoOpConstructionChosen 2120 2139 ) 2121 2140 ); -
src/AST/Decl.cpp
r67ca73e re67a82d 50 50 51 51 const Type * FunctionDecl::get_type() const { return type.get(); } 52 void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); } 52 void FunctionDecl::set_type( const Type * t ) { 53 type = strict_dynamic_cast< const FunctionType * >( t ); 54 } 53 55 54 56 // --- TypeDecl -
src/AST/Decl.hpp
r67ca73e re67a82d 33 33 34 34 // 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); 36 38 37 39 namespace ast { … … 88 90 virtual const Type * get_type() const = 0; 89 91 /// 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; 91 93 92 94 const DeclWithType * accept( Visitor & v ) const override = 0; … … 111 113 112 114 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; } 114 116 115 117 const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); } … … 133 135 134 136 const Type * get_type() const override; 135 void set_type( Type * t) override;137 void set_type( const Type * t ) override; 136 138 137 139 bool has_body() const { return stmts; } … … 150 152 std::vector<ptr<DeclWithType>> assertions; 151 153 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 ) 154 157 : Decl( loc, name, storage, spec ), base( b ), params(), assertions() {} 155 158 … … 186 189 }; 187 190 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 ) {} 192 196 193 197 const char * typeString() const override; -
src/AST/Expr.cpp
r67ca73e re67a82d 20 20 #include <vector> 21 21 22 #include "Copy.hpp" // for shallowCopy 23 #include "Eval.hpp" // for call 22 24 #include "GenericSubstitution.hpp" 25 #include "LinkageSpec.hpp" 23 26 #include "Stmt.hpp" 24 27 #include "Type.hpp" … … 27 30 #include "Common/SemanticError.h" 28 31 #include "GenPoly/Lvalue.h" // for referencesPermissable 29 #include "InitTweak/InitTweak.h" // for get PointerBase32 #include "InitTweak/InitTweak.h" // for getFunction, getPointerBase 30 33 #include "ResolvExpr/typeops.h" // for extractResultType 31 34 #include "Tuples/Tuples.h" // for makeTupleType 32 35 33 36 namespace ast { 37 38 namespace { 39 std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"}; 40 } 41 42 // --- Expr 43 bool Expr::get_lvalue() const { 44 return false; 45 } 34 46 35 47 // --- ApplicationExpr … … 46 58 } 47 59 60 bool 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 48 67 // --- UntypedExpr 49 68 … … 51 70 assert( arg ); 52 71 53 UntypedExpr * ret = new UntypedExpr{ 54 loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } } 55 }; 72 UntypedExpr * ret = call( loc, "*?", arg ); 56 73 if ( const Type * ty = arg->result ) { 57 74 const Type * base = InitTweak::getPointerBase( ty ); … … 65 82 // base type 66 83 ret->result = base; 67 add_qualifiers( ret->result, CV::Lvalue );68 84 } 69 85 } 70 86 return ret; 87 } 88 89 bool UntypedExpr::get_lvalue() const { 90 std::string fname = InitTweak::getFunctionName( this ); 91 return lvalueFunctionNames.count( fname ); 71 92 } 72 93 … … 74 95 assert( lhs && rhs ); 75 96 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 ); 79 98 if ( lhs->result && rhs->result ) { 80 99 // if both expressions are typed, assumes that this assignment is a C bitwise assignment, … … 108 127 AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) { 109 128 if ( arg->result ) { 110 if ( arg-> result->is_lvalue() ) {129 if ( arg->get_lvalue() ) { 111 130 // lvalue, retains all levels of reference, and gains a pointer inside the references 112 131 Type * res = addrType( arg->result ); 113 res->set_lvalue( false ); // result of & is never an lvalue114 132 result = res; 115 133 } else { … … 118 136 dynamic_cast< const ReferenceType * >( arg->result.get() ) ) { 119 137 Type * res = addrType( refType->base ); 120 res->set_lvalue( false ); // result of & is never an lvalue121 138 result = res; 122 139 } else { … … 139 156 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {} 140 157 158 bool 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 141 163 // --- KeywordCastExpr 142 164 143 165 const char * KeywordCastExpr::targetString() const { 144 166 return AggregateDecl::aggrString( target ); 167 } 168 169 // --- UntypedMemberExpr 170 171 bool UntypedMemberExpr::get_lvalue() const { 172 return aggregate->get_lvalue(); 145 173 } 146 174 … … 153 181 assert( aggregate->result ); 154 182 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 157 220 // substitute aggregate generic parameters into member type 158 221 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 226 MemberExpr::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 235 bool MemberExpr::get_lvalue() const { 236 // This is actually wrong by C, but it works with our current set-up. 237 return true; 161 238 } 162 239 … … 170 247 assert( var ); 171 248 assert( var->get_type() ); 172 result = var->get_type(); 173 add_qualifiers( result, CV::Lvalue ); 249 result = shallowCopy( var->get_type() ); 250 } 251 252 bool VariableExpr::get_lvalue() const { 253 // It isn't always an lvalue, but it is never an rvalue. 254 return true; 174 255 } 175 256 … … 258 339 : Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {} 259 340 341 // --- CommaExpr 342 bool 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 260 348 // --- ConstructorExpr 261 349 … … 276 364 assert( t && i ); 277 365 result = t; 278 add_qualifiers( result, CV::Lvalue ); 366 } 367 368 bool CompoundLiteralExpr::get_lvalue() const { 369 return true; 279 370 } 280 371 … … 293 384 // like MemberExpr, TupleIndexExpr is always an lvalue 294 385 result = type->types[ index ]; 295 add_qualifiers( result, CV::Lvalue ); 386 } 387 388 bool TupleIndexExpr::get_lvalue() const { 389 return tuple->get_lvalue(); 296 390 } 297 391 -
src/AST/Expr.hpp
r67ca73e re67a82d 31 31 32 32 // 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 34 37 35 38 class ConverterOldToNew; … … 42 45 struct ParamEntry { 43 46 UniqueId decl; 44 ptr<Decl> declptr;47 readonly<Decl> declptr; 45 48 ptr<Type> actualType; 46 49 ptr<Type> formalType; … … 62 65 class Expr : public ParseNode { 63 66 public: 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 */ 65 73 struct InferUnion { 74 // mode is now unused 66 75 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 } 74 87 } data; 75 88 76 89 /// initializes from other InferUnion 77 90 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); 82 96 } 83 97 } … … 85 99 /// initializes from other InferUnion (move semantics) 86 100 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; 102 105 } 103 106 … … 107 110 InferUnion& operator= ( const InferUnion& ) = delete; 108 111 InferUnion& operator= ( InferUnion&& ) = delete; 109 ~InferUnion() { reset(); } 112 113 bool hasSlots() const { return data.resnSlots; } 110 114 111 115 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(); 116 118 } 117 assertf(false, "unreachable");119 return *data.resnSlots; 118 120 } 119 121 120 122 const ResnSlots& resnSlots() const { 121 if ( mode ==Slots) {122 return data.resnSlots;123 if (data.resnSlots) { 124 return *data.resnSlots; 123 125 } 124 126 assertf(false, "Mode was not already resnSlots"); … … 127 129 128 130 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(); 133 133 } 134 assertf(false, "unreachable");134 return *data.inferParams; 135 135 } 136 136 137 137 const InferredParams& inferParams() const { 138 if ( mode ==Params) {139 return data.inferParams;138 if (data.inferParams) { 139 return *data.inferParams; 140 140 } 141 141 assertf(false, "Mode was not already Params"); … … 143 143 } 144 144 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; 158 150 } 159 151 … … 161 153 /// and the other is in `Params`. 162 154 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; 173 160 } 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 } 175 179 } 176 180 }; … … 185 189 186 190 Expr * set_extension( bool ex ) { extension = ex; return this; } 191 virtual bool get_lvalue() const; 187 192 188 193 virtual const Expr * accept( Visitor & v ) const override = 0; … … 201 206 ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} ); 202 207 208 bool get_lvalue() const final; 209 203 210 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 204 211 private: … … 215 222 UntypedExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} ) 216 223 : Expr( loc ), func( f ), args( std::move(as) ) {} 224 225 bool get_lvalue() const final; 217 226 218 227 /// Creates a new dereference expression … … 291 300 CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {} 292 301 302 bool get_lvalue() const final; 303 293 304 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 294 305 private: … … 338 349 : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); } 339 350 351 bool get_lvalue() const final; 352 340 353 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 341 354 private: … … 352 365 MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg ); 353 366 367 bool get_lvalue() const final; 368 354 369 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 355 370 private: 356 371 MemberExpr * clone() const override { return new MemberExpr{ *this }; } 357 372 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; 358 380 }; 359 381 … … 365 387 VariableExpr( const CodeLocation & loc ); 366 388 VariableExpr( const CodeLocation & loc, const DeclWithType * v ); 389 390 bool get_lvalue() const final; 367 391 368 392 /// generates a function pointer for a given function … … 532 556 533 557 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; 535 563 536 564 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 605 633 CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i ); 606 634 635 bool get_lvalue() const final; 636 607 637 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 608 638 private: … … 660 690 661 691 TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i ); 692 693 bool get_lvalue() const final; 662 694 663 695 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } -
src/AST/Fwd.hpp
r67ca73e re67a82d 10 10 // Created On : Wed May 8 16:05:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Jun 24 09:48:00 201913 // Update Count : 112 // Last Modified On : Thr Jul 23 14:15:00 2020 13 // Update Count : 2 14 14 // 15 15 … … 108 108 class FunctionType; 109 109 class ReferenceToType; 110 class StructInstType; 111 class UnionInstType; 112 class EnumInstType; 110 template<typename decl_t> class SueInstType; 111 using StructInstType = SueInstType<StructDecl>; 112 using UnionInstType = SueInstType<UnionDecl>; 113 using EnumInstType = SueInstType<EnumDecl>; 113 114 class TraitInstType; 114 115 class TypeInstType; -
src/AST/GenericSubstitution.cpp
r67ca73e re67a82d 62 62 Pass<GenericSubstitutionBuilder> builder; 63 63 maybe_accept( ty, builder ); 64 return std::move(builder. pass.sub);64 return std::move(builder.core.sub); 65 65 } 66 66 -
src/AST/Init.hpp
r67ca73e re67a82d 25 25 26 26 // 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); 28 30 29 31 namespace ast { -
src/AST/Node.cpp
r67ca73e re67a82d 9 9 // Author : Thierry Delisle 10 10 // 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 14 14 // 15 15 … … 17 17 #include "Fwd.hpp" 18 18 19 #include <csignal> // MEMORY DEBUG -- for raise 19 20 #include <iostream> 20 21 … … 29 30 #include "Print.hpp" 30 31 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 39 void * MEM_TRAP_OBJ = nullptr; 40 41 void _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 58 template< typename node_t, enum ast::Node::ref_type ref_t > 59 void ast::ptr_base<node_t, ref_t>::_strict_fail() const { 60 strict_fail(node); 61 } 62 63 template< typename node_t, enum ast::Node::ref_type ref_t > 64 void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { 65 node->increment(ref_t); 66 _trap( node ); 67 } 68 69 template< typename node_t, enum ast::Node::ref_type ref_t > 70 void 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 75 template< typename node_t, enum ast::Node::ref_type ref_t > 76 void ast::ptr_base<node_t, ref_t>::_check() const { 77 // if(node) assert(node->was_ever_strong == false || node->strong_count > 0); 78 } 39 79 40 80 template< typename node_t, enum ast::Node::ref_type ref_t > -
src/AST/Node.hpp
r67ca73e re67a82d 10 10 // Created On : Wed May 8 10:27:04 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Jun 3 13:26:00 201913 // Update Count : 512 // Last Modified On : Fri Jun 5 9:47:00 2020 13 // Update Count : 6 14 14 // 15 15 … … 38 38 Node& operator= (const Node&) = delete; 39 39 Node& operator= (Node&&) = delete; 40 virtual ~Node() = default;40 virtual ~Node() {} 41 41 42 42 virtual const Node * accept( Visitor & v ) const = 0; … … 57 57 template<typename node_t> 58 58 friend node_t * mutate(const node_t * node); 59 template<typename node_t> 60 friend node_t * shallowCopy(const node_t * node); 59 61 60 62 mutable size_t strong_count = 0; … … 69 71 } 70 72 71 void decrement(ast::Node::ref_type ref ) const {73 void decrement(ast::Node::ref_type ref, bool do_delete = true) const { 72 74 switch (ref) { 73 75 case ref_type::strong: strong_count--; break; … … 75 77 } 76 78 77 if( !strong_count && !weak_count) {79 if( do_delete && !strong_count && !weak_count) { 78 80 delete this; 79 81 } … … 94 96 assertf( 95 97 node->weak_count == 0, 96 "Error: mutating node with weak references to it will invalid edsome references"98 "Error: mutating node with weak references to it will invalidate some references" 97 99 ); 98 100 return node->clone(); … … 104 106 // skip mutate if equivalent 105 107 if ( node->*field == val ) return node; 106 108 107 109 // mutate and return 108 110 node_t * ret = mutate( node ); … … 123 125 (ret->*field)[i] = std::forward< field_t >( val ); 124 126 return ret; 127 } 128 129 /// Mutate an entire indexed collection by cloning to accepted value 130 template<typename node_t, typename parent_t, typename coll_t> 131 const 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; 125 136 } 126 137 … … 219 230 operator const node_t * () const { _check(); return node; } 220 231 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 221 241 /// wrapper for convenient access to dynamic_cast 222 242 template<typename o_node_t> 223 243 const o_node_t * as() const { _check(); return dynamic_cast<const o_node_t *>(node); } 224 244 225 /// wrapper for convenient access to strict_dynamic_cast245 /// Wrapper that makes sure dynamic_cast returns non-null. 226 246 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; } 228 255 229 256 /// Returns a mutable version of the pointer in this node. … … 244 271 245 272 void _inc( const node_t * other ); 246 void _dec( const node_t * other );273 void _dec( const node_t * other, bool do_delete = true ); 247 274 void _check() const; 275 void _strict_fail() const __attribute__((noreturn)); 248 276 249 277 const node_t * node; -
src/AST/Pass.hpp
r67ca73e re67a82d 8 8 // 9 9 // Author : Thierry Delisle 10 // Created On : Thu May 09 15: :37::05 201910 // Created On : Thu May 09 15:37:05 2019 11 11 // Last Modified By : 12 12 // Last Modified On : … … 35 35 #include "AST/SymbolTable.hpp" 36 36 37 #include "AST/ForallSubstitutionTable.hpp" 38 37 39 // Private prelude header, needed for some of the magic tricks this class pulls off 38 40 #include "AST/Pass.proto.hpp" … … 46 48 // 47 49 // 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 64 67 //------------------------------------------------------------------------------------------------- 65 template< typename pass_t >68 template< typename core_t > 66 69 class Pass final : public ast::Visitor { 67 70 public: 71 using core_type = core_t; 72 using type = Pass<core_t>; 73 68 74 /// Forward any arguments to the pass constructor 69 75 /// Propagate 'this' if necessary 70 76 template< typename... Args > 71 77 Pass( Args &&... args) 72 : pass( std::forward<Args>( args )... )78 : core( std::forward<Args>( args )... ) 73 79 { 74 80 // 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); 77 82 if(visitor) { 78 *const_cast<t his_t**>( visitor ) = this;83 *const_cast<type **>( visitor ) = this; 79 84 } 80 85 } … … 82 87 virtual ~Pass() = default; 83 88 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 84 102 /// Storage for the actual pass 85 pass_t pass;103 core_t core; 86 104 87 105 /// Visit function declarations … … 179 197 const ast::TypeSubstitution * visit( const ast::TypeSubstitution * ) override final; 180 198 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 ); 183 201 private: 184 202 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; } 186 204 187 205 private: … … 202 220 container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container ); 203 221 222 /// Mutate forall-list, accounting for presence of type substitution map 223 template<typename node_t> 224 void mutate_forall( const node_t *& ); 225 204 226 public: 205 227 /// Logic to call the accept and mutate the parent if needed, delegates call to accept … … 210 232 /// Internal RAII guard for symbol table features 211 233 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; 215 237 }; 216 238 217 239 /// Internal RAII guard for scope features 218 240 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; 222 253 }; 223 254 … … 227 258 228 259 /// 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 );260 template<typename core_t> 261 void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor ); 231 262 232 263 //------------------------------------------------------------------------------------------------- … … 268 299 }; 269 300 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 ); 272 303 public: 273 304 … … 305 336 306 337 /// Used to get a pointer to the pass with its wrapped type 307 template<typename pass_t>338 template<typename core_t> 308 339 struct WithVisitorRef { 309 Pass< pass_t> * const visitor = nullptr;340 Pass<core_t> * const visitor = nullptr; 310 341 }; 311 342 … … 314 345 SymbolTable symtab; 315 346 }; 347 348 /// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl 349 struct WithForallSubstitutor { 350 ForallSubstitutionTable subs; 351 }; 352 316 353 } 317 354 … … 321 358 extern struct PassVisitorStats { 322 359 size_t depth = 0; 323 Stats::Counters::MaxCounter<double> * max = nullptr;324 Stats::Counters::AverageCounter<double> * avg = nullptr;360 Stats::Counters::MaxCounter<double> * max; 361 Stats::Counters::AverageCounter<double> * avg; 325 362 } pass_visitor_stats; 326 363 } -
src/AST/Pass.impl.hpp
r67ca73e re67a82d 25 25 using namespace ast; \ 26 26 /* back-up the visit children */ \ 27 __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children( pass, 0) ); \27 __attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 0) ); \ 28 28 /* setup the scope for passes that want to run code at exit */ \ 29 __attribute__((unused)) ast::__pass::guard_value guard2( ast::__pass::at_cleanup (pass, 0) ); \ 29 __attribute__((unused)) ast::__pass::guard_value guard2( ast::__pass::at_cleanup (core, 0) ); \ 30 /* begin tracing memory allocation if requested by this pass */ \ 31 __pass::beginTrace( core, 0 ); \ 30 32 /* call the implementation of the previsit of this pass */ \ 31 __pass::previsit( pass, node, 0 );33 __pass::previsit( core, node, 0 ); 32 34 33 35 #define VISIT( code... ) \ … … 40 42 #define VISIT_END( type, node ) \ 41 43 /* call the implementation of the postvisit of this pass */ \ 42 auto __return = __pass::postvisit( pass, node, 0 ); \44 auto __return = __pass::postvisit( core, node, 0 ); \ 43 45 assertf(__return, "post visit should never return null"); \ 46 /* end tracing memory allocation if requested by this pass */ \ 47 __pass::endTrace( core, 0 ); \ 44 48 return __return; 45 49 … … 119 123 } 120 124 121 template< typename pass_t >125 template< typename core_t > 122 126 template< typename node_t > 123 auto ast::Pass< pass_t >::call_accept( const node_t * node )127 auto ast::Pass< core_t >::call_accept( const node_t * node ) 124 128 -> typename std::enable_if< 125 129 !std::is_base_of<ast::Expr, node_t>::value && … … 127 131 , decltype( node->accept(*this) ) 128 132 >::type 129 130 133 { 131 134 __pedantic_pass_assert( __visit_children() ); 132 __pedantic_pass_assert( expr);135 __pedantic_pass_assert( node ); 133 136 134 137 static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR"); … … 138 141 } 139 142 140 template< typename pass_t >141 const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {143 template< typename core_t > 144 const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) { 142 145 __pedantic_pass_assert( __visit_children() ); 143 146 __pedantic_pass_assert( expr ); 144 147 145 const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);148 const ast::TypeSubstitution ** env_ptr = __pass::env( core, 0); 146 149 if ( env_ptr && expr->env ) { 147 150 *env_ptr = expr->env; … … 151 154 } 152 155 153 template< typename pass_t >154 const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {156 template< typename core_t > 157 const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) { 155 158 __pedantic_pass_assert( __visit_children() ); 156 159 __pedantic_pass_assert( stmt ); … … 160 163 161 164 // get the stmts/decls that will need to be spliced in 162 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);163 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);164 auto decls_before = __pass::declsToAddBefore( pass, 0);165 auto decls_after = __pass::declsToAddAfter ( pass, 0);165 auto stmts_before = __pass::stmtsToAddBefore( core, 0); 166 auto stmts_after = __pass::stmtsToAddAfter ( core, 0); 167 auto decls_before = __pass::declsToAddBefore( core, 0); 168 auto decls_after = __pass::declsToAddAfter ( core, 0); 166 169 167 170 // These may be modified by subnode but most be restored once we exit this statemnet. 168 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::env( pass, 0) );171 ValueGuardPtr< const ast::TypeSubstitution * > __old_env ( __pass::env( core, 0) ); 169 172 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 170 173 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); … … 202 205 } 203 206 204 template< typename pass_t >207 template< typename core_t > 205 208 template< template <class...> class container_t > 206 container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {209 container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) { 207 210 __pedantic_pass_assert( __visit_children() ); 208 211 if( statements.empty() ) return {}; … … 215 218 216 219 // get the stmts/decls that will need to be spliced in 217 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);218 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);219 auto decls_before = __pass::declsToAddBefore( pass, 0);220 auto decls_after = __pass::declsToAddAfter ( pass, 0);220 auto stmts_before = __pass::stmtsToAddBefore( core, 0); 221 auto stmts_after = __pass::stmtsToAddAfter ( core, 0); 222 auto decls_before = __pass::declsToAddBefore( core, 0); 223 auto decls_after = __pass::declsToAddAfter ( core, 0); 221 224 222 225 // These may be modified by subnode but most be restored once we exit this statemnet. … … 268 271 } 269 272 270 template< typename pass_t >273 template< typename core_t > 271 274 template< template <class...> class container_t, typename node_t > 272 container_t< ast::ptr<node_t> > ast::Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {275 container_t< ast::ptr<node_t> > ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) { 273 276 __pedantic_pass_assert( __visit_children() ); 274 277 if( container.empty() ) return {}; … … 299 302 } 300 303 301 template< typename pass_t >304 template< typename core_t > 302 305 template<typename node_t, typename parent_t, typename child_t> 303 void ast::Pass< pass_t >::maybe_accept(306 void ast::Pass< core_t >::maybe_accept( 304 307 const node_t * & parent, 305 308 child_t parent_t::*child … … 323 326 } 324 327 328 329 template< typename core_t > 330 template< typename node_t > 331 void ast::Pass< core_t >::mutate_forall( const node_t *& node ) { 332 if ( auto subs = __pass::forall::subs( core, 0 ) ) { 333 // tracking TypeDecl substitution, full clone 334 if ( node->forall.empty() ) return; 335 336 node_t * mut = mutate( node ); 337 mut->forall = subs->clone( node->forall, *this ); 338 node = mut; 339 } else { 340 // not tracking TypeDecl substitution, just mutate 341 maybe_accept( node, &node_t::forall ); 342 } 343 } 325 344 } 326 345 … … 333 352 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 334 353 335 template< typename pass_t >336 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {354 template< typename core_t > 355 inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< core_t > & visitor ) { 337 356 // We are going to aggregate errors for all these statements 338 357 SemanticErrorException errors; … … 342 361 343 362 // get the stmts/decls that will need to be spliced in 344 auto decls_before = __pass::declsToAddBefore( visitor. pass, 0);345 auto decls_after = __pass::declsToAddAfter ( visitor. pass, 0);363 auto decls_before = __pass::declsToAddBefore( visitor.core, 0); 364 auto decls_after = __pass::declsToAddAfter ( visitor.core, 0); 346 365 347 366 // update pass statitistics … … 392 411 //-------------------------------------------------------------------------- 393 412 // ObjectDecl 394 template< typename pass_t >395 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {413 template< typename core_t > 414 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::ObjectDecl * node ) { 396 415 VISIT_START( node ); 397 416 … … 406 425 ) 407 426 408 __pass::symtab::addId( pass, 0, node );427 __pass::symtab::addId( core, 0, node ); 409 428 410 429 VISIT_END( DeclWithType, node ); … … 413 432 //-------------------------------------------------------------------------- 414 433 // FunctionDecl 415 template< typename pass_t >416 const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {417 VISIT_START( node ); 418 419 __pass::symtab::addId( pass, 0, node );434 template< typename core_t > 435 const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::FunctionDecl * node ) { 436 VISIT_START( node ); 437 438 __pass::symtab::addId( core, 0, node ); 420 439 421 440 VISIT(maybe_accept( node, &FunctionDecl::withExprs );) … … 425 444 // shadow with exprs and not the other way around. 426 445 guard_symtab guard { *this }; 427 __pass::symtab::addWith( pass, 0, node->withExprs, node );446 __pass::symtab::addWith( core, 0, node->withExprs, node ); 428 447 { 429 448 guard_symtab guard { *this }; 430 449 // implicit add __func__ identifier as specified in the C manual 6.4.2.2 431 static ast:: ObjectDecl func(432 node->location, "__func__",433 new ast::ArrayType (434 new ast::BasicType ( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),450 static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{ 451 CodeLocation{}, "__func__", 452 new ast::ArrayType{ 453 new ast::BasicType{ ast::BasicType::Char, ast::CV::Const }, 435 454 nullptr, VariableLen, DynamicDim 436 )437 );438 __pass::symtab::addId( pass, 0, &func );455 } 456 } }; 457 __pass::symtab::addId( core, 0, func ); 439 458 VISIT( 440 459 maybe_accept( node, &FunctionDecl::type ); … … 454 473 //-------------------------------------------------------------------------- 455 474 // StructDecl 456 template< typename pass_t >457 const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {475 template< typename core_t > 476 const ast::Decl * ast::Pass< core_t >::visit( const ast::StructDecl * node ) { 458 477 VISIT_START( node ); 459 478 460 479 // make up a forward declaration and add it before processing the members 461 480 // needs to be on the heap because addStruct saves the pointer 462 __pass::symtab::addStructFwd( pass, 0, node );481 __pass::symtab::addStructFwd( core, 0, node ); 463 482 464 483 VISIT({ … … 469 488 470 489 // this addition replaces the forward declaration 471 __pass::symtab::addStruct( pass, 0, node );490 __pass::symtab::addStruct( core, 0, node ); 472 491 473 492 VISIT_END( Decl, node ); … … 476 495 //-------------------------------------------------------------------------- 477 496 // UnionDecl 478 template< typename pass_t >479 const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {497 template< typename core_t > 498 const ast::Decl * ast::Pass< core_t >::visit( const ast::UnionDecl * node ) { 480 499 VISIT_START( node ); 481 500 482 501 // make up a forward declaration and add it before processing the members 483 __pass::symtab::addUnionFwd( pass, 0, node );502 __pass::symtab::addUnionFwd( core, 0, node ); 484 503 485 504 VISIT({ … … 489 508 }) 490 509 491 __pass::symtab::addUnion( pass, 0, node );510 __pass::symtab::addUnion( core, 0, node ); 492 511 493 512 VISIT_END( Decl, node ); … … 496 515 //-------------------------------------------------------------------------- 497 516 // EnumDecl 498 template< typename pass_t >499 const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {500 VISIT_START( node ); 501 502 __pass::symtab::addEnum( pass, 0, node );517 template< typename core_t > 518 const ast::Decl * ast::Pass< core_t >::visit( const ast::EnumDecl * node ) { 519 VISIT_START( node ); 520 521 __pass::symtab::addEnum( core, 0, node ); 503 522 504 523 VISIT( … … 513 532 //-------------------------------------------------------------------------- 514 533 // TraitDecl 515 template< typename pass_t >516 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {534 template< typename core_t > 535 const ast::Decl * ast::Pass< core_t >::visit( const ast::TraitDecl * node ) { 517 536 VISIT_START( node ); 518 537 … … 523 542 }) 524 543 525 __pass::symtab::addTrait( pass, 0, node );544 __pass::symtab::addTrait( core, 0, node ); 526 545 527 546 VISIT_END( Decl, node ); … … 530 549 //-------------------------------------------------------------------------- 531 550 // TypeDecl 532 template< typename pass_t >533 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {551 template< typename core_t > 552 const ast::Decl * ast::Pass< core_t >::visit( const ast::TypeDecl * node ) { 534 553 VISIT_START( node ); 535 554 … … 543 562 // note that assertions come after the type is added to the symtab, since they are not part of the type proper 544 563 // and may depend on the type itself 545 __pass::symtab::addType( pass, 0, node );564 __pass::symtab::addType( core, 0, node ); 546 565 547 566 VISIT( … … 559 578 //-------------------------------------------------------------------------- 560 579 // TypedefDecl 561 template< typename pass_t >562 const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {580 template< typename core_t > 581 const ast::Decl * ast::Pass< core_t >::visit( const ast::TypedefDecl * node ) { 563 582 VISIT_START( node ); 564 583 … … 569 588 }) 570 589 571 __pass::symtab::addType( pass, 0, node );590 __pass::symtab::addType( core, 0, node ); 572 591 573 592 VISIT( maybe_accept( node, &TypedefDecl::assertions ); ) … … 578 597 //-------------------------------------------------------------------------- 579 598 // AsmDecl 580 template< typename pass_t >581 const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {599 template< typename core_t > 600 const ast::AsmDecl * ast::Pass< core_t >::visit( const ast::AsmDecl * node ) { 582 601 VISIT_START( node ); 583 602 … … 591 610 //-------------------------------------------------------------------------- 592 611 // StaticAssertDecl 593 template< typename pass_t >594 const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {612 template< typename core_t > 613 const ast::StaticAssertDecl * ast::Pass< core_t >::visit( const ast::StaticAssertDecl * node ) { 595 614 VISIT_START( node ); 596 615 … … 605 624 //-------------------------------------------------------------------------- 606 625 // CompoundStmt 607 template< typename pass_t >608 const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {626 template< typename core_t > 627 const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) { 609 628 VISIT_START( node ); 610 629 VISIT({ 611 630 // do not enter a new scope if inFunction is true - needs to check old state before the assignment 612 auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {613 if ( ! inFunction ) __pass::symtab::enter(pass, 0);614 }, [this, inFunction = this->inFunction]() {615 if ( ! inFunction ) __pass::symtab::leave(pass, 0);631 auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() { 632 if ( ! inFunctionCpy ) __pass::symtab::enter(core, 0); 633 }, [this, inFunctionCpy = this->inFunction]() { 634 if ( ! inFunctionCpy ) __pass::symtab::leave(core, 0); 616 635 }); 617 636 ValueGuard< bool > guard2( inFunction ); … … 625 644 //-------------------------------------------------------------------------- 626 645 // ExprStmt 627 template< typename pass_t >628 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {646 template< typename core_t > 647 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ExprStmt * node ) { 629 648 VISIT_START( node ); 630 649 … … 638 657 //-------------------------------------------------------------------------- 639 658 // AsmStmt 640 template< typename pass_t >641 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {659 template< typename core_t > 660 const ast::Stmt * ast::Pass< core_t >::visit( const ast::AsmStmt * node ) { 642 661 VISIT_START( node ) 643 662 … … 654 673 //-------------------------------------------------------------------------- 655 674 // DirectiveStmt 656 template< typename pass_t >657 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {675 template< typename core_t > 676 const ast::Stmt * ast::Pass< core_t >::visit( const ast::DirectiveStmt * node ) { 658 677 VISIT_START( node ) 659 678 … … 663 682 //-------------------------------------------------------------------------- 664 683 // IfStmt 665 template< typename pass_t >666 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {684 template< typename core_t > 685 const ast::Stmt * ast::Pass< core_t >::visit( const ast::IfStmt * node ) { 667 686 VISIT_START( node ); 668 687 … … 681 700 //-------------------------------------------------------------------------- 682 701 // WhileStmt 683 template< typename pass_t >684 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {702 template< typename core_t > 703 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) { 685 704 VISIT_START( node ); 686 705 … … 698 717 //-------------------------------------------------------------------------- 699 718 // ForStmt 700 template< typename pass_t >701 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ForStmt * node ) {719 template< typename core_t > 720 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForStmt * node ) { 702 721 VISIT_START( node ); 703 722 … … 716 735 //-------------------------------------------------------------------------- 717 736 // SwitchStmt 718 template< typename pass_t >719 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SwitchStmt * node ) {737 template< typename core_t > 738 const ast::Stmt * ast::Pass< core_t >::visit( const ast::SwitchStmt * node ) { 720 739 VISIT_START( node ); 721 740 … … 730 749 //-------------------------------------------------------------------------- 731 750 // CaseStmt 732 template< typename pass_t >733 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CaseStmt * node ) {751 template< typename core_t > 752 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CaseStmt * node ) { 734 753 VISIT_START( node ); 735 754 … … 744 763 //-------------------------------------------------------------------------- 745 764 // BranchStmt 746 template< typename pass_t >747 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::BranchStmt * node ) {765 template< typename core_t > 766 const ast::Stmt * ast::Pass< core_t >::visit( const ast::BranchStmt * node ) { 748 767 VISIT_START( node ); 749 768 VISIT_END( Stmt, node ); … … 752 771 //-------------------------------------------------------------------------- 753 772 // ReturnStmt 754 template< typename pass_t >755 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ReturnStmt * node ) {773 template< typename core_t > 774 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ReturnStmt * node ) { 756 775 VISIT_START( node ); 757 776 … … 765 784 //-------------------------------------------------------------------------- 766 785 // ThrowStmt 767 template< typename pass_t >768 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ThrowStmt * node ) {786 template< typename core_t > 787 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ThrowStmt * node ) { 769 788 VISIT_START( node ); 770 789 … … 779 798 //-------------------------------------------------------------------------- 780 799 // TryStmt 781 template< typename pass_t >782 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::TryStmt * node ) {800 template< typename core_t > 801 const ast::Stmt * ast::Pass< core_t >::visit( const ast::TryStmt * node ) { 783 802 VISIT_START( node ); 784 803 … … 794 813 //-------------------------------------------------------------------------- 795 814 // CatchStmt 796 template< typename pass_t >797 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {815 template< typename core_t > 816 const ast::Stmt * ast::Pass< core_t >::visit( const ast::CatchStmt * node ) { 798 817 VISIT_START( node ); 799 818 … … 811 830 //-------------------------------------------------------------------------- 812 831 // FinallyStmt 813 template< typename pass_t >814 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {832 template< typename core_t > 833 const ast::Stmt * ast::Pass< core_t >::visit( const ast::FinallyStmt * node ) { 815 834 VISIT_START( node ); 816 835 … … 824 843 //-------------------------------------------------------------------------- 825 844 // FinallyStmt 826 template< typename pass_t >827 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SuspendStmt * node ) {845 template< typename core_t > 846 const ast::Stmt * ast::Pass< core_t >::visit( const ast::SuspendStmt * node ) { 828 847 VISIT_START( node ); 829 848 … … 837 856 //-------------------------------------------------------------------------- 838 857 // WaitForStmt 839 template< typename pass_t >840 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {858 template< typename core_t > 859 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitForStmt * node ) { 841 860 VISIT_START( node ); 842 861 // for( auto & clause : node->clauses ) { … … 906 925 //-------------------------------------------------------------------------- 907 926 // WithStmt 908 template< typename pass_t >909 const ast::Decl * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {927 template< typename core_t > 928 const ast::Decl * ast::Pass< core_t >::visit( const ast::WithStmt * node ) { 910 929 VISIT_START( node ); 911 930 … … 915 934 // catch statements introduce a level of scope (for the caught exception) 916 935 guard_symtab guard { *this }; 917 __pass::symtab::addWith( pass, 0, node->exprs, node );936 __pass::symtab::addWith( core, 0, node->exprs, node ); 918 937 maybe_accept( node, &WithStmt::stmt ); 919 938 } … … 924 943 //-------------------------------------------------------------------------- 925 944 // NullStmt 926 template< typename pass_t >927 const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {945 template< typename core_t > 946 const ast::NullStmt * ast::Pass< core_t >::visit( const ast::NullStmt * node ) { 928 947 VISIT_START( node ); 929 948 VISIT_END( NullStmt, node ); … … 932 951 //-------------------------------------------------------------------------- 933 952 // DeclStmt 934 template< typename pass_t >935 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {953 template< typename core_t > 954 const ast::Stmt * ast::Pass< core_t >::visit( const ast::DeclStmt * node ) { 936 955 VISIT_START( node ); 937 956 … … 945 964 //-------------------------------------------------------------------------- 946 965 // ImplicitCtorDtorStmt 947 template< typename pass_t >948 const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {966 template< typename core_t > 967 const ast::Stmt * ast::Pass< core_t >::visit( const ast::ImplicitCtorDtorStmt * node ) { 949 968 VISIT_START( node ); 950 969 951 970 // For now this isn't visited, it is unclear if this causes problem 952 971 // if all tests are known to pass, remove this code 953 //VISIT(954 //maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );955 //)972 VISIT( 973 maybe_accept( node, &ImplicitCtorDtorStmt::callStmt ); 974 ) 956 975 957 976 VISIT_END( Stmt, node ); … … 960 979 //-------------------------------------------------------------------------- 961 980 // ApplicationExpr 962 template< typename pass_t >963 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {981 template< typename core_t > 982 const ast::Expr * ast::Pass< core_t >::visit( const ast::ApplicationExpr * node ) { 964 983 VISIT_START( node ); 965 984 … … 978 997 //-------------------------------------------------------------------------- 979 998 // UntypedExpr 980 template< typename pass_t >981 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {999 template< typename core_t > 1000 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedExpr * node ) { 982 1001 VISIT_START( node ); 983 1002 … … 996 1015 //-------------------------------------------------------------------------- 997 1016 // NameExpr 998 template< typename pass_t >999 const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {1017 template< typename core_t > 1018 const ast::Expr * ast::Pass< core_t >::visit( const ast::NameExpr * node ) { 1000 1019 VISIT_START( node ); 1001 1020 … … 1010 1029 //-------------------------------------------------------------------------- 1011 1030 // CastExpr 1012 template< typename pass_t >1013 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {1031 template< typename core_t > 1032 const ast::Expr * ast::Pass< core_t >::visit( const ast::CastExpr * node ) { 1014 1033 VISIT_START( node ); 1015 1034 … … 1026 1045 //-------------------------------------------------------------------------- 1027 1046 // KeywordCastExpr 1028 template< typename pass_t >1029 const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {1047 template< typename core_t > 1048 const ast::Expr * ast::Pass< core_t >::visit( const ast::KeywordCastExpr * node ) { 1030 1049 VISIT_START( node ); 1031 1050 … … 1042 1061 //-------------------------------------------------------------------------- 1043 1062 // VirtualCastExpr 1044 template< typename pass_t >1045 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {1063 template< typename core_t > 1064 const ast::Expr * ast::Pass< core_t >::visit( const ast::VirtualCastExpr * node ) { 1046 1065 VISIT_START( node ); 1047 1066 … … 1058 1077 //-------------------------------------------------------------------------- 1059 1078 // AddressExpr 1060 template< typename pass_t >1061 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {1079 template< typename core_t > 1080 const ast::Expr * ast::Pass< core_t >::visit( const ast::AddressExpr * node ) { 1062 1081 VISIT_START( node ); 1063 1082 … … 1074 1093 //-------------------------------------------------------------------------- 1075 1094 // LabelAddressExpr 1076 template< typename pass_t >1077 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {1095 template< typename core_t > 1096 const ast::Expr * ast::Pass< core_t >::visit( const ast::LabelAddressExpr * node ) { 1078 1097 VISIT_START( node ); 1079 1098 … … 1088 1107 //-------------------------------------------------------------------------- 1089 1108 // UntypedMemberExpr 1090 template< typename pass_t >1091 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {1109 template< typename core_t > 1110 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedMemberExpr * node ) { 1092 1111 VISIT_START( node ); 1093 1112 … … 1105 1124 //-------------------------------------------------------------------------- 1106 1125 // MemberExpr 1107 template< typename pass_t >1108 const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {1126 template< typename core_t > 1127 const ast::Expr * ast::Pass< core_t >::visit( const ast::MemberExpr * node ) { 1109 1128 VISIT_START( node ); 1110 1129 … … 1121 1140 //-------------------------------------------------------------------------- 1122 1141 // VariableExpr 1123 template< typename pass_t >1124 const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {1142 template< typename core_t > 1143 const ast::Expr * ast::Pass< core_t >::visit( const ast::VariableExpr * node ) { 1125 1144 VISIT_START( node ); 1126 1145 … … 1135 1154 //-------------------------------------------------------------------------- 1136 1155 // ConstantExpr 1137 template< typename pass_t >1138 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {1156 template< typename core_t > 1157 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstantExpr * node ) { 1139 1158 VISIT_START( node ); 1140 1159 … … 1149 1168 //-------------------------------------------------------------------------- 1150 1169 // SizeofExpr 1151 template< typename pass_t >1152 const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {1170 template< typename core_t > 1171 const ast::Expr * ast::Pass< core_t >::visit( const ast::SizeofExpr * node ) { 1153 1172 VISIT_START( node ); 1154 1173 … … 1169 1188 //-------------------------------------------------------------------------- 1170 1189 // AlignofExpr 1171 template< typename pass_t >1172 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {1190 template< typename core_t > 1191 const ast::Expr * ast::Pass< core_t >::visit( const ast::AlignofExpr * node ) { 1173 1192 VISIT_START( node ); 1174 1193 … … 1189 1208 //-------------------------------------------------------------------------- 1190 1209 // UntypedOffsetofExpr 1191 template< typename pass_t >1192 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {1210 template< typename core_t > 1211 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedOffsetofExpr * node ) { 1193 1212 VISIT_START( node ); 1194 1213 … … 1205 1224 //-------------------------------------------------------------------------- 1206 1225 // OffsetofExpr 1207 template< typename pass_t >1208 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {1226 template< typename core_t > 1227 const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetofExpr * node ) { 1209 1228 VISIT_START( node ); 1210 1229 … … 1221 1240 //-------------------------------------------------------------------------- 1222 1241 // OffsetPackExpr 1223 template< typename pass_t >1224 const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {1242 template< typename core_t > 1243 const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetPackExpr * node ) { 1225 1244 VISIT_START( node ); 1226 1245 … … 1237 1256 //-------------------------------------------------------------------------- 1238 1257 // LogicalExpr 1239 template< typename pass_t >1240 const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {1258 template< typename core_t > 1259 const ast::Expr * ast::Pass< core_t >::visit( const ast::LogicalExpr * node ) { 1241 1260 VISIT_START( node ); 1242 1261 … … 1254 1273 //-------------------------------------------------------------------------- 1255 1274 // ConditionalExpr 1256 template< typename pass_t >1257 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {1275 template< typename core_t > 1276 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConditionalExpr * node ) { 1258 1277 VISIT_START( node ); 1259 1278 … … 1272 1291 //-------------------------------------------------------------------------- 1273 1292 // CommaExpr 1274 template< typename pass_t >1275 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {1293 template< typename core_t > 1294 const ast::Expr * ast::Pass< core_t >::visit( const ast::CommaExpr * node ) { 1276 1295 VISIT_START( node ); 1277 1296 … … 1289 1308 //-------------------------------------------------------------------------- 1290 1309 // TypeExpr 1291 template< typename pass_t >1292 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {1310 template< typename core_t > 1311 const ast::Expr * ast::Pass< core_t >::visit( const ast::TypeExpr * node ) { 1293 1312 VISIT_START( node ); 1294 1313 … … 1305 1324 //-------------------------------------------------------------------------- 1306 1325 // AsmExpr 1307 template< typename pass_t >1308 const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {1326 template< typename core_t > 1327 const ast::Expr * ast::Pass< core_t >::visit( const ast::AsmExpr * node ) { 1309 1328 VISIT_START( node ); 1310 1329 … … 1322 1341 //-------------------------------------------------------------------------- 1323 1342 // ImplicitCopyCtorExpr 1324 template< typename pass_t >1325 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {1343 template< typename core_t > 1344 const ast::Expr * ast::Pass< core_t >::visit( const ast::ImplicitCopyCtorExpr * node ) { 1326 1345 VISIT_START( node ); 1327 1346 … … 1338 1357 //-------------------------------------------------------------------------- 1339 1358 // ConstructorExpr 1340 template< typename pass_t >1341 const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {1359 template< typename core_t > 1360 const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstructorExpr * node ) { 1342 1361 VISIT_START( node ); 1343 1362 … … 1354 1373 //-------------------------------------------------------------------------- 1355 1374 // CompoundLiteralExpr 1356 template< typename pass_t >1357 const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {1375 template< typename core_t > 1376 const ast::Expr * ast::Pass< core_t >::visit( const ast::CompoundLiteralExpr * node ) { 1358 1377 VISIT_START( node ); 1359 1378 … … 1370 1389 //-------------------------------------------------------------------------- 1371 1390 // RangeExpr 1372 template< typename pass_t >1373 const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {1391 template< typename core_t > 1392 const ast::Expr * ast::Pass< core_t >::visit( const ast::RangeExpr * node ) { 1374 1393 VISIT_START( node ); 1375 1394 … … 1387 1406 //-------------------------------------------------------------------------- 1388 1407 // UntypedTupleExpr 1389 template< typename pass_t >1390 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {1408 template< typename core_t > 1409 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedTupleExpr * node ) { 1391 1410 VISIT_START( node ); 1392 1411 … … 1403 1422 //-------------------------------------------------------------------------- 1404 1423 // TupleExpr 1405 template< typename pass_t >1406 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {1424 template< typename core_t > 1425 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleExpr * node ) { 1407 1426 VISIT_START( node ); 1408 1427 … … 1419 1438 //-------------------------------------------------------------------------- 1420 1439 // TupleIndexExpr 1421 template< typename pass_t >1422 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {1440 template< typename core_t > 1441 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleIndexExpr * node ) { 1423 1442 VISIT_START( node ); 1424 1443 … … 1435 1454 //-------------------------------------------------------------------------- 1436 1455 // TupleAssignExpr 1437 template< typename pass_t >1438 const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {1456 template< typename core_t > 1457 const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleAssignExpr * node ) { 1439 1458 VISIT_START( node ); 1440 1459 … … 1451 1470 //-------------------------------------------------------------------------- 1452 1471 // StmtExpr 1453 template< typename pass_t >1454 const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {1472 template< typename core_t > 1473 const ast::Expr * ast::Pass< core_t >::visit( const ast::StmtExpr * node ) { 1455 1474 VISIT_START( node ); 1456 1475 1457 1476 VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr 1458 1477 // get the stmts that will need to be spliced in 1459 auto stmts_before = __pass::stmtsToAddBefore( pass, 0);1460 auto stmts_after = __pass::stmtsToAddAfter ( pass, 0);1478 auto stmts_before = __pass::stmtsToAddBefore( core, 0); 1479 auto stmts_after = __pass::stmtsToAddAfter ( core, 0); 1461 1480 1462 1481 // These may be modified by subnode but most be restored once we exit this statemnet. 1463 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( pass, 0) );1482 ValueGuardPtr< const ast::TypeSubstitution * > __old_env( __pass::env( core, 0) ); 1464 1483 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before ); 1465 1484 ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after ); … … 1479 1498 //-------------------------------------------------------------------------- 1480 1499 // UniqueExpr 1481 template< typename pass_t >1482 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {1500 template< typename core_t > 1501 const ast::Expr * ast::Pass< core_t >::visit( const ast::UniqueExpr * node ) { 1483 1502 VISIT_START( node ); 1484 1503 … … 1495 1514 //-------------------------------------------------------------------------- 1496 1515 // UntypedInitExpr 1497 template< typename pass_t >1498 const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {1516 template< typename core_t > 1517 const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedInitExpr * node ) { 1499 1518 VISIT_START( node ); 1500 1519 … … 1512 1531 //-------------------------------------------------------------------------- 1513 1532 // InitExpr 1514 template< typename pass_t >1515 const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {1533 template< typename core_t > 1534 const ast::Expr * ast::Pass< core_t >::visit( const ast::InitExpr * node ) { 1516 1535 VISIT_START( node ); 1517 1536 … … 1529 1548 //-------------------------------------------------------------------------- 1530 1549 // DeletedExpr 1531 template< typename pass_t >1532 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {1550 template< typename core_t > 1551 const ast::Expr * ast::Pass< core_t >::visit( const ast::DeletedExpr * node ) { 1533 1552 VISIT_START( node ); 1534 1553 … … 1546 1565 //-------------------------------------------------------------------------- 1547 1566 // DefaultArgExpr 1548 template< typename pass_t >1549 const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {1567 template< typename core_t > 1568 const ast::Expr * ast::Pass< core_t >::visit( const ast::DefaultArgExpr * node ) { 1550 1569 VISIT_START( node ); 1551 1570 … … 1562 1581 //-------------------------------------------------------------------------- 1563 1582 // GenericExpr 1564 template< typename pass_t >1565 const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {1583 template< typename core_t > 1584 const ast::Expr * ast::Pass< core_t >::visit( const ast::GenericExpr * node ) { 1566 1585 VISIT_START( node ); 1567 1586 … … 1602 1621 //-------------------------------------------------------------------------- 1603 1622 // VoidType 1604 template< typename pass_t >1605 const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {1623 template< typename core_t > 1624 const ast::Type * ast::Pass< core_t >::visit( const ast::VoidType * node ) { 1606 1625 VISIT_START( node ); 1607 1626 … … 1611 1630 //-------------------------------------------------------------------------- 1612 1631 // BasicType 1613 template< typename pass_t >1614 const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {1632 template< typename core_t > 1633 const ast::Type * ast::Pass< core_t >::visit( const ast::BasicType * node ) { 1615 1634 VISIT_START( node ); 1616 1635 … … 1620 1639 //-------------------------------------------------------------------------- 1621 1640 // PointerType 1622 template< typename pass_t >1623 const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {1641 template< typename core_t > 1642 const ast::Type * ast::Pass< core_t >::visit( const ast::PointerType * node ) { 1624 1643 VISIT_START( node ); 1625 1644 … … 1634 1653 //-------------------------------------------------------------------------- 1635 1654 // ArrayType 1636 template< typename pass_t >1637 const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {1655 template< typename core_t > 1656 const ast::Type * ast::Pass< core_t >::visit( const ast::ArrayType * node ) { 1638 1657 VISIT_START( node ); 1639 1658 … … 1648 1667 //-------------------------------------------------------------------------- 1649 1668 // ReferenceType 1650 template< typename pass_t >1651 const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {1669 template< typename core_t > 1670 const ast::Type * ast::Pass< core_t >::visit( const ast::ReferenceType * node ) { 1652 1671 VISIT_START( node ); 1653 1672 … … 1661 1680 //-------------------------------------------------------------------------- 1662 1681 // QualifiedType 1663 template< typename pass_t >1664 const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {1682 template< typename core_t > 1683 const ast::Type * ast::Pass< core_t >::visit( const ast::QualifiedType * node ) { 1665 1684 VISIT_START( node ); 1666 1685 … … 1675 1694 //-------------------------------------------------------------------------- 1676 1695 // FunctionType 1677 template< typename pass_t > 1678 const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) { 1679 VISIT_START( node ); 1680 1681 VISIT( 1682 maybe_accept( node, &FunctionType::forall ); 1696 template< typename core_t > 1697 const ast::Type * ast::Pass< core_t >::visit( const ast::FunctionType * node ) { 1698 VISIT_START( node ); 1699 1700 VISIT({ 1701 guard_forall_subs forall_guard { *this, node }; 1702 mutate_forall( node ); 1683 1703 maybe_accept( node, &FunctionType::returns ); 1684 1704 maybe_accept( node, &FunctionType::params ); 1685 )1705 }) 1686 1706 1687 1707 VISIT_END( Type, node ); … … 1690 1710 //-------------------------------------------------------------------------- 1691 1711 // StructInstType 1692 template< typename pass_t >1693 const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {1694 VISIT_START( node ); 1695 1696 __pass::symtab::addStruct( pass, 0, node->name );1712 template< typename core_t > 1713 const ast::Type * ast::Pass< core_t >::visit( const ast::StructInstType * node ) { 1714 VISIT_START( node ); 1715 1716 __pass::symtab::addStruct( core, 0, node->name ); 1697 1717 1698 1718 VISIT({ 1699 1719 guard_symtab guard { *this }; 1700 maybe_accept( node, &StructInstType::forall ); 1720 guard_forall_subs forall_guard { *this, node }; 1721 mutate_forall( node ); 1701 1722 maybe_accept( node, &StructInstType::params ); 1702 1723 }) … … 1707 1728 //-------------------------------------------------------------------------- 1708 1729 // UnionInstType 1709 template< typename pass_t >1710 const ast::Type * ast::Pass< pass_t >::visit( const ast::UnionInstType * node ) {1711 VISIT_START( node ); 1712 1713 __pass::symtab::add Struct( pass, 0, node->name );1714 1715 {1730 template< typename core_t > 1731 const ast::Type * ast::Pass< core_t >::visit( const ast::UnionInstType * node ) { 1732 VISIT_START( node ); 1733 1734 __pass::symtab::addUnion( core, 0, node->name ); 1735 1736 VISIT({ 1716 1737 guard_symtab guard { *this }; 1717 maybe_accept( node, &UnionInstType::forall ); 1738 guard_forall_subs forall_guard { *this, node }; 1739 mutate_forall( node ); 1718 1740 maybe_accept( node, &UnionInstType::params ); 1719 } 1741 }) 1720 1742 1721 1743 VISIT_END( Type, node ); … … 1724 1746 //-------------------------------------------------------------------------- 1725 1747 // EnumInstType 1726 template< typename pass_t > 1727 const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) { 1728 VISIT_START( node ); 1729 1730 VISIT( 1731 maybe_accept( node, &EnumInstType::forall ); 1748 template< typename core_t > 1749 const ast::Type * ast::Pass< core_t >::visit( const ast::EnumInstType * node ) { 1750 VISIT_START( node ); 1751 1752 VISIT({ 1753 guard_forall_subs forall_guard { *this, node }; 1754 mutate_forall( node ); 1732 1755 maybe_accept( node, &EnumInstType::params ); 1733 )1756 }) 1734 1757 1735 1758 VISIT_END( Type, node ); … … 1738 1761 //-------------------------------------------------------------------------- 1739 1762 // TraitInstType 1740 template< typename pass_t > 1741 const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) { 1742 VISIT_START( node ); 1743 1744 VISIT( 1745 maybe_accept( node, &TraitInstType::forall ); 1763 template< typename core_t > 1764 const ast::Type * ast::Pass< core_t >::visit( const ast::TraitInstType * node ) { 1765 VISIT_START( node ); 1766 1767 VISIT({ 1768 guard_forall_subs forall_guard { *this, node }; 1769 mutate_forall( node ); 1746 1770 maybe_accept( node, &TraitInstType::params ); 1747 )1771 }) 1748 1772 1749 1773 VISIT_END( Type, node ); … … 1752 1776 //-------------------------------------------------------------------------- 1753 1777 // TypeInstType 1754 template< typename pass_t > 1755 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeInstType * node ) { 1756 VISIT_START( node ); 1757 1758 VISIT( 1759 maybe_accept( node, &TypeInstType::forall ); 1760 maybe_accept( node, &TypeInstType::params ); 1778 template< typename core_t > 1779 const ast::Type * ast::Pass< core_t >::visit( const ast::TypeInstType * node ) { 1780 VISIT_START( node ); 1781 1782 VISIT( 1783 { 1784 guard_forall_subs forall_guard { *this, node }; 1785 mutate_forall( node ); 1786 maybe_accept( node, &TypeInstType::params ); 1787 } 1788 // ensure that base re-bound if doing substitution 1789 __pass::forall::replace( core, 0, node ); 1761 1790 ) 1762 1791 … … 1766 1795 //-------------------------------------------------------------------------- 1767 1796 // TupleType 1768 template< typename pass_t >1769 const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {1797 template< typename core_t > 1798 const ast::Type * ast::Pass< core_t >::visit( const ast::TupleType * node ) { 1770 1799 VISIT_START( node ); 1771 1800 … … 1780 1809 //-------------------------------------------------------------------------- 1781 1810 // TypeofType 1782 template< typename pass_t >1783 const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {1811 template< typename core_t > 1812 const ast::Type * ast::Pass< core_t >::visit( const ast::TypeofType * node ) { 1784 1813 VISIT_START( node ); 1785 1814 … … 1793 1822 //-------------------------------------------------------------------------- 1794 1823 // VarArgsType 1795 template< typename pass_t >1796 const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {1824 template< typename core_t > 1825 const ast::Type * ast::Pass< core_t >::visit( const ast::VarArgsType * node ) { 1797 1826 VISIT_START( node ); 1798 1827 … … 1802 1831 //-------------------------------------------------------------------------- 1803 1832 // ZeroType 1804 template< typename pass_t >1805 const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {1833 template< typename core_t > 1834 const ast::Type * ast::Pass< core_t >::visit( const ast::ZeroType * node ) { 1806 1835 VISIT_START( node ); 1807 1836 … … 1811 1840 //-------------------------------------------------------------------------- 1812 1841 // OneType 1813 template< typename pass_t >1814 const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {1842 template< typename core_t > 1843 const ast::Type * ast::Pass< core_t >::visit( const ast::OneType * node ) { 1815 1844 VISIT_START( node ); 1816 1845 … … 1820 1849 //-------------------------------------------------------------------------- 1821 1850 // GlobalScopeType 1822 template< typename pass_t >1823 const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {1851 template< typename core_t > 1852 const ast::Type * ast::Pass< core_t >::visit( const ast::GlobalScopeType * node ) { 1824 1853 VISIT_START( node ); 1825 1854 … … 1830 1859 //-------------------------------------------------------------------------- 1831 1860 // Designation 1832 template< typename pass_t >1833 const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {1861 template< typename core_t > 1862 const ast::Designation * ast::Pass< core_t >::visit( const ast::Designation * node ) { 1834 1863 VISIT_START( node ); 1835 1864 … … 1841 1870 //-------------------------------------------------------------------------- 1842 1871 // SingleInit 1843 template< typename pass_t >1844 const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {1872 template< typename core_t > 1873 const ast::Init * ast::Pass< core_t >::visit( const ast::SingleInit * node ) { 1845 1874 VISIT_START( node ); 1846 1875 … … 1854 1883 //-------------------------------------------------------------------------- 1855 1884 // ListInit 1856 template< typename pass_t >1857 const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {1885 template< typename core_t > 1886 const ast::Init * ast::Pass< core_t >::visit( const ast::ListInit * node ) { 1858 1887 VISIT_START( node ); 1859 1888 … … 1868 1897 //-------------------------------------------------------------------------- 1869 1898 // ConstructorInit 1870 template< typename pass_t >1871 const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {1899 template< typename core_t > 1900 const ast::Init * ast::Pass< core_t >::visit( const ast::ConstructorInit * node ) { 1872 1901 VISIT_START( node ); 1873 1902 … … 1883 1912 //-------------------------------------------------------------------------- 1884 1913 // Attribute 1885 template< typename pass_t >1886 const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node ) {1914 template< typename core_t > 1915 const ast::Attribute * ast::Pass< core_t >::visit( const ast::Attribute * node ) { 1887 1916 VISIT_START( node ); 1888 1917 … … 1896 1925 //-------------------------------------------------------------------------- 1897 1926 // TypeSubstitution 1898 template< typename pass_t >1899 const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {1927 template< typename core_t > 1928 const ast::TypeSubstitution * ast::Pass< core_t >::visit( const ast::TypeSubstitution * node ) { 1900 1929 VISIT_START( node ); 1901 1930 … … 1907 1936 guard_symtab guard { *this }; 1908 1937 auto new_node = p.second->accept( *this ); 1909 if (new_node != p.second) mutated = false;1938 if (new_node != p.second) mutated = true; 1910 1939 new_map.insert({ p.first, new_node }); 1911 1940 } … … 1923 1952 guard_symtab guard { *this }; 1924 1953 auto new_node = p.second->accept( *this ); 1925 if (new_node != p.second) mutated = false;1954 if (new_node != p.second) mutated = true; 1926 1955 new_map.insert({ p.first, new_node }); 1927 1956 } -
src/AST/Pass.proto.hpp
r67ca73e re67a82d 17 17 // IWYU pragma: private, include "Pass.hpp" 18 18 19 #include "Common/Stats/Heap.h" 20 19 21 namespace ast { 20 template<typename pass_type>22 template<typename core_t> 21 23 class Pass; 22 24 … … 82 84 }; 83 85 84 std::stack< cleanup_t > cleanups;86 std::stack< cleanup_t, std::vector<cleanup_t> > cleanups; 85 87 }; 86 88 … … 111 113 /// "Short hand" to check if this is a valid previsit function 112 114 /// Mostly used to make the static_assert look (and print) prettier 113 template<typename pass_t, typename node_t>115 template<typename core_t, typename node_t> 114 116 struct is_valid_previsit { 115 using ret_t = decltype( (( pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );117 using ret_t = decltype( ((core_t*)nullptr)->previsit( (const node_t *)nullptr ) ); 116 118 117 119 static constexpr bool value = std::is_void< ret_t >::value || … … 127 129 template<> 128 130 struct __assign<true> { 129 template<typename pass_t, typename node_t>130 static inline void result( pass_t & pass, const node_t * & node ) {131 pass.previsit( node );131 template<typename core_t, typename node_t> 132 static inline void result( core_t & core, const node_t * & node ) { 133 core.previsit( node ); 132 134 } 133 135 }; … … 135 137 template<> 136 138 struct __assign<false> { 137 template<typename pass_t, typename node_t>138 static inline void result( pass_t & pass, const node_t * & node ) {139 node = pass.previsit( node );139 template<typename core_t, typename node_t> 140 static inline void result( core_t & core, const node_t * & node ) { 141 node = core.previsit( node ); 140 142 assertf(node, "Previsit must not return NULL"); 141 143 } … … 150 152 template<> 151 153 struct __return<true> { 152 template<typename pass_t, typename node_t>153 static inline const node_t * result( pass_t & pass, const node_t * & node ) {154 pass.postvisit( node );154 template<typename core_t, typename node_t> 155 static inline const node_t * result( core_t & core, const node_t * & node ) { 156 core.postvisit( node ); 155 157 return node; 156 158 } … … 159 161 template<> 160 162 struct __return<false> { 161 template<typename pass_t, typename node_t>162 static inline auto result( pass_t & pass, const node_t * & node ) {163 return pass.postvisit( node );163 template<typename core_t, typename node_t> 164 static inline auto result( core_t & core, const node_t * & node ) { 165 return core.postvisit( node ); 164 166 } 165 167 }; … … 180 182 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 181 183 // PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call 182 template<typename pass_t, typename node_t>183 static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {184 template<typename core_t, typename node_t> 185 static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) { 184 186 static_assert( 185 is_valid_previsit< pass_t, node_t>::value,187 is_valid_previsit<core_t, node_t>::value, 186 188 "Previsit may not change the type of the node. It must return its paremeter or void." 187 189 ); … … 189 191 __assign< 190 192 std::is_void< 191 decltype( pass.previsit( node ) )193 decltype( core.previsit( node ) ) 192 194 >::value 193 >::result( pass, node );195 >::result( core, node ); 194 196 } 195 197 196 template<typename pass_t, typename node_t>197 static inline auto previsit( pass_t &, const node_t *, long ) {}198 template<typename core_t, typename node_t> 199 static inline auto previsit( core_t &, const node_t *, long ) {} 198 200 199 201 // PostVisit : never mutates the passed pointer but may return a different node 200 template<typename pass_t, typename node_t>201 static inline auto postvisit( pass_t & pass, const node_t * node, int ) ->202 decltype( pass.postvisit( node ), node->accept( *(Visitor*)nullptr ) )202 template<typename core_t, typename node_t> 203 static inline auto postvisit( core_t & core, const node_t * node, int ) -> 204 decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) ) 203 205 { 204 206 return __return< 205 207 std::is_void< 206 decltype( pass.postvisit( node ) )208 decltype( core.postvisit( node ) ) 207 209 >::value 208 >::result( pass, node );210 >::result( core, node ); 209 211 } 210 212 211 template<typename pass_t, typename node_t>212 static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }213 template<typename core_t, typename node_t> 214 static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; } 213 215 214 216 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------- … … 225 227 // The type is not strictly enforced but does match the accessory 226 228 #define FIELD_PTR( name, default_type ) \ 227 template< typename pass_t > \228 static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \229 template< typename core_t > \ 230 static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \ 229 231 \ 230 template< typename pass_t > \231 static inline default_type * name( pass_t &, long ) { return nullptr; }232 template< typename core_t > \ 233 static inline default_type * name( core_t &, long ) { return nullptr; } 232 234 233 235 // List of fields and their expected types … … 239 241 FIELD_PTR( visit_children, __pass::bool_ref ) 240 242 FIELD_PTR( at_cleanup, __pass::at_cleanup_t ) 241 FIELD_PTR( visitor, ast::Pass< pass_t> * const )243 FIELD_PTR( visitor, ast::Pass<core_t> * const ) 242 244 243 245 // Remove the macro to make sure we don't clash 244 246 #undef FIELD_PTR 247 248 template< typename core_t > 249 static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 250 // Stats::Heap::stacktrace_push(core_t::traceId); 251 } 252 253 template< typename core_t > 254 static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) { 255 // Stats::Heap::stacktrace_pop(); 256 } 257 258 template< typename core_t > 259 static void beginTrace(core_t &, long) {} 260 261 template< typename core_t > 262 static void endTrace(core_t &, long) {} 245 263 246 264 // Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement. … … 248 266 // detect it using the same strategy 249 267 namespace scope { 250 template<typename pass_t>251 static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {252 pass.beginScope();253 } 254 255 template<typename pass_t>256 static inline void enter( pass_t &, long ) {}257 258 template<typename pass_t>259 static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {260 pass.endScope();261 } 262 263 template<typename pass_t>264 static inline void leave( pass_t &, long ) {}265 } ;266 267 // Finally certain pass desire an up to date symbol table automatically268 template<typename core_t> 269 static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) { 270 core.beginScope(); 271 } 272 273 template<typename core_t> 274 static inline void enter( core_t &, long ) {} 275 276 template<typename core_t> 277 static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) { 278 core.endScope(); 279 } 280 281 template<typename core_t> 282 static inline void leave( core_t &, long ) {} 283 } // namespace scope 284 285 // Certain passes desire an up to date symbol table automatically 268 286 // detect the presence of a member name `symtab` and call all the members appropriately 269 287 namespace symtab { 270 288 // Some simple scoping rules 271 template<typename pass_t>272 static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab.enterScope(), void() ) {273 pass.symtab.enterScope();274 } 275 276 template<typename pass_t>277 static inline auto enter( pass_t &, long ) {}278 279 template<typename pass_t>280 static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab.leaveScope(), void() ) {281 pass.symtab.leaveScope();282 } 283 284 template<typename pass_t>285 static inline auto leave( pass_t &, long ) {}289 template<typename core_t> 290 static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) { 291 core.symtab.enterScope(); 292 } 293 294 template<typename core_t> 295 static inline auto enter( core_t &, long ) {} 296 297 template<typename core_t> 298 static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) { 299 core.symtab.leaveScope(); 300 } 301 302 template<typename core_t> 303 static inline auto leave( core_t &, long ) {} 286 304 287 305 // The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments 288 306 // Create macro to condense these common patterns 289 307 #define SYMTAB_FUNC1( func, type ) \ 290 template<typename pass_t> \291 static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.symtab.func( arg ), void() ) {\292 pass.symtab.func( arg ); \308 template<typename core_t> \ 309 static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\ 310 core.symtab.func( arg ); \ 293 311 } \ 294 312 \ 295 template<typename pass_t> \296 static inline void func( pass_t &, long, type ) {}313 template<typename core_t> \ 314 static inline void func( core_t &, long, type ) {} 297 315 298 316 #define SYMTAB_FUNC2( func, type1, type2 ) \ 299 template<typename pass_t> \300 static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.symtab.func( arg1, arg2 ), void () ) {\301 pass.symtab.func( arg1, arg2 ); \317 template<typename core_t> \ 318 static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\ 319 core.symtab.func( arg1, arg2 ); \ 302 320 } \ 303 321 \ 304 template<typename pass_t> \305 static inline void func( pass_t &, long, type1, type2 ) {}322 template<typename core_t> \ 323 static inline void func( core_t &, long, type1, type2 ) {} 306 324 307 325 SYMTAB_FUNC1( addId , const DeclWithType * ); … … 311 329 SYMTAB_FUNC1( addUnion , const UnionDecl * ); 312 330 SYMTAB_FUNC1( addTrait , const TraitDecl * ); 313 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Node* );331 SYMTAB_FUNC2( addWith , const std::vector< ptr<Expr> > &, const Decl * ); 314 332 315 333 // A few extra functions have more complicated behaviour, they are hand written 316 template<typename pass_t>317 static inline auto addStructFwd( pass_t & pass, int, const ast::StructDecl * decl ) -> decltype( pass.symtab.addStruct( decl ), void() ) {334 template<typename core_t> 335 static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) { 318 336 ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name ); 319 337 fwd->params = decl->params; 320 pass.symtab.addStruct( fwd );321 } 322 323 template<typename pass_t>324 static inline void addStructFwd( pass_t &, long, const ast::StructDecl * ) {}325 326 template<typename pass_t>327 static inline auto addUnionFwd( pass_t & pass, int, const ast::UnionDecl * decl ) -> decltype( pass.symtab.addUnion( decl ), void() ) {338 core.symtab.addStruct( fwd ); 339 } 340 341 template<typename core_t> 342 static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {} 343 344 template<typename core_t> 345 static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) { 328 346 UnionDecl * fwd = new UnionDecl( decl->location, decl->name ); 329 347 fwd->params = decl->params; 330 pass.symtab.addUnion( fwd );331 } 332 333 template<typename pass_t>334 static inline void addUnionFwd( pass_t &, long, const ast::UnionDecl * ) {}335 336 template<typename pass_t>337 static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addStruct( str ), void() ) {338 if ( ! pass.symtab.lookupStruct( str ) ) {339 pass.symtab.addStruct( str );348 core.symtab.addUnion( fwd ); 349 } 350 351 template<typename core_t> 352 static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {} 353 354 template<typename core_t> 355 static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) { 356 if ( ! core.symtab.lookupStruct( str ) ) { 357 core.symtab.addStruct( str ); 340 358 } 341 359 } 342 360 343 template<typename pass_t>344 static inline void addStruct( pass_t &, long, const std::string & ) {}345 346 template<typename pass_t>347 static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.symtab.addUnion( str ), void() ) {348 if ( ! pass.symtab.lookupUnion( str ) ) {349 pass.symtab.addUnion( str );361 template<typename core_t> 362 static inline void addStruct( core_t &, long, const std::string & ) {} 363 364 template<typename core_t> 365 static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) { 366 if ( ! core.symtab.lookupUnion( str ) ) { 367 core.symtab.addUnion( str ); 350 368 } 351 369 } 352 370 353 template<typename pass_t>354 static inline void addUnion( pass_t &, long, const std::string & ) {}371 template<typename core_t> 372 static inline void addUnion( core_t &, long, const std::string & ) {} 355 373 356 374 #undef SYMTAB_FUNC1 357 375 #undef SYMTAB_FUNC2 358 }; 359 }; 360 }; 376 } // namespace symtab 377 378 // Some passes need to mutate TypeDecl and properly update their pointing TypeInstType. 379 // Detect the presence of a member name `subs` and call all members appropriately 380 namespace forall { 381 // Some simple scoping rules 382 template<typename core_t> 383 static inline auto enter( core_t & core, int, const ast::ParameterizedType * type ) 384 -> decltype( core.subs, void() ) { 385 if ( ! type->forall.empty() ) core.subs.beginScope(); 386 } 387 388 template<typename core_t> 389 static inline auto enter( core_t &, long, const ast::ParameterizedType * ) {} 390 391 template<typename core_t> 392 static inline auto leave( core_t & core, int, const ast::ParameterizedType * type ) 393 -> decltype( core.subs, void() ) { 394 if ( ! type->forall.empty() ) { core.subs.endScope(); } 395 } 396 397 template<typename core_t> 398 static inline auto leave( core_t &, long, const ast::ParameterizedType * ) {} 399 400 // Get the substitution table, if present 401 template<typename core_t> 402 static inline auto subs( core_t & core, int ) -> decltype( &core.subs ) { 403 return &core.subs; 404 } 405 406 template<typename core_t> 407 static inline ast::ForallSubstitutionTable * subs( core_t &, long ) { return nullptr; } 408 409 // Replaces a TypeInstType's base TypeDecl according to the table 410 template<typename core_t> 411 static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst ) 412 -> decltype( core.subs, void() ) { 413 inst = ast::mutate_field( 414 inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) ); 415 } 416 417 template<typename core_t> 418 static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {} 419 420 } // namespace forall 421 } // namespace __pass 422 } // namespace ast -
src/AST/Print.cpp
r67ca73e re67a82d 29 29 30 30 template <typename C, typename... T> 31 constexpr auto make_array(T&&... values) -> 32 array<C,sizeof...(T)> 31 constexpr array<C,sizeof...(T)> make_array(T&&... values) 33 32 { 34 33 return array<C,sizeof...(T)>{ … … 129 128 130 129 void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) { 131 switch ( inferred.mode ) { 132 case ast::Expr::InferUnion::Empty: return; 133 case ast::Expr::InferUnion::Slots: { 134 os << indent << "with " << inferred.data.resnSlots.size() 130 if (inferred.data.resnSlots && !inferred.data.resnSlots->empty()) { 131 os << indent << "with " << inferred.data.resnSlots->size() 135 132 << " pending inference slots" << endl; 136 return; 137 } 138 case ast::Expr::InferUnion::Params: { 133 } 134 if (inferred.data.inferParams && !inferred.data.inferParams->empty()) { 139 135 os << indent << "with inferred parameters " << level << ":" << endl; 140 136 ++indent; 141 for ( const auto & i : inferred.data.inferParams ) {137 for ( const auto & i : *inferred.data.inferParams ) { 142 138 os << indent; 143 short_print( Decl::fromId( i.second.decl ));139 short_print( i.second.declptr ); 144 140 os << endl; 145 141 print( i.second.expr->inferred, level+1 ); 146 142 } 147 143 --indent; 148 return;149 }150 144 } 151 145 } … … 233 227 } 234 228 235 if ( ! short_mode && !node->assertions.empty() ) {229 if ( ! node->assertions.empty() ) { 236 230 os << endl << indent << "... with assertions" << endl; 237 231 ++indent; … … 243 237 void postprint( const ast::Expr * node ) { 244 238 print( node->inferred ); 239 240 if ( node->result ) { 241 os << endl << indent << "... with resolved type:" << endl; 242 ++indent; 243 os << indent; 244 node->result->accept( *this ); 245 --indent; 246 } 245 247 246 248 if ( node->env ) { … … 842 844 virtual const ast::Expr * visit( const ast::CastExpr * node ) override final { 843 845 ++indent; 844 os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;846 os << (node->isGenerated ? "Generated" : "Explicit") << " Cast of:" << endl << indent; 845 847 safe_print( node->arg ); 846 848 os << endl << indent-1 << "... to:"; -
src/AST/Stmt.hpp
r67ca73e re67a82d 27 27 28 28 // Must be included in *all* AST classes; should be #undef'd at the end of the file 29 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 29 #define MUTATE_FRIEND \ 30 template<typename node_t> friend node_t * mutate(const node_t * node); \ 31 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 30 32 31 33 namespace ast { … … 412 414 class ImplicitCtorDtorStmt final : public Stmt { 413 415 public: 414 readonly<Stmt> callStmt;416 ptr<Stmt> callStmt; 415 417 416 418 ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt, -
src/AST/Type.cpp
r67ca73e re67a82d 9 9 // Author : Aaron B. Moss 10 10 // Created On : Mon May 13 15:00:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Sun Dec 15 16:56:28 201913 // Update Count : 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Jul 23 14:16:00 2020 13 // Update Count : 5 14 14 // 15 15 … … 21 21 22 22 #include "Decl.hpp" 23 #include "ForallSubstitutor.hpp" // for substituteForall 23 24 #include "Init.hpp" 25 #include "Common/utility.h" // for copy, move 24 26 #include "InitTweak/InitTweak.h" // for getPointerBase 25 27 #include "Tuples/Tuples.h" // for isTtype … … 90 92 // GENERATED END 91 93 94 // --- ParameterizedType 95 96 void ParameterizedType::initWithSub( 97 const ParameterizedType & o, Pass< ForallSubstitutor > & sub 98 ) { 99 forall = sub.core( o.forall ); 100 } 101 92 102 // --- FunctionType 103 104 FunctionType::FunctionType( const FunctionType & o ) 105 : ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(), 106 isVarArgs( o.isVarArgs ) { 107 Pass< ForallSubstitutor > sub; 108 initWithSub( o, sub ); // initialize substitution map 109 returns = sub.core( o.returns ); // apply to return and parameter types 110 params = sub.core( o.params ); 111 } 93 112 94 113 namespace { … … 106 125 107 126 // --- ReferenceToType 127 128 void ReferenceToType::initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ) { 129 ParameterizedType::initWithSub( o, sub ); // initialize substitution 130 params = sub.core( o.params ); // apply to parameters 131 } 132 133 ReferenceToType::ReferenceToType( const ReferenceToType & o ) 134 : ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ), 135 hoistType( o.hoistType ) { 136 Pass< ForallSubstitutor > sub; 137 initWithSub( o, sub ); 138 } 139 108 140 std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const { 109 141 assertf( aggr(), "Must have aggregate to perform lookup" ); … … 116 148 } 117 149 118 // --- StructInstType 119 120 StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q, 121 std::vector<ptr<Attribute>>&& as ) 122 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {} 123 124 bool StructInstType::isComplete() const { return base ? base->body : false; } 125 126 // --- UnionInstType 127 128 UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q, 129 std::vector<ptr<Attribute>>&& as ) 130 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {} 131 132 bool UnionInstType::isComplete() const { return base ? base->body : false; } 133 134 // --- EnumInstType 135 136 EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q, 137 std::vector<ptr<Attribute>>&& as ) 138 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {} 139 140 bool EnumInstType::isComplete() const { return base ? base->body : false; } 150 // --- SueInstType (StructInstType, UnionInstType, EnumInstType) 151 152 template<typename decl_t> 153 SueInstType<decl_t>::SueInstType( 154 const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 155 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 156 157 template<typename decl_t> 158 bool SueInstType<decl_t>::isComplete() const { 159 return base ? base->body : false; 160 } 161 162 template class SueInstType<StructDecl>; 163 template class SueInstType<UnionDecl>; 164 template class SueInstType<EnumDecl>; 141 165 142 166 // --- TraitInstType 143 167 144 TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,145 std::vector<ptr<Attribute>>&& as )146 : ReferenceToType( b->name, q, std::move(as) ), base( b ) {}168 TraitInstType::TraitInstType( 169 const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as ) 170 : ReferenceToType( b->name, q, move(as) ), base( b ) {} 147 171 148 172 // --- TypeInstType 173 174 TypeInstType::TypeInstType( const TypeInstType & o ) 175 : ReferenceToType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) { 176 Pass< ForallSubstitutor > sub; 177 initWithSub( o, sub ); // initialize substitution 178 base = sub.core( o.base ); // apply to base type 179 } 149 180 150 181 void TypeInstType::set_base( const TypeDecl * b ) { … … 158 189 159 190 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q ) 160 : Type( q ), types( std::move(ts) ), members() {191 : Type( q ), types( move(ts) ), members() { 161 192 // This constructor is awkward. `TupleType` needs to contain objects so that members can be 162 193 // named, but members without initializer nodes end up getting constructors, which breaks -
src/AST/Type.hpp
r67ca73e re67a82d 9 9 // Author : Aaron B. Moss 10 10 // Created On : Thu May 9 10:00:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Wed Dec 11 21:56:46 201913 // Update Count : 511 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu Jul 23 14:15:00 2020 13 // Update Count : 6 14 14 // 15 15 … … 29 29 30 30 // Must be included in *all* AST classes; should be #undef'd at the end of the file 31 #define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node); 31 #define MUTATE_FRIEND \ 32 template<typename node_t> friend node_t * mutate(const node_t * node); \ 33 template<typename node_t> friend node_t * shallowCopy(const node_t * node); 32 34 33 35 namespace ast { 36 37 template< typename T > class Pass; 38 39 struct ForallSubstitutor; 34 40 35 41 class Type : public Node { … … 44 50 bool is_volatile() const { return qualifiers.is_volatile; } 45 51 bool is_restrict() const { return qualifiers.is_restrict; } 46 bool is_lvalue() const { return qualifiers.is_lvalue; }47 52 bool is_mutex() const { return qualifiers.is_mutex; } 48 53 bool is_atomic() const { return qualifiers.is_atomic; } … … 51 56 Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; } 52 57 Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; } 53 Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }54 58 Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; } 55 59 Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; } … … 163 167 static const char *typeNames[]; 164 168 165 BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 169 BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 166 170 : Type(q, std::move(as)), kind(k) {} 167 171 … … 265 269 /// Base type for potentially forall-qualified types 266 270 class ParameterizedType : public Type { 271 protected: 272 /// initializes forall with substitutor 273 void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub ); 267 274 public: 268 275 using ForallList = std::vector<ptr<TypeDecl>>; … … 276 283 ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} ) 277 284 : Type(q, std::move(as)), forall() {} 285 286 // enforce use of ForallSubstitutor to copy parameterized type 287 ParameterizedType( const ParameterizedType & ) = delete; 288 289 ParameterizedType( ParameterizedType && ) = default; 290 291 // no need to change destructor, and operator= deleted in Node 278 292 279 293 private: … … 301 315 : ParameterizedType(q), returns(), params(), isVarArgs(va) {} 302 316 317 FunctionType( const FunctionType & o ); 318 303 319 /// true if either the parameters or return values contain a tttype 304 320 bool isTtype() const; … … 314 330 /// base class for types that refer to types declared elsewhere (aggregates and typedefs) 315 331 class ReferenceToType : public ParameterizedType { 332 protected: 333 /// Initializes forall and parameters based on substitutor 334 void initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ); 316 335 public: 317 336 std::vector<ptr<Expr>> params; … … 319 338 bool hoistType = false; 320 339 321 ReferenceToType( const std::string& n, CV::Qualifiers q = {},322 std::vector<ptr<Attribute>> && as = {} )340 ReferenceToType( 341 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 323 342 : ParameterizedType(q, std::move(as)), params(), name(n) {} 343 344 ReferenceToType( const ReferenceToType & o ); 324 345 325 346 /// Gets aggregate declaration this type refers to … … 333 354 }; 334 355 335 /// instance of struct type 336 class StructInstType final : public ReferenceToType { 337 public: 338 readonly<StructDecl> base; 339 340 StructInstType( const std::string& n, CV::Qualifiers q = {}, 341 std::vector<ptr<Attribute>> && as = {} ) 356 // Common implementation for the SUE instance types. Not to be used directly. 357 template<typename decl_t> 358 class SueInstType final : public ReferenceToType { 359 public: 360 using base_type = decl_t; 361 readonly<decl_t> base; 362 363 SueInstType( 364 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 342 365 : ReferenceToType( n, q, std::move(as) ), base() {} 343 StructInstType( const StructDecl * b, CV::Qualifiers q = {}, 344 std::vector<ptr<Attribute>> && as = {} ); 366 367 SueInstType( 368 const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 345 369 346 370 bool isComplete() const override; 347 371 348 const StructDecl * aggr() const override { return base; } 349 350 const Type * accept( Visitor & v ) const override { return v.visit( this ); } 351 private: 352 StructInstType * clone() const override { return new StructInstType{ *this }; } 353 MUTATE_FRIEND 354 }; 355 356 /// instance of union type 357 class UnionInstType final : public ReferenceToType { 358 public: 359 readonly<UnionDecl> base; 360 361 UnionInstType( const std::string& n, CV::Qualifiers q = {}, 362 std::vector<ptr<Attribute>> && as = {} ) 372 const decl_t * aggr() const override { return base; } 373 374 const Type * accept( Visitor & v ) const override { return v.visit( this ); } 375 private: 376 SueInstType<decl_t> * clone() const override { return new SueInstType<decl_t>{ *this }; } 377 MUTATE_FRIEND 378 }; 379 380 /// An instance of a struct type. 381 using StructInstType = SueInstType<StructDecl>; 382 383 /// An instance of a union type. 384 using UnionInstType = SueInstType<UnionDecl>; 385 386 /// An instance of an enum type. 387 using EnumInstType = SueInstType<EnumDecl>; 388 389 /// An instance of a trait type. 390 class TraitInstType final : public ReferenceToType { 391 public: 392 readonly<TraitDecl> base; 393 394 TraitInstType( 395 const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 363 396 : ReferenceToType( n, q, std::move(as) ), base() {} 364 UnionInstType( const UnionDecl * b, CV::Qualifiers q = {}, 365 std::vector<ptr<Attribute>> && as = {} ); 366 367 bool isComplete() const override; 368 369 const UnionDecl * aggr() const override { return base; } 370 371 const Type * accept( Visitor & v ) const override { return v.visit( this ); } 372 private: 373 UnionInstType * clone() const override { return new UnionInstType{ *this }; } 374 MUTATE_FRIEND 375 }; 376 377 /// instance of enum type 378 class EnumInstType final : public ReferenceToType { 379 public: 380 readonly<EnumDecl> base; 381 382 EnumInstType( const std::string& n, CV::Qualifiers q = {}, 383 std::vector<ptr<Attribute>> && as = {} ) 384 : ReferenceToType( n, q, std::move(as) ), base() {} 385 EnumInstType( const EnumDecl * b, CV::Qualifiers q = {}, 386 std::vector<ptr<Attribute>> && as = {} ); 387 388 bool isComplete() const override; 389 390 const EnumDecl * aggr() const override { return base; } 391 392 const Type * accept( Visitor & v ) const override { return v.visit( this ); } 393 private: 394 EnumInstType * clone() const override { return new EnumInstType{ *this }; } 395 MUTATE_FRIEND 396 }; 397 398 /// instance of trait type 399 class TraitInstType final : public ReferenceToType { 400 public: 401 readonly<TraitDecl> base; 402 403 TraitInstType( const std::string& n, CV::Qualifiers q = {}, 404 std::vector<ptr<Attribute>> && as = {} ) 405 : ReferenceToType( n, q, std::move(as) ), base() {} 406 TraitInstType( const TraitDecl * b, CV::Qualifiers q = {}, 407 std::vector<ptr<Attribute>> && as = {} ); 397 398 TraitInstType( 399 const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ); 408 400 409 401 // not meaningful for TraitInstType … … 424 416 TypeDecl::Kind kind; 425 417 426 TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 418 TypeInstType( 419 const std::string& n, const TypeDecl * b, CV::Qualifiers q = {}, 427 420 std::vector<ptr<Attribute>> && as = {} ) 428 421 : ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {} … … 431 424 : ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {} 432 425 426 TypeInstType( const TypeInstType & o ); 427 433 428 /// sets `base`, updating `kind` correctly 434 429 void set_base( const TypeDecl * ); -
src/AST/TypeEnvironment.cpp
r67ca73e re67a82d 59 59 std::copy( clz.vars.begin(), clz.vars.end(), std::ostream_iterator< std::string >( out, " " ) ); 60 60 out << ")"; 61 61 62 62 if ( clz.bound ) { 63 63 out << " -> "; … … 92 92 } 93 93 } 94 94 95 95 i = next; // go to next node even if this removed 96 96 } … … 161 161 Pass<Occurs> occur{ var, env }; 162 162 maybe_accept( ty, occur ); 163 return occur. pass.result;164 } 165 } 166 167 bool TypeEnvironment::combine( 163 return occur.core.result; 164 } 165 } 166 167 bool TypeEnvironment::combine( 168 168 const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) { 169 169 // short-circuit easy cases … … 199 199 auto st = internal_lookup( *vt ); 200 200 if ( st == env.end() ) { 201 // unbound, safe to add if occurs 201 // unbound, safe to add if occurs 202 202 if ( r.bound && occurs( r.bound, *vt, *this ) ) return false; 203 203 r.vars.emplace( *vt ); … … 266 266 } 267 267 268 bool TypeEnvironment::bindVar( 269 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 270 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 271 const SymbolTable & symtab 268 bool TypeEnvironment::bindVar( 269 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 270 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 271 const SymbolTable & symtab 272 272 ) { 273 273 // remove references from bound type, so that type variables can only bind to value types … … 286 286 ptr<Type> newType = it->bound; 287 287 reset_qualifiers( newType, typeInst->qualifiers ); 288 if ( unifyInexact( 289 newType, target, *this, need, have, open, 288 if ( unifyInexact( 289 newType, target, *this, need, have, open, 290 290 widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) { 291 291 if ( common ) { … … 300 300 } 301 301 } else { 302 env.emplace_back( 302 env.emplace_back( 303 303 typeInst->name, target, widen.first && widen.second, data ); 304 304 } … … 306 306 } 307 307 308 bool TypeEnvironment::bindVarToVar( 309 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 310 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 311 WidenMode widen, const SymbolTable & symtab 308 bool TypeEnvironment::bindVarToVar( 309 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 310 AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 311 WidenMode widen, const SymbolTable & symtab 312 312 ) { 313 313 auto c1 = internal_lookup( var1->name ); 314 314 auto c2 = internal_lookup( var2->name ); 315 315 316 316 // exit early if variables already bound together 317 317 if ( c1 != env.end() && c1 == c2 ) { … … 396 396 } 397 397 398 bool TypeEnvironment::mergeBound( 398 bool TypeEnvironment::mergeBound( 399 399 EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) { 400 400 if ( from.bound ) { … … 406 406 AssertionSet need, have; 407 407 408 if ( unifyInexact( 408 if ( unifyInexact( 409 409 toType, fromType, *this, need, have, open, widen, symtab, common ) ) { 410 410 // unifies, set common type if necessary … … 424 424 } 425 425 426 bool TypeEnvironment::mergeClasses( 426 bool TypeEnvironment::mergeClasses( 427 427 ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab 428 428 ) { -
src/AST/TypeEnvironment.hpp
r67ca73e re67a82d 37 37 /// Adding this comparison operator significantly improves assertion satisfaction run time for 38 38 /// some cases. The current satisfaction algorithm's speed partially depends on the order of 39 /// assertions. Assertions which have fewer possible matches should appear before assertions 40 /// which have more possible matches. This seems to imply that this could be further improved 41 /// by providing an indexer as an additional argument and ordering based on the number of 39 /// assertions. Assertions which have fewer possible matches should appear before assertions 40 /// which have more possible matches. This seems to imply that this could be further improved 41 /// by providing an indexer as an additional argument and ordering based on the number of 42 42 /// matches of the same kind (object, function) for the names of the declarations. 43 43 /// 44 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 44 /// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 45 45 /// comparator. 46 46 /// 47 /// Note: since this compares pointers for position, minor changes in the source file that 48 /// affect memory layout can alter compilation time in unpredictable ways. For example, the 49 /// placement of a line directive can reorder type pointers with respect to each other so that 50 /// assertions are seen in different orders, causing a potentially different number of 51 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 52 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so 53 /// that assertions compare more consistently. I've tried to modify this to compare on mangle 54 /// name instead of type as the second comparator, but this causes some assertions to never be 47 /// Note: since this compares pointers for position, minor changes in the source file that 48 /// affect memory layout can alter compilation time in unpredictable ways. For example, the 49 /// placement of a line directive can reorder type pointers with respect to each other so that 50 /// assertions are seen in different orders, causing a potentially different number of 51 /// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 52 /// seconds by reordering line directives alone, so it would be nice to fix this comparison so 53 /// that assertions compare more consistently. I've tried to modify this to compare on mangle 54 /// name instead of type as the second comparator, but this causes some assertions to never be 55 55 /// recorded. More investigation is needed. 56 56 struct AssertCompare { … … 86 86 void print( std::ostream &, const OpenVarSet &, Indenter indent = {} ); 87 87 88 /// Represents an equivalence class of bound type variables, optionally with the concrete type 88 /// Represents an equivalence class of bound type variables, optionally with the concrete type 89 89 /// they bind to. 90 90 struct EqvClass { … … 95 95 96 96 EqvClass() : vars(), bound(), allowWidening( true ), data() {} 97 97 98 98 /// Copy-with-bound constructor 99 EqvClass( const EqvClass & o, const Type * b ) 99 EqvClass( const EqvClass & o, const Type * b ) 100 100 : vars( o.vars ), bound( b ), allowWidening( o.allowWidening ), data( o.data ) {} 101 101 … … 142 142 void writeToSubstitution( TypeSubstitution & sub ) const; 143 143 144 template< typename node_t , enum Node::ref_type ref_t>145 int apply( ptr_base< node_t, ref_t >& type ) const {144 template< typename node_t > 145 auto apply( node_t && type ) const { 146 146 TypeSubstitution sub; 147 147 writeToSubstitution( sub ); 148 return sub.apply( type);149 } 150 151 template< typename node_t , enum Node::ref_type ref_t>152 int applyFree( ptr_base< node_t, ref_t >& type ) const {148 return sub.apply( std::forward<node_t>(type) ); 149 } 150 151 template< typename node_t > 152 auto applyFree( node_t && type ) const { 153 153 TypeSubstitution sub; 154 154 writeToSubstitution( sub ); 155 return sub.applyFree( type);155 return sub.applyFree( std::forward<node_t>(type) ); 156 156 } 157 157 … … 172 172 void addActual( const TypeEnvironment & actualEnv, OpenVarSet & openVars ); 173 173 174 /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 174 /// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 175 175 /// needed. Returns false on failure. 176 bool bindVar( 177 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 178 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 176 bool bindVar( 177 const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 178 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 179 179 ResolvExpr::WidenMode widen, const SymbolTable & symtab ); 180 181 /// Binds the type classes represented by `var1` and `var2` together; will add one or both 180 181 /// Binds the type classes represented by `var1` and `var2` together; will add one or both 182 182 /// classes if needed. Returns false on failure. 183 bool bindVarToVar( 184 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 185 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 183 bool bindVarToVar( 184 const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 185 AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 186 186 ResolvExpr::WidenMode widen, const SymbolTable & symtab ); 187 187 … … 198 198 199 199 /// Unifies the type bound of `to` with the type bound of `from`, returning false if fails 200 bool mergeBound( 200 bool mergeBound( 201 201 EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab ); 202 202 203 203 /// Merges two type classes from local environment, returning false if fails 204 bool mergeClasses( 205 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 204 bool mergeClasses( 205 ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 206 206 const SymbolTable & symtab ); 207 207 -
src/AST/TypeSubstitution.cpp
r67ca73e re67a82d 18 18 19 19 namespace ast { 20 21 22 // size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution"); 20 23 21 24 TypeSubstitution::TypeSubstitution() { … … 92 95 namespace { 93 96 struct EnvTrimmer { 94 ptr<TypeSubstitution>env;97 const TypeSubstitution * env; 95 98 TypeSubstitution * newEnv; 96 99 EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){} … … 108 111 if ( env ) { 109 112 TypeSubstitution * newEnv = new TypeSubstitution(); 110 #if TIME_TO_CONVERT_PASSES111 113 Pass<EnvTrimmer> trimmer( env, newEnv ); 112 114 expr->accept( trimmer ); 113 #else114 (void)expr;115 (void)env;116 #endif117 115 return newEnv; 118 116 } … … 121 119 122 120 void TypeSubstitution::normalize() { 123 #if TIME_TO_CONVERT_PASSES 124 PassVisitor<Substituter> sub( *this, true ); 121 Pass<Substituter> sub( *this, true ); 125 122 do { 126 sub. pass.subCount = 0;127 sub. pass.freeOnly = true;123 sub.core.subCount = 0; 124 sub.core.freeOnly = true; 128 125 for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) { 129 i->second = i->second->acceptMutator( sub ); 130 } 131 } while ( sub.pass.subCount ); 132 #endif 133 } 134 135 #if TIME_TO_CONVERT_PASSES 136 137 Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) { 126 i->second = i->second->accept( sub ); 127 } 128 } while ( sub.core.subCount ); 129 } 130 131 const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) { 138 132 BoundVarsType::const_iterator bound = boundVars.find( inst->name ); 139 133 if ( bound != boundVars.end() ) return inst; … … 146 140 // Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here. 147 141 // TODO: investigate preventing type variables from being bound to themselves in the first place. 148 if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {142 if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) { 149 143 if ( inst->name == replacement->name ) { 150 144 return inst; … … 153 147 // std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl; 154 148 subCount++; 155 Type * newtype = i->second->clone(); 156 newtype->get_qualifiers() |= inst->get_qualifiers(); 157 delete inst; 158 // Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode. 159 return newtype->acceptMutator( *visitor ); 160 } // if 161 } 162 163 Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) { 149 ptr<Type> newType = i->second; // force clone if needed 150 add_qualifiers( newType, inst->qualifiers ); 151 // Note: need to recursively apply substitution to the new type because normalize does not 152 // substitute bound vars, but bound vars must be substituted when not in freeOnly mode. 153 newType = newType->accept( *visitor ); 154 return newType.release(); 155 } // if 156 } 157 158 const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) { 164 159 VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name ); 165 160 if ( i == sub.varEnv.end() ) { … … 167 162 } else { 168 163 subCount++; 169 delete nameExpr; 170 return i->second->clone(); 171 } // if 172 } 173 174 void TypeSubstitution::Substituter::premutate( Type * type ) { 164 return i->second; 165 } // if 166 } 167 168 void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) { 175 169 GuardValue( boundVars ); 176 170 // bind type variables from forall-qualifiers 177 171 if ( freeOnly ) { 178 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar) {179 boundVars.insert( (*tyvar)->name );172 for ( const TypeDecl * tyvar : ptype->forall ) { 173 boundVars.insert( tyvar->name ); 180 174 } // for 181 175 } // if 182 176 } 183 177 184 template< typename TypeClass > 185 void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) { 178 void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) { 186 179 GuardValue( boundVars ); 187 180 // bind type variables from forall-qualifiers 188 181 if ( freeOnly ) { 189 for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar) {190 boundVars.insert( (*tyvar)->name );182 for ( const TypeDecl * tyvar : type->forall ) { 183 boundVars.insert( tyvar->name ); 191 184 } // for 192 185 // bind type variables from generic type instantiations 193 std::list< TypeDecl* > *baseParameters = type->get_baseParameters(); 194 if ( baseParameters && ! type->parameters.empty() ) { 195 for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) { 196 boundVars.insert( (*tyvar)->name ); 197 } // for 198 } // if 199 } // if 200 } 201 202 void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) { 186 if ( auto decl = type->aggr() ) { 187 if ( ! type->params.empty() ) { 188 for ( const TypeDecl * tyvar : decl->params ) { 189 boundVars.insert( tyvar->name ); 190 } // for 191 } // if 192 } 193 } // if 194 } 195 196 void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) { 203 197 handleAggregateType( aggregateUseType ); 204 198 } 205 199 206 void TypeSubstitution::Substituter::pre mutate(UnionInstType *aggregateUseType ) {200 void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) { 207 201 handleAggregateType( aggregateUseType ); 208 202 } 209 210 #endif211 203 212 204 } // namespace ast -
src/AST/TypeSubstitution.hpp
r67ca73e re67a82d 44 44 TypeSubstitution &operator=( const TypeSubstitution &other ); 45 45 46 template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const; 47 template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const; 46 template< typename SynTreeClass > 47 struct ApplyResult { 48 // const SynTreeClass * node; 49 ast::ptr<SynTreeClass> node; 50 int count; 51 }; 52 53 template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const; 54 template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const; 48 55 49 56 template< typename node_t, enum Node::ref_type ref_t > 50 57 int apply( ptr_base< node_t, ref_t > & input ) const { 51 58 const node_t * p = input.get(); 52 intret = apply(p);53 input = p;54 return ret ;59 auto ret = apply(p); 60 input = ret.node; 61 return ret.count; 55 62 } 56 63 … … 58 65 int applyFree( ptr_base< node_t, ref_t > & input ) const { 59 66 const node_t * p = input.get(); 60 intret = applyFree(p);61 input = p;62 return ret ;67 auto ret = applyFree(p); 68 input = ret.node; 69 return ret.count; 63 70 } 64 71 … … 92 99 void initialize( const TypeSubstitution &src, TypeSubstitution &dest ); 93 100 94 template<typename pass_type>101 template<typename core_t> 95 102 friend class Pass; 96 103 … … 147 154 // PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals. 148 155 #include "Pass.hpp" 156 #include "Copy.hpp" 149 157 150 158 namespace ast { … … 152 160 // definitition must happen after PassVisitor is included so that WithGuards can be used 153 161 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> { 162 static size_t traceId; 154 163 155 164 Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {} 156 165 157 #if TIME_TO_CONVERT_PASSES 158 159 Type * postmutate( TypeInstType * aggregateUseType ); 160 Expression * postmutate( NameExpr * nameExpr ); 166 const Type * postvisit( const TypeInstType * aggregateUseType ); 167 const Expr * postvisit( const NameExpr * nameExpr ); 161 168 162 169 /// Records type variable bindings from forall-statements 163 void pre mutate(Type * type );170 void previsit( const ParameterizedType * type ); 164 171 /// Records type variable bindings from forall-statements and instantiations of generic types 165 template< typename TypeClass > void handleAggregateType( TypeClass * type ); 166 167 void premutate( StructInstType * aggregateUseType ); 168 void premutate( UnionInstType * aggregateUseType ); 169 170 #endif 172 void handleAggregateType( const ReferenceToType * type ); 173 174 void previsit( const StructInstType * aggregateUseType ); 175 void previsit( const UnionInstType * aggregateUseType ); 171 176 172 177 const TypeSubstitution & sub; … … 179 184 180 185 template< typename SynTreeClass > 181 int TypeSubstitution::apply( const SynTreeClass *&input ) const {186 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const { 182 187 assert( input ); 183 188 Pass<Substituter> sub( *this, false ); 184 input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) ); 185 /// std::cerr << "substitution result is: "; 186 /// newType->print( std::cerr ); 187 /// std::cerr << std::endl; 188 return sub.pass.subCount; 189 input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) ); 190 return { input, sub.core.subCount }; 189 191 } 190 192 191 193 template< typename SynTreeClass > 192 int TypeSubstitution::applyFree( const SynTreeClass *&input ) const {194 TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const { 193 195 assert( input ); 194 196 Pass<Substituter> sub( *this, true ); 195 input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) ); 196 /// std::cerr << "substitution result is: "; 197 /// newType->print( std::cerr ); 198 /// std::cerr << std::endl; 199 return sub.pass.subCount; 197 input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) ); 198 return { input, sub.core.subCount }; 200 199 } 201 200 -
src/AST/module.mk
r67ca73e re67a82d 22 22 AST/DeclReplacer.cpp \ 23 23 AST/Expr.cpp \ 24 AST/ForallSubstitutionTable.cpp \ 24 25 AST/GenericSubstitution.cpp \ 25 26 AST/Init.cpp \ -
src/AST/porting.md
r67ca73e re67a82d 47 47 template<typename node_t> 48 48 friend node_t * mutate(const node_t * node); 49 template<typename node_t> 50 friend node_t * shallowCopy(const node_t * node); 51 or equilant. 52 * You should use the `mutate` function where possible as it avoids extra copies. 53 * If you must copy use `shallowCopy` or `deepCopy` as required. 49 54 50 55 All leaves of the `Node` inheritance tree are now declared `final` -
src/Common/Eval.cc
r67ca73e re67a82d 168 168 if (expr) { 169 169 expr->accept(ev); 170 return std::make_pair(ev. pass.value, ev.pass.valid);170 return std::make_pair(ev.core.value, ev.core.valid); 171 171 } else { 172 172 return std::make_pair(0, false); -
src/Common/ScopedMap.h
r67ca73e re67a82d 249 249 250 250 /// Gets the note at the given scope 251 Note& getNote() { return scopes.back().note; } 252 const Note& getNote() const { return scopes.back().note; } 251 253 Note& getNote( size_type i ) { return scopes[i].note; } 252 254 const Note& getNote( size_type i ) const { return scopes[i].note; } -
src/Common/Stats/Heap.cc
r67ca73e re67a82d 53 53 const size_t passes_size = sizeof(passes) / sizeof(passes[0]); 54 54 size_t passes_cnt = 1; 55 56 StatBlock stacktrace_stats[100]; 57 size_t stacktrace_stats_count = 0; 58 bool stacktrace_stats_enabled = true; 59 60 size_t trace[1000]; 61 const size_t stacktrace_max_depth = sizeof(trace) / sizeof(size_t); 62 size_t stacktrace_depth; 63 64 size_t new_stacktrace_id(const char * const name) { 65 stacktrace_stats[stacktrace_stats_count].name = name; 66 return stacktrace_stats_count++; 67 } 68 69 void stacktrace_push(size_t id) { 70 ++stacktrace_depth; 71 assertf(stacktrace_depth < stacktrace_max_depth, "Stack trace too deep: increase size of array in Heap.cc"); 72 trace[stacktrace_depth] = id; 73 } 74 75 void stacktrace_pop() { 76 assertf(stacktrace_depth > 0, "Invalid stack tracing operation: trace is empty"); 77 --stacktrace_depth; 78 } 55 79 56 80 void newPass( const char * const name ) { … … 116 140 for(size_t i = 0; i < passes_cnt; i++) { 117 141 print(passes[i], nc, total_mallocs, total_frees, overall_peak); 142 } 143 144 print('-', nct); 145 std::cerr << std::setw(nc) << "Trace"; 146 std::cerr << " | Malloc Count | Free Count | Peak Allocs |" << std::endl; 147 148 print('-', nct); 149 for (size_t i = 0; i < stacktrace_stats_count; i++) { 150 print(stacktrace_stats[i], nc, total_mallocs, total_frees, overall_peak); 118 151 } 119 152 print('-', nct); … … 188 221 = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs); 189 222 } 223 224 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 225 stacktrace_stats[trace[stacktrace_depth]].mallocs++; 226 } 190 227 return __malloc( size ); 191 228 } … … 196 233 passes[passes_cnt - 1].frees++; 197 234 passes[passes_cnt - 1].n_allocs--; 235 } 236 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 237 stacktrace_stats[trace[stacktrace_depth]].frees++; 198 238 } 199 239 return __free( ptr ); … … 208 248 = std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs); 209 249 } 250 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 251 stacktrace_stats[trace[stacktrace_depth]].mallocs++; 252 } 210 253 return __calloc( nelem, size ); 211 254 } … … 218 261 passes[passes_cnt - 1].frees++; 219 262 } // if 263 if ( stacktrace_stats_enabled && stacktrace_depth > 0) { 264 stacktrace_stats[trace[stacktrace_depth]].mallocs++; 265 stacktrace_stats[trace[stacktrace_depth]].frees++; 266 } 220 267 return s; 221 268 } -
src/Common/Stats/Heap.h
r67ca73e re67a82d 20 20 void newPass( const char * const name ); 21 21 void print(); 22 23 size_t new_stacktrace_id(const char * const name); 24 void stacktrace_push(size_t id); 25 void stacktrace_pop(); 22 26 } 23 27 } -
src/CompilationState.cc
r67ca73e re67a82d 14 14 // 15 15 16 #include "config.h" 17 16 18 int 17 19 astp = false, … … 28 30 genproto = false, 29 31 deterministic_output = false, 32 useNewAST = CFA_USE_NEW_AST, 30 33 nomainp = false, 31 34 parsep = false, -
src/CompilationState.h
r67ca73e re67a82d 29 29 genproto, 30 30 deterministic_output, 31 useNewAST, 31 32 nomainp, 32 33 parsep, -
src/InitTweak/InitTweak.cc
r67ca73e re67a82d 127 127 ast::Pass< InitFlattener_new > flattener; 128 128 maybe_accept( init, flattener ); 129 return std::move( flattener. pass.argList );129 return std::move( flattener.core.argList ); 130 130 } 131 131 … … 561 561 ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } }; 562 562 maybe_accept( stmt, finder ); 563 return std::move( finder. pass.matches );563 return std::move( finder.core.matches ); 564 564 } 565 565 -
src/Parser/ExpressionNode.cc
r67ca73e re67a82d 10 10 // Created On : Sat May 16 13:17:07 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Jul 15 08:24:08202013 // Update Count : 10 4612 // Last Modified On : Thu Aug 20 14:01:46 2020 13 // Update Count : 1076 14 14 // 15 15 … … 65 65 66 66 void lnthSuffix( string & str, int & type, int & ltype ) { 67 // 'u' can appear before or after length suffix 67 68 string::size_type posn = str.find_last_of( "lL" ); 68 69 69 70 if ( posn == string::npos ) return; // no suffix 70 if ( posn == str.length() - 1 ) { type = 3; return; } // no length => long 71 71 size_t end = str.length() - 1; 72 if ( posn == end ) { type = 3; return; } // no length after 'l' => long 73 72 74 string::size_type next = posn + 1; // advance to length 73 75 if ( str[next] == '3' ) { // 32 … … 84 86 } // if 85 87 } // if 86 // remove "lL" for these cases because it may not imply long 87 str.erase( posn ); // remove length suffix and "uU" 88 89 char fix = '\0'; 90 if ( str[end] == 'u' || str[end] == 'U' ) fix = str[end]; // ends with 'uU' ? 91 str.erase( posn ); // remove length suffix and possibly uU 92 if ( type == 5 ) { // L128 does not need uU 93 end = str.length() - 1; 94 if ( str[end] == 'u' || str[end] == 'U' ) str.erase( end ); // ends with 'uU' ? remove 95 } else if ( fix != '\0' ) str += fix; // put 'uU' back if removed 88 96 } // lnthSuffix 89 97 … … 156 164 if ( isdigit( str[str.length() - 1] ) ) { // no suffix ? 157 165 lnthSuffix( str, type, ltype ); // could have length suffix 158 if ( type == 5 && Unsigned ) str.erase( str.length() - 1 ); // L128 and terminating "uU" ?159 166 } else { 160 167 // At least one digit in integer constant, so safe to backup while looking for suffix. … … 195 202 if ( type < 5 ) { // not L128 ? 196 203 sscanf( (char *)str.c_str(), "%llx", &v ); 204 #if defined(__SIZEOF_INT128__) 197 205 } else { // hex int128 constant 198 206 unsigned int len = str.length(); … … 204 212 FHEX1: ; 205 213 sscanf( (char *)str.c_str(), "%llx", &v ); 214 #endif // __SIZEOF_INT128__ 206 215 } // if 207 216 //printf( "%llx %llu\n", v, v ); 208 217 } else if ( checkB( str[1] ) ) { // binary constant ? 218 #if defined(__SIZEOF_INT128__) 209 219 unsigned int len = str.length(); 210 220 if ( type == 5 && len > 2 + 64 ) { … … 214 224 scanbin( str2, v2 ); 215 225 } // if 226 #endif // __SIZEOF_INT128__ 216 227 scanbin( str, v ); 217 228 //printf( "%#llx %llu\n", v, v ); … … 223 234 unsigned int len = str.length(); 224 235 if ( len > 1 + 43 || (len == 1 + 43 && str[0] > '3') ) SemanticError( yylloc, "128-bit octal constant to large " + str ); 236 char buf[32]; 225 237 if ( len <= 1 + 21 ) { // value < 21 octal digitis 226 sscanf( (char *)str.c_str(), "%llo", &v ); // leave value in octal238 sscanf( (char *)str.c_str(), "%llo", &v ); 227 239 } else { 228 240 sscanf( &str[len - 21], "%llo", &v ); … … 237 249 } // if 238 250 v = val >> 64; v2 = (uint64_t)val; // replace octal constant with 2 hex constants 239 char buf[32];240 251 sprintf( buf, "%#llx", v2 ); 241 252 str2 = buf; 242 sprintf( buf, "%#llx", v );243 str = buf;244 253 } // if 254 sprintf( buf, "%#llx", v ); 255 str = buf; 245 256 #endif // __SIZEOF_INT128__ 246 257 } // if … … 256 267 if ( str.length() == 39 && str > (Unsigned ? "340282366920938463463374607431768211455" : "170141183460469231731687303715884105727") ) 257 268 SemanticError( yylloc, "128-bit decimal constant to large " + str ); 269 char buf[32]; 258 270 if ( len <= 19 ) { // value < 19 decimal digitis 259 sscanf( (char *)str.c_str(), "%llu", &v ); // leave value in decimal271 sscanf( (char *)str.c_str(), "%llu", &v ); 260 272 } else { 261 273 sscanf( &str[len - 19], "%llu", &v ); … … 270 282 } // if 271 283 v = val >> 64; v2 = (uint64_t)val; // replace decimal constant with 2 hex constants 272 char buf[32];273 284 sprintf( buf, "%#llx", v2 ); 274 285 str2 = buf; 275 sprintf( buf, "%#llx", v );276 str = buf;277 286 } // if 287 sprintf( buf, "%#llx", v ); 288 str = buf; 278 289 #endif // __SIZEOF_INT128__ 279 290 } // if -
src/ResolvExpr/AdjustExprType.cc
r67ca73e re67a82d 100 100 101 101 namespace { 102 struct AdjustExprType_new final : public ast::WithShortCircuiting { 102 class AdjustExprType_new final : public ast::WithShortCircuiting { 103 const ast::SymbolTable & symtab; 104 public: 103 105 const ast::TypeEnvironment & tenv; 104 const ast::SymbolTable & symtab;105 106 106 107 AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms ) 107 : tenv( e ), symtab( syms) {}108 : symtab( syms ), tenv( e ) {} 108 109 109 void pre mutate( const ast::VoidType * ) { visit_children = false; }110 void pre mutate( const ast::BasicType * ) { visit_children = false; }111 void pre mutate( const ast::PointerType * ) { visit_children = false; }112 void pre mutate( const ast::ArrayType * ) { visit_children = false; }113 void pre mutate( const ast::FunctionType * ) { visit_children = false; }114 void pre mutate( const ast::StructInstType * ) { visit_children = false; }115 void pre mutate( const ast::UnionInstType * ) { visit_children = false; }116 void pre mutate( const ast::EnumInstType * ) { visit_children = false; }117 void pre mutate( const ast::TraitInstType * ) { visit_children = false; }118 void pre mutate( const ast::TypeInstType * ) { visit_children = false; }119 void pre mutate( const ast::TupleType * ) { visit_children = false; }120 void pre mutate( const ast::VarArgsType * ) { visit_children = false; }121 void pre mutate( const ast::ZeroType * ) { visit_children = false; }122 void pre mutate( const ast::OneType * ) { visit_children = false; }110 void previsit( const ast::VoidType * ) { visit_children = false; } 111 void previsit( const ast::BasicType * ) { visit_children = false; } 112 void previsit( const ast::PointerType * ) { visit_children = false; } 113 void previsit( const ast::ArrayType * ) { visit_children = false; } 114 void previsit( const ast::FunctionType * ) { visit_children = false; } 115 void previsit( const ast::StructInstType * ) { visit_children = false; } 116 void previsit( const ast::UnionInstType * ) { visit_children = false; } 117 void previsit( const ast::EnumInstType * ) { visit_children = false; } 118 void previsit( const ast::TraitInstType * ) { visit_children = false; } 119 void previsit( const ast::TypeInstType * ) { visit_children = false; } 120 void previsit( const ast::TupleType * ) { visit_children = false; } 121 void previsit( const ast::VarArgsType * ) { visit_children = false; } 122 void previsit( const ast::ZeroType * ) { visit_children = false; } 123 void previsit( const ast::OneType * ) { visit_children = false; } 123 124 124 const ast::Type * post mutate( const ast::ArrayType * at ) {125 const ast::Type * postvisit( const ast::ArrayType * at ) { 125 126 return new ast::PointerType{ at->base, at->qualifiers }; 126 127 } 127 128 128 const ast::Type * post mutate( const ast::FunctionType * ft ) {129 const ast::Type * postvisit( const ast::FunctionType * ft ) { 129 130 return new ast::PointerType{ ft }; 130 131 } 131 132 132 const ast::Type * post mutate( const ast::TypeInstType * inst ) {133 const ast::Type * postvisit( const ast::TypeInstType * inst ) { 133 134 // replace known function-type-variables with pointer-to-function 134 135 if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) { -
src/ResolvExpr/Candidate.hpp
r67ca73e re67a82d 51 51 52 52 Candidate( const ast::Expr * x, const ast::TypeEnvironment & e ) 53 : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {} 53 : expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() { 54 assert(x->result); 55 } 54 56 55 57 Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero ) 56 58 : expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ), 57 need( o.need ) {} 59 need( o.need ) { 60 assert(x->result); 61 } 58 62 59 63 Candidate( 60 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 64 const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 61 65 const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero ) 62 : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {} 66 : expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) { 67 assert(x->result); 68 } 63 69 64 70 Candidate( … … 66 72 ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero ) 67 73 : expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ), 68 need( n.begin(), n.end() ) {} 74 need( n.begin(), n.end() ) { 75 assert(x->result); 76 } 69 77 }; 70 78 -
src/ResolvExpr/CandidateFinder.cpp
r67ca73e re67a82d 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed Jun 5 14:30:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed Jun 5 14:30:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 14:55:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 54 54 return new ast::CastExpr{ expr, expr->result->stripReferences() }; 55 55 } 56 56 57 57 return expr; 58 58 } … … 61 61 UniqueId globalResnSlot = 0; 62 62 63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,65 const ast:: TypeEnvironment & env63 Cost computeConversionCost( 64 const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue, 65 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 66 66 ) { 67 67 PRINT( … … 74 74 std::cerr << std::endl; 75 75 ) 76 Cost convCost = conversionCost( argType, paramType, symtab, env );76 Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env ); 77 77 PRINT( 78 78 std::cerr << std::endl << "cost is " << convCost << std::endl; … … 107 107 108 108 /// Computes conversion cost for a given expression to a given type 109 const ast::Expr * computeExpressionConversionCost( 110 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 109 const ast::Expr * computeExpressionConversionCost( 110 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 111 111 ) { 112 Cost convCost = computeConversionCost( arg->result, paramType, symtab, env ); 112 Cost convCost = computeConversionCost( 113 arg->result, paramType, arg->get_lvalue(), symtab, env ); 113 114 outCost += convCost; 114 115 115 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 116 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 116 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 117 // conversion. Ignore poly cost for now, since this requires resolution of the cast to 117 118 // infer parameters and this does not currently work for the reason stated below 118 119 Cost tmpCost = convCost; … … 123 124 return new ast::CastExpr{ arg, newType }; 124 125 125 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 126 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 126 // xxx - *should* be able to resolve this cast, but at the moment pointers are not 127 // castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 127 128 // once this is fixed it should be possible to resolve the cast. 128 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 129 // but it shouldn't be because this makes the conversion from DT* to DT* since 129 // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 130 // but it shouldn't be because this makes the conversion from DT* to DT* since 130 131 // commontype(zero_t, DT*) is DT*, rather than nothing 131 132 132 133 // CandidateFinder finder{ symtab, env }; 133 134 // finder.find( arg, ResolvMode::withAdjustment() ); 134 // assertf( finder.candidates.size() > 0, 135 // assertf( finder.candidates.size() > 0, 135 136 // "Somehow castable expression failed to find alternatives." ); 136 // assertf( finder.candidates.size() == 1, 137 // assertf( finder.candidates.size() == 1, 137 138 // "Somehow got multiple alternatives for known cast expression." ); 138 139 // return finder.candidates.front()->expr; … … 143 144 144 145 /// Computes conversion cost for a given candidate 145 Cost computeApplicationConversionCost( 146 CandidateRef cand, const ast::SymbolTable & symtab 146 Cost computeApplicationConversionCost( 147 CandidateRef cand, const ast::SymbolTable & symtab 147 148 ) { 148 149 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >(); … … 167 168 if ( function->isVarArgs ) { 168 169 convCost.incUnsafe(); 169 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 170 PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 170 171 << convCost << std::endl; ; ) 171 172 // convert reference-typed expressions into value-typed expressions 172 cand->expr = ast::mutate_field_index( 173 appExpr, &ast::ApplicationExpr::args, i, 173 cand->expr = ast::mutate_field_index( 174 appExpr, &ast::ApplicationExpr::args, i, 174 175 referenceToRvalueConversion( args[i], convCost ) ); 175 176 continue; … … 180 181 // Default arguments should be free - don't include conversion cost. 181 182 // Unwrap them here because they are not relevant to the rest of the system 182 cand->expr = ast::mutate_field_index( 183 cand->expr = ast::mutate_field_index( 183 184 appExpr, &ast::ApplicationExpr::args, i, def->expr ); 184 185 ++param; … … 188 189 // mark conversion cost and also specialization cost of param type 189 190 const ast::Type * paramType = (*param)->get_type(); 190 cand->expr = ast::mutate_field_index( 191 appExpr, &ast::ApplicationExpr::args, i, 192 computeExpressionConversionCost( 191 cand->expr = ast::mutate_field_index( 192 appExpr, &ast::ApplicationExpr::args, i, 193 computeExpressionConversionCost( 193 194 args[i], paramType, symtab, cand->env, convCost ) ); 194 195 convCost.decSpec( specCost( paramType ) ); … … 198 199 if ( param != params.end() ) return Cost::infinity; 199 200 200 // specialization cost of return types can't be accounted for directly, it disables 201 // specialization cost of return types can't be accounted for directly, it disables 201 202 // otherwise-identical calls, like this example based on auto-newline in the I/O lib: 202 203 // … … 215 216 } 216 217 217 void makeUnifiableVars( 218 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 219 ast::AssertionSet & need 218 void makeUnifiableVars( 219 const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 220 ast::AssertionSet & need 220 221 ) { 221 222 for ( const ast::TypeDecl * tyvar : type->forall ) { … … 254 255 255 256 ArgPack() 256 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 257 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 257 258 tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 258 259 ArgPack( 260 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 259 260 ArgPack( 261 const ast::TypeEnvironment & env, const ast::AssertionSet & need, 261 262 const ast::AssertionSet & have, const ast::OpenVarSet & open ) 262 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 263 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 263 264 open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {} 264 265 265 266 ArgPack( 266 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 267 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 268 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 267 std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 268 ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 269 unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 269 270 unsigned nextExpl = 0, unsigned explAlt = 0 ) 270 271 : parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ), 271 272 have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ), 272 273 nextExpl( nextExpl ), explAlt( explAlt ) {} 273 274 274 275 ArgPack( 275 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 276 const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 276 277 ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added ) 277 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 278 need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 278 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 279 need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 279 280 tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {} 280 281 281 282 /// true if this pack is in the middle of an exploded argument 282 283 bool hasExpl() const { return nextExpl > 0; } … … 286 287 return args[ nextArg-1 ][ explAlt ]; 287 288 } 288 289 289 290 /// Ends a tuple expression, consolidating the appropriate args 290 291 void endTuple( const std::vector< ArgPack > & packs ) { … … 307 308 308 309 /// Instantiates an argument to match a parameter, returns false if no matching results left 309 bool instantiateArgument( 310 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 311 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 312 unsigned nTuples = 0 310 bool instantiateArgument( 311 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 312 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 313 unsigned nTuples = 0 313 314 ) { 314 315 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) { … … 318 319 // xxx - dropping initializer changes behaviour from previous, but seems correct 319 320 // ^^^ need to handle the case where a tuple has a default argument 320 if ( ! instantiateArgument( 321 if ( ! instantiateArgument( 321 322 type, nullptr, args, results, genStart, symtab, nTuples ) ) return false; 322 323 nTuples = 0; … … 329 330 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) { 330 331 // paramType is a ttype, consumes all remaining arguments 331 332 332 333 // completed tuples; will be spliced to end of results to finish 333 334 std::vector< ArgPack > finalResults{}; … … 342 343 for ( std::size_t i = genStart; i < genEnd; ++i ) { 343 344 unsigned nextArg = results[i].nextArg; 344 345 345 346 // use next element of exploded tuple if present 346 347 if ( results[i].hasExpl() ) { … … 352 353 results.emplace_back( 353 354 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ), 354 copy( results[i].need ), copy( results[i].have ), 355 copy( results[i].need ), copy( results[i].have ), 355 356 copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl, 356 357 results[i].explAlt ); … … 370 371 // push empty tuple expression 371 372 newResult.parent = i; 372 std::vector< ast::ptr< ast::Expr > > emptyList; 373 newResult.expr = 374 new ast::TupleExpr{ CodeLocation{}, move( emptyList ) }; 373 newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} }; 375 374 argType = newResult.expr->result; 376 375 } else { … … 400 399 401 400 // check unification for ttype before adding to final 402 if ( 403 unify( 401 if ( 402 unify( 404 403 ttype, argType, newResult.env, newResult.need, newResult.have, 405 newResult.open, symtab ) 404 newResult.open, symtab ) 406 405 ) { 407 406 finalResults.emplace_back( move( newResult ) ); … … 424 423 if ( expl.exprs.empty() ) { 425 424 results.emplace_back( 426 results[i], move( env ), copy( results[i].need ), 425 results[i], move( env ), copy( results[i].need ), 427 426 copy( results[i].have ), move( open ), nextArg + 1, expl.cost ); 428 427 429 428 continue; 430 429 } … … 432 431 // add new result 433 432 results.emplace_back( 434 i, expl.exprs.front(), move( env ), copy( results[i].need ), 435 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 433 i, expl.exprs.front(), move( env ), copy( results[i].need ), 434 copy( results[i].have ), move( open ), nextArg + 1, nTuples, 436 435 expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 437 436 } … … 479 478 480 479 results.emplace_back( 481 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 480 i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 482 481 nTuples, Cost::zero, nextExpl, results[i].explAlt ); 483 482 } … … 495 494 if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) { 496 495 results.emplace_back( 497 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 496 i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 498 497 move( need ), move( have ), move( open ), nextArg, nTuples ); 499 498 } … … 517 516 if ( expl.exprs.empty() ) { 518 517 results.emplace_back( 519 results[i], move( env ), move( need ), move( have ), move( open ), 518 results[i], move( env ), move( need ), move( have ), move( open ), 520 519 nextArg + 1, expl.cost ); 521 520 522 521 continue; 523 522 } … … 539 538 // add new result 540 539 results.emplace_back( 541 i, expr, move( env ), move( need ), move( have ), move( open ), 540 i, expr, move( env ), move( need ), move( have ), move( open ), 542 541 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j ); 543 542 } … … 548 547 genStart = genEnd; 549 548 550 return genEnd != results.size(); 549 return genEnd != results.size(); // were any new results added? 551 550 } 552 551 553 552 /// Generate a cast expression from `arg` to `toType` 554 const ast::Expr * restructureCast( 553 const ast::Expr * restructureCast( 555 554 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast 556 555 ) { 557 if ( 558 arg->result->size() > 1 559 && ! toType->isVoid() 560 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 556 if ( 557 arg->result->size() > 1 558 && ! toType->isVoid() 559 && ! dynamic_cast< const ast::ReferenceType * >( toType ) 561 560 ) { 562 // Argument is a tuple and the target type is neither void nor a reference. Cast each 563 // member of the tuple to its corresponding target type, producing the tuple of those 564 // cast expressions. If there are more components of the tuple than components in the 565 // target type, then excess components do not come out in the result expression (but 561 // Argument is a tuple and the target type is neither void nor a reference. Cast each 562 // member of the tuple to its corresponding target type, producing the tuple of those 563 // cast expressions. If there are more components of the tuple than components in the 564 // target type, then excess components do not come out in the result expression (but 566 565 // UniqueExpr ensures that the side effects will still be produced) 567 566 if ( Tuples::maybeImpureIgnoreUnique( arg ) ) { 568 // expressions which may contain side effects require a single unique instance of 567 // expressions which may contain side effects require a single unique instance of 569 568 // the expression 570 569 arg = new ast::UniqueExpr{ arg->location, arg }; … … 574 573 // cast each component 575 574 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i }; 576 components.emplace_back( 575 components.emplace_back( 577 576 restructureCast( idx, toType->getComponent( i ), isGenerated ) ); 578 577 } … … 594 593 595 594 /// Actually visits expressions to find their candidate interpretations 596 struct Finder final : public ast::WithShortCircuiting { 595 class Finder final : public ast::WithShortCircuiting { 596 const ast::SymbolTable & symtab; 597 public: 598 static size_t traceId; 597 599 CandidateFinder & selfFinder; 598 const ast::SymbolTable & symtab;599 600 CandidateList & candidates; 600 601 const ast::TypeEnvironment & tenv; 601 602 ast::ptr< ast::Type > & targetType; 602 603 604 enum Errors { 605 NotFound, 606 NoMatch, 607 ArgsToFew, 608 ArgsToMany, 609 RetsToFew, 610 RetsToMany, 611 NoReason 612 }; 613 614 struct { 615 Errors code = NotFound; 616 } reason; 617 603 618 Finder( CandidateFinder & f ) 604 : s elfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ),619 : symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ), 605 620 targetType( f.targetType ) {} 606 621 607 622 void previsit( const ast::Node * ) { visit_children = false; } 608 623 … … 611 626 void addCandidate( Args &&... args ) { 612 627 candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } ); 628 reason.code = NoReason; 613 629 } 614 630 … … 639 655 640 656 /// Completes a function candidate with arguments located 641 void validateFunctionCandidate( 642 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 643 CandidateList & out 657 void validateFunctionCandidate( 658 const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 659 CandidateList & out 644 660 ) { 645 ast::ApplicationExpr * appExpr = 661 ast::ApplicationExpr * appExpr = 646 662 new ast::ApplicationExpr{ func->expr->location, func->expr }; 647 663 // sum cost and accumulate arguments … … 657 673 appExpr->args = move( vargs ); 658 674 // build and validate new candidate 659 auto newCand = 675 auto newCand = 660 676 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost ); 661 677 PRINT( … … 669 685 /// Builds a list of candidates for a function, storing them in out 670 686 void makeFunctionCandidates( 671 const CandidateRef & func, const ast::FunctionType * funcType, 687 const CandidateRef & func, const ast::FunctionType * funcType, 672 688 const ExplodedArgs_new & args, CandidateList & out 673 689 ) { … … 676 692 ast::TypeEnvironment funcEnv{ func->env }; 677 693 makeUnifiableVars( funcType, funcOpen, funcNeed ); 678 // add all type variables as open variables now so that those not used in the parameter679 // list are still considered open694 // add all type variables as open variables now so that those not used in the 695 // parameter list are still considered open 680 696 funcEnv.add( funcType->forall ); 681 697 … … 683 699 // attempt to narrow based on expected target type 684 700 const ast::Type * returnType = funcType->returns.front()->get_type(); 685 if ( ! unify( 686 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 701 if ( ! unify( 702 returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 687 703 ) { 688 704 // unification failed, do not pursue this candidate … … 698 714 for ( const ast::DeclWithType * param : funcType->params ) { 699 715 auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param ); 700 // Try adding the arguments corresponding to the current parameter to the existing 716 // Try adding the arguments corresponding to the current parameter to the existing 701 717 // matches 702 if ( ! instantiateArgument( 718 if ( ! instantiateArgument( 703 719 obj->type, obj->init, args, results, genStart, symtab ) ) return; 704 720 } … … 750 766 if ( expl.exprs.empty() ) { 751 767 results.emplace_back( 752 results[i], move( env ), copy( results[i].need ), 753 copy( results[i].have ), move( open ), nextArg + 1, 768 results[i], move( env ), copy( results[i].need ), 769 copy( results[i].have ), move( open ), nextArg + 1, 754 770 expl.cost ); 755 771 … … 760 776 results.emplace_back( 761 777 i, expl.exprs.front(), move( env ), copy( results[i].need ), 762 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 778 copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 763 779 expl.exprs.size() == 1 ? 0 : 1, j ); 764 780 } … … 780 796 /// Adds implicit struct-conversions to the alternative list 781 797 void addAnonConversions( const CandidateRef & cand ) { 782 // adds anonymous member interpretations whenever an aggregate value type is seen. 783 // it's okay for the aggregate expression to have reference type -- cast it to the 798 // adds anonymous member interpretations whenever an aggregate value type is seen. 799 // it's okay for the aggregate expression to have reference type -- cast it to the 784 800 // base type to treat the aggregate as the referenced value 785 801 ast::ptr< ast::Expr > aggrExpr( cand->expr ); 786 802 ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result; 787 803 cand->env.apply( aggrType ); 788 804 789 805 if ( aggrType.as< ast::ReferenceType >() ) { 790 806 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() }; … … 799 815 800 816 /// Adds aggregate member interpretations 801 void addAggMembers( 802 const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 803 const Candidate & cand, const Cost & addedCost, const std::string & name 817 void addAggMembers( 818 const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 819 const Candidate & cand, const Cost & addedCost, const std::string & name 804 820 ) { 805 821 for ( const ast::Decl * decl : aggrInst->lookup( name ) ) { 806 822 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl ); 807 CandidateRef newCand = std::make_shared<Candidate>( 823 CandidateRef newCand = std::make_shared<Candidate>( 808 824 cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost ); 809 // add anonymous member interpretations whenever an aggregate value type is seen 825 // add anonymous member interpretations whenever an aggregate value type is seen 810 826 // as a member expression 811 827 addAnonConversions( newCand ); … … 815 831 816 832 /// Adds tuple member interpretations 817 void addTupleMembers( 818 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 819 const Cost & addedCost, const ast::Expr * member 833 void addTupleMembers( 834 const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 835 const Cost & addedCost, const ast::Expr * member 820 836 ) { 821 837 if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) { 822 // get the value of the constant expression as an int, must be between 0 and the 838 // get the value of the constant expression as an int, must be between 0 and the 823 839 // length of the tuple to have meaning 824 840 long long val = constantExpr->intValue(); 825 841 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) { 826 842 addCandidate( 827 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 843 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 828 844 addedCost ); 829 845 } … … 837 853 if ( funcFinder.candidates.empty() ) return; 838 854 839 std::vector< CandidateFinder > argCandidates = 855 reason.code = NoMatch; 856 857 std::vector< CandidateFinder > argCandidates = 840 858 selfFinder.findSubExprs( untypedExpr->args ); 841 859 842 860 // take care of possible tuple assignments 843 861 // if not tuple assignment, handled as normal function call … … 877 895 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 878 896 CandidateRef newFunc{ new Candidate{ *func } }; 879 newFunc->expr = 897 newFunc->expr = 880 898 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 881 899 makeFunctionCandidates( newFunc, function, argExpansions, found ); 882 900 } 883 } else if ( 884 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 901 } else if ( 902 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 885 903 ) { 886 904 if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) { 887 905 if ( auto function = clz->bound.as< ast::FunctionType >() ) { 888 906 CandidateRef newFunc{ new Candidate{ *func } }; 889 newFunc->expr = 907 newFunc->expr = 890 908 referenceToRvalueConversion( newFunc->expr, newFunc->cost ); 891 909 makeFunctionCandidates( newFunc, function, argExpansions, found ); … … 901 919 std::vector< ExplodedArg > funcE; 902 920 funcE.reserve( funcFinder.candidates.size() ); 903 for ( const CandidateRef & func : funcFinder ) { 921 for ( const CandidateRef & func : funcFinder ) { 904 922 funcE.emplace_back( *func, symtab ); 905 923 } … … 913 931 if ( auto function = pointer->base.as< ast::FunctionType >() ) { 914 932 CandidateRef newOp{ new Candidate{ *op} }; 915 newOp->expr = 933 newOp->expr = 916 934 referenceToRvalueConversion( newOp->expr, newOp->cost ); 917 935 makeFunctionCandidates( newOp, function, argExpansions, found ); … … 922 940 } 923 941 924 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 942 // Implement SFINAE; resolution errors are only errors if there aren't any non-error 925 943 // candidates 926 944 if ( found.empty() && ! errors.isEmpty() ) { throw errors; } … … 934 952 auto pointer = appExpr->func->result.strict_as< ast::PointerType >(); 935 953 auto function = pointer->base.strict_as< ast::FunctionType >(); 936 954 937 955 std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl; 938 956 std::cerr << "parameters are:" << std::endl; … … 957 975 promoteCvtCost( winners ); 958 976 959 // function may return a struct/union value, in which case we need to add candidates 960 // for implicit conversions to each of the anonymous members, which must happen after 977 // function may return a struct/union value, in which case we need to add candidates 978 // for implicit conversions to each of the anonymous members, which must happen after 961 979 // `findMinCost`, since anon conversions are never the cheapest 962 980 for ( const CandidateRef & c : winners ) { … … 966 984 967 985 if ( candidates.empty() && targetType && ! targetType->isVoid() ) { 968 // If resolution is unsuccessful with a target type, try again without, since it 986 // If resolution is unsuccessful with a target type, try again without, since it 969 987 // will sometimes succeed when it wouldn't with a target type binding. 970 988 // For example: … … 983 1001 /// true if expression is an lvalue 984 1002 static bool isLvalue( const ast::Expr * x ) { 985 return x->result && ( x-> result->is_lvalue() || x->result.as< ast::ReferenceType >() );1003 return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() ); 986 1004 } 987 1005 … … 989 1007 CandidateFinder finder{ symtab, tenv }; 990 1008 finder.find( addressExpr->arg ); 1009 1010 if( finder.candidates.empty() ) return; 1011 1012 reason.code = NoMatch; 1013 991 1014 for ( CandidateRef & r : finder.candidates ) { 992 1015 if ( ! isLvalue( r->expr ) ) continue; … … 1009 1032 finder.find( castExpr->arg, ResolvMode::withAdjustment() ); 1010 1033 1034 if( !finder.candidates.empty() ) reason.code = NoMatch; 1035 1011 1036 CandidateList matches; 1012 1037 for ( CandidateRef & cand : finder.candidates ) { … … 1016 1041 cand->env.extractOpenVars( open ); 1017 1042 1018 // It is possible that a cast can throw away some values in a multiply-valued 1019 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1020 // subexpression results that are cast directly. The candidate is invalid if it 1043 // It is possible that a cast can throw away some values in a multiply-valued 1044 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 1045 // subexpression results that are cast directly. The candidate is invalid if it 1021 1046 // has fewer results than there are types to cast to. 1022 1047 int discardedValues = cand->expr->result->size() - toType->size(); … … 1025 1050 // unification run for side-effects 1026 1051 unify( toType, cand->expr->result, cand->env, need, have, open, symtab ); 1027 Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env ); 1052 Cost thisCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1053 symtab, cand->env ); 1028 1054 PRINT( 1029 1055 std::cerr << "working on cast with result: " << toType << std::endl; … … 1037 1063 // count one safe conversion for each value that is thrown away 1038 1064 thisCost.incSafe( discardedValues ); 1039 CandidateRef newCand = std::make_shared<Candidate>( 1040 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1041 copy( cand->env ), move( open ), move( need ), cand->cost, 1065 CandidateRef newCand = std::make_shared<Candidate>( 1066 restructureCast( cand->expr, toType, castExpr->isGenerated ), 1067 copy( cand->env ), move( open ), move( need ), cand->cost, 1042 1068 cand->cost + thisCost ); 1043 1069 inferParameters( newCand, matches ); … … 1057 1083 finder.find( castExpr->arg, ResolvMode::withoutPrune() ); 1058 1084 for ( CandidateRef & r : finder.candidates ) { 1059 addCandidate( 1060 *r, 1085 addCandidate( 1086 *r, 1061 1087 new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } ); 1062 1088 } … … 1067 1093 aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() ); 1068 1094 for ( CandidateRef & agg : aggFinder.candidates ) { 1069 // it's okay for the aggregate expression to have reference type -- cast it to the 1095 // it's okay for the aggregate expression to have reference type -- cast it to the 1070 1096 // base type to treat the aggregate as the referenced value 1071 1097 Cost addedCost = Cost::zero; … … 1074 1100 // find member of the given type 1075 1101 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) { 1076 addAggMembers( 1102 addAggMembers( 1077 1103 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1078 1104 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) { 1079 addAggMembers( 1105 addAggMembers( 1080 1106 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) ); 1081 1107 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) { … … 1092 1118 std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name ); 1093 1119 PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; ) 1120 if( declList.empty() ) return; 1121 1122 reason.code = NoMatch; 1123 1094 1124 for ( auto & data : declList ) { 1095 1125 Cost cost = Cost::zero; … … 1097 1127 1098 1128 CandidateRef newCand = std::make_shared<Candidate>( 1099 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1129 newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 1100 1130 cost ); 1101 1131 PRINT( … … 1107 1137 std::cerr << std::endl; 1108 1138 ) 1109 newCand->expr = ast::mutate_field( 1110 newCand->expr.get(), &ast::Expr::result, 1139 newCand->expr = ast::mutate_field( 1140 newCand->expr.get(), &ast::Expr::result, 1111 1141 renameTyVars( newCand->expr->result ) ); 1112 // add anonymous member interpretations whenever an aggregate value type is seen 1142 // add anonymous member interpretations whenever an aggregate value type is seen 1113 1143 // as a name expression 1114 1144 addAnonConversions( newCand ); … … 1120 1150 // not sufficient to just pass `variableExpr` here, type might have changed since 1121 1151 // creation 1122 addCandidate( 1152 addCandidate( 1123 1153 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv ); 1124 1154 } … … 1130 1160 void postvisit( const ast::SizeofExpr * sizeofExpr ) { 1131 1161 if ( sizeofExpr->type ) { 1132 addCandidate( 1133 new ast::SizeofExpr{ 1134 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1162 addCandidate( 1163 new ast::SizeofExpr{ 1164 sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 1135 1165 tenv ); 1136 1166 } else { … … 1141 1171 CandidateList winners = findMinCost( finder.candidates ); 1142 1172 if ( winners.size() != 1 ) { 1143 SemanticError( 1173 SemanticError( 1144 1174 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " ); 1145 1175 } … … 1154 1184 void postvisit( const ast::AlignofExpr * alignofExpr ) { 1155 1185 if ( alignofExpr->type ) { 1156 addCandidate( 1157 new ast::AlignofExpr{ 1158 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1186 addCandidate( 1187 new ast::AlignofExpr{ 1188 alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 1159 1189 tenv ); 1160 1190 } else { … … 1165 1195 CandidateList winners = findMinCost( finder.candidates ); 1166 1196 if ( winners.size() != 1 ) { 1167 SemanticError( 1197 SemanticError( 1168 1198 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " ); 1169 1199 } … … 1172 1202 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost ); 1173 1203 choice->cost = Cost::zero; 1174 addCandidate( 1204 addCandidate( 1175 1205 *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } ); 1176 1206 } … … 1185 1215 for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) { 1186 1216 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member ); 1187 addCandidate( 1217 addCandidate( 1188 1218 new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv ); 1189 1219 } … … 1206 1236 finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() ); 1207 1237 if ( finder2.candidates.empty() ) return; 1238 1239 reason.code = NoMatch; 1208 1240 1209 1241 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1218 1250 1219 1251 addCandidate( 1220 new ast::LogicalExpr{ 1252 new ast::LogicalExpr{ 1221 1253 logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd }, 1222 1254 move( env ), move( open ), move( need ), r1->cost + r2->cost ); … … 1240 1272 finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() ); 1241 1273 if ( finder3.candidates.empty() ) return; 1274 1275 reason.code = NoMatch; 1242 1276 1243 1277 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1256 1290 ast::AssertionSet have; 1257 1291 1258 // unify true and false results, then infer parameters to produce new 1292 // unify true and false results, then infer parameters to produce new 1259 1293 // candidates 1260 1294 ast::ptr< ast::Type > common; 1261 if ( 1262 unify( 1263 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1264 common ) 1295 if ( 1296 unify( 1297 r2->expr->result, r3->expr->result, env, need, have, open, symtab, 1298 common ) 1265 1299 ) { 1266 1300 // generate typed expression 1267 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1301 ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 1268 1302 conditionalExpr->location, r1->expr, r2->expr, r3->expr }; 1269 1303 newExpr->result = common ? common : r2->expr->result; 1270 1304 // convert both options to result type 1271 1305 Cost cost = r1->cost + r2->cost + r3->cost; 1272 newExpr->arg2 = computeExpressionConversionCost( 1306 newExpr->arg2 = computeExpressionConversionCost( 1273 1307 newExpr->arg2, newExpr->result, symtab, env, cost ); 1274 1308 newExpr->arg3 = computeExpressionConversionCost( … … 1287 1321 ast::TypeEnvironment env{ tenv }; 1288 1322 ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env ); 1289 1323 1290 1324 CandidateFinder finder2{ symtab, env }; 1291 1325 finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() ); … … 1317 1351 finder2.find( rangeExpr->high, ResolvMode::withAdjustment() ); 1318 1352 if ( finder2.candidates.empty() ) return; 1353 1354 reason.code = NoMatch; 1319 1355 1320 1356 for ( const CandidateRef & r1 : finder1.candidates ) { … … 1330 1366 1331 1367 ast::ptr< ast::Type > common; 1332 if ( 1333 unify( 1334 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1335 common ) 1368 if ( 1369 unify( 1370 r1->expr->result, r2->expr->result, env, need, have, open, symtab, 1371 common ) 1336 1372 ) { 1337 1373 // generate new expression 1338 ast::RangeExpr * newExpr = 1374 ast::RangeExpr * newExpr = 1339 1375 new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr }; 1340 1376 newExpr->result = common ? common : r1->expr->result; 1341 1377 // add candidate 1342 1378 CandidateRef newCand = std::make_shared<Candidate>( 1343 newExpr, move( env ), move( open ), move( need ), 1379 newExpr, move( env ), move( open ), move( need ), 1344 1380 r1->cost + r2->cost ); 1345 1381 inferParameters( newCand, candidates ); … … 1350 1386 1351 1387 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) { 1352 std::vector< CandidateFinder > subCandidates = 1388 std::vector< CandidateFinder > subCandidates = 1353 1389 selfFinder.findSubExprs( tupleExpr->exprs ); 1354 1390 std::vector< CandidateList > possibilities; … … 1370 1406 1371 1407 addCandidate( 1372 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1408 new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 1373 1409 move( env ), move( open ), move( need ), sumCost( subs ) ); 1374 1410 } … … 1412 1448 toType = SymTab::validateType( initExpr->location, toType, symtab ); 1413 1449 toType = adjustExprType( toType, tenv, symtab ); 1414 // The call to find must occur inside this loop, otherwise polymorphic return 1415 // types are not bound to the initialization type, since return type variables are 1416 // only open for the duration of resolving the UntypedExpr. 1450 // The call to find must occur inside this loop, otherwise polymorphic return 1451 // types are not bound to the initialization type, since return type variables are 1452 // only open for the duration of resolving the UntypedExpr. 1417 1453 CandidateFinder finder{ symtab, tenv, toType }; 1418 1454 finder.find( initExpr->expr, ResolvMode::withAdjustment() ); 1419 1455 for ( CandidateRef & cand : finder.candidates ) { 1456 if(reason.code == NotFound) reason.code = NoMatch; 1457 1420 1458 ast::TypeEnvironment env{ cand->env }; 1421 1459 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have; … … 1426 1464 ) 1427 1465 1428 // It is possible that a cast can throw away some values in a multiply-valued 1429 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1430 // the subexpression results that are cast directly. The candidate is invalid 1466 // It is possible that a cast can throw away some values in a multiply-valued 1467 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 1468 // the subexpression results that are cast directly. The candidate is invalid 1431 1469 // if it has fewer results than there are types to cast to. 1432 1470 int discardedValues = cand->expr->result->size() - toType->size(); … … 1435 1473 // unification run for side-effects 1436 1474 unify( toType, cand->expr->result, env, need, have, open, symtab ); 1437 Cost thisCost = castCost( cand->expr->result, toType, symtab, env ); 1438 1475 Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), 1476 symtab, env ); 1477 1439 1478 if ( thisCost != Cost::infinity ) { 1440 1479 // count one safe conversion for each value that is thrown away 1441 1480 thisCost.incSafe( discardedValues ); 1442 CandidateRef newCand = std::make_shared<Candidate>( 1443 new ast::InitExpr{ 1444 initExpr->location, restructureCast( cand->expr, toType ), 1445 initAlt.designation }, 1446 copy( cand->env), move( open ), move( need ), cand->cost, thisCost );1481 CandidateRef newCand = std::make_shared<Candidate>( 1482 new ast::InitExpr{ 1483 initExpr->location, restructureCast( cand->expr, toType ), 1484 initAlt.designation }, 1485 move(env), move( open ), move( need ), cand->cost, thisCost ); 1447 1486 inferParameters( newCand, matches ); 1448 1487 } … … 1469 1508 }; 1470 1509 1471 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1510 // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder"); 1511 /// Prunes a list of candidates down to those that have the minimum conversion cost for a given 1472 1512 /// return type. Skips ambiguous candidates. 1473 1513 CandidateList pruneCandidates( CandidateList & candidates ) { … … 1486 1526 { 1487 1527 ast::ptr< ast::Type > newType = candidate->expr->result; 1528 assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get()); 1488 1529 candidate->env.apply( newType ); 1489 1530 mangleName = Mangle::mangle( newType ); … … 1494 1535 if ( candidate->cost < found->second.candidate->cost ) { 1495 1536 PRINT( 1496 std::cerr << "cost " << candidate->cost << " beats " 1537 std::cerr << "cost " << candidate->cost << " beats " 1497 1538 << found->second.candidate->cost << std::endl; 1498 1539 ) … … 1500 1541 found->second = PruneStruct{ candidate }; 1501 1542 } else if ( candidate->cost == found->second.candidate->cost ) { 1502 // if one of the candidates contains a deleted identifier, can pick the other, 1503 // since deleted expressions should not be ambiguous if there is another option 1543 // if one of the candidates contains a deleted identifier, can pick the other, 1544 // since deleted expressions should not be ambiguous if there is another option 1504 1545 // that is at least as good 1505 1546 if ( findDeletedExpr( candidate->expr ) ) { … … 1515 1556 } else { 1516 1557 PRINT( 1517 std::cerr << "cost " << candidate->cost << " loses to " 1558 std::cerr << "cost " << candidate->cost << " loses to " 1518 1559 << found->second.candidate->cost << std::endl; 1519 1560 ) … … 1530 1571 1531 1572 CandidateRef cand = target.second.candidate; 1532 1573 1533 1574 ast::ptr< ast::Type > newResult = cand->expr->result; 1534 1575 cand->env.applyFree( newResult ); 1535 1576 cand->expr = ast::mutate_field( 1536 1577 cand->expr.get(), &ast::Expr::result, move( newResult ) ); 1537 1578 1538 1579 out.emplace_back( cand ); 1539 1580 } … … 1549 1590 1550 1591 if ( mode.failFast && candidates.empty() ) { 1551 SemanticError( expr, "No reasonable alternatives for expression " ); 1592 switch(finder.core.reason.code) { 1593 case Finder::NotFound: 1594 { SemanticError( expr, "No alternatives for expression " ); break; } 1595 case Finder::NoMatch: 1596 { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; } 1597 case Finder::ArgsToFew: 1598 case Finder::ArgsToMany: 1599 case Finder::RetsToFew: 1600 case Finder::RetsToMany: 1601 case Finder::NoReason: 1602 default: 1603 { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); } 1604 } 1552 1605 } 1553 1606 … … 1558 1611 std::vector< std::string > errors; 1559 1612 for ( CandidateRef & candidate : candidates ) { 1560 satisfyAssertions( candidate, symtab, satisfied, errors );1613 satisfyAssertions( candidate, localSyms, satisfied, errors ); 1561 1614 } 1562 1615 … … 1583 1636 1584 1637 CandidateList pruned = pruneCandidates( candidates ); 1585 1638 1586 1639 if ( mode.failFast && pruned.empty() ) { 1587 1640 std::ostringstream stream; … … 1602 1655 ) 1603 1656 PRINT( 1604 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1657 std::cerr << "there are " << candidates.size() << " alternatives after elimination" 1605 1658 << std::endl; 1606 1659 ) 1607 1660 } 1608 1661 1609 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1662 // adjust types after pruning so that types substituted by pruneAlternatives are correctly 1610 1663 // adjusted 1611 1664 if ( mode.adjust ) { 1612 1665 for ( CandidateRef & r : candidates ) { 1613 r->expr = ast::mutate_field( 1614 r->expr.get(), &ast::Expr::result, 1615 adjustExprType( r->expr->result, r->env, symtab) );1666 r->expr = ast::mutate_field( 1667 r->expr.get(), &ast::Expr::result, 1668 adjustExprType( r->expr->result, r->env, localSyms ) ); 1616 1669 } 1617 1670 } … … 1625 1678 } 1626 1679 1627 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1628 const std::vector< ast::ptr< ast::Expr > > & xs 1680 std::vector< CandidateFinder > CandidateFinder::findSubExprs( 1681 const std::vector< ast::ptr< ast::Expr > > & xs 1629 1682 ) { 1630 1683 std::vector< CandidateFinder > out; 1631 1684 1632 1685 for ( const auto & x : xs ) { 1633 out.emplace_back( symtab, env );1686 out.emplace_back( localSyms, env ); 1634 1687 out.back().find( x, ResolvMode::withAdjustment() ); 1635 1688 1636 1689 PRINT( 1637 1690 std::cerr << "findSubExprs" << std::endl; -
src/ResolvExpr/CandidateFinder.hpp
r67ca73e re67a82d 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed Jun 5 14:30:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Wed Jun 5 14:30:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 9:51:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 28 28 struct CandidateFinder { 29 29 CandidateList candidates; ///< List of candidate resolutions 30 const ast::SymbolTable & symtab; ///< Symbol table to lookup candidates30 const ast::SymbolTable & localSyms; ///< Symbol table to lookup candidates 31 31 const ast::TypeEnvironment & env; ///< Substitutions performed in this resolution 32 32 ast::ptr< ast::Type > targetType; ///< Target type for resolution 33 33 34 CandidateFinder( 35 const ast::SymbolTable & sym tab, const ast::TypeEnvironment & env,34 CandidateFinder( 35 const ast::SymbolTable & syms, const ast::TypeEnvironment & env, 36 36 const ast::Type * tt = nullptr ) 37 : candidates(), symtab( symtab), env( env ), targetType( tt ) {}37 : candidates(), localSyms( syms ), env( env ), targetType( tt ) {} 38 38 39 39 /// Fill candidates with feasible resolutions for `expr` … … 49 49 iterator begin() { return candidates.begin(); } 50 50 const_iterator begin() const { return candidates.begin(); } 51 51 52 52 iterator end() { return candidates.end(); } 53 53 const_iterator end() const { return candidates.end(); } … … 55 55 56 56 /// Computes conversion cost between two types 57 Cost computeConversionCost( 58 const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab,59 const ast:: TypeEnvironment & env );57 Cost computeConversionCost( 58 const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue, 59 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 60 60 61 61 } // namespace ResolvExpr -
src/ResolvExpr/CastCost.cc
r67ca73e re67a82d 10 10 // Created On : Sun May 17 06:57:43 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Aug 8 16:12:00 201913 // Update Count : 812 // Last Modified On : Tue Oct 4 15:00:00 2019 13 // Update Count : 9 14 14 // 15 15 … … 142 142 143 143 CastCost_new( 144 const ast::Type * dst, const ast::SymbolTable & symtab,144 const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 145 145 const ast::TypeEnvironment & env, CostCalculation costFunc ) 146 : ConversionCost_new( dst, s ymtab, env, costFunc ) {}146 : ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {} 147 147 148 148 void postvisit( const ast::BasicType * basicType ) { … … 152 152 cost = Cost::unsafe; 153 153 } else { 154 cost = conversionCost( basicType, dst, s ymtab, env );154 cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env ); 155 155 } 156 156 } … … 183 183 } 184 184 }; 185 186 #warning For overload resolution between the two versions. 187 int localPtrsCastable(const ast::Type * t1, const ast::Type * t2, 188 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) { 189 return ptrsCastable( t1, t2, symtab, env ); 190 } 191 Cost localCastCost( 192 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 193 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 194 ) { return castCost( src, dst, srcIsLvalue, symtab, env ); } 185 195 } // anonymous namespace 186 196 197 198 187 199 Cost castCost( 188 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,189 const ast:: TypeEnvironment & env200 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 201 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 190 202 ) { 191 203 if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { … … 193 205 // check cast cost against bound type, if present 194 206 if ( eqvClass->bound ) { 195 return castCost( src, eqvClass->bound, s ymtab, env );207 return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env ); 196 208 } else { 197 209 return Cost::infinity; … … 201 213 auto type = strict_dynamic_cast< const ast::TypeDecl * >( named ); 202 214 if ( type->base ) { 203 return castCost( src, type->base, s ymtab, env ) + Cost::safe;215 return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe; 204 216 } 205 217 } … … 224 236 #warning cast on ptrsCastable artifact of having two functions, remove when port done 225 237 return convertToReferenceCost( 226 src, refType, symtab, env, 227 ( int (*)( 228 const ast::Type *, const ast::Type *, const ast::SymbolTable &, 229 const ast::TypeEnvironment & ) 230 ) ptrsCastable ); 238 src, refType, srcIsLvalue, symtab, env, localPtrsCastable ); 231 239 } else { 232 240 #warning cast on castCost artifact of having two functions, remove when port done 233 ast::Pass< CastCost_new > converter{ 234 dst, symtab, env, 235 ( Cost (*)( 236 const ast::Type *, const ast::Type *, const ast::SymbolTable &, 237 const ast::TypeEnvironment & ) 238 ) castCost }; 241 ast::Pass< CastCost_new > converter( 242 dst, srcIsLvalue, symtab, env, localCastCost ); 239 243 src->accept( converter ); 240 return converter. pass.cost;244 return converter.core.cost; 241 245 } 242 246 } -
src/ResolvExpr/CommonType.cc
r67ca73e re67a82d 666 666 const ast::OpenVarSet & open; 667 667 public: 668 static size_t traceId; 668 669 ast::ptr< ast::Type > result; 669 670 … … 893 894 }; 894 895 896 // size_t CommonType_new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new"); 895 897 namespace { 896 898 ast::ptr< ast::Type > handleReference( … … 939 941 ast::ptr< ast::Type > result; 940 942 const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >(); 941 const ast::ReferenceType * ref2 = type 1.as< ast::ReferenceType >();943 const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >(); 942 944 943 945 if ( depth1 > depth2 ) { … … 966 968 ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open }; 967 969 type1->accept( visitor ); 968 ast::ptr< ast::Type > result = visitor. pass.result;970 ast::ptr< ast::Type > result = visitor.core.result; 969 971 970 972 // handling for opaque type declarations (?) -
src/ResolvExpr/ConversionCost.cc
r67ca73e re67a82d 481 481 } 482 482 483 static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2, 484 const ast::SymbolTable &, const ast::TypeEnvironment & env ) {485 return ptrsAssignable( t1, t2, env );486 } 487 488 // TODO: This is used for overload resolution. It might be able to be dropped once the old system 489 // is removed. 490 static Cost localConversionCost( 491 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,492 const ast::TypeEnvironment & env493 ) { return conversionCost( src, dst, symtab, env );}483 namespace { 484 # warning For overload resolution between the two versions. 485 int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2, 486 const ast::SymbolTable &, const ast::TypeEnvironment & env ) { 487 return ptrsAssignable( t1, t2, env ); 488 } 489 Cost localConversionCost( 490 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 491 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 492 ) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); } 493 } 494 494 495 495 Cost conversionCost( 496 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,497 const ast:: TypeEnvironment & env496 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 497 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env 498 498 ) { 499 499 if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) { 500 500 if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) { 501 501 if ( eqv->bound ) { 502 return conversionCost(src, eqv->bound, s ymtab, env );502 return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env ); 503 503 } else { 504 504 return Cost::infinity; … … 508 508 assertf( type, "Unexpected typedef." ); 509 509 if ( type->base ) { 510 return conversionCost( src, type->base, s ymtab, env ) + Cost::safe;510 return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe; 511 511 } 512 512 } … … 518 518 } else if ( const ast::ReferenceType * refType = 519 519 dynamic_cast< const ast::ReferenceType * >( dst ) ) { 520 return convertToReferenceCost( src, refType, s ymtab, env, localPtrsAssignable );520 return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable ); 521 521 } else { 522 ast::Pass<ConversionCost_new> converter( dst, s ymtab, env, localConversionCost );522 ast::Pass<ConversionCost_new> converter( dst, srcIsLvalue, symtab, env, localConversionCost ); 523 523 src->accept( converter ); 524 return converter. pass.cost;525 } 526 } 527 528 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, 524 return converter.core.cost; 525 } 526 } 527 528 static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 529 529 int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 530 NumCostCalculation func ) {530 PtrsCalculation func ) { 531 531 if ( 0 < diff ) { 532 532 Cost cost = convertToReferenceCost( 533 strict_dynamic_cast< const ast::ReferenceType * >( src )->base, 534 dst, (diff - 1), symtab, env, func );533 strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst, 534 srcIsLvalue, (diff - 1), symtab, env, func ); 535 535 cost.incReference(); 536 536 return cost; … … 538 538 Cost cost = convertToReferenceCost( 539 539 src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base, 540 (diff + 1), symtab, env, func );540 srcIsLvalue, (diff + 1), symtab, env, func ); 541 541 cost.incReference(); 542 542 return cost; … … 563 563 } 564 564 } else { 565 ast::Pass<ConversionCost_new> converter( dst, s ymtab, env, localConversionCost );565 ast::Pass<ConversionCost_new> converter( dst, srcIsLvalue, symtab, env, localConversionCost ); 566 566 src->accept( converter ); 567 return converter. pass.cost;567 return converter.core.cost; 568 568 } 569 569 } else { … … 572 572 assert( dstAsRef ); 573 573 if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) { 574 if ( src ->is_lvalue()) {574 if ( srcIsLvalue ) { 575 575 if ( src->qualifiers == dstAsRef->base->qualifiers ) { 576 576 return Cost::reference; … … 591 591 592 592 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst, 593 594 NumCostCalculation func ) {593 bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 594 PtrsCalculation func ) { 595 595 int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth(); 596 return convertToReferenceCost( src, dst, s depth - ddepth, symtab, env, func );596 return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func ); 597 597 } 598 598 … … 651 651 assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) ); 652 652 653 cost = costCalc( refType->base, dst, s ymtab, env );653 cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env ); 654 654 if ( refType->base->qualifiers == dst->qualifiers ) { 655 655 cost.incReference(); … … 667 667 void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) { 668 668 (void)enumInstType; 669 static const ast::BasicType integer( ast::BasicType::SignedInt );670 cost = costCalc( &integer, dst, symtab, env );669 static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) }; 670 cost = costCalc( integer, dst, srcIsLvalue, symtab, env ); 671 671 if ( cost < Cost::unsafe ) { 672 672 cost.incSafe(); … … 680 680 void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) { 681 681 if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) { 682 cost = costCalc( eqv->bound, dst, s ymtab, env );682 cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env ); 683 683 } else if ( const ast::TypeInstType * dstAsInst = 684 684 dynamic_cast< const ast::TypeInstType * >( dst ) ) { … … 690 690 assertf( type, "Unexpected typedef."); 691 691 if ( type->base ) { 692 cost = costCalc( type->base, dst, s ymtab, env ) + Cost::safe;692 cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe; 693 693 } 694 694 } … … 703 703 auto dstEnd = dstAsTuple->types.end(); 704 704 while ( srcIt != srcEnd && dstIt != dstEnd ) { 705 Cost newCost = costCalc( * srcIt++, * dstIt++, s ymtab, env );705 Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env ); 706 706 if ( newCost == Cost::infinity ) { 707 707 return; … … 738 738 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 739 739 } 740 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 741 cost = Cost::zero; 742 // +1 for zero_t ->, +1 for disambiguation 743 cost.incSafe( maxIntCost + 2 ); 740 744 } 741 745 } … … 755 759 cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] ); 756 760 } 757 } else if ( dynamic_cast< const ast::PointerType * >( dst ) ) { 758 cost = Cost::zero; 759 cost.incSafe( maxIntCost + 2 ); 760 } 761 } 762 761 } 762 } 763 // size_t ConversionCost_new::traceId = Stats::Heap::new_stacktrace_id("ConversionCost"); 763 764 764 765 } // namespace ResolvExpr -
src/ResolvExpr/ConversionCost.h
r67ca73e re67a82d 72 72 73 73 // Some function pointer types, differ in return type. 74 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, 74 using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool, 75 75 const ast::SymbolTable &, const ast::TypeEnvironment &)>; 76 using NumCostCalculation = std::function<int(const ast::Type *, const ast::Type *,76 using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *, 77 77 const ast::SymbolTable &, const ast::TypeEnvironment &)>; 78 78 … … 81 81 protected: 82 82 const ast::Type * dst; 83 bool srcIsLvalue; 83 84 const ast::SymbolTable & symtab; 84 85 const ast::TypeEnvironment & env; 85 86 CostCalculation costCalc; 86 87 public: 88 static size_t traceId; 87 89 Cost cost; 88 90 89 ConversionCost_new( const ast::Type * dst, const ast::SymbolTable & symtab,91 ConversionCost_new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab, 90 92 const ast::TypeEnvironment & env, CostCalculation costCalc ) : 91 dst( dst ), symtab( symtab ), env( env ), costCalc( costCalc ), cost( Cost::infinity ) 93 dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ), 94 costCalc( costCalc ), cost( Cost::infinity ) 92 95 {} 93 96 … … 110 113 111 114 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest, 112 const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, NumCostCalculation func ); 115 bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, 116 PtrsCalculation func ); 113 117 114 118 } // namespace ResolvExpr -
src/ResolvExpr/CurrentObject.cc
r67ca73e re67a82d 21 21 #include <string> // for string, operator<<, allocator 22 22 23 #include "AST/Copy.hpp" // for shallowCopy 23 24 #include "AST/Expr.hpp" // for InitAlternative 24 25 #include "AST/GenericSubstitution.hpp" // for genericSubstitution 25 26 #include "AST/Init.hpp" // for Designation 26 27 #include "AST/Node.hpp" // for readonly 28 #include "AST/Print.hpp" // for readonly 27 29 #include "AST/Type.hpp" 28 30 #include "Common/Indenter.h" // for Indenter, operator<< … … 596 598 SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {} 597 599 598 void setPosition( 599 std::deque< ptr< Expr > >::const_iterator begin, 600 void setPosition( 601 std::deque< ptr< Expr > >::const_iterator begin, 600 602 std::deque< ptr< Expr > >::const_iterator end 601 603 ) override { … … 637 639 auto res = eval(expr); 638 640 if ( ! res.second ) { 639 SemanticError( location, 641 SemanticError( location, 640 642 toString("Array designator must be a constant expression: ", expr ) ); 641 643 } … … 644 646 645 647 public: 646 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 648 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 647 649 : location( loc ), array( at ), base( at->base ) { 648 650 PRINT( std::cerr << "Creating array iterator: " << at << std::endl; ) … … 655 657 656 658 void setPosition( const Expr * expr ) { 657 // need to permit integer-constant-expressions, including: integer constants, 658 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 // need to permit integer-constant-expressions, including: integer constants, 660 // enumeration constants, character constants, sizeof expressions, alignof expressions, 659 661 // cast expressions 660 662 if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) { … … 662 664 index = constExpr->intValue(); 663 665 } catch ( SemanticErrorException & ) { 664 SemanticError( expr, 666 SemanticError( expr, 665 667 "Constant expression of non-integral type in array designator: " ); 666 668 } 667 669 } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) { 668 670 setPosition( castExpr->arg ); 669 } else if ( 670 dynamic_cast< const SizeofExpr * >( expr ) 671 || dynamic_cast< const AlignofExpr * >( expr ) 671 } else if ( 672 dynamic_cast< const SizeofExpr * >( expr ) 673 || dynamic_cast< const AlignofExpr * >( expr ) 672 674 ) { 673 675 index = 0; 674 676 } else { 675 assertf( false, 677 assertf( false, 676 678 "bad designator given to ArrayIterator: %s", toString( expr ).c_str() ); 677 679 } 678 680 } 679 681 680 void setPosition( 681 std::deque< ptr< Expr > >::const_iterator begin, 682 void setPosition( 683 std::deque< ptr< Expr > >::const_iterator begin, 682 684 std::deque< ptr< Expr > >::const_iterator end 683 685 ) override { … … 758 760 } 759 761 760 AggregateIterator( 761 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 AggregateIterator( 763 const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 762 764 const MemberList & ms ) 763 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 765 : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 764 766 sub( genericSubstitution( i ) ) { 765 767 PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; ) … … 768 770 769 771 public: 770 void setPosition( 771 std::deque< ptr< Expr > >::const_iterator begin, 772 void setPosition( 773 std::deque< ptr< Expr > >::const_iterator begin, 772 774 std::deque< ptr< Expr > >::const_iterator end 773 775 ) final { … … 786 788 return; 787 789 } 788 assertf( false, 790 assertf( false, 789 791 "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() ); 790 792 } else { 791 assertf( false, 793 assertf( false, 792 794 "bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() ); 793 795 } … … 803 805 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 804 806 // need to substitute for generic types so that casts are to concrete types 807 alt.type = shallowCopy(alt.type.get()); 805 808 PRINT( std::cerr << " type is: " << alt.type; ) 806 809 sub.apply( alt.type ); // also apply to designation?? … … 842 845 for ( InitAlternative & alt : ret ) { 843 846 PRINT( std::cerr << "iterating and adding designators" << std::endl; ) 844 alt.designation.get_and_mutate()->designators.emplace_front( 847 alt.designation.get_and_mutate()->designators.emplace_front( 845 848 new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } ); 846 849 } … … 897 900 class TupleIterator final : public AggregateIterator { 898 901 public: 899 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 900 : AggregateIterator( 901 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 TupleIterator( const CodeLocation & loc, const TupleType * inst ) 903 : AggregateIterator( 904 loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 902 905 ) {} 903 906 … … 926 929 return new UnionIterator{ loc, uit }; 927 930 } else { 928 assertf( 929 dynamic_cast< const EnumInstType * >( aggr )930 || dynamic_cast< const TypeInstType * >( aggr ),931 assertf( 932 dynamic_cast< const EnumInstType * >( type ) 933 || dynamic_cast< const TypeInstType * >( type ), 931 934 "Encountered unhandled ReferenceToType in createMemberIterator: %s", 932 935 toString( type ).c_str() ); … … 949 952 using DesignatorChain = std::deque< ptr< Expr > >; 950 953 PRINT( std::cerr << "___findNext" << std::endl; ) 951 954 952 955 // find all the d's 953 956 std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts; … … 1013 1016 // set new designators 1014 1017 assertf( ! objStack.empty(), "empty object stack when setting designation" ); 1015 Designation * actualDesignation = 1018 Designation * actualDesignation = 1016 1019 new Designation{ designation->location, DesignatorChain{d} }; 1017 1020 objStack.back()->setPosition( d ); // destroys d -
src/ResolvExpr/PolyCost.cc
r67ca73e re67a82d 58 58 59 59 // TODO: When the old PolyCost is torn out get rid of the _new suffix. 60 struct PolyCost_new { 60 class PolyCost_new { 61 const ast::SymbolTable &symtab; 62 public: 61 63 int result; 62 const ast::SymbolTable &symtab;63 64 const ast::TypeEnvironment &env_; 64 65 65 PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :66 result( 0 ), symtab( symtab), env_( env ) {}66 PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 67 : symtab( symtab ), result( 0 ), env_( env ) {} 67 68 68 69 void previsit( const ast::TypeInstType * type ) { … … 86 87 ast::Pass<PolyCost_new> costing( symtab, env ); 87 88 type->accept( costing ); 88 return costing. pass.result;89 return costing.core.result; 89 90 } 90 91 -
src/ResolvExpr/PtrsAssignable.cc
r67ca73e re67a82d 155 155 ast::Pass<PtrsAssignable_new> visitor( dst, env ); 156 156 src->accept( visitor ); 157 return visitor. pass.result;157 return visitor.core.result; 158 158 } 159 159 -
src/ResolvExpr/PtrsCastable.cc
r67ca73e re67a82d 293 293 ast::Pass< PtrsCastable_new > ptrs{ dst, env, symtab }; 294 294 src->accept( ptrs ); 295 return ptrs. pass.result;295 return ptrs.core.result; 296 296 } 297 297 } -
src/ResolvExpr/RenameVars.cc
r67ca73e re67a82d 19 19 #include <utility> // for pair 20 20 21 #include "AST/ForallSubstitutionTable.hpp" 21 22 #include "AST/Pass.hpp" 22 23 #include "AST/Type.hpp" … … 30 31 #include "SynTree/Visitor.h" // for acceptAll, maybeAccept 31 32 33 #include "AST/Copy.hpp" 34 32 35 namespace ResolvExpr { 33 36 … … 37 40 int resetCount = 0; 38 41 ScopedMap< std::string, std::string > nameMap; 42 public: 43 ast::ForallSubstitutionTable subs; 39 44 40 public:41 45 void reset() { 42 46 level = 0; … … 44 48 } 45 49 46 using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;47 48 50 void rename( TypeInstType * type ) { 49 mapConstIteratorit = nameMap.find( type->name );51 auto it = nameMap.find( type->name ); 50 52 if ( it != nameMap.end() ) { 51 53 type->name = it->second; … … 65 67 // ditto for assertion names, the next level in 66 68 level++; 67 // acceptAll( td->assertions, *this ); 68 } // for 69 } // if 69 } 70 } 70 71 } 71 72 … … 77 78 78 79 const ast::TypeInstType * rename( const ast::TypeInstType * type ) { 79 mapConstIterator it = nameMap.find( type->name ); 80 // re-linking of base type handled by WithForallSubstitutor 81 82 // rename 83 auto it = nameMap.find( type->name ); 80 84 if ( it != nameMap.end() ) { 81 ast::TypeInstType * mutType = ast::mutate( type ); 82 mutType->name = it->second; 83 type = mutType; 85 // unconditionally mutate because map will *always* have different name, 86 // if this mutates, will *always* have been mutated by ForallSubstitutor above 87 ast::TypeInstType * mut = ast::mutate( type ); 88 mut->name = it->second; 89 type = mut; 84 90 } 91 85 92 return type; 86 93 } … … 88 95 template<typename NodeT> 89 96 const NodeT * openLevel( const NodeT * type ) { 90 if ( !type->forall.empty() ) { 91 nameMap.beginScope(); 92 // Load new names from this forall clause and perform renaming. 93 NodeT * mutType = ast::mutate( type ); 94 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) { 95 std::ostringstream output; 96 output << "_" << resetCount << "_" << level << "_" << td->name; 97 std::string newname( output.str() ); 98 nameMap[ td->name ] = newname; 99 ++level; 97 if ( type->forall.empty() ) return type; 100 98 101 ast::TypeDecl * decl = ast::mutate( td.get() ); 102 decl->name = newname; 103 td = decl; 104 } 99 nameMap.beginScope(); 100 101 // Load new names from this forall clause and perform renaming. 102 NodeT * mutType = ast::mutate( type ); 103 assert( type == mutType && "mutated type must be unique from ForallSubstitutor" ); 104 for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) { 105 std::ostringstream output; 106 output << "_" << resetCount << "_" << level << "_" << td->name; 107 std::string newname = output.str(); 108 nameMap[ td->name ] = newname; 109 ++level; 110 111 ast::TypeDecl * mutDecl = ast::mutate( td.get() ); 112 assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" ); 113 mutDecl->name = newname; 114 // assertion above means `td = mutDecl;` is unnecessary 105 115 } 116 // assertion above means `type = mutType;` is unnecessary 117 106 118 return type; 107 119 } 108 120 109 template<typename NodeT> 110 const NodeT * closeLevel( const NodeT * type ) { 111 if ( !type->forall.empty() ) { 112 nameMap.endScope(); 113 } 114 return type; 121 void closeLevel( const ast::ParameterizedType * type ) { 122 if ( type->forall.empty() ) return; 123 124 nameMap.endScope(); 115 125 } 116 126 }; … … 119 129 RenamingData renaming; 120 130 121 struct RenameVars {131 struct RenameVars_old { 122 132 void previsit( TypeInstType * instType ) { 123 133 renaming.openLevel( (Type*)instType ); … … 130 140 renaming.closeLevel( type ); 131 141 } 142 }; 143 144 struct RenameVars_new /*: public ast::WithForallSubstitutor*/ { 145 #warning when old RenameVars goes away, replace hack below with global pass inheriting from WithForallSubstitutor 146 ast::ForallSubstitutionTable & subs = renaming.subs; 132 147 133 148 const ast::FunctionType * previsit( const ast::FunctionType * type ) { … … 146 161 return renaming.rename( renaming.openLevel( type ) ); 147 162 } 148 const ast::ParameterizedType *postvisit( const ast::ParameterizedType * type ) {149 re turn renaming.closeLevel( type );163 void postvisit( const ast::ParameterizedType * type ) { 164 renaming.closeLevel( type ); 150 165 } 151 166 }; … … 154 169 155 170 void renameTyVars( Type * t ) { 156 PassVisitor<RenameVars > renamer;171 PassVisitor<RenameVars_old> renamer; 157 172 t->accept( renamer ); 158 173 } 159 174 160 175 const ast::Type * renameTyVars( const ast::Type * t ) { 161 ast::Pass<RenameVars> renamer; 162 return t->accept( renamer ); 176 ast::Type *tc = ast::deepCopy(t); 177 ast::Pass<RenameVars_new> renamer; 178 // return t->accept( renamer ); 179 return tc->accept( renamer ); 163 180 } 164 181 -
src/ResolvExpr/ResolveTypeof.cc
r67ca73e re67a82d 99 99 // replace basetypeof(<enum>) by int 100 100 if ( dynamic_cast<EnumInstType*>(newType) ) { 101 Type* newerType = 102 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 101 Type* newerType = 102 new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 103 103 newType->attributes }; 104 104 delete newType; 105 105 newType = newerType; 106 106 } 107 newType->get_qualifiers().val 107 newType->get_qualifiers().val 108 108 = ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals; 109 109 } else { 110 110 newType->get_qualifiers().val |= oldQuals; 111 111 } 112 112 113 113 return newType; 114 114 } … … 120 120 ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {} 121 121 122 void pre mutate( const ast::TypeofType * ) { visit_children = false; }122 void previsit( const ast::TypeofType * ) { visit_children = false; } 123 123 124 const ast::Type * post mutate( const ast::TypeofType * typeofType ) {124 const ast::Type * postvisit( const ast::TypeofType * typeofType ) { 125 125 // pass on null expression 126 126 if ( ! typeofType->expr ) return typeofType; … … 133 133 // typeof wrapping expression 134 134 ast::TypeEnvironment dummy; 135 ast::ptr< ast::Expr > newExpr = 135 ast::ptr< ast::Expr > newExpr = 136 136 resolveInVoidContext( typeofType->expr, localSymtab, dummy ); 137 137 assert( newExpr->result && ! newExpr->result->isVoid() ); … … 143 143 // replace basetypeof(<enum>) by int 144 144 if ( newType.as< ast::EnumInstType >() ) { 145 newType = new ast::BasicType{ 145 newType = new ast::BasicType{ 146 146 ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) }; 147 147 } 148 reset_qualifiers( 149 newType, 148 reset_qualifiers( 149 newType, 150 150 ( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers ); 151 151 } else { … … 153 153 } 154 154 155 return newType ;155 return newType.release(); 156 156 } 157 157 }; -
src/ResolvExpr/Resolver.cc
r67ca73e re67a82d 982 982 ast::Pass<DeleteFinder_new> finder; 983 983 expr->accept( finder ); 984 return finder. pass.delExpr;984 return finder.core.delExpr; 985 985 } 986 986 … … 1072 1072 /// Strips extraneous casts out of an expression 1073 1073 struct StripCasts_new final { 1074 const ast::Expr * post mutate( const ast::CastExpr * castExpr ) {1074 const ast::Expr * postvisit( const ast::CastExpr * castExpr ) { 1075 1075 if ( 1076 castExpr->isGenerated 1076 castExpr->isGenerated == ast::GeneratedCast 1077 1077 && typesCompatible( castExpr->arg->result, castExpr->result ) 1078 1078 ) { … … 1128 1128 1129 1129 // set up and resolve expression cast to void 1130 ast:: CastExpr *untyped = new ast::CastExpr{ expr };1130 ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr }; 1131 1131 CandidateRef choice = findUnfinishedKindExpression( 1132 1132 untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() ); … … 1236 1236 1237 1237 public: 1238 static size_t traceId; 1238 1239 Resolver_new() = default; 1239 1240 Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; } … … 1266 1267 const ast::ConstructorInit * previsit( const ast::ConstructorInit * ); 1267 1268 }; 1268 1269 void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit ) { 1270 ast::Pass< Resolver_new > resolver;1271 a ccept_all( translationUnit, resolver);1269 // size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver"); 1270 1271 void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) { 1272 ast::Pass< Resolver_new >::run( translationUnit ); 1272 1273 } 1273 1274 … … 1299 1300 // default value expressions have an environment which shouldn't be there and trips up 1300 1301 // later passes. 1301 as t::ptr< ast::FunctionDecl > ret = functionDecl;1302 for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {1303 const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i]; 1304 1305 if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {1302 assert( functionDecl->unique() ); 1303 ast::FunctionType * mutType = mutate( functionDecl->type.get() ); 1304 1305 for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) { 1306 if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) { 1306 1307 if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) { 1307 1308 if ( init->value->env == nullptr ) continue; 1308 1309 // clone initializer minus the initializer environment 1309 ast::chain_mutate( ret ) 1310 ( &ast::FunctionDecl::type ) 1311 ( &ast::FunctionType::params )[i] 1312 ( &ast::ObjectDecl::init ) 1313 ( &ast::SingleInit::value )->env = nullptr; 1314 1315 assert( functionDecl != ret.get() || functionDecl->unique() ); 1316 assert( ! ret->type->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env ); 1310 auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() ); 1311 auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() ); 1312 auto mutValue = mutate( mutInit->value.get() ); 1313 1314 mutValue->env = nullptr; 1315 mutInit->value = mutValue; 1316 mutParam->init = mutInit; 1317 mutType->params[i] = mutParam; 1318 1319 assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env); 1317 1320 } 1318 1321 } 1319 1322 } 1320 return ret.get(); 1323 mutate_field(functionDecl, &ast::FunctionDecl::type, mutType); 1324 return functionDecl; 1321 1325 } 1322 1326 … … 1341 1345 // in case we decide to allow nested enums 1342 1346 GuardValue( inEnumDecl ); 1343 inEnumDecl = false;1347 inEnumDecl = true; 1344 1348 } 1345 1349 -
src/ResolvExpr/SatisfyAssertions.cpp
r67ca73e re67a82d 9 9 // Author : Aaron B. Moss 10 10 // Created On : Mon Jun 10 17:45:00 2019 11 // Last Modified By : A aron B. Moss12 // Last Modified On : Mon Jun 10 17:45:00 201913 // Update Count : 111 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Oct 1 13:56:00 2019 13 // Update Count : 2 14 14 // 15 15 … … 188 188 189 189 matches.emplace_back( 190 cdata, adjType, std::move( newEnv ), std::move( newNeed ), std::move( have ),190 cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ), 191 191 std::move( newOpen ), crntResnSlot ); 192 192 } … … 229 229 InferMatcher( InferCache & inferred ) : inferred( inferred ) {} 230 230 231 const ast::Expr * post mutate( const ast::Expr * expr ) {231 const ast::Expr * postvisit( const ast::Expr * expr ) { 232 232 // Skip if no slots to find 233 if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr; 234 233 if ( !expr->inferred.hasSlots() ) return expr; 234 // if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr; 235 std::vector<UniqueId> missingSlots; 235 236 // find inferred parameters for resolution slots 236 ast::InferredParams newInferred;237 ast::InferredParams * newInferred = new ast::InferredParams(); 237 238 for ( UniqueId slot : expr->inferred.resnSlots() ) { 238 239 // fail if no matching assertions found 239 240 auto it = inferred.find( slot ); 240 241 if ( it == inferred.end() ) { 241 assert(!"missing assertion"); 242 std::cerr << "missing assertion " << slot << std::endl; 243 missingSlots.push_back(slot); 244 continue; 242 245 } 243 246 … … 245 248 for ( auto & entry : it->second ) { 246 249 // recurse on inferParams of resolved expressions 247 entry.second.expr = post mutate( entry.second.expr );248 auto res = newInferred .emplace( entry );250 entry.second.expr = postvisit( entry.second.expr ); 251 auto res = newInferred->emplace( entry ); 249 252 assert( res.second && "all assertions newly placed" ); 250 253 } … … 252 255 253 256 ast::Expr * ret = mutate( expr ); 254 ret->inferred.set_inferParams( std::move( newInferred ) ); 257 ret->inferred.set_inferParams( newInferred ); 258 if (!missingSlots.empty()) ret->inferred.resnSlots() = missingSlots; 255 259 return ret; 256 260 } … … 299 303 Cost cost; 300 304 301 OutType( 302 const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 305 OutType( 306 const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 303 307 const std::vector< DeferRef > & as, const ast::SymbolTable & symtab ) 304 308 : env( e ), open( o ), assns( as ), cost( Cost::zero ) { … … 306 310 for ( const DeferRef & assn : assns ) { 307 311 // compute conversion cost from satisfying decl to assertion 308 cost += computeConversionCost( 309 assn.match.adjType, assn.decl->get_type(), symtab, env );310 312 cost += computeConversionCost( 313 assn.match.adjType, assn.decl->get_type(), false, symtab, env ); 314 311 315 // mark vars+specialization on function-type assertions 312 const ast::FunctionType * func = 316 const ast::FunctionType * func = 313 317 GenPoly::getFunctionType( assn.match.cdata.id->get_type() ); 314 318 if ( ! func ) continue; … … 317 321 cost.decSpec( specCost( param->get_type() ) ); 318 322 } 319 323 320 324 cost.incVar( func->forall.size() ); 321 325 322 326 for ( const ast::TypeDecl * td : func->forall ) { 323 327 cost.decSpec( td->assertions.size() ); … … 329 333 }; 330 334 331 CandidateEnvMerger( 332 const ast::TypeEnvironment & env, const ast::OpenVarSet & open, 335 CandidateEnvMerger( 336 const ast::TypeEnvironment & env, const ast::OpenVarSet & open, 333 337 const ast::SymbolTable & syms ) 334 338 : crnt(), envs{ env }, opens{ open }, symtab( syms ) {} -
src/ResolvExpr/SatisfyAssertions.hpp
r67ca73e re67a82d 28 28 29 29 /// Recursively satisfies all assertions provided in a candidate; returns true if succeeds 30 void satisfyAssertions( 31 CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 30 void satisfyAssertions( 31 CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 32 32 std::vector<std::string> & errors ); 33 33 -
src/ResolvExpr/SpecCost.cc
r67ca73e re67a82d 10 10 // Created On : Tue Oct 02 15:50:00 2018 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Jun 19 10:43:00 2019 13 // Update Count : 2 14 // 15 12 // Last Modified On : Wed Jul 3 11:07:00 2019 13 // Update Count : 3 14 // 15 16 #include <cassert> 16 17 #include <limits> 17 18 #include <list> … … 129 130 typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type; 130 131 132 #warning Should use a standard maybe_accept 133 void maybe_accept( ast::Type const * type ) { 134 if ( type ) { 135 auto node = type->accept( *visitor ); 136 assert( node == nullptr || node == type ); 137 } 138 } 139 131 140 // Update the minimum to the new lowest non-none value. 132 141 template<typename T> … … 134 143 for ( const auto & node : list ) { 135 144 count = -1; 136 ma pper( node )->accept( *visitor);145 maybe_accept( mapper( node ) ); 137 146 if ( count != -1 && count < minimum ) minimum = count; 138 147 } … … 208 217 } 209 218 ast::Pass<SpecCounter> counter; 210 type->accept( *counter.pass.visitor );211 return counter. pass.get_count();219 type->accept( counter ); 220 return counter.core.get_count(); 212 221 } 213 222 -
src/ResolvExpr/Unify.cc
r67ca73e re67a82d 25 25 #include <vector> 26 26 27 #include "AST/Copy.hpp" 27 28 #include "AST/Decl.hpp" 28 29 #include "AST/Node.hpp" 29 30 #include "AST/Pass.hpp" 31 #include "AST/Print.hpp" 30 32 #include "AST/Type.hpp" 31 33 #include "AST/TypeEnvironment.hpp" … … 135 137 findOpenVars( newSecond, open, closed, need, have, FirstOpen ); 136 138 137 return unifyExact( 138 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 139 return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 139 140 } 140 141 … … 148 149 newFirst->get_qualifiers() = Type::Qualifiers(); 149 150 newSecond->get_qualifiers() = Type::Qualifiers(); 150 /// std::cerr << "first is "; 151 /// first->print( std::cerr ); 152 /// std::cerr << std::endl << "second is "; 153 /// second->print( std::cerr ); 154 /// std::cerr << std::endl << "newFirst is "; 155 /// newFirst->print( std::cerr ); 156 /// std::cerr << std::endl << "newSecond is "; 157 /// newSecond->print( std::cerr ); 158 /// std::cerr << std::endl; 151 159 152 bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer ); 160 153 delete newFirst; … … 170 163 ast::AssertionSet need, have; 171 164 172 ast::ptr<ast::Type> newFirst{ first }, newSecond{ second }; 173 env.apply( newFirst ); 174 env.apply( newSecond ); 175 reset_qualifiers( newFirst ); 176 reset_qualifiers( newSecond ); 165 ast::Type * newFirst = shallowCopy( first ); 166 ast::Type * newSecond = shallowCopy( second ); 167 newFirst ->qualifiers = {}; 168 newSecond->qualifiers = {}; 169 ast::ptr< ast::Type > t1_(newFirst ); 170 ast::ptr< ast::Type > t2_(newSecond); 171 172 ast::ptr< ast::Type > subFirst = env.apply(newFirst).node; 173 ast::ptr< ast::Type > subSecond = env.apply(newSecond).node; 177 174 178 175 return unifyExact( 179 newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab ); 176 subFirst, 177 subSecond, 178 newEnv, need, have, open, noWiden(), symtab ); 180 179 } 181 180 … … 326 325 327 326 void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) { 328 /// std::cerr << "assertion set is" << std::endl;329 /// printAssertionSet( assertions, std::cerr, 8 );330 /// std::cerr << "looking for ";331 /// assert->print( std::cerr );332 /// std::cerr << std::endl;333 327 AssertionSet::iterator i = assertions.find( assert ); 334 328 if ( i != assertions.end() ) { 335 /// std::cerr << "found it!" << std::endl;336 329 i->second.isUsed = true; 337 330 } // if … … 709 702 const ast::SymbolTable & symtab; 710 703 public: 704 static size_t traceId; 711 705 bool result; 712 706 … … 797 791 for ( const ast::DeclWithType * d : src ) { 798 792 ast::Pass<TtypeExpander_new> expander{ env }; 799 d = d->accept( expander ); 800 auto types = flatten( d->get_type() ); 793 // TtypeExpander pass is impure (may mutate nodes in place) 794 // need to make nodes shared to prevent accidental mutation 795 ast::ptr<ast::DeclWithType> dc = d; 796 dc = dc->accept( expander ); 797 auto types = flatten( dc->get_type() ); 801 798 for ( ast::ptr< ast::Type > & t : types ) { 802 799 // outermost const, volatile, _Atomic qualifiers in parameters should not play … … 807 804 // requirements than a non-mutex function 808 805 remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic ); 809 dst.emplace_back( new ast::ObjectDecl{ d ->location, "", t } );806 dst.emplace_back( new ast::ObjectDecl{ dc->location, "", t } ); 810 807 } 811 808 } … … 943 940 944 941 private: 945 template< typename RefType > 946 const RefType * handleRefType( const RefType * inst, const ast::Type * other ) { 942 // Returns: other, cast as XInstType 943 // Assigns this->result: whether types are compatible (up to generic parameters) 944 template< typename XInstType > 945 const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) { 947 946 // check that the other type is compatible and named the same 948 auto otherInst = dynamic_cast< const RefType * >( other );949 result = otherInst && inst->name == otherInst->name;947 auto otherInst = dynamic_cast< const XInstType * >( other ); 948 this->result = otherInst && inst->name == otherInst->name; 950 949 return otherInst; 951 950 } … … 968 967 } 969 968 970 template< typename RefType >971 void handleGenericRefType( const RefType * inst, const ast::Type * other ) {969 template< typename XInstType > 970 void handleGenericRefType( const XInstType * inst, const ast::Type * other ) { 972 971 // check that other type is compatible and named the same 973 const RefType * inst2= handleRefType( inst, other );974 if ( ! inst2) return;972 const XInstType * otherInst = handleRefType( inst, other ); 973 if ( ! this->result ) return; 975 974 976 975 // check that parameters of types unify, if any 977 976 const std::vector< ast::ptr< ast::Expr > > & params = inst->params; 978 const std::vector< ast::ptr< ast::Expr > > & params2 = inst2->params;977 const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params; 979 978 980 979 auto it = params.begin(); … … 1114 1113 1115 1114 ast::Pass<TtypeExpander_new> expander{ tenv }; 1116 const ast::Type * flat = tuple->accept( expander ); 1117 const ast::Type * flat2 = tuple2->accept( expander ); 1115 1116 ast::ptr<ast::TupleType> tuplec = tuple; 1117 ast::ptr<ast::TupleType> tuple2c = tuple2; 1118 const ast::Type * flat = tuplec->accept( expander ); 1119 const ast::Type * flat2 = tuple2c->accept( expander ); 1118 1120 1119 1121 auto types = flatten( flat ); … … 1140 1142 }; 1141 1143 1144 // size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new"); 1142 1145 bool unify( 1143 1146 const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2, … … 1188 1191 ast::Pass<Unify_new> comparator{ type2, env, need, have, open, widen, symtab }; 1189 1192 type1->accept( comparator ); 1190 return comparator. pass.result;1193 return comparator.core.result; 1191 1194 } 1192 1195 } … … 1202 1205 // force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and 1203 1206 // type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1 1204 ast::ptr<ast::Type> t1{ type1 }, t2{ type2 }; 1205 reset_qualifiers( t1 ); 1206 reset_qualifiers( t2 ); 1207 ast::Type * t1 = shallowCopy(type1.get()); 1208 ast::Type * t2 = shallowCopy(type2.get()); 1209 t1->qualifiers = {}; 1210 t2->qualifiers = {}; 1211 ast::ptr< ast::Type > t1_(t1); 1212 ast::ptr< ast::Type > t2_(t2); 1207 1213 1208 1214 if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) { 1209 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1210 1211 1215 // if exact unification on unqualified types, try to merge qualifiers 1212 1216 if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) { 1213 common = type1;1214 reset_qualifiers( common, q1 | q2 );1217 t1->qualifiers = q1 | q2; 1218 common = t1; 1215 1219 return true; 1216 1220 } else { … … 1219 1223 1220 1224 } else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) { 1221 t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones1222 1223 1225 // no exact unification, but common type 1224 reset_qualifiers( common, q1 | q2 ); 1226 auto c = shallowCopy(common.get()); 1227 c->qualifiers = q1 | q2; 1228 common = c; 1225 1229 return true; 1226 1230 } else { -
src/ResolvExpr/typeops.h
r67ca73e re67a82d 10 10 // Created On : Sun May 17 07:28:22 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hu Aug 8 16:36:00 201913 // Update Count : 512 // Last Modified On : Tue Oct 1 09:45:00 2019 13 // Update Count : 6 14 14 // 15 15 … … 83 83 const SymTab::Indexer & indexer, const TypeEnvironment & env ); 84 84 Cost castCost( 85 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,86 const ast:: TypeEnvironment & env );85 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 86 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 87 87 88 88 // in ConversionCost.cc … … 90 90 const SymTab::Indexer & indexer, const TypeEnvironment & env ); 91 91 Cost conversionCost( 92 const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,93 const ast:: TypeEnvironment & env );92 const ast::Type * src, const ast::Type * dst, bool srcIsLvalue, 93 const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ); 94 94 95 95 // in AlternativeFinder.cc -
src/SymTab/Autogen.h
r67ca73e re67a82d 21 21 22 22 #include "AST/Decl.hpp" 23 #include "AST/Eval.hpp" 23 24 #include "AST/Expr.hpp" 24 25 #include "AST/Init.hpp" … … 265 266 } 266 267 267 ast::ptr< ast::Expr > begin, end, cmp, update; 268 ast::ptr< ast::Expr > begin, end; 269 std::string cmp, update; 268 270 269 271 if ( forward ) { … … 271 273 begin = ast::ConstantExpr::from_int( loc, 0 ); 272 274 end = array->dimension; 273 cmp = new ast::NameExpr{ loc, "?<?" };274 update = new ast::NameExpr{ loc, "++?" };275 cmp = "?<?"; 276 update = "++?"; 275 277 } else { 276 278 // generate: for ( int i = N-1; i >= 0; --i ) 277 begin = new ast::UntypedExpr{ 278 loc, new ast::NameExpr{ loc, "?-?" }, 279 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } }; 279 begin = ast::call( 280 loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) ); 280 281 end = ast::ConstantExpr::from_int( loc, 0 ); 281 cmp = new ast::NameExpr{ loc, "?>=?" };282 update = new ast::NameExpr{ loc, "--?" };282 cmp = "?>=?"; 283 update = "--?"; 283 284 } 284 285 … … 286 287 loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 287 288 new ast::SingleInit{ loc, begin } }; 288 289 ast::ptr< ast::Expr > cond = new ast::UntypedExpr{ 290 loc, cmp, { new ast::VariableExpr{ loc, index }, end } }; 291 292 ast::ptr< ast::Expr > inc = new ast::UntypedExpr{ 293 loc, update, { new ast::VariableExpr{ loc, index } } }; 294 295 ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{ 296 loc, new ast::NameExpr{ loc, "?[?]" }, 297 { dstParam, new ast::VariableExpr{ loc, index } } }; 289 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index }; 290 291 ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end ); 292 293 ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar ); 294 295 ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar ); 298 296 299 297 // srcParam must keep track of the array indices to build the source parameter and/or 300 298 // array list initializer 301 srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );299 srcParam.addArrayIndex( indexVar, array->dimension ); 302 300 303 301 // for stmt's body, eventually containing call … … 385 383 if ( isUnnamedBitfield( obj ) ) return {}; 386 384 387 ast::ptr< ast::Type > addCast = nullptr;385 ast::ptr< ast::Type > addCast; 388 386 if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) { 389 387 assert( dstParam->result ); -
src/SymTab/FixFunction.cc
r67ca73e re67a82d 106 106 bool isVoid = false; 107 107 108 void pre mutate( const ast::FunctionDecl * ) { visit_children = false; }108 void previsit( const ast::FunctionDecl * ) { visit_children = false; } 109 109 110 const ast::DeclWithType * post mutate( const ast::FunctionDecl * func ) {110 const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) { 111 111 return new ast::ObjectDecl{ 112 112 func->location, func->name, new ast::PointerType{ func->type }, nullptr, … … 114 114 } 115 115 116 void pre mutate( const ast::ArrayType * ) { visit_children = false; }116 void previsit( const ast::ArrayType * ) { visit_children = false; } 117 117 118 const ast::Type * post mutate( const ast::ArrayType * array ) {118 const ast::Type * postvisit( const ast::ArrayType * array ) { 119 119 return new ast::PointerType{ 120 120 array->base, array->dimension, array->isVarLen, array->isStatic, … … 122 122 } 123 123 124 void pre mutate( const ast::VoidType * ) { isVoid = true; }124 void previsit( const ast::VoidType * ) { isVoid = true; } 125 125 126 void pre mutate( const ast::BasicType * ) { visit_children = false; }127 void pre mutate( const ast::PointerType * ) { visit_children = false; }128 void pre mutate( const ast::StructInstType * ) { visit_children = false; }129 void pre mutate( const ast::UnionInstType * ) { visit_children = false; }130 void pre mutate( const ast::EnumInstType * ) { visit_children = false; }131 void pre mutate( const ast::TraitInstType * ) { visit_children = false; }132 void pre mutate( const ast::TypeInstType * ) { visit_children = false; }133 void pre mutate( const ast::TupleType * ) { visit_children = false; }134 void pre mutate( const ast::VarArgsType * ) { visit_children = false; }135 void pre mutate( const ast::ZeroType * ) { visit_children = false; }136 void pre mutate( const ast::OneType * ) { visit_children = false; }126 void previsit( const ast::BasicType * ) { visit_children = false; } 127 void previsit( const ast::PointerType * ) { visit_children = false; } 128 void previsit( const ast::StructInstType * ) { visit_children = false; } 129 void previsit( const ast::UnionInstType * ) { visit_children = false; } 130 void previsit( const ast::EnumInstType * ) { visit_children = false; } 131 void previsit( const ast::TraitInstType * ) { visit_children = false; } 132 void previsit( const ast::TypeInstType * ) { visit_children = false; } 133 void previsit( const ast::TupleType * ) { visit_children = false; } 134 void previsit( const ast::VarArgsType * ) { visit_children = false; } 135 void previsit( const ast::ZeroType * ) { visit_children = false; } 136 void previsit( const ast::OneType * ) { visit_children = false; } 137 137 }; 138 138 } // anonymous namespace … … 141 141 ast::Pass< FixFunction_new > fixer; 142 142 dwt = dwt->accept( fixer ); 143 isVoid |= fixer. pass.isVoid;143 isVoid |= fixer.core.isVoid; 144 144 return dwt; 145 145 } -
src/SymTab/Mangler.cc
r67ca73e re67a82d 447 447 ast::Pass<Mangler_new> mangler( mode ); 448 448 maybeAccept( decl, mangler ); 449 return mangler. pass.get_mangleName();449 return mangler.core.get_mangleName(); 450 450 } 451 451 … … 691 691 mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ); 692 692 assert->accept( sub_mangler ); 693 assertionNames.push_back( sub_mangler. pass.get_mangleName() );693 assertionNames.push_back( sub_mangler.core.get_mangleName() ); 694 694 acount++; 695 695 } // for -
src/SynTree/ApplicationExpr.cc
r67ca73e re67a82d 34 34 35 35 ParamEntry::ParamEntry( const ParamEntry &other ) : 36 decl( other.decl ), declptr( maybeClone( other.declptr )), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {36 decl( other.decl ), declptr( other.declptr ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) { 37 37 } 38 38 39 39 ParamEntry::~ParamEntry() { 40 delete declptr;40 // delete declptr; 41 41 delete actualType; 42 42 delete formalType; -
src/SynTree/Expression.cc
r67ca73e re67a82d 69 69 void Expression::print( std::ostream & os, Indenter indent ) const { 70 70 printInferParams( inferParams, os, indent+1, 0 ); 71 72 if ( result ) { 73 os << std::endl << indent << "with resolved type:" << std::endl; 74 os << (indent+1); 75 result->print( os, indent+1 ); 76 } 71 77 72 78 if ( env ) { -
src/SynTree/Statement.h
r67ca73e re67a82d 518 518 class ImplicitCtorDtorStmt : public Statement { 519 519 public: 520 // Non-owned pointer to the constructor/destructor statement520 // the constructor/destructor call statement; owned here for a while, eventually transferred elsewhere 521 521 Statement * callStmt; 522 522 -
src/Tuples/Explode.cc
r67ca73e re67a82d 129 129 for ( const ast::Expr * expr : tupleExpr->exprs ) { 130 130 exprs.emplace_back( applyCast( expr, false ) ); 131 //exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );132 131 } 133 132 if ( first ) { … … 148 147 } 149 148 150 const ast::Expr * post mutate( const ast::UniqueExpr * node ) {149 const ast::Expr * postvisit( const ast::UniqueExpr * node ) { 151 150 // move cast into unique expr so that the unique expr has type T& rather than 152 151 // type T. In particular, this transformation helps with generating the … … 162 161 castAdded = false; 163 162 const ast::Type * newType = getReferenceBase( newNode->result ); 164 return new ast::CastExpr{ newNode->location, n ode, newType };163 return new ast::CastExpr{ newNode->location, newNode, newType }; 165 164 } 166 165 return newNode; 167 166 } 168 167 169 const ast::Expr * post mutate( const ast::TupleIndexExpr * tupleExpr ) {168 const ast::Expr * postvisit( const ast::TupleIndexExpr * tupleExpr ) { 170 169 // tuple index expr needs to be rebuilt to ensure that the type of the 171 170 // field is consistent with the type of the tuple expr, since the field … … 180 179 ast::Pass<CastExploderCore> exploder; 181 180 expr = expr->accept( exploder ); 182 if ( ! exploder. pass.foundUniqueExpr ) {181 if ( ! exploder.core.foundUniqueExpr ) { 183 182 expr = new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } }; 184 183 } -
src/Tuples/Explode.h
r67ca73e re67a82d 210 210 } 211 211 // Cast a reference away to a value-type to allow further explosion. 212 if ( dynamic_cast< const ast::ReferenceType *>( local->result.get()) ) {212 if ( local->result.as< ast::ReferenceType >() ) { 213 213 local = new ast::CastExpr{ local, tupleType }; 214 214 } … … 220 220 // delete idx; 221 221 } 222 // delete local;223 222 } 224 223 } else { -
src/Tuples/TupleAssignment.cc
r67ca73e re67a82d 465 465 // resolve ctor/dtor for the new object 466 466 ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit( 467 InitTweak::genCtorInit( location, ret ), spotter.crntFinder. symtab);467 InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms ); 468 468 // remove environments from subexpressions of stmtExpr 469 469 ast::Pass< EnvRemover > rm{ env }; … … 504 504 505 505 std::vector< ast::ptr< ast::Expr > > match() override { 506 static UniqueName lhsNamer( "__massassign_L" ); 507 static UniqueName rhsNamer( "__massassign_R" ); 506 // temporary workaround for new and old ast to coexist and avoid name collision 507 static UniqueName lhsNamer( "__massassign_Ln" ); 508 static UniqueName rhsNamer( "__massassign_Rn" ); 508 509 // empty tuple case falls into this matcher 509 510 assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 ); … … 534 535 535 536 std::vector< ast::ptr< ast::Expr > > match() override { 536 static UniqueName lhsNamer( "__multassign_L" ); 537 static UniqueName rhsNamer( "__multassign_R" ); 537 // temporary workaround for new and old ast to coexist and avoid name collision 538 static UniqueName lhsNamer( "__multassign_Ln" ); 539 static UniqueName rhsNamer( "__multassign_Rn" ); 538 540 539 541 if ( lhs.size() != rhs.size() ) return {}; … … 560 562 // resolve the cast expression so that rhsCand return type is bound by the cast 561 563 // type as needed, and transfer the resulting environment 562 ResolvExpr::CandidateFinder finder{ spotter.crntFinder. symtab, env };564 ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env }; 563 565 finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() ); 564 566 assert( finder.candidates.size() == 1 ); … … 609 611 // explode the LHS so that each field of a tuple-valued expr is assigned 610 612 ResolvExpr::CandidateList lhs; 611 explode( *lhsCand, crntFinder. symtab, back_inserter(lhs), true );613 explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true ); 612 614 for ( ResolvExpr::CandidateRef & cand : lhs ) { 613 615 // each LHS value must be a reference - some come in with a cast, if not … … 629 631 if ( isTuple( rhsCand->expr ) ) { 630 632 // multiple assignment 631 explode( *rhsCand, crntFinder. symtab, back_inserter(rhs), true );633 explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true ); 632 634 matcher.reset( 633 635 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); … … 648 650 // multiple assignment 649 651 ResolvExpr::CandidateList rhs; 650 explode( rhsCand, crntFinder. symtab, back_inserter(rhs), true );652 explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true ); 651 653 matcher.reset( 652 654 new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } ); … … 678 680 ) 679 681 680 ResolvExpr::CandidateFinder finder{ crntFinder. symtab, matcher->env };682 ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env }; 681 683 682 684 try { -
src/Tuples/TupleExpansion.cc
r67ca73e re67a82d 323 323 std::vector<ast::ptr<ast::Type>> types; 324 324 ast::CV::Qualifiers quals{ 325 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |325 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | 326 326 ast::CV::Atomic | ast::CV::Mutex }; 327 327 -
src/Tuples/Tuples.cc
r67ca73e re67a82d 43 43 }; 44 44 struct ImpurityDetectorIgnoreUnique : public ImpurityDetector { 45 using ImpurityDetector::previsit; 45 46 void previsit( ast::UniqueExpr const * ) { 46 47 visit_children = false; … … 52 53 ast::Pass<Detector> detector; 53 54 expr->accept( detector ); 54 return detector. pass.maybeImpure;55 return detector.core.maybeImpure; 55 56 } 56 57 } // namespace -
src/config.h.in
r67ca73e re67a82d 27 27 /* Location of cfa install. */ 28 28 #undef CFA_PREFIX 29 30 /* Sets whether or not to use the new-ast, this is adefault value and can be 31 overrided by --old-ast and --new-ast */ 32 #undef CFA_USE_NEW_AST 29 33 30 34 /* Major.Minor */ -
src/main.cc
r67ca73e re67a82d 31 31 using namespace std; 32 32 33 33 #include "AST/Convert.hpp" 34 34 #include "CompilationState.h" 35 35 #include "../config.h" // for CFA_LIBDIR … … 340 340 } // if 341 341 342 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); 342 if( useNewAST) { 343 auto transUnit = convert( move( translationUnit ) ); 344 PASS( "Resolve", ResolvExpr::resolve( transUnit ) ); 345 translationUnit = convert( move( transUnit ) ); 346 } else { 347 PASS( "Resolve", ResolvExpr::resolve( translationUnit ) ); 348 } 349 343 350 if ( exprp ) { 344 351 dump( translationUnit ); … … 458 465 { "prototypes", no_argument, nullptr, 'p' }, 459 466 { "deterministic-out", no_argument, nullptr, 'd' }, 467 { "old-ast", no_argument, nullptr, 'O'}, 468 { "new-ast", no_argument, nullptr, 'A'}, 460 469 { "print", required_argument, nullptr, 'P' }, 461 470 { "prelude-dir", required_argument, nullptr, PreludeDir }, … … 479 488 "generate prototypes for prelude functions", // -p 480 489 "don't print output that isn't deterministic", // -d 490 "Use the old-ast", // -O 491 "Use the new-ast", // -A 481 492 "print", // -P 482 493 "<directory> prelude directory for debug/nodebug", // no flag … … 584 595 break; 585 596 case 'd': // don't print non-deterministic output 586 deterministic_output = true; 597 deterministic_output = true; 598 break; 599 case 'O': // don't print non-deterministic output 600 useNewAST = false; 601 break; 602 case 'A': // don't print non-deterministic output 603 useNewAST = true; 587 604 break; 588 605 case 'P': // print options -
tests/.expect/alloc-ERROR.txt
r67ca73e re67a82d 16 16 Name: stp 17 17 18 with resolved type: 19 unsigned long int 18 20 19 21 … … 28 30 Name: stp 29 31 constant expression (10 10: signed int) 32 with resolved type: 33 signed int 30 34 31 35 -
tests/.expect/castError.txt
r67ca73e re67a82d 3 3 Name: f 4 4 ... to: 5 char 6 with resolved type: 5 7 char Alternatives are: 6 8 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of: … … 9 11 ... returning nothing 10 12 13 with resolved type: 14 pointer to function 15 accepting unspecified arguments 16 ... returning nothing 17 11 18 ... to: 19 char 20 with resolved type: 12 21 char 13 22 (types: … … 18 27 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of: 19 28 Variable Expression: f: double 29 with resolved type: 30 double 20 31 ... to: 32 char 33 with resolved type: 21 34 char 22 35 (types: … … 27 40 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of: 28 41 Variable Expression: f: signed int 42 with resolved type: 43 signed int 29 44 ... to: 45 char 46 with resolved type: 30 47 char 31 48 (types: … … 39 56 Comma Expression: 40 57 constant expression (3 3: signed int) 58 with resolved type: 59 signed int 41 60 Name: v 42 ... to: nothing Alternatives are: 61 ... to: nothing 62 with resolved type: 63 void Alternatives are: 43 64 Cost ( 0, 0, 2, 0, 0, 0, 0 ): Generated Cast of: 44 65 Comma Expression: 45 66 constant expression (3 3: signed int) 67 with resolved type: 68 signed int 46 69 Variable Expression: v: unsigned char 70 with resolved type: 71 unsigned char 72 with resolved type: 73 unsigned char 47 74 ... to: nothing 75 with resolved type: 76 void 48 77 (types: 49 78 void … … 54 83 Comma Expression: 55 84 constant expression (3 3: signed int) 85 with resolved type: 86 signed int 56 87 Variable Expression: v: signed short int 88 with resolved type: 89 signed short int 90 with resolved type: 91 signed short int 57 92 ... to: nothing 93 with resolved type: 94 void 58 95 (types: 59 96 void … … 69 106 char 70 107 108 with resolved type: 109 instance of struct S with body 1 110 ... with parameters 111 char 112 -
tests/.expect/declarationSpecifier.x64.txt
r67ca73e re67a82d 1129 1129 static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); } 1130 1130 static inline signed int invoke_main(signed int argc, char **argv, char **envp); 1131 signed int _X13cfa_args_argci_1; 1132 char **_X13cfa_args_argvPPc_1; 1133 char **_X13cfa_args_envpPPc_1; 1131 1134 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){ 1132 1135 __attribute__ ((unused)) signed int _X12_retval_maini_1; 1133 1136 { 1137 ((void)(_X13cfa_args_argci_1=_X4argci_1)); 1138 } 1139 1140 { 1141 ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1)); 1142 } 1143 1144 { 1145 ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1)); 1146 } 1147 1148 { 1134 1149 signed int _tmp_cp_ret4; 1135 1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); -
tests/.expect/declarationSpecifier.x86.txt
r67ca73e re67a82d 1129 1129 static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); } 1130 1130 static inline signed int invoke_main(signed int argc, char **argv, char **envp); 1131 signed int _X13cfa_args_argci_1; 1132 char **_X13cfa_args_argvPPc_1; 1133 char **_X13cfa_args_envpPPc_1; 1131 1134 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){ 1132 1135 __attribute__ ((unused)) signed int _X12_retval_maini_1; 1133 1136 { 1137 ((void)(_X13cfa_args_argci_1=_X4argci_1)); 1138 } 1139 1140 { 1141 ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1)); 1142 } 1143 1144 { 1145 ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1)); 1146 } 1147 1148 { 1134 1149 signed int _tmp_cp_ret4; 1135 1150 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); -
tests/.expect/gccExtensions.x64.txt
r67ca73e re67a82d 321 321 static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); } 322 322 static inline signed int invoke_main(signed int argc, char **argv, char **envp); 323 signed int _X13cfa_args_argci_1; 324 char **_X13cfa_args_argvPPc_1; 325 char **_X13cfa_args_envpPPc_1; 323 326 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){ 324 327 __attribute__ ((unused)) signed int _X12_retval_maini_1; 325 328 { 329 ((void)(_X13cfa_args_argci_1=_X4argci_1)); 330 } 331 332 { 333 ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1)); 334 } 335 336 { 337 ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1)); 338 } 339 340 { 326 341 signed int _tmp_cp_ret4; 327 342 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); -
tests/.expect/gccExtensions.x86.txt
r67ca73e re67a82d 299 299 static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); } 300 300 static inline signed int invoke_main(signed int argc, char **argv, char **envp); 301 signed int _X13cfa_args_argci_1; 302 char **_X13cfa_args_argvPPc_1; 303 char **_X13cfa_args_envpPPc_1; 301 304 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){ 302 305 __attribute__ ((unused)) signed int _X12_retval_maini_1; 303 306 { 307 ((void)(_X13cfa_args_argci_1=_X4argci_1)); 308 } 309 310 { 311 ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1)); 312 } 313 314 { 315 ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1)); 316 } 317 318 { 304 319 signed int _tmp_cp_ret4; 305 320 ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */); -
tests/.expect/init1.txt
r67ca73e re67a82d 11 11 ... to: 12 12 reference to signed int 13 with resolved type: 14 reference to signed int 13 15 init1.cfa:97:1 error: No reasonable alternatives for expression Applying untyped: 14 16 Name: ?{} … … 16 18 Generated Cast of: 17 19 Variable Expression: _retval_f_py: pointer to signed int 20 with resolved type: 21 pointer to signed int 18 22 ... to: 23 reference to pointer to signed int 24 with resolved type: 19 25 reference to pointer to signed int 20 26 Name: px … … 24 30 ... to: 25 31 reference to float 32 with resolved type: 33 reference to float 26 34 init1.cfa:107:1 error: No reasonable alternatives for expression Applying untyped: 27 35 Name: ?{} … … 29 37 Generated Cast of: 30 38 Variable Expression: _retval_f_py2: pointer to float 39 with resolved type: 40 pointer to float 31 41 ... to: 42 reference to pointer to float 43 with resolved type: 32 44 reference to pointer to float 33 45 Name: cpx … … 37 49 ... to: 38 50 reference to instance of type T (not function type) 51 with resolved type: 52 reference to instance of type T (not function type) 39 53 init1.cfa:118:1 error: No reasonable alternatives for expression Applying untyped: 40 54 Name: ?{} … … 42 56 Generated Cast of: 43 57 Variable Expression: _retval_anycvt: pointer to instance of type T (not function type) 58 with resolved type: 59 pointer to instance of type T (not function type) 44 60 ... to: 61 reference to pointer to instance of type T (not function type) 62 with resolved type: 45 63 reference to pointer to instance of type T (not function type) 46 64 Name: s -
tests/.expect/minmax.txt
r67ca73e re67a82d 1 1 char z a min a 2 signed int 4 3 min32 signed int 4 -3 min -3 3 3 unsigned int 4 3 min 3 4 signed long int 4 3 min34 signed long int 4 -3 min -3 5 5 unsigned long int 4 3 min 3 6 signed long long int 4 3 min36 signed long long int 4 -3 min -3 7 7 unsigned long long int 4 3 min 3 8 8 float 4. 3.1 min 3.1 … … 11 11 12 12 char z a max z 13 signed int 4 3 max 413 signed int 4 -3 max 4 14 14 unsigned int 4 3 max 4 15 signed long int 4 3 max 415 signed long int 4 -3 max 4 16 16 unsigned long int 4 3 max 4 17 signed long long int 4 3 max 417 signed long long int 4 -3 max 4 18 18 unsigned long long int 4 3 max 4 19 19 float 4. 3.1 max 4. -
tests/Makefile.am
r67ca73e re67a82d 163 163 $(CFACOMPILETEST) -DERR2 -c -fsyntax-only -o $(abspath ${@}) 164 164 165 # Exception Tests 166 # Test with libcfathread; it changes how storage works. 167 168 exceptions/%-threads : exceptions/%.cfa $(CFACCBIN) 169 $(CFACOMPILETEST) -include exceptions/with-threads.hfa -c -o $(abspath ${@}).o 170 $(CFACCLOCAL) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g')) $(abspath ${@}).o -o $(abspath ${@}) 171 165 172 #------------------------------------------------------------------------------ 166 173 # Other targets -
tests/alloc.cfa
r67ca73e re67a82d 10 10 // Created On : Wed Feb 3 07:56:22 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 6 21:08:23202013 // Update Count : 4 2812 // Last Modified On : Fri Aug 14 16:59:59 2020 13 // Update Count : 430 14 14 // 15 15 … … 90 90 // do not free 91 91 92 ip1 = alloc_set( 2 * dim, ip );// CFA array alloc, fill92 ip1 = alloc_set( 2 * dim, ip, 2 * dim ); // CFA array alloc, fill 93 93 printf( "CFA array alloc, fill from array\n" ); 94 94 for ( i; 2 * dim ) { printf( "%#x %#x, ", ip[i], ip1[i] ); } … … 288 288 // do not free 289 289 290 stp1 = alloc_align_set( Alignment, dim, stp );// CFA array memalign, fill290 stp1 = alloc_align_set( Alignment, dim, stp, dim ); // CFA array memalign, fill 291 291 assert( (uintptr_t)stp % Alignment == 0 ); 292 292 printf( "CFA array alloc_align, fill array\n" ); -
tests/errors/.expect/completeType.x64.txt
r67ca73e re67a82d 6 6 Name: x 7 7 8 ... to: nothing Alternatives are: 8 ... to: nothing 9 with resolved type: 10 void Alternatives are: 9 11 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of: 10 12 Application of … … 20 22 21 23 24 with resolved type: 25 pointer to forall 26 _90_4_DT: data type 27 function 28 ... with parameters 29 intrinsic pointer to instance of type _90_4_DT (not function type) 30 ... returning 31 _retval__operator_deref: reference to instance of type _90_4_DT (not function type) 32 ... with attributes: 33 Attribute with name: unused 34 35 22 36 ... to arguments 23 37 Variable Expression: x: pointer to instance of struct A with body 0 24 38 with resolved type: 39 pointer to instance of struct A with body 0 40 41 with resolved type: 42 reference to instance of struct A with body 0 25 43 ... to: nothing 44 with resolved type: 45 void 26 46 (types: 27 47 void … … 43 63 44 64 65 with resolved type: 66 pointer to forall 67 _90_4_DT: data type 68 function 69 ... with parameters 70 intrinsic pointer to instance of type _90_4_DT (not function type) 71 ... returning 72 _retval__operator_deref: reference to instance of type _90_4_DT (not function type) 73 ... with attributes: 74 Attribute with name: unused 75 76 45 77 ... to arguments 46 78 Variable Expression: x: pointer to instance of struct B with body 1 47 79 with resolved type: 80 pointer to instance of struct B with body 1 81 82 with resolved type: 83 reference to instance of struct B with body 1 48 84 ... to: nothing 85 with resolved type: 86 void 49 87 (types: 50 88 void … … 121 159 ... returning nothing 122 160 161 with resolved type: 162 pointer to forall 163 _109_0_T: sized data type 164 ... with assertions 165 ?=?: pointer to function 166 ... with parameters 167 reference to instance of type _109_0_T (not function type) 168 instance of type _109_0_T (not function type) 169 ... returning 170 _retval__operator_assign: instance of type _109_0_T (not function type) 171 ... with attributes: 172 Attribute with name: unused 173 174 175 ?{}: pointer to function 176 ... with parameters 177 reference to instance of type _109_0_T (not function type) 178 ... returning nothing 179 180 ?{}: pointer to function 181 ... with parameters 182 reference to instance of type _109_0_T (not function type) 183 instance of type _109_0_T (not function type) 184 ... returning nothing 185 186 ^?{}: pointer to function 187 ... with parameters 188 reference to instance of type _109_0_T (not function type) 189 ... returning nothing 190 191 192 function 193 ... with parameters 194 pointer to instance of type _109_0_T (not function type) 195 ... returning nothing 196 123 197 ... to arguments 124 198 Variable Expression: z: pointer to instance of type T (not function type) 125 199 with resolved type: 200 pointer to instance of type T (not function type) 201 202 with resolved type: 203 void 126 204 (types: 127 205 void -
tests/errors/.expect/completeType.x86.txt
r67ca73e re67a82d 6 6 Name: x 7 7 8 ... to: nothing Alternatives are: 8 ... to: nothing 9 with resolved type: 10 void Alternatives are: 9 11 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of: 10 12 Application of … … 20 22 21 23 24 with resolved type: 25 pointer to forall 26 _89_4_DT: data type 27 function 28 ... with parameters 29 intrinsic pointer to instance of type _89_4_DT (not function type) 30 ... returning 31 _retval__operator_deref: reference to instance of type _89_4_DT (not function type) 32 ... with attributes: 33 Attribute with name: unused 34 35 22 36 ... to arguments 23 37 Variable Expression: x: pointer to instance of struct A with body 0 24 38 with resolved type: 39 pointer to instance of struct A with body 0 40 41 with resolved type: 42 reference to instance of struct A with body 0 25 43 ... to: nothing 44 with resolved type: 45 void 26 46 (types: 27 47 void … … 43 63 44 64 65 with resolved type: 66 pointer to forall 67 _89_4_DT: data type 68 function 69 ... with parameters 70 intrinsic pointer to instance of type _89_4_DT (not function type) 71 ... returning 72 _retval__operator_deref: reference to instance of type _89_4_DT (not function type) 73 ... with attributes: 74 Attribute with name: unused 75 76 45 77 ... to arguments 46 78 Variable Expression: x: pointer to instance of struct B with body 1 47 79 with resolved type: 80 pointer to instance of struct B with body 1 81 82 with resolved type: 83 reference to instance of struct B with body 1 48 84 ... to: nothing 85 with resolved type: 86 void 49 87 (types: 50 88 void … … 121 159 ... returning nothing 122 160 161 with resolved type: 162 pointer to forall 163 _108_0_T: sized data type 164 ... with assertions 165 ?=?: pointer to function 166 ... with parameters 167 reference to instance of type _108_0_T (not function type) 168 instance of type _108_0_T (not function type) 169 ... returning 170 _retval__operator_assign: instance of type _108_0_T (not function type) 171 ... with attributes: 172 Attribute with name: unused 173 174 175 ?{}: pointer to function 176 ... with parameters 177 reference to instance of type _108_0_T (not function type) 178 ... returning nothing 179 180 ?{}: pointer to function 181 ... with parameters 182 reference to instance of type _108_0_T (not function type) 183 instance of type _108_0_T (not function type) 184 ... returning nothing 185 186 ^?{}: pointer to function 187 ... with parameters 188 reference to instance of type _108_0_T (not function type) 189 ... returning nothing 190 191 192 function 193 ... with parameters 194 pointer to instance of type _108_0_T (not function type) 195 ... returning nothing 196 123 197 ... to arguments 124 198 Variable Expression: z: pointer to instance of type T (not function type) 125 199 with resolved type: 200 pointer to instance of type T (not function type) 201 202 with resolved type: 203 void 126 204 (types: 127 205 void -
tests/exceptions/terminate.cfa
r67ca73e re67a82d 142 142 } 143 143 } 144 -
tests/heap.cfa
r67ca73e re67a82d 10 10 // Created On : Tue Nov 6 17:54:56 2018 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Aug 4 06:36:17202013 // Update Count : 5 612 // Last Modified On : Sun Aug 9 08:05:16 2020 13 // Update Count : 57 14 14 // 15 15 … … 232 232 size_t s = i + default_mmap_start(); // cross over point 233 233 char * area = (char *)calloc( 1, s ); 234 // if ( area == 0p ) abort( "calloc/realloc/free out of memory" );235 234 if ( area[0] != '\0' || area[s - 1] != '\0' || 236 235 area[malloc_size( area ) - 1] != '\0' || 237 ! malloc_zero_fill( area ) ) //abort( "calloc/realloc/free corrupt storage3" ); 238 printf( "C %zd %d %d %d %d\n", s, area[0] != '\0', area[s - 1] != '\0', area[malloc_size( area ) - 1] != '\0', ! malloc_zero_fill( area ) ); 236 ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage3" ); 239 237 240 238 // Do not start this loop index at 0 because realloc of 0 bytes frees the storage. 241 239 for ( r; i ~ 256 * 1024 ~ 26 ) { // start at initial memory request 242 240 area = (char *)realloc( area, r ); // attempt to reuse storage 243 // if ( area == 0p ) abort( "calloc/realloc/free out of memory" );244 241 if ( area[0] != '\0' || area[r - 1] != '\0' || 245 242 area[malloc_size( area ) - 1] != '\0' || … … 255 252 // initial N byte allocation 256 253 char * area = (char *)memalign( a, amount ); // aligned N-byte allocation 257 // if ( area == 0p ) abort( "memalign/realloc/free out of memory" ); // no storage ?258 254 //sout | alignments[a] | area; 259 255 if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment -
tests/linking/withthreads.cfa
r67ca73e re67a82d 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // nothreads.cfa --7 // withthreads.cfa -- 8 8 // 9 9 // Author : Thierry Delisle -
tests/literals.cfa
r67ca73e re67a82d 10 10 // Created On : Sat Sep 9 16:34:38 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Feb 12 08:07:39 201913 // Update Count : 22 412 // Last Modified On : Thu Aug 20 13:51:12 2020 13 // Update Count : 225 14 14 // 15 15 … … 214 214 -01234567_l8; -01234567_l16; -01234567_l32; -01234567_l64; -01234567_l8u; -01234567_ul16; -01234567_l32u; -01234567_ul64; 215 215 216 #if def __LP64__ // 64-bit processor216 #if defined( __SIZEOF_INT128__ ) 217 217 01234567_l128; 01234567_ul128; 218 218 +01234567_l128; +01234567_ul128; 219 219 -01234567_l128; -01234567_ul128; 220 #endif // __ LP64__220 #endif // __SIZEOF_INT128__ 221 221 222 222 // decimal … … 225 225 -1234567890L8; -1234567890L16; -1234567890l32; -1234567890l64; -1234567890UL8; -1234567890L16U; -1234567890Ul32; -1234567890l64u; 226 226 227 #if def __LP64__ // 64-bit processor227 #if defined( __SIZEOF_INT128__ ) 228 228 1234567890l128; 1234567890l128u; 229 229 +1234567890l128; +1234567890l128u; 230 230 -1234567890l128; -1234567890l128u; 231 #endif // __LP64__ 231 1234567890123456789_L128u; 1234567890123456789_L128u; 232 18446708753438544741_l64u; 18446708753438544741_Ul64; 233 #endif // __SIZEOF_INT128__ 232 234 233 235 // hexadecimal -
tests/minmax.cfa
r67ca73e re67a82d 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Dec 4 21:45:31 201813 // Update Count : 5 212 // Last Modified On : Sat Aug 15 08:28:01 2020 13 // Update Count : 54 14 14 // 15 15 … … 23 23 24 24 sout | "char\t\t\t" | 'z' | ' ' | 'a' | "\tmin " | min( 'z', 'a' ); 25 sout | "signed int\t\t" | 4 | 3 | "\tmin" | min( 4,3 );25 sout | "signed int\t\t" | 4 | -3 | "\tmin" | min( 4, -3 ); 26 26 sout | "unsigned int\t\t" | 4u | 3u | "\tmin" | min( 4u, 3u ); 27 sout | "signed long int\t\t" | 4l | 3l | "\tmin" | min( 4l,3l );27 sout | "signed long int\t\t" | 4l | -3l | "\tmin" | min( 4l, -3l ); 28 28 sout | "unsigned long int\t" | 4ul | 3ul | "\tmin" | min( 4ul, 3ul ); 29 sout | "signed long long int\t" | 4ll | 3ll | "\tmin" | min( 4ll,3ll );29 sout | "signed long long int\t" | 4ll | -3ll | "\tmin" | min( 4ll, -3ll ); 30 30 sout | "unsigned long long int\t" | 4ull | 3ull | "\tmin" | min( 4ull, 3ull ); 31 31 sout | "float\t\t\t" | 4.0f | 3.1f | "\tmin" | min( 4.0f, 3.1f ); … … 36 36 37 37 sout | "char\t\t\t" | 'z' | ' ' | 'a' | "\tmax " | max( 'z', 'a' ); 38 sout | "signed int\t\t" | 4 | 3 | "\tmax" | max( 4,3 );38 sout | "signed int\t\t" | 4 | -3 | "\tmax" | max( 4, -3 ); 39 39 sout | "unsigned int\t\t" | 4u | 3u | "\tmax" | max( 4u, 3u ); 40 sout | "signed long int\t\t" | 4l | 3l | "\tmax" | max( 4l,3l );40 sout | "signed long int\t\t" | 4l | -3l | "\tmax" | max( 4l, -3l ); 41 41 sout | "unsigned long int\t" | 4ul | 3ul | "\tmax" | max( 4ul, 3ul ); 42 sout | "signed long long int\t" | 4ll | 3ll | "\tmax" | max( 4ll,3ll );42 sout | "signed long long int\t" | 4ll | -3ll | "\tmax" | max( 4ll, -3ll ); 43 43 sout | "unsigned long long int\t" | 4ull | 3ull | "\tmax" | max( 4ull, 3ull ); 44 44 sout | "float\t\t\t" | 4.0f | 3.1f | "\tmax" | max( 4.0f, 3.1f ); -
tests/pybin/tools.py
r67ca73e re67a82d 246 246 # transform path to canonical form 247 247 def canonical_path(path): 248 abspath = os.path.abspath( __main__.__file__)248 abspath = os.path.abspath(os.path.realpath(__main__.__file__)) 249 249 dname = os.path.dirname(abspath) 250 250 return os.path.join(dname, os.path.normpath(path) ) -
tests/raii/.expect/ctor-autogen-ERR1.txt
r67ca73e re67a82d 7 7 x: signed int 8 8 ... returning nothing 9 10 with resolved type: 11 function 12 ... with parameters 13 _dst: reference to instance of struct Managed with body 1 14 x: signed int 15 ... returning nothing 9 16 10 17 ... deleted by: ?{}: function … … 26 33 27 34 35 with resolved type: 36 pointer to function 37 ... with parameters 38 intrinsic reference to signed int 39 intrinsic signed int 40 ... returning 41 _retval__operator_assign: signed int 42 ... with attributes: 43 Attribute with name: unused 44 45 28 46 ... to arguments 29 47 Generated Cast of: … … 33 51 Generated Cast of: 34 52 Variable Expression: m: reference to instance of struct Managed with body 1 53 with resolved type: 54 reference to instance of struct Managed with body 1 35 55 ... to: 36 56 instance of struct Managed with body 1 57 with resolved type: 58 instance of struct Managed with body 1 59 with resolved type: 60 signed int 37 61 ... to: 62 reference to signed int 63 with resolved type: 38 64 reference to signed int 39 65 Generated Cast of: 40 66 constant expression (0 0: zero_t) 67 with resolved type: 68 zero_t 41 69 ... to: 42 70 signed int 71 with resolved type: 72 signed int 43 73 74 with resolved type: 75 signed int 44 76 ... with environment: 45 77 Types: … … 50 82 Generated Cast of: 51 83 Variable Expression: x: instance of struct Managed with body 1 84 with resolved type: 85 instance of struct Managed with body 1 52 86 ... to: 53 87 reference to instance of struct Managed with body 1 88 with resolved type: 89 reference to instance of struct Managed with body 1 54 90 constant expression (123 123: signed int) 91 with resolved type: 92 signed int 55 93 94 with resolved type: 95 void 56 96 ... to: nothing 97 with resolved type: 98 void -
tests/warnings/.expect/self-assignment.txt
r67ca73e re67a82d 1 1 warnings/self-assignment.cfa:29:1 warning: self assignment of expression: Generated Cast of: 2 2 Variable Expression: j: signed int 3 with resolved type: 4 signed int 3 5 ... to: 6 reference to signed int 7 with resolved type: 4 8 reference to signed int 5 9 warnings/self-assignment.cfa:30:1 warning: self assignment of expression: Generated Cast of: 6 10 Variable Expression: s: instance of struct S with body 1 11 with resolved type: 12 instance of struct S with body 1 7 13 ... to: 14 reference to instance of struct S with body 1 15 with resolved type: 8 16 reference to instance of struct S with body 1 9 17 warnings/self-assignment.cfa:31:1 warning: self assignment of expression: Generated Cast of: … … 12 20 ... from aggregate: 13 21 Variable Expression: s: instance of struct S with body 1 22 with resolved type: 23 instance of struct S with body 1 24 with resolved type: 25 signed int 14 26 ... to: 27 reference to signed int 28 with resolved type: 15 29 reference to signed int 16 30 warnings/self-assignment.cfa:32:1 warning: self assignment of expression: Generated Cast of: … … 22 36 ... from aggregate: 23 37 Variable Expression: t: instance of struct T with body 1 38 with resolved type: 39 instance of struct T with body 1 40 with resolved type: 41 instance of struct S with body 1 42 with resolved type: 43 signed int 24 44 ... to: 25 45 reference to signed int 46 with resolved type: 47 reference to signed int
Note:
See TracChangeset
for help on using the changeset viewer.