Changes in / [5407cdc:feacef9]


Ignore:
Files:
49 added
110 deleted
183 edited

Legend:

Unmodified
Added
Removed
  • Jenkins/FullBuild

    r5407cdc rfeacef9  
    1818
    1919                                parallel (
    20                                         gcc_8_x86_new: { trigger_build( 'gcc-8',   'x86', true  ) },
    21                                         gcc_7_x86_new: { trigger_build( 'gcc-7',   'x86', true  ) },
    22                                         gcc_6_x86_new: { trigger_build( 'gcc-6',   'x86', true  ) },
    23                                         gcc_9_x64_new: { trigger_build( 'gcc-9',   'x64', true  ) },
    24                                         gcc_8_x64_new: { trigger_build( 'gcc-8',   'x64', true  ) },
    25                                         gcc_7_x64_new: { trigger_build( 'gcc-7',   'x64', true  ) },
    26                                         gcc_6_x64_new: { trigger_build( 'gcc-6',   'x64', true  ) },
    27                                         gcc_5_x64_new: { trigger_build( 'gcc-5',   'x64', true  ) },
     20                                        gcc_8_x86_old: { trigger_build( 'gcc-8',   'x86', false ) },
     21                                        gcc_7_x86_old: { trigger_build( 'gcc-7',   'x86', false ) },
     22                                        gcc_6_x86_old: { trigger_build( 'gcc-6',   'x86', false ) },
     23                                        gcc_9_x64_old: { trigger_build( 'gcc-9',   'x64', false ) },
     24                                        gcc_8_x64_old: { trigger_build( 'gcc-8',   'x64', false ) },
     25                                        gcc_7_x64_old: { trigger_build( 'gcc-7',   'x64', false ) },
     26                                        gcc_6_x64_old: { trigger_build( 'gcc-6',   'x64', false ) },
     27                                        gcc_5_x64_old: { trigger_build( 'gcc-5',   'x64', false ) },
     28                                        clang_x64_old: { trigger_build( 'clang',   'x64', false ) },
    2829                                        clang_x64_new: { trigger_build( 'clang',   'x64', true  ) },
    29                                         clang_x64_old: { trigger_build( 'clang',   'x64', false ) },
    3030                                )
    3131                        }
     
    6666
    6767def trigger_build(String cc, String arch, boolean new_ast) {
    68         // Randomly delay the builds by a random amount to avoid hitting the SC server to hard
    69         sleep(time: 5 * Math.random(), unit:"MINUTES")
    70 
    71         // Run the build
    72         // Don't propagate, it doesn't play nice with our email setup
    7368        def result = build job: 'Cforall/master',               \
    7469                parameters: [                                           \
  • Jenkinsfile

    r5407cdc rfeacef9  
    148148def test() {
    149149        try {
    150                 // Print potential limits before testing
    151                 // in case jenkins messes with them
    152                 sh 'free -h'
    153                 sh 'ulimit -a'
    154 
    155150                Tools.BuildStage('Test: short', !Settings.RunAllTests) {
    156151                        dir (BuildDir) {
  • benchmark/Makefile.am

    r5407cdc rfeacef9  
    502502
    503503compile-io$(EXEEXT):
    504         $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/io/io.cfa
     504        $(CFACOMPILE) -DNO_COMPILED_PRAGMA -fsyntax-only -w $(testdir)/io1.cfa
    505505
    506506compile-monitor$(EXEEXT):
  • benchmark/basic/ttst_lock.c

    r5407cdc rfeacef9  
    99#define CALIGN __attribute__(( aligned (CACHE_ALIGN) ))
    1010#define CACHE_ALIGN 128
    11 #if defined( __i386 ) || defined( __x86_64 )
    12         #define Pause() __asm__ __volatile__ ( "pause" : : : )
    13 #elif defined( __ARM_ARCH )
    14         #define Pause() __asm__ __volatile__ ( "YIELD" : : : )
    15 #else
    16         #error unsupported architecture
    17 #endif
     11#define Pause() __asm__ __volatile__ ( "pause" : : : )
    1812
    1913typedef uintptr_t TYPE;                                                                 // addressable word-size
  • benchmark/benchcltr.hfa

    r5407cdc rfeacef9  
    114114        for() {
    115115                sleep(100`ms);
    116                 end = timeHiRes();
     116                end = getTimeNsec();
    117117                Duration delta = end - start;
    118118                /*if(is_tty)*/ {
     
    126126}
    127127#else
    128 uint64_t timeHiRes() {
     128uint64_t getTimeNsec() {
    129129        timespec curr;
    130130        clock_gettime( CLOCK_REALTIME, &curr );
     
    140140        for(;;) {
    141141                usleep(100000);
    142                 end = timeHiRes();
     142                end = getTimeNsec();
    143143                uint64_t delta = end - start;
    144144                /*if(is_tty)*/ {
  • benchmark/io/http/http_ring.cpp

    r5407cdc rfeacef9  
    2020                socklen_t *addrlen;
    2121                int flags;
    22                 unsigned cnt;
    2322        } acpt;
    2423
     
    6867thread_local stats_block_t stats;
    6968stats_block_t global_stats;
    70 
    71 thread_local struct __attribute__((aligned(128))) {
    72         size_t to_submit = 0;
    73 } local;
    7469
    7570// Get an array of current connections
     
    197192        static void submit(struct io_uring * ring, struct io_uring_sqe * sqe, connection * conn) {
    198193                (void)ring;
    199                 local.to_submit++;
    200194                #ifdef USE_ASYNC
    201195                        io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
     
    412406                switch(state) {
    413407                case ACCEPTING:
    414                         // connection::accept(ring, opt);
     408                        connection::accept(ring, opt);
    415409                        newconn(ring, res);
    416410                        break;
     
    426420
    427421//=========================================================
    428 extern "C" {
    429         #include <sys/eventfd.h>  // use for termination
    430 }
    431 
    432422// Main loop of the WebServer
    433423// Effectively uses one thread_local copy of everything per kernel thread
     
    437427        struct io_uring * ring = opt.ring;
    438428
    439         int blockfd = eventfd(0, 0);
    440         if (blockfd < 0) {
    441                 fprintf( stderr, "eventfd create error: (%d) %s\n", (int)errno, strerror(errno) );
    442                 exit(EXIT_FAILURE);
    443         }
    444 
    445         int ret = io_uring_register_eventfd(ring, blockfd);
    446         if (ret < 0) {
    447                 fprintf( stderr, "io_uring S&W error: (%d) %s\n", (int)-ret, strerror(-ret) );
    448                 exit(EXIT_FAILURE);
    449         }
    450 
    451429        // Track the shutdown using a event_fd
    452430        char endfd_buf[8];
     
    455433        // Accept our first connection
    456434        // May not take effect until io_uring_submit_and_wait
    457         for(unsigned i = 0; i < opt.acpt.cnt; i++) {
    458                 connection::accept(ring, opt);
    459         }
     435        connection::accept(ring, opt);
    460436
    461437        int reset = 1;       // Counter to print stats once in a while
     
    465441        while(!done) {
    466442                // Submit all the answers we have and wait for responses
    467                 int ret = io_uring_submit(ring);
    468                 local.to_submit = 0;
     443                int ret = io_uring_submit_and_wait(ring, 1);
    469444
    470445                // check errors
     
    477452                sqes += ret;
    478453                call++;
    479 
    480 
    481                 eventfd_t val;
    482                 ret = eventfd_read(blockfd, &val);
    483 
    484                 // check errors
    485                 if (ret < 0) {
    486                         fprintf( stderr, "eventfd read error: (%d) %s\n", (int)errno, strerror(errno) );
    487                         exit(EXIT_FAILURE);
    488                 }
    489454
    490455                struct io_uring_cqe *cqe;
     
    498463                                break;
    499464                        }
    500 
    501                         if(local.to_submit > 30) break;
    502465
    503466                        auto req = (class connection *)cqe->user_data;
     
    546509        #include <pthread.h>      // for pthreads
    547510        #include <signal.h>       // for signal(SIGPIPE, SIG_IGN);
     511        #include <sys/eventfd.h>  // use for termination
    548512        #include <sys/socket.h>   // for sockets in general
    549513        #include <netinet/in.h>   // for sockaddr_in, AF_INET
     
    564528        unsigned entries = 256;     // number of entries per ring/kernel thread
    565529        unsigned backlog = 262144;  // backlog argument to listen
    566         unsigned preaccept = 1;     // start by accepting X per threads
    567530        bool attach = false;        // Whether or not to attach all the rings
    568531        bool sqpoll = false;        // Whether or not to use SQ Polling
     
    571534        // Arguments Parsing
    572535        int c;
    573         while ((c = getopt (argc, argv, "t:p:e:b:c:aS")) != -1) {
     536        while ((c = getopt (argc, argv, "t:p:e:b:aS")) != -1) {
    574537                switch (c)
    575538                {
     
    585548                case 'b':
    586549                        backlog = atoi(optarg);
    587                         break;
    588                 case 'c':
    589                         preaccept = atoi(optarg);
    590550                        break;
    591551                case 'a':
     
    721681                thrd_opts[i].acpt.addrlen = (socklen_t*)&addrlen;
    722682                thrd_opts[i].acpt.flags   = 0;
    723                 thrd_opts[i].acpt.cnt     = preaccept;
    724683                thrd_opts[i].endfd        = efd;
    725684                thrd_opts[i].ring         = &thrd_rings[i].storage;
  • benchmark/io/http/main.cfa

    r5407cdc rfeacef9  
    2929
    3030//=============================================================================================
     31// Globals
     32//=============================================================================================
     33struct ServerProc {
     34        processor self;
     35};
     36
     37void ?{}( ServerProc & this ) {
     38        /* paranoid */ assert( options.clopts.instance != 0p );
     39        (this.self){ "Benchmark Processor", *options.clopts.instance };
     40
     41        #if !defined(__CFA_NO_STATISTICS__)
     42                if( options.clopts.procstats ) {
     43                        print_stats_at_exit( this.self, options.clopts.instance->print_stats );
     44                }
     45                if( options.clopts.viewhalts ) {
     46                        print_halts( this.self );
     47                }
     48        #endif
     49}
     50
     51extern void init_protocol(void);
     52extern void deinit_protocol(void);
     53
     54//=============================================================================================
    3155// Stats Printer
    3256//============================================================================================='
     
    3458thread StatsPrinter {};
    3559
    36 void ?{}( StatsPrinter & this, cluster & cl ) {
    37         ((thread&)this){ "Stats Printer Thread", cl };
    38 }
    39 
    40 void ^?{}( StatsPrinter & mutex this ) {}
     60void ?{}( StatsPrinter & this ) {
     61        ((thread&)this){ "Stats Printer Thread" };
     62}
    4163
    4264void main(StatsPrinter & this) {
     
    4971                sleep(10`s);
    5072
    51                 print_stats_now( *active_cluster(), CFA_STATS_READY_Q | CFA_STATS_IO );
    52         }
    53 }
    54 
    55 //=============================================================================================
    56 // Globals
    57 //=============================================================================================
    58 struct ServerCluster {
    59         cluster self;
    60         processor    * procs;
    61         // io_context   * ctxs;
    62         StatsPrinter * prnt;
    63 
    64 };
    65 
    66 void ?{}( ServerCluster & this ) {
    67         (this.self){ "Server Cluster", options.clopts.params };
    68 
    69         this.procs = alloc(options.clopts.nprocs);
    70         for(i; options.clopts.nprocs) {
    71                 (this.procs[i]){ "Benchmark Processor", this.self };
    72 
    73                 #if !defined(__CFA_NO_STATISTICS__)
    74                         if( options.clopts.procstats ) {
    75                                 print_stats_at_exit( *this.procs, this.self.print_stats );
    76                         }
    77                         if( options.clopts.viewhalts ) {
    78                                 print_halts( *this.procs );
    79                         }
    80                 #endif
    81         }
    82 
    83         if(options.stats) {
    84                 this.prnt = alloc();
    85                 (*this.prnt){ this.self };
    86         } else {
    87                 this.prnt = 0p;
    88         }
    89 
    90         #if !defined(__CFA_NO_STATISTICS__)
    91                 print_stats_at_exit( this.self, CFA_STATS_READY_Q | CFA_STATS_IO );
    92         #endif
    93 
    94         options.clopts.instance[options.clopts.cltr_cnt] = &this.self;
    95         options.clopts.cltr_cnt++;
    96 }
    97 
    98 void ^?{}( ServerCluster & this ) {
    99         delete(this.prnt);
    100 
    101         for(i; options.clopts.nprocs) {
    102                 ^(this.procs[i]){};
    103         }
    104         free(this.procs);
    105 
    106         ^(this.self){};
    107 }
    108 
    109 extern void init_protocol(void);
    110 extern void deinit_protocol(void);
     73                print_stats_now( *options.clopts.instance, CFA_STATS_READY_Q | CFA_STATS_IO );
     74        }
     75}
    11176
    11277//=============================================================================================
     
    172137        // Run Server Cluster
    173138        {
     139                cluster cl = { "Server Cluster", options.clopts.params };
     140                #if !defined(__CFA_NO_STATISTICS__)
     141                        print_stats_at_exit( cl, CFA_STATS_READY_Q | CFA_STATS_IO );
     142                #endif
     143                options.clopts.instance = &cl;
     144
     145
    174146                int pipe_cnt = options.clopts.nworkers * 2;
    175147                int pipe_off;
     
    181153                }
    182154
    183                 // if(options.file_cache.path && options.file_cache.fixed_fds) {
    184                 //      register_fixed_files(cl, fds, pipe_off);
    185                 // }
     155                if(options.file_cache.path && options.file_cache.fixed_fds) {
     156                        register_fixed_files(cl, fds, pipe_off);
     157                }
    186158
    187159                {
    188                         ServerCluster cl[options.clopts.nclusters];
     160                        ServerProc procs[options.clopts.nprocs];
     161                        StatsPrinter printer;
    189162
    190163                        init_protocol();
     
    207180                                        unpark( workers[i] );
    208181                                }
    209                                 sout | options.clopts.nworkers | "workers started on" | options.clopts.nprocs | "processors /" | options.clopts.nclusters | "clusters";
    210                                 for(i; options.clopts.nclusters) {
    211                                         sout | options.clopts.thrd_cnt[i] | nonl;
    212                                 }
    213                                 sout | nl;
     182                                sout | options.clopts.nworkers | "workers started on" | options.clopts.nprocs | "processors";
    214183                                {
    215184                                        char buffer[128];
    216                                         for() {
    217                                                 int ret = cfa_read(0, buffer, 128, 0);
    218                                                 if(ret == 0) break;
     185                                        while(int ret = cfa_read(0, buffer, 128, 0, -1`s, 0p, 0p); ret != 0) {
    219186                                                if(ret < 0) abort( "main read error: (%d) %s\n", (int)errno, strerror(errno) );
    220                                                 sout | "User wrote '" | "" | nonl;
    221                                                 write(sout, buffer, ret - 1);
    222                                                 sout | "'";
    223187                                        }
    224188
     
    229193                                for(i; options.clopts.nworkers) {
    230194                                        workers[i].done = true;
     195                                        cancel(workers[i].cancel);
    231196                                }
    232197                                sout | "done";
     
    256221                        sout | "done";
    257222
    258                         sout | "Stopping processors/clusters..." | nonl; flush( sout );
     223                        sout | "Stopping processors..." | nonl; flush( sout );
    259224                }
    260225                sout | "done";
  • benchmark/io/http/options.cfa

    r5407cdc rfeacef9  
    1313#include <kernel.hfa>
    1414#include <parseargs.hfa>
    15 #include <stdlib.hfa>
    1615
    1716#include <stdlib.h>
     
    2019Options options @= {
    2120        false, // log
    22         false, // stats
    2321
    2422        { // file_cache
     
    3836
    3937        { // cluster
    40                 1,     // nclusters;
    4138                1,     // nprocs;
    4239                1,     // nworkers;
     
    4946
    5047void parse_options( int argc, char * argv[] ) {
    51         // bool fixedfd = false;
    52         // bool sqkpoll = false;
    53         // bool iokpoll = false;
     48        bool subthrd = false;
     49        bool eagrsub = false;
     50        bool fixedfd = false;
     51        bool sqkpoll = false;
     52        bool iokpoll = false;
     53        unsigned sublen = 16;
    5454        unsigned nentries = 16;
    55         bool isolate = false;
    5655
    5756
     
    6059                { 'c', "cpus",           "Number of processors to use", options.clopts.nprocs},
    6160                { 't', "threads",        "Number of worker threads to use", options.clopts.nworkers},
    62                 {'\0', "isolate",        "Create one cluster per processor", isolate, parse_settrue},
    6361                {'\0', "log",            "Enable logs", options.log, parse_settrue},
    64                 {'\0', "stats",          "Enable statistics", options.stats, parse_settrue},
    6562                {'\0', "accept-backlog", "Maximum number of pending accepts", options.socket.backlog},
    6663                {'\0', "request_len",    "Maximum number of bytes in the http request, requests with more data will be answered with Http Code 414", options.socket.buflen},
     
    6865                {'\0', "cache-size",     "Size of the cache to use, if set to small, will uses closes power of 2", options.file_cache.size },
    6966                {'\0', "list-files",     "List the files in the specified path and exit", options.file_cache.list, parse_settrue },
    70                 // { 'f', "fixed-fds",      "If set, files are open eagerly and pre-registered with the cluster", fixedfd, parse_settrue},
    71                 // { 'k', "kpollsubmit",    "If set, cluster uses IORING_SETUP_SQPOLL, implies -f", sqkpoll, parse_settrue },
    72                 // { 'i', "kpollcomplete",  "If set, cluster uses IORING_SETUP_IOPOLL", iokpoll, parse_settrue },
    73                 {'e', "numentries",     "Number of I/O entries", nentries },
     67                { 's', "submitthread",   "If set, cluster uses polling thread to submit I/O", subthrd, parse_settrue },
     68                { 'e', "eagersubmit",    "If set, cluster submits I/O eagerly but still aggregates submits", eagrsub, parse_settrue},
     69                { 'f', "fixed-fds",      "If set, files are open eagerly and pre-registered with the cluster", fixedfd, parse_settrue},
     70                { 'k', "kpollsubmit",    "If set, cluster uses IORING_SETUP_SQPOLL, implies -f", sqkpoll, parse_settrue },
     71                { 'i', "kpollcomplete",  "If set, cluster uses IORING_SETUP_IOPOLL", iokpoll, parse_settrue },
     72                {'\0', "submitlength",   "Max number of submitions that can be submitted together", sublen },
     73                {'\0', "numentries",     "Number of I/O entries", nentries },
    7474
    7575        };
     
    9191                nentries = v;
    9292        }
    93         if(isolate) {
    94                 options.clopts.nclusters = options.clopts.nprocs;
    95                 options.clopts.nprocs = 1;
    96         }
    9793        options.clopts.params.num_entries = nentries;
    98         options.clopts.instance = alloc(options.clopts.nclusters);
    99         options.clopts.thrd_cnt = alloc(options.clopts.nclusters);
    100         options.clopts.cltr_cnt = 0;
    101         for(i; options.clopts.nclusters) {
    102                 options.clopts.thrd_cnt[i] = 0;
     94
     95        options.clopts.params.poller_submits = subthrd;
     96        options.clopts.params.eager_submits  = eagrsub;
     97
     98        if( fixedfd ) {
     99                options.file_cache.fixed_fds = true;
    103100        }
    104101
     102        if( sqkpoll ) {
     103                options.clopts.params.poll_submit = true;
     104                options.file_cache.fixed_fds = true;
     105        }
    105106
    106         // if( fixedfd ) {
    107         //      options.file_cache.fixed_fds = true;
    108         // }
     107        if( iokpoll ) {
     108                options.clopts.params.poll_complete = true;
     109                options.file_cache.open_flags |= O_DIRECT;
     110        }
    109111
    110         // if( sqkpoll ) {
    111         //      options.file_cache.fixed_fds = true;
    112         // }
    113 
    114         // if( iokpoll ) {
    115         //      options.file_cache.open_flags |= O_DIRECT;
    116         // }
     112        options.clopts.params.num_ready = sublen;
    117113
    118114        if( left[0] == 0p ) { return; }
  • benchmark/io/http/options.hfa

    r5407cdc rfeacef9  
    99struct Options {
    1010        bool log;
    11         bool stats;
    1211
    1312        struct {
     
    2726
    2827        struct {
    29                 int nclusters;
    3028                int nprocs;
    3129                int nworkers;
     
    3331                bool procstats;
    3432                bool viewhalts;
    35                 cluster ** instance;
    36                 size_t   * thrd_cnt;
    37                 size_t     cltr_cnt;
     33                cluster * instance;
    3834        } clopts;
    3935};
  • benchmark/io/http/protocol.cfa

    r5407cdc rfeacef9  
    55        #include <fcntl.h>
    66}
    7 
    8 #define xstr(s) str(s)
    9 #define str(s) #s
    107
    118#include <fstream.hfa>
     
    2320#include "options.hfa"
    2421
    25 #define PLAINTEXT_1WRITE
    26 #define PLAINTEXT_MEMCPY
    27 #define PLAINTEXT_NOCOPY
    28 
    29 struct https_msg_str {
    30         char msg[512];
    31         size_t len;
    32 };
    33 
    34 const https_msg_str * volatile http_msgs[KNOWN_CODES] = { 0 };
     22const char * volatile date = 0p;
     23
     24const char * http_msgs[] = {
     25        "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: %zu \n\n",
     26        "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     27        "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     28        "HTTP/1.1 405 Method Not Allowed\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     29        "HTTP/1.1 408 Request Timeout\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     30        "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     31        "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
     32};
    3533
    3634_Static_assert( KNOWN_CODES == (sizeof(http_msgs ) / sizeof(http_msgs [0])));
    3735
    38 const int http_codes[KNOWN_CODES] = {
    39         200,
     36const int http_codes[] = {
    4037        200,
    4138        400,
     
    5653        while(len > 0) {
    5754                // Call write
    58                 int ret = cfa_send(fd, it, len, 0, CFA_IO_LAZY);
     55                int ret = cfa_write(fd, it, len, 0, -1`s, 0p, 0p);
     56                // int ret = write(fd, it, len);
    5957                if( ret < 0 ) {
    6058                        if( errno == ECONNRESET || errno == EPIPE ) return -ECONNRESET;
     
    7472        /* paranoid */ assert( code < KNOWN_CODES && code != OK200 );
    7573        int idx = (int)code;
    76         return answer( fd, http_msgs[idx]->msg, http_msgs[idx]->len );
     74        return answer( fd, http_msgs[idx], strlen( http_msgs[idx] ) );
    7775}
    7876
    7977int answer_header( int fd, size_t size ) {
    80         char buffer[512];
    81         char * it = buffer;
    82         memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
    83         it += http_msgs[OK200]->len;
    84         int len = http_msgs[OK200]->len;
    85         len += snprintf(it, 512 - len, "%d \n\n", size);
     78        const char * fmt = http_msgs[OK200];
     79        int len = 200;
     80        char buffer[len];
     81        len = snprintf(buffer, len, fmt, date, size);
    8682        return answer( fd, buffer, len );
    8783}
    8884
    89 #if defined(PLAINTEXT_NOCOPY)
    90 int answer_plaintext( int fd ) {
    91         return answer(fd, http_msgs[OK200_PlainText]->msg, http_msgs[OK200_PlainText]->len); // +1 cause snprintf doesn't count nullterminator
    92 }
    93 #elif defined(PLAINTEXT_MEMCPY)
    94 #define TEXTSIZE 15
    95 int answer_plaintext( int fd ) {
    96         char text[] = "Hello, World!\n\n";
    97         char ts[] = xstr(TEXTSIZE) " \n\n";
    98         _Static_assert(sizeof(text) - 1 == TEXTSIZE);
    99         char buffer[512 + TEXTSIZE];
    100         char * it = buffer;
    101         memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
    102         it += http_msgs[OK200]->len;
    103         int len = http_msgs[OK200]->len;
    104         memcpy(it, ts, sizeof(ts) - 1);
    105         it += sizeof(ts) - 1;
    106         len += sizeof(ts) - 1;
    107         memcpy(it, text, TEXTSIZE);
    108         return answer(fd, buffer, len + TEXTSIZE);
    109 }
    110 #elif defined(PLAINTEXT_1WRITE)
    111 int answer_plaintext( int fd ) {
    112         char text[] = "Hello, World!\n\n";
    113         char buffer[512 + sizeof(text)];
    114         char * it = buffer;
    115         memcpy(it, http_msgs[OK200]->msg, http_msgs[OK200]->len);
    116         it += http_msgs[OK200]->len;
    117         int len = http_msgs[OK200]->len;
    118         int r = snprintf(it, 512 - len, "%d \n\n", sizeof(text));
    119         it += r;
    120         len += r;
    121         memcpy(it, text, sizeof(text));
    122         return answer(fd, buffer, len + sizeof(text));
    123 }
    124 #else
    125 int answer_plaintext( int fd ) {
    126         char text[] = "Hello, World!\n\n";
    127         int ret = answer_header(fd, sizeof(text));
     85int answer_plain( int fd, char buffer[], size_t size ) {
     86        int ret = answer_header(fd, size);
    12887        if( ret < 0 ) return ret;
    129         return answer(fd, text, sizeof(text));
    130 }
    131 #endif
     88        return answer(fd, buffer, size);
     89}
    13290
    13391int answer_empty( int fd ) {
     
    13694
    13795
    138 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len) {
     96[HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len, io_cancellation * cancel) {
    13997        char * it = buffer;
    14098        size_t count = len - 1;
     
    142100        READ:
    143101        for() {
    144                 int ret = cfa_recv(fd, (void*)it, count, 0, CFA_IO_LAZY);
     102                int ret = cfa_read(fd, (void*)it, count, 0, -1`s, cancel, 0p);
    145103                // int ret = read(fd, (void*)it, count);
    146104                if(ret == 0 ) return [OK200, true, 0, 0];
     
    181139        ssize_t ret;
    182140        SPLICE1: while(count > 0) {
    183                 ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, sflags, CFA_IO_LAZY);
     141                ret = cfa_splice(ans_fd, &offset, pipe[1], 0p, count, sflags, 0, -1`s, 0p, 0p);
     142                // ret = splice(ans_fd, &offset, pipe[1], 0p, count, sflags);
    184143                if( ret < 0 ) {
    185144                        if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE1;
     
    193152                size_t in_pipe = ret;
    194153                SPLICE2: while(in_pipe > 0) {
    195                         ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, sflags, CFA_IO_LAZY);
     154                        ret = cfa_splice(pipe[0], 0p, fd, 0p, in_pipe, sflags, 0, -1`s, 0p, 0p);
     155                        // ret = splice(pipe[0], 0p, fd, 0p, in_pipe, sflags);
    196156                        if( ret < 0 ) {
    197157                                if( errno != EAGAIN && errno != EWOULDBLOCK) continue SPLICE2;
     
    213173#include <thread.hfa>
    214174
    215 const char * original_http_msgs[] = {
    216         "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: ",
    217         "HTTP/1.1 200 OK\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 15\n\nHello, World!\n\n",
    218         "HTTP/1.1 400 Bad Request\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    219         "HTTP/1.1 404 Not Found\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    220         "HTTP/1.1 405 Method Not Allowed\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    221         "HTTP/1.1 408 Request Timeout\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    222         "HTTP/1.1 413 Payload Too Large\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    223         "HTTP/1.1 414 URI Too Long\nServer: HttoForall\nDate: %s \nContent-Type: text/plain\nContent-Length: 0 \n\n",
    224 };
    225 
    226175struct date_buffer {
    227         https_msg_str strs[KNOWN_CODES];
     176        char buff[100];
    228177};
    229178
     
    234183
    235184void ?{}( DateFormater & this ) {
    236         ((thread&)this){ "Server Date Thread", *options.clopts.instance[0] };
     185        ((thread&)this){ "Server Date Thread", *options.clopts.instance };
    237186        this.idx = 0;
    238         memset( &this.buffers[0], 0, sizeof(this.buffers[0]) );
    239         memset( &this.buffers[1], 0, sizeof(this.buffers[1]) );
     187        memset( this.buffers[0].buff, 0, sizeof(this.buffers[0]) );
     188        memset( this.buffers[1].buff, 0, sizeof(this.buffers[1]) );
    240189}
    241190
     
    247196                or else {}
    248197
    249 
    250                 char buff[100];
    251                 Time now = timeHiRes();
    252                 strftime( buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now );
    253                 sout | "Updated date to '" | buff | "'";
    254 
    255                 for(i; KNOWN_CODES) {
    256                         size_t len = snprintf( this.buffers[this.idx].strs[i].msg, 512, original_http_msgs[i], buff );
    257                         this.buffers[this.idx].strs[i].len = len;
    258                 }
    259 
    260                 for(i; KNOWN_CODES) {
    261                         https_msg_str * next = &this.buffers[this.idx].strs[i];
    262                         __atomic_exchange_n((https_msg_str * volatile *)&http_msgs[i], next, __ATOMIC_SEQ_CST);
    263                 }
     198                Time now = getTimeNsec();
     199
     200                strftime( this.buffers[this.idx].buff, 100, "%a, %d %b %Y %H:%M:%S %Z", now );
     201
     202                char * next = this.buffers[this.idx].buff;
     203                __atomic_exchange_n((char * volatile *)&date, next, __ATOMIC_SEQ_CST);
    264204                this.idx = (this.idx + 1) % 2;
    265 
    266                 sout | "Date thread sleeping";
    267205
    268206                sleep(1`s);
  • benchmark/io/http/protocol.hfa

    r5407cdc rfeacef9  
    11#pragma once
     2
     3struct io_cancellation;
    24
    35enum HttpCode {
    46        OK200 = 0,
    5         OK200_PlainText,
    67        E400,
    78        E404,
     
    1718int answer_error( int fd, HttpCode code );
    1819int answer_header( int fd, size_t size );
    19 int answer_plaintext( int fd );
     20int answer_plain( int fd, char buffer [], size_t size );
    2021int answer_empty( int fd );
    2122
    22 [HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len);
     23[HttpCode code, bool closed, * const char file, size_t len] http_read(int fd, []char buffer, size_t len, io_cancellation *);
    2324
    2425int sendfile( int pipe[2], int fd, int ans_fd, size_t count );
  • benchmark/io/http/worker.cfa

    r5407cdc rfeacef9  
    1717//=============================================================================================
    1818void ?{}( Worker & this ) {
    19         size_t cli = rand() % options.clopts.cltr_cnt;
    20         ((thread&)this){ "Server Worker Thread", *options.clopts.instance[cli], 512000 };
    21         options.clopts.thrd_cnt[cli]++;
     19        ((thread&)this){ "Server Worker Thread", *options.clopts.instance };
    2220        this.pipe[0] = -1;
    2321        this.pipe[1] = -1;
     
    3735        for() {
    3836                if( options.log ) sout | "=== Accepting connection ===";
    39                 int fd = cfa_accept4( this.[sockfd, addr, addrlen, flags], CFA_IO_LAZY );
     37                int fd = cfa_accept4( this.[sockfd, addr, addrlen, flags], 0, -1`s, &this.cancel, 0p );
     38                // int fd = accept4( this.[sockfd, addr, addrlen, flags] );
    4039                if(fd < 0) {
    4140                        if( errno == ECONNABORTED ) break;
     
    4342                        abort( "accept error: (%d) %s\n", (int)errno, strerror(errno) );
    4443                }
    45                 if(this.done) break;
    4644
    4745                if( options.log ) sout | "=== New connection" | fd | "" | ", waiting for requests ===";
     
    5755                        char buffer[len];
    5856                        if( options.log ) sout | "=== Reading request ===";
    59                         [code, closed, file, name_size] = http_read(fd, buffer, len);
     57                        [code, closed, file, name_size] = http_read(fd, buffer, len, &this.cancel);
    6058
    6159                        // if we are done, break out of the loop
     
    7270                                if( options.log ) sout | "=== Request for /plaintext ===";
    7371
    74                                 int ret = answer_plaintext(fd);
     72                                char text[] = "Hello, World!\n";
     73
     74                                // Send the header
     75                                int ret = answer_plain(fd, text, sizeof(text));
    7576                                if( ret == -ECONNRESET ) break REQUEST;
    7677
  • benchmark/io/http/worker.hfa

    r5407cdc rfeacef9  
    1717        socklen_t * addrlen;
    1818        int flags;
     19        io_cancellation cancel;
    1920        volatile bool done;
    2021};
  • benchmark/io/readv-posix.c

    r5407cdc rfeacef9  
    111111                                printf("Starting\n");
    112112                                bool is_tty = isatty(STDOUT_FILENO);
    113                                 start = timeHiRes();
     113                                start = getTimeNsec();
    114114                                run = true;
    115115
     
    118118
    119119                                run = false;
    120                                 end = timeHiRes();
     120                                end = getTimeNsec();
    121121                                printf("\nDone\n");
    122122
  • benchmark/io/readv.cfa

    r5407cdc rfeacef9  
    147147                                printf("Starting\n");
    148148                                bool is_tty = isatty(STDOUT_FILENO);
    149                                 start = timeHiRes();
     149                                start = getTimeNsec();
    150150                                run = true;
    151151
     
    156156
    157157                                run = false;
    158                                 end = timeHiRes();
     158                                end = getTimeNsec();
    159159                                printf("\nDone\n");
    160160                        }
  • benchmark/readyQ/cycle.cc

    r5407cdc rfeacef9  
    8989
    9090                        bool is_tty = isatty(STDOUT_FILENO);
    91                         start = timeHiRes();
     91                        start = getTimeNsec();
    9292
    9393                        for(int i = 0; i < nthreads; i++) {
     
    9797
    9898                        stop = true;
    99                         end = timeHiRes();
     99                        end = getTimeNsec();
    100100                        printf("\nDone\n");
    101101
  • benchmark/readyQ/cycle.cfa

    r5407cdc rfeacef9  
    6565
    6666                        bool is_tty = isatty(STDOUT_FILENO);
    67                         start = timeHiRes();
     67                        start = getTimeNsec();
    6868
    6969                        for(i; nthreads) {
     
    7373
    7474                        stop = true;
    75                         end = timeHiRes();
     75                        end = getTimeNsec();
    7676                        printf("\nDone\n");
    7777
  • benchmark/readyQ/cycle.cpp

    r5407cdc rfeacef9  
    33#include <libfibre/fibre.h>
    44
     5class __attribute__((aligned(128))) bench_sem {
     6        Fibre * volatile ptr = nullptr;
     7public:
     8        inline bool wait() {
     9                static Fibre * const ready  = reinterpret_cast<Fibre * const>(1ull);
     10                for(;;) {
     11                        Fibre * expected = this->ptr;
     12                        if(expected == ready) {
     13                                if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     14                                        return false;
     15                                }
     16                        }
     17                        else {
     18                                /* paranoid */ assert( expected == nullptr );
     19                                if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     20                                        fibre_park();
     21                                        return true;
     22                                }
     23                        }
     24
     25                }
     26        }
     27
     28        inline bool post() {
     29                static Fibre * const ready  = reinterpret_cast<Fibre * const>(1ull);
     30                for(;;) {
     31                        Fibre * expected = this->ptr;
     32                        if(expected == ready) return false;
     33                        if(expected == nullptr) {
     34                                if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     35                                        return false;
     36                                }
     37                        }
     38                        else {
     39                                if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     40                                        fibre_unpark( expected );
     41                                        return true;
     42                                }
     43                        }
     44                }
     45        }
     46};
    547struct Partner {
    648        unsigned long long count  = 0;
     
    5193
    5294                        bool is_tty = isatty(STDOUT_FILENO);
    53                         start = timeHiRes();
     95                        start = getTimeNsec();
    5496
    5597                        for(int i = 0; i < nthreads; i++) {
     
    59101
    60102                        stop = true;
    61                         end = timeHiRes();
     103                        end = getTimeNsec();
    62104                        printf("\nDone\n");
    63105
  • benchmark/readyQ/locality.cfa

    r5407cdc rfeacef9  
    232232
    233233                        bool is_tty = isatty(STDOUT_FILENO);
    234                         start = timeHiRes();
     234                        start = getTimeNsec();
    235235
    236236                        for(i; nthreads) {
     
    240240
    241241                        stop = true;
    242                         end = timeHiRes();
     242                        end = getTimeNsec();
    243243                        printf("\nDone\n");
    244244
  • benchmark/readyQ/locality.cpp

    r5407cdc rfeacef9  
    99        uint64_t dmigs = 0;
    1010        uint64_t gmigs = 0;
     11};
     12
     13class __attribute__((aligned(128))) bench_sem {
     14        Fibre * volatile ptr = nullptr;
     15public:
     16        inline bool wait() {
     17                static Fibre * const ready  = reinterpret_cast<Fibre * const>(1ull);
     18                for(;;) {
     19                        Fibre * expected = this->ptr;
     20                        if(expected == ready) {
     21                                if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     22                                        return false;
     23                                }
     24                        }
     25                        else {
     26                                /* paranoid */ assert( expected == nullptr );
     27                                if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     28                                        fibre_park();
     29                                        return true;
     30                                }
     31                        }
     32
     33                }
     34        }
     35
     36        inline bool post() {
     37                static Fibre * const ready  = reinterpret_cast<Fibre * const>(1ull);
     38                for(;;) {
     39                        Fibre * expected = this->ptr;
     40                        if(expected == ready) return false;
     41                        if(expected == nullptr) {
     42                                if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     43                                        return false;
     44                                }
     45                        }
     46                        else {
     47                                if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
     48                                        fibre_unpark( expected );
     49                                        return true;
     50                                }
     51                        }
     52                }
     53        }
    1154};
    1255
     
    244287
    245288                        bool is_tty = isatty(STDOUT_FILENO);
    246                         start = timeHiRes();
     289                        start = getTimeNsec();
    247290
    248291                        for(size_t i = 0; i < nthreads; i++) {
     
    252295
    253296                        stop = true;
    254                         end = timeHiRes();
     297                        end = getTimeNsec();
    255298                        printf("\nDone\n");
    256299
  • benchmark/readyQ/rq_bench.hfa

    r5407cdc rfeacef9  
    44#include <stdio.h>
    55#include <stdlib.hfa>
    6 #include <stats.hfa>
    76#include <thread.hfa>
    87#include <time.hfa>
     
    6463                (*p){ "Benchmark Processor", this.cl };
    6564        }
    66         #if !defined(__CFA_NO_STATISTICS__)
    67                 print_stats_at_exit( this.cl, CFA_STATS_READY_Q );
    68         #endif
    6965}
    7066
     
    7773        for() {
    7874                sleep(100`ms);
    79                 Time end = timeHiRes();
     75                Time end = getTimeNsec();
    8076                Duration delta = end - start;
    8177                if(is_tty) {
  • benchmark/readyQ/rq_bench.hpp

    r5407cdc rfeacef9  
    66#include <time.h>                                                                               // timespec
    77#include <sys/time.h>                                                                   // timeval
    8 
    9 typedef __uint128_t __lehmer64_state_t;
    10 static inline uint64_t __lehmer64( __lehmer64_state_t & state ) {
    11         state *= 0xda942042e4dd58b5;
    12         return state >> 64;
    13 }
    148
    159enum { TIMEGRAN = 1000000000LL };                                       // nanosecond granularity, except for timeval
     
    5246        }
    5347
    54 uint64_t timeHiRes() {
     48uint64_t getTimeNsec() {
    5549        timespec curr;
    5650        clock_gettime( CLOCK_REALTIME, &curr );
     
    6660        for(;;) {
    6761                Sleeper::usleep(100000);
    68                 uint64_t end = timeHiRes();
     62                uint64_t end = getTimeNsec();
    6963                uint64_t delta = end - start;
    7064                if(is_tty) {
     
    8074        }
    8175}
    82 
    83 class Fibre;
    84 int fibre_park();
    85 int fibre_unpark( Fibre * );
    86 Fibre * fibre_self();
    87 
    88 class __attribute__((aligned(128))) bench_sem {
    89         Fibre * volatile ptr = nullptr;
    90 public:
    91         inline bool wait() {
    92                 static Fibre * const ready  = reinterpret_cast<Fibre *>(1ull);
    93                 for(;;) {
    94                         Fibre * expected = this->ptr;
    95                         if(expected == ready) {
    96                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    97                                         return false;
    98                                 }
    99                         }
    100                         else {
    101                                 /* paranoid */ assert( expected == nullptr );
    102                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, fibre_self(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    103                                         fibre_park();
    104                                         return true;
    105                                 }
    106                         }
    107 
    108                 }
    109         }
    110 
    111         inline bool post() {
    112                 static Fibre * const ready  = reinterpret_cast<Fibre *>(1ull);
    113                 for(;;) {
    114                         Fibre * expected = this->ptr;
    115                         if(expected == ready) return false;
    116                         if(expected == nullptr) {
    117                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, ready, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    118                                         return false;
    119                                 }
    120                         }
    121                         else {
    122                                 if(__atomic_compare_exchange_n(&this->ptr, &expected, nullptr, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    123                                         fibre_unpark( expected );
    124                                         return true;
    125                                 }
    126                         }
    127                 }
    128         }
    129 };
    13076
    13177// ==========================================================================================
     
    242188                this->help       = help;
    243189                this->variable   = reinterpret_cast<void*>(&variable);
    244                 #pragma GCC diagnostic push
    245                 #pragma GCC diagnostic ignored "-Wcast-function-type"
    246                                 this->parse_fun  = reinterpret_cast<bool (*)(const char *, void * )>(static_cast<bool (*)(const char *, T & )>(parse));
    247                 #pragma GCC diagnostic pop
     190                this->parse_fun  = reinterpret_cast<bool (*)(const char *, void * )>(static_cast<bool (*)(const char *, T & )>(parse));
    248191        }
    249192
     
    254197                this->help       = help;
    255198                this->variable   = reinterpret_cast<void*>(&variable);
    256                 #pragma GCC diagnostic push
    257                 #pragma GCC diagnostic ignored "-Wcast-function-type"
    258                         this->parse_fun  = reinterpret_cast<bool (*)(const char *, void * )>(parse);
    259                 #pragma GCC diagnostic pop
     199                this->parse_fun  = reinterpret_cast<bool (*)(const char *, void * )>(parse);
    260200        }
    261201};
  • benchmark/readyQ/yield.cfa

    r5407cdc rfeacef9  
    6666
    6767                                bool is_tty = isatty(STDOUT_FILENO);
    68                                 start = timeHiRes();
     68                                start = getTimeNsec();
    6969                                run = true;
    7070
     
    7575
    7676                                run = false;
    77                                 end = timeHiRes();
     77                                end = getTimeNsec();
    7878                                printf("\nDone\n");
    7979                        }
  • doc/LaTeXmacros/lstlang.sty

    r5407cdc rfeacef9  
    88%% Created On       : Sat May 13 16:34:42 2017
    99%% Last Modified By : Peter A. Buhr
    10 %% Last Modified On : Wed Feb 17 09:21:15 2021
    11 %% Update Count     : 27
     10%% Last Modified On : Wed Sep 23 22:40:04 2020
     11%% Update Count     : 24
    1212%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1313
     
    113113        morekeywords={
    114114                _Alignas, _Alignof, __alignof, __alignof__, asm, __asm, __asm__, __attribute, __attribute__,
    115                 auto, basetypeof, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__,
    116                 coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally, fixup,
     115                auto, _Bool, catch, catchResume, choose, _Complex, __complex, __complex__, __const, __const__,
     116                coroutine, disable, dtype, enable, exception, __extension__, fallthrough, fallthru, finally,
    117117                __float80, float80, __float128, float128, forall, ftype, generator, _Generic, _Imaginary, __imag, __imag__,
    118118                inline, __inline, __inline__, __int128, int128, __label__, monitor, mutex, _Noreturn, one_t, or,
    119                 otype, restrict, __restrict, __restrict__, recover, report, __signed, __signed__, _Static_assert, suspend,
    120                 thread, _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,
     119                otype, restrict, __restrict, __restrict__, __signed, __signed__, _Static_assert, suspend, thread,
     120                _Thread_local, throw, throwResume, timeout, trait, try, ttype, typeof, __typeof, __typeof__,
    121121                virtual, __volatile, __volatile__, waitfor, when, with, zero_t,
    122122    },
  • doc/bibliography/pl.bib

    r5407cdc rfeacef9  
    17971797}
    17981798
    1799 @article{Delisle21,
     1799@article{Delisle20,
    18001800    keywords    = {concurrency, Cforall},
    18011801    contributer = {pabuhr@plg},
    18021802    author      = {Thierry Delisle and Peter A. Buhr},
    18031803    title       = {Advanced Control-flow and Concurrency in \textsf{C}$\mathbf{\forall}$},
     1804    year        = 2020,
    18041805    journal     = spe,
    1805     month       = may,
    1806     year        = 2021,
    1807     volume      = 51,
    1808     number      = 5,
    1809     pages       = {1005-1042},
    1810     note        = {\href{https://onlinelibrary.wiley.com/doi/10.1002/spe.2925}{https://\-onlinelibrary.wiley.com/\-doi/\-10.1002/\-spe.2925}},
     1806    pages       = {1-38},
     1807    note        = {\href{https://doi-org.proxy.lib.uwaterloo.ca/10.1002/spe.2925}{https://\-doi-org.proxy.lib.uwaterloo.ca/\-10.1002/\-spe.2925}},
     1808    note        = {},
    18111809}
    18121810
     
    33023300    month       = jan,
    33033301    address     = {Waterloo, Ontario, Canada, N2L 3G1},
    3304     note        = {\href{http://uwspace.uwaterloo.ca/bitstream/10012/3501/1/Thesis.pdf}{http://\-uwspace.uwaterloo.ca/\-bitstream/\-10012/\-3501/\-1/\-Thesis.pdf}},
     3302    note        = {\textsf{http://uwspace.uwaterloo.ca/\-bitstream/\-10012/\-3501/\-1/\-Thesis.pdf}},
    33053303}
    33063304
  • doc/theses/andrew_beach_MMath/Makefile

    r5407cdc rfeacef9  
    44BUILD=out
    55TEXSRC=$(wildcard *.tex)
    6 FIGSRC=$(wildcard *.fig)
    76BIBSRC=$(wildcard *.bib)
    87STYSRC=$(wildcard *.sty)
     
    1413BASE= ${DOC:%.pdf=%}
    1514
    16 RAWSRC=${TEXSRC} ${BIBSRC} ${STYSRC} ${CLSSRC}
    17 FIGTEX=${FIGSRC:%.fig=${BUILD}/%.tex}
    18 
    1915### Special Rules:
    2016
     
    2218
    2319### Commands:
    24 LATEX=TEXINPUTS=${TEXLIB} latex -halt-on-error -output-directory=${BUILD}
     20LATEX=TEXINPUTS=${TEXLIB} pdflatex -halt-on-error -output-directory=${BUILD}
    2521BIBTEX=BIBINPUTS=${BIBLIB} bibtex
    2622GLOSSARY=INDEXSTYLE=${BUILD} makeglossaries-lite
     
    3026all: ${DOC}
    3127
    32 # The main rule, it does all the tex/latex processing.
    33 ${BUILD}/${BASE}.dvi: ${RAWSRC} ${FIGTEX} Makefile | ${BUILD}
     28${BUILD}/${DOC}: ${TEXSRC} ${BIBSRC} ${STYSRC} ${CLSSRC} Makefile | ${BUILD}
    3429        ${LATEX} ${BASE}
    3530        ${BIBTEX} ${BUILD}/${BASE}
     
    3833        ${LATEX} ${BASE}
    3934
    40 # Convert xfig output to tex. (Generates \special declarations.)
    41 ${FIGTEX}: ${BUILD}/%.tex: %.fig | ${BUILD}
    42         fig2dev -L eepic $< > $@
    43 
    44 # Step through dvi & postscript to handle xfig specials.
    45 %.pdf : ${BUILD}/%.dvi
    46         dvipdf $^ $@
     35${DOC}: ${BUILD}/${DOC}
     36        cp $< $@
    4737
    4838${BUILD}:
  • doc/theses/andrew_beach_MMath/existing.tex

    r5407cdc rfeacef9  
    1414\section{Overloading and \lstinline{extern}}
    1515\CFA has extensive overloading, allowing multiple definitions of the same name
    16 to be defined~\cite{Moss18}.
     16to be defined.~\cite{Moss18}
    1717\begin{cfa}
    1818char i; int i; double i;                        $\C[3.75in]{// variable overload}$
     
    4646pointers using the ampersand (@&@) instead of the pointer asterisk (@*@). \CFA
    4747references may also be mutable or non-mutable. If mutable, a reference variable
    48 may be assigned using the address-of operator (@&@), which converts the
     48may be assigned to using the address-of operator (@&@), which converts the
    4949reference to a pointer.
    5050\begin{cfa}
     
    5858\section{Constructors and Destructors}
    5959
    60 Both constructors and destructors are operators, which means they are
     60Both constructors and destructors are operators, which means they are just
    6161functions with special operator names rather than type names in \Cpp. The
    6262special operator names may be used to call the functions explicitly (not
     
    6464
    6565In general, operator names in \CFA are constructed by bracketing an operator
    66 token with @?@, which indicates the position of the arguments. For example, infixed
     66token with @?@, which indicates where the arguments. For example, infixed
    6767multiplication is @?*?@ while prefix dereference is @*?@. This syntax make it
    6868easy to tell the difference between prefix operations (such as @++?@) and
     
    8989definition, \CFA creates a default and copy constructor, destructor and
    9090assignment (like \Cpp). It is possible to define constructors/destructors for
    91 basic and existing types (unlike \Cpp).
     91basic and existing types.
    9292
    9393\section{Polymorphism}
     
    120120        do_once(value);
    121121}
    122 void do_once(@int@ i) { ... }  // provide assertion
    123 @int@ i;
     122void do_once(int i) { ... }  // provide assertion
     123int i;
    124124do_twice(i); // implicitly pass assertion do_once to do_twice
    125125\end{cfa}
     
    172172declarations instead of parameters, returns, and local variable declarations.
    173173\begin{cfa}
    174 forall(dtype @T@)
     174forall(dtype T)
    175175struct node {
    176         node(@T@) * next;  // generic linked node
    177         @T@ * data;
    178 }
    179 node(@int@) inode;
     176        node(T) * next;  // generic linked node
     177        T * data;
     178}
    180179\end{cfa}
    181180The generic type @node(T)@ is an example of a polymorphic-type usage.  Like \Cpp
    182 template usage, a polymorphic-type usage must specify a type parameter.
     181templates usage, a polymorphic-type usage must specify a type parameter.
    183182
    184183There are many other polymorphism features in \CFA but these are the ones used
    185184by the exception system.
    186185
    187 \section{Control Flow}
    188 \CFA has a number of advanced control-flow features: @generator@, @coroutine@, @monitor@, @mutex@ parameters, and @thread@.
    189 The two features that interact with
    190 the exception system are @coroutine@ and @thread@; they and their supporting
     186\section{Concurrency}
     187\CFA has a number of concurrency features: @thread@, @monitor@, @mutex@
     188parameters, @coroutine@ and @generator@. The two features that interact with
     189the exception system are @thread@ and @coroutine@; they and their supporting
    191190constructs are described here.
    192191
     
    217216CountUp countup;
    218217\end{cfa}
    219 Each coroutine has a @main@ function, which takes a reference to a coroutine
     218Each coroutine has @main@ function, which takes a reference to a coroutine
    220219object and returns @void@.
    221220\begin{cfa}[numbers=left]
     
    231230In this function, or functions called by this function (helper functions), the
    232231@suspend@ statement is used to return execution to the coroutine's caller
    233 without terminating the coroutine's function.
     232without terminating the coroutine.
    234233
    235234A coroutine is resumed by calling the @resume@ function, \eg @resume(countup)@.
     
    243242@resume(countup).next@.
    244243
    245 \subsection{Monitor and Mutex Parameter}
     244\subsection{Monitors and Mutex}
    246245Concurrency does not guarantee ordering; without ordering results are
    247246non-deterministic. To claw back ordering, \CFA uses monitors and @mutex@
     
    261260and only one runs at a time.
    262261
    263 \subsection{Thread}
     262\subsection{Threads}
    264263Functions, generators, and coroutines are sequential so there is only a single
    265264(but potentially sophisticated) execution path in a program. Threads introduce
     
    269268monitors and mutex parameters. For threads to work safely with other threads,
    270269also requires mutual exclusion in the form of a communication rendezvous, which
    271 also supports internal synchronization as for mutex objects. For exceptions,
    272 only two basic thread operations are important: fork and join.
     270also supports internal synchronization as for mutex objects. For exceptions
     271only the basic two basic operations are important: thread fork and join.
    273272
    274273Threads are created like coroutines with an associated @main@ function:
  • doc/theses/andrew_beach_MMath/features.tex

    r5407cdc rfeacef9  
    22
    33This chapter covers the design and user interface of the \CFA
    4 exception-handling mechanism (EHM). % or exception system.
    5 
    6 We will begin with an overview of EHMs in general. It is not a strict
    7 definition of all EHMs nor an exaustive list of all possible features.
    8 However it does cover the most common structure and features found in them.
    9 
    10 % We should cover what is an exception handling mechanism and what is an
    11 % exception before this. Probably in the introduction. Some of this could
    12 % move there.
    13 \paragraph{Raise / Handle}
    14 An exception operation has two main parts: raise and handle.
    15 These terms are sometimes also known as throw and catch but this work uses
    16 throw/catch as a particular kind of raise/handle.
    17 These are the two parts that the user will write themselves and may
    18 be the only two pieces of the EHM that have any syntax in the language.
    19 
    20 \subparagraph{Raise}
    21 The raise is the starting point for exception handling. It marks the beginning
    22 of exception handling by \newterm{raising} an excepion, which passes it to
    23 the EHM.
    24 
    25 Some well known examples include the @throw@ statements of \Cpp and Java and
    26 the \codePy{raise} statement from Python. In real systems a raise may preform
    27 some other work (such as memory management) but for the purposes of this
    28 overview that can be ignored.
    29 
    30 \subparagraph{Handle}
    31 The purpose of most exception operations is to run some user code to handle
    32 that exception. This code is given, with some other information, in a handler.
    33 
    34 A handler has three common features: the previously mentioned user code, a
    35 region of code they cover and an exception label/condition that matches
    36 certain exceptions.
    37 Only raises inside the covered region and raising exceptions that match the
    38 label can be handled by a given handler.
    39 Different EHMs will have different rules to pick a handler
    40 if multipe handlers could be used such as ``best match" or ``first found".
    41 
    42 The @try@ statements of \Cpp, Java and Python are common examples. All three
    43 also show another common feature of handlers, they are grouped by the covered
    44 region.
    45 
    46 \paragraph{Propagation}
    47 After an exception is raised comes what is usually the biggest step for the
    48 EHM: finding and setting up the handler. The propogation from raise to
    49 handler can be broken up into three different tasks: searching for a handler,
    50 matching against the handler and installing the handler.
    51 
    52 \subparagraph{Searching}
    53 The EHM begins by searching for handlers that might be used to handle
    54 the exception. Searching is usually independent of the exception that was
    55 thrown as it looks for handlers that have the raise site in their covered
    56 region.
    57 This includes handlers in the current function, as well as any in callers
    58 on the stack that have the function call in their covered region.
    59 
    60 \subparagraph{Matching}
    61 Each handler found has to be matched with the raised exception. The exception
    62 label defines a condition that be use used with exception and decides if
    63 there is a match or not.
    64 
    65 In languages where the first match is used this step is intertwined with
    66 searching, a match check is preformed immediately after the search finds
    67 a possible handler.
    68 
    69 \subparagraph{Installing}
    70 After a handler is chosen it must be made ready to run.
    71 The implementation can vary widely to fit with the rest of the
    72 design of the EHM. The installation step might be trivial or it could be
    73 the most expensive step in handling an exception. The latter tends to be the
    74 case when stack unwinding is involved.
    75 
    76 If a matching handler is not guarantied to be found the EHM will need a
    77 different course of action here in the cases where no handler matches.
    78 This is only required with unchecked exceptions as checked exceptions
    79 (such as in Java) can make than guaranty.
    80 This different action can also be installing a handler but it is usually an
    81 implicat and much more general one.
    82 
    83 \subparagraph{Hierarchy}
    84 A common way to organize exceptions is in a hierarchical structure.
    85 This is especially true in object-orientated languages where the
    86 exception hierarchy is a natural extension of the object hierarchy.
    87 
    88 Consider the following hierarchy of exceptions:
     4exception-handling mechanism.
     5
     6\section{Virtuals}
     7Virtual types and casts are not part of the exception system nor are they
     8required for an exception system. But an object-oriented style hierarchy is a
     9great way of organizing exceptions so a minimal virtual system has been added
     10to \CFA.
     11
     12The pattern of a simple hierarchy was borrowed from object-oriented
     13programming was chosen for several reasons.
     14The first is that it allows new exceptions to be added in user code
     15and in libraries independently of each other. Another is it allows for
     16different levels of exception grouping (all exceptions, all IO exceptions or
     17a particular IO exception). Also it also provides a simple way of passing
     18data back and forth across the throw.
     19
     20Virtual types and casts are not required for a basic exception-system but are
     21useful for advanced exception features. However, \CFA is not object-oriented so
     22there is no obvious concept of virtuals. Hence, to create advanced exception
     23features for this work, I needed to design and implement a virtual-like
     24system for \CFA.
     25
     26% NOTE: Maybe we should but less of the rational here.
     27Object-oriented languages often organized exceptions into a simple hierarchy,
     28\eg Java.
    8929\begin{center}
    90 \input{exception-hierarchy}
     30\setlength{\unitlength}{4000sp}%
     31\begin{picture}(1605,612)(2011,-1951)
     32\put(2100,-1411){\vector(1, 0){225}}
     33\put(3450,-1411){\vector(1, 0){225}}
     34\put(3550,-1411){\line(0,-1){225}}
     35\put(3550,-1636){\vector(1, 0){150}}
     36\put(3550,-1636){\line(0,-1){225}}
     37\put(3550,-1861){\vector(1, 0){150}}
     38\put(2025,-1490){\makebox(0,0)[rb]{\LstBasicStyle{exception}}}
     39\put(2400,-1460){\makebox(0,0)[lb]{\LstBasicStyle{arithmetic}}}
     40\put(3750,-1460){\makebox(0,0)[lb]{\LstBasicStyle{underflow}}}
     41\put(3750,-1690){\makebox(0,0)[lb]{\LstBasicStyle{overflow}}}
     42\put(3750,-1920){\makebox(0,0)[lb]{\LstBasicStyle{zerodivide}}}
     43\end{picture}%
    9144\end{center}
    92 
    93 A handler labelled with any given exception can handle exceptions of that
    94 type or any child type of that exception. The root of the exception hierarchy
    95 (here \codeC{exception}) acts as a catch-all, leaf types catch single types
    96 and the exceptions in the middle can be used to catch different groups of
    97 related exceptions.
    98 
    99 This system has some notable advantages, such as multiple levels of grouping,
    100 the ability for libraries to add new exception types and the isolation
    101 between different sub-hierarchies.
    102 This design is used in \CFA even though it is not a object-orientated
    103 language using different tools to create the hierarchy.
    104 
    105 % Could I cite the rational for the Python IO exception rework?
    106 
    107 \paragraph{Completion}
    108 After the handler has finished the entire exception operation has to complete
    109 and continue executing somewhere else. This step is usually simple,
    110 both logically and in its implementation, as the installation of the handler
    111 is usually set up to do most of the work.
    112 
    113 The EHM can return control to many different places,
    114 the most common are after the handler definition and after the raise.
    115 
    116 \paragraph{Communication}
    117 For effective exception handling, additional information is usually passed
    118 from the raise to the handler.
    119 So far only communication of the exceptions' identity has been covered.
    120 A common method is putting fields into the exception instance and giving the
    121 handler access to them.
    122 
    123 \section{Virtuals}
    124 Virtual types and casts are not part of \CFA's EHM nor are they required for
    125 any EHM. But \CFA uses a hierarchial system of exceptions and this feature
    126 is leveraged to create that.
    127 
    128 % Maybe talk about why the virtual system is so minimal.
    129 % Created for but not a part of the exception system.
    130 
    131 The virtual system supports multiple ``trees" of types. Each tree is
    132 a simple hierarchy with a single root type. Each type in a tree has exactly
    133 one parent -- except for the root type which has zero parents -- and any
    134 number of children.
    135 Any type that belongs to any of these trees is called a virtual type.
    136 
    137 % A type's ancestors are its parent and its parent's ancestors.
    138 % The root type has no ancestors.
    139 % A type's decendents are its children and its children's decendents.
    140 
    141 Every virtual type also has a list of virtual members. Children inherit
    142 their parent's list of virtual members but may add new members to it.
    143 It is important to note that these are virtual members, not virtual methods
    144 of object-orientated programming, and can be of any type.
    145 However, since \CFA has function pointers and they are allowed, virtual
    146 members can be used to mimic virtual methods.
    147 
    148 Each virtual type has a unique id.
    149 This unique id and all the virtual members are combined
    150 into a virtual table type. Each virtual type has a pointer to a virtual table
    151 as a hidden field.
    152 
    153 Up until this point the virtual system is similar to ones found in
    154 object-orientated languages but this where \CFA diverges. Objects encapsulate a
    155 single set of behaviours in each type, universally across the entire program,
    156 and indeed all programs that use that type definition. In this sense the
    157 types are ``closed" and cannot be altered.
    158 
    159 In \CFA types do not encapsulate any behaviour. Traits are local and
    160 types can begin to statify a trait, stop satifying a trait or satify the same
    161 trait in a different way at any lexical location in the program.
    162 In this sense they are ``open" as they can change at any time. This means it
    163 is implossible to pick a single set of functions that repersent the type's
    164 implementation across the program.
    165 
    166 \CFA side-steps this issue by not having a single virtual table for each
    167 type. A user can define virtual tables which are filled in at their
    168 declaration and given a name. Anywhere that name is visible, even if it was
    169 defined locally inside a function (although that means it will not have a
    170 static lifetime), it can be used.
    171 Specifically, a virtual type is ``bound" to a virtual table which
    172 sets the virtual members for that object. The virtual members can be accessed
    173 through the object.
     45The hierarchy provides the ability to handle an exception at different degrees
     46of specificity (left to right). Hence, it is possible to catch a more general
     47exception-type in higher-level code where the implementation details are
     48unknown, which reduces tight coupling to the lower-level implementation.
     49Otherwise, low-level code changes require higher-level code changes, \eg,
     50changing from raising @underflow@ to @overflow@ at the low level means changing
     51the matching catch at the high level versus catching the general @arithmetic@
     52exception. In detail, each virtual type may have a parent and can have any
     53number of children. A type's descendants are its children and its children's
     54descendants. A type may not be its own descendant.
     55
     56The exception hierarchy allows a handler (@catch@ clause) to match multiple
     57exceptions, \eg a base-type handler catches both base and derived
     58exception-types.
     59\begin{cfa}
     60try {
     61        ...
     62} catch(arithmetic &) {
     63        ... // handle arithmetic, underflow, overflow, zerodivide
     64}
     65\end{cfa}
     66Most exception mechanisms perform a linear search of the handlers and select
     67the first matching handler, so the order of handers is now important because
     68matching is many to one.
     69
     70Each virtual type needs an associated virtual table. A virtual table is a
     71structure with fields for all the virtual members of a type. A virtual type has
     72all the virtual members of its parent and can add more. It may also update the
     73values of the virtual members and often does.
    17474
    17575While much of the virtual infrastructure is created, it is currently only used
     
    18383\Cpp syntax for special casts. Both the type of @EXPRESSION@ and @TYPE@ must be
    18484a pointer to a virtual type.
    185 The cast dynamically checks if the @EXPRESSION@ type is the same or a sub-type
     85The cast dynamically checks if the @EXPRESSION@ type is the same or a subtype
    18686of @TYPE@, and if true, returns a pointer to the
    18787@EXPRESSION@ object, otherwise it returns @0p@ (null pointer).
     
    201101\end{cfa}
    202102The trait is defined over two types, the exception type and the virtual table
    203 type. This should be one-to-one: each exception type has only one virtual
     103type. This should be one-to-one, each exception type has only one virtual
    204104table type and vice versa. The only assertion in the trait is
    205105@get_exception_vtable@, which takes a pointer of the exception type and
    206106returns a reference to the virtual table type instance.
    207107
    208 % TODO: This section, and all references to get_exception_vtable, are
    209 % out-of-data. Perhaps wait until the update is finished before rewriting it.
    210108The function @get_exception_vtable@ is actually a constant function.
    211 Regardless of the value passed in (including the null pointer) it should
     109Recardless of the value passed in (including the null pointer) it should
    212110return a reference to the virtual table instance for that type.
    213111The reason it is a function instead of a constant is that it make type
     
    221119% similar system I know of (except Agda's I guess) so I took it out.
    222120
    223 There are two more traits for exceptions defined as follows:
     121There are two more traits for exceptions @is_termination_exception@ and
     122@is_resumption_exception@. They are defined as follows:
     123
    224124\begin{cfa}
    225125trait is_termination_exception(
     
    233133};
    234134\end{cfa}
    235 Both traits ensure a pair of types are an exception type and its virtual table
    236 and defines one of the two default handlers. The default handlers are used
    237 as fallbacks and are discussed in detail in \VRef{s:ExceptionHandling}.
    238 
    239 However, all three of these traits can be tricky to use directly.
    240 While there is a bit of repetition required,
     135
     136In other words they make sure that a given type and virtual type is an
     137exception and defines one of the two default handlers. These default handlers
     138are used in the main exception handling operations \see{Exception Handling}
     139and their use will be detailed there.
     140
     141However all three of these traits can be trickly to use directly.
     142There is a bit of repetition required but
    241143the largest issue is that the virtual table type is mangled and not in a user
    242 facing way. So these three macros are provided to wrap these traits to
    243 simplify referring to the names:
     144facing way. So there are three macros that can be used to wrap these traits
     145when you need to refer to the names:
    244146@IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@ and @IS_RESUMPTION_EXCEPTION@.
    245147
    246 All three take one or two arguments. The first argument is the name of the
    247 exception type. The macro passes its unmangled and mangled form to the trait.
     148All take one or two arguments. The first argument is the name of the
     149exception type. Its unmangled and mangled form are passed to the trait.
    248150The second (optional) argument is a parenthesized list of polymorphic
    249 arguments. This argument is only used with polymorphic exceptions and the
    250 list is be passed to both types.
    251 In the current set-up, the two types always have the same polymorphic
    252 arguments so these macros can be used without losing flexibility.
     151arguments. This argument should only with polymorphic exceptions and the
     152list will be passed to both types.
     153In the current set-up the base name and the polymorphic arguments have to
     154match so these macros can be used without losing flexability.
    253155
    254156For example consider a function that is polymorphic over types that have a
     
    260162
    261163\section{Exception Handling}
    262 \label{s:ExceptionHandling}
    263 \CFA provides two kinds of exception handling: termination and resumption.
    264 These twin operations are the core of \CFA's exception handling mechanism.
     164\CFA provides two kinds of exception handling, termination and resumption.
     165These twin operations are the core of the exception handling mechanism and
     166are the reason for the features of exceptions.
    265167This section will cover the general patterns shared by the two operations and
    266168then go on to cover the details each individual operation.
    267169
    268 Both operations follow the same set of steps.
    269 Both start with the user preforming a raise on an exception.
    270 Then the exception propogates up the stack.
    271 If a handler is found the exception is caught and the handler is run.
    272 After that control returns to normal execution.
     170Both operations follow the same set of steps to do their operation. They both
     171start with the user preforming a throw on an exception.
     172Then there is the search for a handler, if one is found than the exception
     173is caught and the handler is run. After that control returns to normal
     174execution.
     175
    273176If the search fails a default handler is run and then control
    274 returns to normal execution after the raise.
    275 
    276 This general description covers what the two kinds have in common.
    277 Differences include how propogation is preformed, where exception continues
    278 after an exception is caught and handled and which default handler is run.
     177returns to normal execution immediately. That is where the default handlers
     178@defaultTermiationHandler@ and @defaultResumptionHandler@ are used.
    279179
    280180\subsection{Termination}
    281181\label{s:Termination}
    282 Termination handling is the familiar kind and used in most programming
     182
     183Termination handling is more familiar kind and used in most programming
    283184languages with exception handling.
    284 It is dynamic, non-local goto. If the raised exception is matched and
    285 handled the stack is unwound and control will (usually) continue the function
    286 on the call stack that defined the handler.
    287 Termination is commonly used when an error has occurred and recovery is
    288 impossible locally.
     185It is dynamic, non-local goto. If a throw is successful then the stack will
     186be unwound and control will (usually) continue in a different function on
     187the call stack. They are commonly used when an error has occured and recovery
     188is impossible in the current function.
    289189
    290190% (usually) Control can continue in the current function but then a different
    291191% control flow construct should be used.
    292192
    293 A termination raise is started with the @throw@ statement:
     193A termination throw is started with the @throw@ statement:
    294194\begin{cfa}
    295195throw EXPRESSION;
    296196\end{cfa}
    297197The expression must return a reference to a termination exception, where the
    298 termination exception is any type that satisfies the trait
    299 @is_termination_exception@ at the call site.
    300 Through \CFA's trait system the trait functions are implicity passed into the
    301 throw code and the EHM.
    302 A new @defaultTerminationHandler@ can be defined in any scope to
     198termination exception is any type that satifies @is_termination_exception@
     199at the call site.
     200Through \CFA's trait system the functions in the traits are passed into the
     201throw code. A new @defaultTerminationHandler@ can be defined in any scope to
    303202change the throw's behavior (see below).
    304203
    305 The throw will copy the provided exception into managed memory to ensure
    306 the exception is not destroyed if the stack is unwound.
    307 It is the user's responsibility to ensure the original exception is cleaned
    308 up wheither the stack is unwound or not. Allocating it on the stack is
    309 usually sufficient.
    310 
    311 Then propogation starts with the search. \CFA uses a ``first match" rule so
    312 matching is preformed with the copied exception as the search continues.
    313 It starts from the throwing function and proceeds to the base of the stack,
     204The throw will copy the provided exception into managed memory. It is the
     205user's responcibility to ensure the original exception is cleaned up if the
     206stack is unwound (allocating it on the stack should be sufficient).
     207
     208Then the exception system searches the stack using the copied exception.
     209It starts starts from the throw and proceeds to the base of the stack,
    314210from callee to caller.
    315211At each stack frame, a check is made for resumption handlers defined by the
     
    318214try {
    319215        GUARDED_BLOCK
    320 } catch (EXCEPTION_TYPE$\(_1\)$ * [NAME$\(_1\)$]) {
     216} catch (EXCEPTION_TYPE$\(_1\)$ * NAME$\(_1\)$) {
    321217        HANDLER_BLOCK$\(_1\)$
    322 } catch (EXCEPTION_TYPE$\(_2\)$ * [NAME$\(_2\)$]) {
     218} catch (EXCEPTION_TYPE$\(_2\)$ * NAME$\(_2\)$) {
    323219        HANDLER_BLOCK$\(_2\)$
    324220}
    325221\end{cfa}
    326 When viewed on its own, a try statement will simply execute the statements
    327 in @GUARDED_BLOCK@ and when those are finished the try statement finishes.
     222When viewed on its own a try statement will simply exceute the statements in
     223@GUARDED_BLOCK@ and when those are finished the try statement finishes.
    328224
    329225However, while the guarded statements are being executed, including any
    330 invoked functions, all the handlers in the statement are now on the search
    331 path. If a termination exception is thrown and not handled further up the
    332 stack they will be matched against the exception.
    333 
    334 Exception matching checks the handler in each catch clause in the order
    335 they appear, top to bottom. If the representation of the thrown exception type
    336 is the same or a descendant of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$
    337 (if provided) is
     226functions they invoke, all the handlers following the try block are now
     227or any functions invoked from those
     228statements, throws an exception, and the exception
     229is not handled by a try statement further up the stack, the termination
     230handlers are searched for a matching exception type from top to bottom.
     231
     232Exception matching checks the representation of the thrown exception-type is
     233the same or a descendant type of the exception types in the handler clauses. If
     234it is the same of a descendent of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$ is
    338235bound to a pointer to the exception and the statements in @HANDLER_BLOCK@$_i$
    339236are executed. If control reaches the end of the handler, the exception is
    340237freed and control continues after the try statement.
    341238
    342 If no termination handler is found during the search then the default handler
    343 (@defaultTerminationHandler@) is run.
     239If no handler is found during the search then the default handler is run.
    344240Through \CFA's trait system the best match at the throw sight will be used.
    345241This function is run and is passed the copied exception. After the default
    346242handler is run control continues after the throw statement.
    347243
    348 There is a global @defaultTerminationHandler@ that is polymorphic over all
    349 exception types. Since it is so general a more specific handler can be
    350 defined and will be used for those types, effectively overriding the handler
    351 for particular exception type.
    352 The global default termination handler performs a cancellation
    353 \see{\VRef{s:Cancellation}} on the current stack with the copied exception.
     244There is a global @defaultTerminationHandler@ that cancels the current stack
     245with the copied exception. However it is generic over all exception types so
     246new default handlers can be defined for different exception types and so
     247different exception types can have different default handlers.
    354248
    355249\subsection{Resumption}
    356250\label{s:Resumption}
    357251
    358 Resumption exception handling is less common than termination but is
    359 just as old~\cite{Goodenough75} and is simpler in many ways.
    360 It is a dynamic, non-local function call. If the raised exception is
    361 matched a closure will be taken from up the stack and executed,
    362 after which the raising function will continue executing.
    363 These are most often used when an error occurred and if the error is repaired
     252Resumption exception handling is a less common form than termination but is
     253just as old~\cite{Goodenough75} and is in some sense simpler.
     254It is a dynamic, non-local function call. If the throw is successful a
     255closure will be taken from up the stack and executed, after which the throwing
     256function will continue executing.
     257These are most often used when an error occured and if the error is repaired
    364258then the function can continue.
    365259
     
    368262throwResume EXPRESSION;
    369263\end{cfa}
    370 It works much the same way as the termination throw.
    371 The expression must return a reference to a resumption exception,
    372 where the resumption exception is any type that satisfies the trait
    373 @is_resumption_exception@ at the call site.
    374 The assertions from this trait are available to
     264The semantics of the @throwResume@ statement are like the @throw@, but the
     265expression has return a reference a type that satifies the trait
     266@is_resumption_exception@. The assertions from this trait are available to
    375267the exception system while handling the exception.
    376268
    377 At run-time, no exception copy is made.
    378 As the stack is not unwound the exception and
     269At runtime, no copies are made. As the stack is not unwound the exception and
    379270any values on the stack will remain in scope while the resumption is handled.
    380271
    381 The EHM then begins propogation. The search starts from the raise in the
    382 resuming function and proceeds to the base of the stack, from callee to caller.
     272Then the exception system searches the stack using the provided exception.
     273It starts starts from the throw and proceeds to the base of the stack,
     274from callee to caller.
    383275At each stack frame, a check is made for resumption handlers defined by the
    384276@catchResume@ clauses of a @try@ statement.
     
    386278try {
    387279        GUARDED_BLOCK
    388 } catchResume (EXCEPTION_TYPE$\(_1\)$ * [NAME$\(_1\)$]) {
     280} catchResume (EXCEPTION_TYPE$\(_1\)$ * NAME$\(_1\)$) {
    389281        HANDLER_BLOCK$\(_1\)$
    390 } catchResume (EXCEPTION_TYPE$\(_2\)$ * [NAME$\(_2\)$]) {
     282} catchResume (EXCEPTION_TYPE$\(_2\)$ * NAME$\(_2\)$) {
    391283        HANDLER_BLOCK$\(_2\)$
    392284}
    393285\end{cfa}
    394 % I wonder if there would be some good central place for this.
    395 Note that termination handlers and resumption handlers may be used together
    396 in a single try statement, intermixing @catch@ and @catchResume@ freely.
    397 Each type of handler will only interact with exceptions from the matching
    398 type of raise.
    399 When a try statement is executed it simply executes the statements in the
    400 @GUARDED_BLOCK@ and then finishes.
    401 
    402 However, while the guarded statements are being executed, including any
    403 invoked functions, all the handlers in the statement are now on the search
    404 path. If a resumption exception is reported and not handled further up the
    405 stack they will be matched against the exception.
    406 
    407 Exception matching checks the handler in each catch clause in the order
    408 they appear, top to bottom. If the representation of the thrown exception type
    409 is the same or a descendant of @EXCEPTION_TYPE@$_i$ then @NAME@$_i$
    410 (if provided) is bound to a pointer to the exception and the statements in
    411 @HANDLER_BLOCK@$_i$ are executed.
    412 If control reaches the end of the handler, execution continues after the
    413 the raise statement that raised the handled exception.
     286If the handlers are not involved in a search this will simply execute the
     287@GUARDED_BLOCK@ and then continue to the next statement.
     288Its purpose is to add handlers onto the stack.
     289(Note, termination and resumption handlers may be intermixed in a @try@
     290statement but the kind of throw must be the same as the handler for it to be
     291considered as a possible match.)
     292
     293If a search for a resumption handler reaches a try block it will check each
     294@catchResume@ clause, top-to-bottom.
     295At each handler if the thrown exception is or is a child type of
     296@EXCEPTION_TYPE@$_i$ then the a pointer to the exception is bound to
     297@NAME@$_i$ and then @HANDLER_BLOCK@$_i$ is executed. After the block is
     298finished control will return to the @throwResume@ statement.
    414299
    415300Like termination, if no resumption handler is found, the default handler
     
    417302call sight according to \CFA's overloading rules. The default handler is
    418303passed the exception given to the throw. When the default handler finishes
    419 execution continues after the raise statement.
     304execution continues after the throw statement.
    420305
    421306There is a global @defaultResumptionHandler@ is polymorphic over all
    422307termination exceptions and preforms a termination throw on the exception.
    423 The @defaultTerminationHandler@ for that raise is matched at the original
    424 raise statement (the resumption @throwResume@) and it can be customized by
     308The @defaultTerminationHandler@ for that throw is matched at the original
     309throw statement (the resumption @throwResume@) and it can be customized by
    425310introducing a new or better match as well.
    426311
    427 \subsubsection{Resumption Marking}
     312% \subsubsection?
     313
    428314A key difference between resumption and termination is that resumption does
    429315not unwind the stack. A side effect that is that when a handler is matched
     
    445331search and match the handler in the @catchResume@ clause. This will be
    446332call and placed on the stack on top of the try-block. The second throw then
    447 throws and will search the same try block and put call another instance of the
     333throws and will seach the same try block and put call another instance of the
    448334same handler leading to an infinite loop.
    449335
     
    451337can form with multiple handlers and different exception types.
    452338
    453 To prevent all of these cases we mark try statements on the stack.
    454 A try statement is marked when a match check is preformed with it and an
    455 exception. The statement will be unmarked when the handling of that exception
    456 is completed or the search completes without finding a handler.
    457 While a try statement is marked its handlers are never matched, effectify
    458 skipping over it to the next try statement.
    459 
    460 \begin{center}
    461 \input{stack-marking}
    462 \end{center}
    463 
    464 These rules mirror what happens with termination.
    465 When a termination throw happens in a handler the search will not look at
    466 any handlers from the original throw to the original catch because that
    467 part of the stack has been unwound.
    468 A resumption raise in the same situation wants to search the entire stack,
    469 but it will not try to match the exception with try statements in the section
    470 that would have been unwound as they are marked.
    471 
    472 The symmetry between resumption termination is why this pattern was picked.
    473 Other patterns, such as marking just the handlers that caught, also work but
    474 lack the symmetry means there are less rules to remember.
     339To prevent all of these cases we mask sections of the stack, or equvilantly
     340the try statements on the stack, so that the resumption seach skips over
     341them and continues with the next unmasked section of the stack.
     342
     343A section of the stack is marked when it is searched to see if it contains
     344a handler for an exception and unmarked when that exception has been handled
     345or the search was completed without finding a handler.
     346
     347% This might need a diagram. But it is an important part of the justification
     348% of the design of the traversal order.
     349\begin{verbatim}
     350       throwResume2 ----------.
     351            |                 |
     352 generated from handler       |
     353            |                 |
     354         handler              |
     355            |                 |
     356        throwResume1 -----.   :
     357            |             |   :
     358           try            |   : search skip
     359            |             |   :
     360        catchResume  <----'   :
     361            |                 |
     362\end{verbatim}
     363
     364The rules can be remembered as thinking about what would be searched in
     365termination. So when a throw happens in a handler; a termination handler
     366skips everything from the original throw to the original catch because that
     367part of the stack has been unwound, a resumption handler skips the same
     368section of stack because it has been masked.
     369A throw in a default handler will preform the same search as the original
     370throw because; for termination nothing has been unwound, for resumption
     371the mask will be the same.
     372
     373The symmetry with termination is why this pattern was picked. Other patterns,
     374such as marking just the handlers that caught, also work but lack the
     375symmetry whih means there is more to remember.
    475376
    476377\section{Conditional Catch}
     
    478379condition to further control which exceptions they handle:
    479380\begin{cfa}
    480 catch (EXCEPTION_TYPE * [NAME] ; CONDITION)
     381catch (EXCEPTION_TYPE * NAME ; CONDITION)
    481382\end{cfa}
    482383First, the same semantics is used to match the exception type. Second, if the
     
    486387matches. Otherwise, the exception search continues as if the exception type
    487388did not match.
    488 
    489 The condition matching allows finer matching by allowing the match to check
    490 more kinds of information than just the exception type.
    491 \begin{cfa}
    492 try {
    493         handle1 = open( f1, ... );
    494         handle2 = open( f2, ... );
    495         handle3 = open( f3, ... );
     389\begin{cfa}
     390try {
     391        f1 = open( ... );
     392        f2 = open( ... );
    496393        ...
    497394} catch( IOFailure * f ; fd( f ) == f1 ) {
    498         // Only handle IO failure for f1.
    499 } catch( IOFailure * f ; fd( f ) == f3 ) {
    500         // Only handle IO failure for f3.
    501 }
    502 // Can't handle a failure relating to f2 here.
    503 \end{cfa}
    504 In this example the file that experianced the IO error is used to decide
    505 which handler should be run, if any at all.
    506 
    507 \begin{comment}
    508 % I know I actually haven't got rid of them yet, but I'm going to try
    509 % to write it as if I had and see if that makes sense:
    510 \section{Reraising}
    511 \label{s:Reraising}
     395        // only handle IO failure for f1
     396}
     397\end{cfa}
     398Note, catching @IOFailure@, checking for @f1@ in the handler, and reraising the
     399exception if not @f1@ is different because the reraise does not examine any of
     400remaining handlers in the current try statement.
     401
     402\section{Rethrowing}
     403\colour{red}{From Andrew: I recomend we talk about why the language doesn't
     404have rethrows/reraises instead.}
     405
     406\label{s:Rethrowing}
    512407Within the handler block or functions called from the handler block, it is
    513408possible to reraise the most recently caught exception with @throw@ or
     
    528423is part of an unwound stack frame. To prevent this problem, a new default
    529424handler is generated that does a program-level abort.
    530 \end{comment}
    531 
    532 \subsection{Comparison with Reraising}
    533 A more popular way to allow handlers to match in more detail is to reraise
    534 the exception after it has been caught if it could not be handled here.
    535 On the surface these two features seem interchangable.
    536 
    537 If we used @throw;@ to start a termination reraise then these two statements
    538 would have the same behaviour:
    539 \begin{cfa}
    540 try {
    541     do_work_may_throw();
    542 } catch(exception_t * exc ; can_handle(exc)) {
    543     handle(exc);
    544 }
    545 \end{cfa}
    546 
    547 \begin{cfa}
    548 try {
    549     do_work_may_throw();
    550 } catch(exception_t * exc) {
    551     if (can_handle(exc)) {
    552         handle(exc);
    553     } else {
    554         throw;
    555     }
    556 }
    557 \end{cfa}
    558 If there are further handlers after this handler only the first version will
    559 check them. If multiple handlers on a single try block could handle the same
    560 exception the translations get more complex but they are equivilantly
    561 powerful.
    562 
    563 Until stack unwinding comes into the picture. In termination handling, a
    564 conditional catch happens before the stack is unwound, but a reraise happens
    565 afterwards. Normally this might only cause you to loose some debug
    566 information you could get from a stack trace (and that can be side stepped
    567 entirely by collecting information during the unwind). But for \CFA there is
    568 another issue, if the exception isn't handled the default handler should be
    569 run at the site of the original raise.
    570 
    571 There are two problems with this: the site of the original raise doesn't
    572 exist anymore and the default handler might not exist anymore. The site will
    573 always be removed as part of the unwinding, often with the entirety of the
    574 function it was in. The default handler could be a stack allocated nested
    575 function removed during the unwind.
    576 
    577 This means actually trying to pretend the catch didn't happening, continuing
    578 the original raise instead of starting a new one, is infeasible.
    579 That is the expected behaviour for most languages and we can't replicate
    580 that behaviour.
    581425
    582426\section{Finally Clauses}
    583 \label{s:FinallyClauses}
    584427Finally clauses are used to preform unconditional clean-up when leaving a
    585 scope and are placed at the end of a try statement after any handler clauses:
     428scope. They are placed at the end of a try statement:
    586429\begin{cfa}
    587430try {
     
    599442
    600443Execution of the finally block should always finish, meaning control runs off
    601 the end of the block. This requirement ensures control always continues as if
    602 the finally clause is not present, \ie finally is for cleanup not changing
    603 control flow.
    604 Because of this requirement, local control flow out of the finally block
     444the end of the block. This requirement ensures always continues as if the
     445finally clause is not present, \ie finally is for cleanup not changing control
     446flow. Because of this requirement, local control flow out of the finally block
    605447is forbidden. The compiler precludes any @break@, @continue@, @fallthru@ or
    606448@return@ that causes control to leave the finally block. Other ways to leave
    607449the finally block, such as a long jump or termination are much harder to check,
    608 and at best requiring additional run-time overhead, and so are only
     450and at best requiring additional run-time overhead, and so are mearly
    609451discouraged.
    610452
    611 Not all languages with unwinding have finally clauses. Notably \Cpp does
     453Not all languages with exceptions have finally clauses. Notably \Cpp does
    612454without it as descructors serve a similar role. Although destructors and
    613455finally clauses can be used in many of the same areas they have their own
    614456use cases like top-level functions and lambda functions with closures.
    615457Destructors take a bit more work to set up but are much easier to reuse while
    616 finally clauses are good for one-off uses and
    617 can easily include local information.
     458finally clauses are good for once offs and can include local information.
    618459
    619460\section{Cancellation}
    620 \label{s:Cancellation}
    621461Cancellation is a stack-level abort, which can be thought of as as an
    622 uncatchable termination. It unwinds the entire current stack, and if
     462uncatchable termination. It unwinds the entirety of the current stack, and if
    623463possible forwards the cancellation exception to a different stack.
    624464
     
    626466There is no special statement for starting a cancellation; instead the standard
    627467library function @cancel_stack@ is called passing an exception. Unlike a
    628 raise, this exception is not used in matching only to pass information about
     468throw, this exception is not used in matching only to pass information about
    629469the cause of the cancellation.
    630 (This also means matching cannot fail so there is no default handler.)
    631 
    632 After @cancel_stack@ is called the exception is copied into the EHM's memory
    633 and the current stack is
     470(This also means matching cannot fail so there is no default handler either.)
     471
     472After @cancel_stack@ is called the exception is copied into the exception
     473handling mechanism's memory. Then the entirety of the current stack is
    634474unwound. After that it depends one which stack is being cancelled.
    635475\begin{description}
    636476\item[Main Stack:]
    637477The main stack is the one used by the program main at the start of execution,
    638 and is the only stack in a sequential program.
    639 After the main stack is unwound there is a program-level abort.
    640 
    641 There are two reasons for this. The first is that it obviously had to do this
    642 in a sequential program as there is nothing else to notify and the simplicity
    643 of keeping the same behaviour in sequential and concurrent programs is good.
    644 Also, even in concurrent programs there is no stack that an innate connection
    645 to, so it would have be explicitly managed.
     478and is the only stack in a sequential program. Even in a concurrent program
     479the main stack is only dependent on the environment that started the program.
     480Hence, when the main stack is cancelled there is nowhere else in the program
     481to notify. After the stack is unwound, there is a program-level abort.
    646482
    647483\item[Thread Stack:]
    648 A thread stack is created for a \CFA @thread@ object or object that satisfies
    649 the @is_thread@ trait.
    650 After a thread stack is unwound there exception is stored until another
    651 thread attempts to join with it. Then the exception @ThreadCancelled@,
    652 which stores a reference to the thread and to the exception passed to the
    653 cancellation, is reported from the join.
    654 There is one difference between an explicit join (with the @join@ function)
    655 and an implicit join (from a destructor call). The explicit join takes the
    656 default handler (@defaultResumptionHandler@) from its calling context while
    657 the implicit join provides its own which does a program abort if the
    658 @ThreadCancelled@ exception cannot be handled.
    659 
    660 Communication is done at join because a thread only has to have to points of
    661 communication with other threads: start and join.
    662 Since a thread must be running to perform a cancellation (and cannot be
    663 cancelled from another stack), the cancellation must be after start and
    664 before the join. So join is the one that we will use.
    665 
    666 % TODO: Find somewhere to discuss unwind collisions.
    667 The difference between the explicit and implicit join is for safety and
    668 debugging. It helps prevent unwinding collisions by avoiding throwing from
    669 a destructor and prevents cascading the error across multiple threads if
    670 the user is not equipped to deal with it.
    671 Also you can always add an explicit join if that is the desired behaviour.
    672 
    673 \item[Coroutine Stack:]
    674 A coroutine stack is created for a @coroutine@ object or object that
    675 satisfies the @is_coroutine@ trait.
    676 After a coroutine stack is unwound control returns to the resume function
    677 that most recently resumed it. The resume statement reports a
    678 @CoroutineCancelled@ exception, which contains a references to the cancelled
    679 coroutine and the exception used to cancel it.
    680 The resume function also takes the @defaultResumptionHandler@ from the
    681 caller's context and passes it to the internal report.
    682 
    683 A coroutine knows of two other coroutines, its starter and its last resumer.
    684 The starter has a much more distant connection while the last resumer just
    685 (in terms of coroutine state) called resume on this coroutine, so the message
    686 is passed to the latter.
     484A thread stack is created for a @thread@ object or object that satisfies the
     485@is_thread@ trait. A thread only has two points of communication that must
     486happen: start and join. As the thread must be running to perform a
     487cancellation, it must occur after start and before join, so join is used
     488for communication here.
     489After the stack is unwound, the thread halts and waits for
     490another thread to join with it. The joining thread checks for a cancellation,
     491and if present, resumes exception @ThreadCancelled@.
     492
     493There is a subtle difference between the explicit join (@join@ function) and
     494implicit join (from a destructor call). The explicit join takes the default
     495handler (@defaultResumptionHandler@) from its calling context, which is used if
     496the exception is not caught. The implicit join does a program abort instead.
     497
     498This semantics is for safety. If an unwind is triggered while another unwind
     499is underway only one of them can proceed as they both want to ``consume'' the
     500stack. Letting both try to proceed leads to very undefined behaviour.
     501Both termination and cancellation involve unwinding and, since the default
     502@defaultResumptionHandler@ preforms a termination that could more easily
     503happen in an implicate join inside a destructor. So there is an error message
     504and an abort instead.
     505\todo{Perhaps have a more general disucssion of unwind collisions before
     506this point.}
     507
     508The recommended way to avoid the abort is to handle the intial resumption
     509from the implicate join. If required you may put an explicate join inside a
     510finally clause to disable the check and use the local
     511@defaultResumptionHandler@ instead.
     512
     513\item[Coroutine Stack:] A coroutine stack is created for a @coroutine@ object
     514or object that satisfies the @is_coroutine@ trait. A coroutine only knows of
     515two other coroutines, its starter and its last resumer. Of the two the last
     516resumer has the tightest coupling to the coroutine it activated and the most
     517up-to-date information.
     518
     519Hence, cancellation of the active coroutine is forwarded to the last resumer
     520after the stack is unwound. When the resumer restarts, it resumes exception
     521@CoroutineCancelled@, which is polymorphic over the coroutine type and has a
     522pointer to the cancelled coroutine.
     523
     524The resume function also has an assertion that the @defaultResumptionHandler@
     525for the exception. So it will use the default handler like a regular throw.
    687526\end{description}
  • doc/theses/andrew_beach_MMath/future.tex

    r5407cdc rfeacef9  
    8383patterns to find the handler.
    8484
    85 \section{Checked Exceptions}
    86 Checked exceptions make exceptions part of a function's type by adding the
    87 exception signature. An exception signature must declare all checked
    88 exceptions that could propogate from the function (either because they were
    89 raised inside the function or came from a sub-function). This improves safety
    90 by making sure every checked exception is either handled or consciously
    91 passed on.
    92 
    93 However checked exceptions were never seriously considered for this project
    94 for two reasons. The first is due to time constraints, even copying an
    95 existing checked exception system would be pushing the remaining time and
    96 trying to address the second problem would take even longer. The second
    97 problem is that checked exceptions have some real usability trade-offs in
    98 exchange for the increased safety.
    99 
    100 These trade-offs are most problematic when trying to pass exceptions through
    101 higher-order functions from the functions the user passed into the
    102 higher-order function. There are no well known solutions to this problem
    103 that were statifactory for \CFA (which carries some of C's flexability
    104 over safety design) so one would have to be researched and developed.
    105 
    106 Follow-up work might add checked exceptions to \CFA, possibly using
    107 polymorphic exception signatures, a form of tunneling\cite{Zhang19} or
    108 checked and unchecked raises.
    109 
    11085\section{Zero-Cost Try}
    11186\CFA does not have zero-cost try-statements because the compiler generates C
  • doc/theses/andrew_beach_MMath/implement.tex

    r5407cdc rfeacef9  
    1313library.
    1414
    15 \subsection{Virtual Type}
    16 Virtual types only have one change to their structure, the addition of a
    17 pointer to the virtual table. This is always the first field so that
    18 if it is cast to a supertype the field's location is still known.
    19 
    20 This field is set as part of all new generated constructors.
    21 \todo{They only come as part exceptions and don't work.}
    22 After the object is created the field is constant.
    23 
    24 However it can be read from, internally it is just a regular field called
    25 @virtual_table@. Dereferencing it gives the virtual table and access to the
    26 type's virtual members.
    27 
    2815\subsection{Virtual Table}
    29 Every time a virtual type is defined the new virtual table type must also be
    30 defined.
    31 
    32 The unique instance is important because the address of the virtual table
    33 instance is used as the identifier for the virtual type. So a pointer to the
    34 virtual table and the ID for the virtual type are interchangable.
    35 \todo{Unique instances might be going so we will have to talk about the new
    36 system instead.}
    37 
    38 The first step in putting it all together is to create the virtual table type.
    39 The virtual table type is just a structure and can be described in terms of
    40 its fields. The first field is always the parent type ID (or a pointer to
    41 the parent virtual table) or 0 (the null pointer).
    42 Next are other fields on the parent virtual table are repeated.
    43 Finally are the fields used to store any new virtual members of the new
    44 The virtual type
    45 
    4616The virtual system is accessed through a private constant field inserted at the
    4717beginning of every virtual type, called the virtual-table pointer. This field
    4818points at a type's virtual table and is assigned during the object's
    49 construction. The address of a virtual table acts as the unique identifier for
     19construction.  The address of a virtual table acts as the unique identifier for
    5020the virtual type, and the first field of a virtual table is a pointer to the
    51 parent virtual-table or @0p@. The remaining fields are duplicated from the
     21parent virtual-table or @0p@.  The remaining fields are duplicated from the
    5222parent tables in this type's inheritance chain, followed by any fields this type
    53 introduces. Parent fields are duplicated so they can be changed (all virtual
    54 members are overridable), so that references to the dispatched type
     23introduces. Parent fields are duplicated so they can be changed (\CC
     24\lstinline[language=c++]|override|), so that references to the dispatched type
    5525are replaced with the current virtual type.
     26\PAB{Can you create a simple diagram of the layout?}
    5627% These are always taken by pointer or reference.
    57 
    58 % Simple ascii diragram:
    59 \begin{verbatim}
    60 parent_pointer  \
    61 parent_field0   |
    62 ...             | Same layout as parent.
    63 parent_fieldN   /
    64 child_field0
    65 ...
    66 child_fieldN
    67 \end{verbatim}
    68 \todo{Refine the diagram}
    6928
    7029% For each virtual type, a virtual table is constructed. This is both a new type
     
    7534A virtual table is created when the virtual type is created. The name of the
    7635type is created by mangling the name of the base type. The name of the instance
    77 is also generated by name mangling. The fields are initialized automatically.
     36is also generated by name mangling.  The fields are initialized automatically.
    7837The parent field is initialized by getting the type of the parent field and
    7938using that to calculate the mangled name of the parent's virtual table type.
     
    10867\begin{sloppypar}
    10968Coroutines and threads need instances of @CoroutineCancelled@ and
    110 @ThreadCancelled@ respectively to use all of their functionality. When a new
     69@ThreadCancelled@ respectively to use all of their functionality.  When a new
    11170data type is declared with @coroutine@ or @thread@ the forward declaration for
    11271the instance is created as well. The definition of the virtual table is created
     
    12180The function is
    12281\begin{cfa}
    123 void * __cfa__virtual_cast(
    124         struct __cfa__parent_vtable const * parent,
     82void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent,
    12583        struct __cfa__parent_vtable const * const * child );
     84}
    12685\end{cfa}
    127 and it is implemented in the standard library. The structure reperents the
    128 head of a vtable which is the pointer to the parent virtual table. The
    129 @parent@ points directly at the parent type virtual table while the @child@
    130 points at the object of the (possibe) child type.
    131 
    132 In terms of the virtual cast expression, @parent@ comes from looking up the
    133 type being cast to and @child@ is the result of the expression being cast.
    134 Because the complier outputs C code, some type C type casts are also used.
    135 The last bit of glue is an map that saves every virtual type the compiler
    136 sees. This is used to check the type used in a virtual cast is a virtual
    137 type and to get its virtual table.
    138 (It also checks for conflicting definitions.)
    139 
    140 Inside the function it is a simple conditional. If the type repersented by
    141 @parent@ is or is an ancestor of the type repersented by @*child@ (it
    142 requires one more level of derefence to pass through the object) then @child@
    143 is returned, otherwise the null pointer is returned.
    144 
    145 The check itself is preformed is a simple linear search. If the child
    146 virtual table or any of its ancestors (which are retreved through the first
    147 field of every virtual table) are the same as the parent virtual table then
    148 the cast succeeds.
     86and it is implemented in the standard library. It takes a pointer to the target
     87type's virtual table and the object pointer being cast. The function performs a
     88linear search starting at the object's virtual-table and walking through the
     89the parent pointers, checking to if it or any of its ancestors are the same as
     90the target-type virtual table-pointer.
     91
     92For the generated code, a forward declaration of the virtual works as follows.
     93There is a forward declaration of @__cfa__virtual_cast@ in every \CFA file so
     94it can just be used. The object argument is the expression being cast so that
     95is just placed in the argument list.
     96
     97To build the target type parameter, the compiler creates a mapping from
     98concrete type-name -- so for polymorphic types the parameters are filled in --
     99to virtual table address. Every virtual table declaration is added to the this
     100table; repeats are ignored unless they have conflicting definitions.  Note,
     101these declarations do not have to be in scope, but they should usually be
     102introduced as part of the type definition.
     103
     104\PAB{I do not understood all of \VRef{s:VirtualSystem}. I think you need to
     105write more to make it clear.}
     106
    149107
    150108\section{Exceptions}
     
    163121stack. On function entry and return, unwinding is handled directly by the code
    164122embedded in the function. Usually, the stack-frame size is known statically
    165 based on parameter and local variable declarations. For dynamically-sized
     123based on parameter and local variable declarations.  For dynamically-sized
    166124local variables, a runtime computation is necessary to know the frame
    167125size. Finally, a function's frame-size may change during execution as local
     
    221179
    222180To use libunwind, each function must have a personality function and a Language
    223 Specific Data Area (LSDA). The LSDA has the unique information for each
     181Specific Data Area (LSDA).  The LSDA has the unique information for each
    224182function to tell the personality function where a function is executing, its
    225 current stack frame, and what handlers should be checked. Theoretically, the
     183current stack frame, and what handlers should be checked.  Theoretically, the
    226184LSDA can contain any information but conventionally it is a table with entries
    227185representing regions of the function and what has to be done there during
     
    238196
    239197The GCC compilation flag @-fexceptions@ causes the generation of an LSDA and
    240 attaches its personality function. However, this
    241 flag only handles the cleanup attribute:
    242 \todo{Peter: What is attached? Andrew: It uses the .cfi\_personality directive
    243 and that's all I know.}
     198attaches its personality function. \PAB{to what is it attached?}  However, this
     199flag only handles the cleanup attribute
    244200\begin{cfa}
    245201void clean_up( int * var ) { ... }
    246 int avar __attribute__(( cleanup(clean_up) ));
     202int avar __attribute__(( __cleanup(clean_up) ));
    247203\end{cfa}
    248 which is used on a variable and specifies a function, in this case @clean_up@,
    249 run when the variable goes out of scope.
    250 The function is passed a pointer to the object being removed from the stack
    251 so it can be used to mimic destructors.
    252 However, this feature cannot be used to mimic @try@ statements as it cannot
    253 control the unwinding.
     204which is used on a variable and specifies a function, \eg @clean_up@, run when
     205the variable goes out of scope. The function is passed a pointer to the object
     206so it can be used to mimic destructors. However, this feature cannot be used to
     207mimic @try@ statements.
    254208
    255209\subsection{Personality Functions}
    256 Personality functions have a complex interface specified by libunwind. This
     210Personality functions have a complex interface specified by libunwind.  This
    257211section covers some of the important parts of the interface.
    258212
    259 A personality function can preform different actions depending on how it is
    260 called.
     213A personality function performs four tasks, although not all have to be
     214present.
    261215\begin{lstlisting}[language=C,{moredelim=**[is][\color{red}]{@}{@}}]
    262216typedef _Unwind_Reason_Code (*@_Unwind_Personality_Fn@) (
     
    271225\item
    272226@_UA_SEARCH_PHASE@ specifies a search phase and tells the personality function
    273 to check for handlers. If there is a handler in a stack frame, as defined by
     227to check for handlers.  If there is a handler in a stack frame, as defined by
    274228the language, the personality function returns @_URC_HANDLER_FOUND@; otherwise
    275229it return @_URC_CONTINUE_UNWIND@.
     
    342296\end{cfa}
    343297It also unwinds the stack but it does not use the search phase. Instead another
    344 function, the stop function, is used to stop searching. The exception is the
     298function, the stop function, is used to stop searching.  The exception is the
    345299same as the one passed to raise exception. The extra arguments are the stop
    346300function and the stop parameter. The stop function has a similar interface as a
     
    364318
    365319\begin{sloppypar}
    366 Its arguments are the same as the paired personality function. The actions
     320Its arguments are the same as the paired personality function.  The actions
    367321@_UA_CLEANUP_PHASE@ and @_UA_FORCE_UNWIND@ are always set when it is
    368322called. Beyond the libunwind standard, both GCC and Clang add an extra action
     
    389343strong symbol replacing the sequential version.
    390344
    391 The sequential @this_exception_context@ returns a hard-coded pointer to the
    392 global execption context.
    393 The concurrent version adds the exception context to the data stored at the
    394 base of each stack. When @this_exception_context@ is called it retrieves the
    395 active stack and returns the address of the context saved there.
     345% The version of the function defined in @libcfa@ is very simple. It returns a
     346% pointer to a global static variable. With only one stack this global instance
     347% is associated with the only stack.
     348
     349For coroutines, @this_exception_context@ accesses the exception context stored
     350at the base of the stack. For threads, @this_exception_context@ uses the
     351concurrency library to access the current stack of the thread or coroutine
     352being executed by the thread, and then accesses the exception context stored at
     353the base of this stack.
    396354
    397355\section{Termination}
     
    411369per-exception storage.
    412370
    413 [Quick ASCII diagram to get started.]
    414 \begin{verbatim}
    415 Fixed Header  | _Unwind_Exception   <- pointer target
    416               |
    417               | Cforall storage
    418               |
    419 Variable Body | the exception       <- fixed offset
    420               V ...
    421 \end{verbatim}
    422 
    423 Exceptions are stored in variable-sized blocks.
    424 The first component is a fixed sized data structure that contains the
     371Exceptions are stored in variable-sized blocks. \PAB{Show a memory layout
     372figure.} The first component is a fixed sized data structure that contains the
    425373information for libunwind and the exception system. The second component is an
    426374area of memory big enough to store the exception. Macros with pointer arthritic
     
    440388exception type. The size and copy function are used immediately to copy an
    441389exception into managed memory. After the exception is handled the free function
    442 is used to clean up the exception and then the entire node is passed to free
    443 so the memory can be given back to the heap.
     390is used to clean up the exception and then the entire node is passed to free.
    444391
    445392\subsection{Try Statements and Catch Clauses}
     
    452399library. The contents of a try block and the termination handlers are converted
    453400into functions. These are then passed to the try terminate function and it
    454 calls them.
    455 Because this function is known and fixed (and not an arbitrary function that
    456 happens to contain a try statement) this means the LSDA can be generated ahead
    457 of time.
    458 
    459 Both the LSDA and the personality function are set ahead of time using
    460 embedded assembly. This is handcrafted using C @asm@ statements and contains
    461 enough information for the single try statement the function repersents.
     401calls them. This approach puts a try statement in its own functions so that no
     402function has to deal with both termination handlers and destructors. \PAB{I do
     403not understand the previous sentence.}
     404
     405This function has some custom embedded assembly that defines \emph{its}
     406personality function and LSDA. The assembly is created with handcrafted C @asm@
     407statements, which is why there is only one version of it. The personality
     408function is structured so that it can be expanded, but currently it only
     409handles this one function.  Notably, it does not handle any destructors so the
     410function is constructed so that it does need to run it. \PAB{I do not
     411understand the previous sentence.}
    462412
    463413The three functions passed to try terminate are:
     
    469419
    470420\item[match function:] This function is called during the search phase and
    471 decides if a catch clause matches the termination exception. It is constructed
     421decides if a catch clause matches the termination exception.  It is constructed
    472422from the conditional part of each handler and runs each check, top to bottom,
    473423in turn, first checking to see if the exception type matches and then if the
     
    478428\item[handler function:] This function handles the exception. It takes a
    479429pointer to the exception and the handler's id and returns nothing. It is called
    480 after the cleanup phase. It is constructed by stitching together the bodies of
     430after the cleanup phase.  It is constructed by stitching together the bodies of
    481431each handler and dispatches to the selected handler.
    482432\end{description}
     
    484434can be used to create closures, functions that can refer to the state of other
    485435functions on the stack. This approach allows the functions to refer to all the
    486 variables in scope for the function containing the @try@ statement. These
     436variables in scope for the function containing the @try@ statement.  These
    487437nested functions and all other functions besides @__cfaehm_try_terminate@ in
    488438\CFA use the GCC personality function and the @-fexceptions@ flag to generate
     
    505455handler that matches. If no handler matches then the function returns
    506456false. Otherwise the matching handler is run; if it completes successfully, the
    507 function returns true. Rethrowing, through the @throwResume;@ statement,
    508 causes the function to return true.
     457function returns true. Reresume, through the @throwResume;@ statement, cause
     458the function to return true.
    509459
    510460% Recursive Resumption Stuff:
     
    532482providing zero-cost enter/exit using the LSDA. Unfortunately, there is no way
    533483to return from a libunwind search without installing a handler or raising an
    534 error. Although workarounds might be possible, they are beyond the scope of
     484error.  Although workarounds might be possible, they are beyond the scope of
    535485this thesis. The current resumption implementation has simplicity in its
    536486favour.
     
    553503
    554504Cancellation also uses libunwind to do its stack traversal and unwinding,
    555 however it uses a different primary function @_Unwind_ForcedUnwind@. Details
     505however it uses a different primary function @_Unwind_ForcedUnwind@.  Details
    556506of its interface can be found in the \VRef{s:ForcedUnwind}.
    557507
     
    561511its main coroutine and the coroutine it is currently executing.
    562512
    563 So if the active thread's main and current coroutine are the same. If they
    564 are then the current stack is a thread stack, otherwise it is a coroutine
    565 stack. If it is a thread stack then an equality check with the stored main
    566 thread pointer and current thread pointer is enough to tell if the current
    567 thread is the main thread or not.
     513The first check is if the current thread's main and current coroutine do not
     514match, implying a coroutine cancellation; otherwise, it is a thread
     515cancellation. Otherwise it is a main thread cancellation. \PAB{Previous
     516sentence does not make sense.}
    568517
    569518However, if the threading library is not linked, the sequential execution is on
  • doc/theses/andrew_beach_MMath/uw-ethesis.tex

    r5407cdc rfeacef9  
    7474% ======================================================================
    7575%   D O C U M E N T   P R E A M B L E
    76 \RequirePackage{etoolbox}
    77 
    78 % Control if this for print (set true) or will stay digital (default).
    79 % Print is two sided, digital uses more colours.
    80 \newtoggle{printversion}
    81 %\toggletrue{printversion}
    82 
    83 \iftoggle{printversion}{%
    84   \documentclass[letterpaper,12pt,titlepage,openright,twoside,final]{book}
    85 }{%
    86   \documentclass[letterpaper,12pt,titlepage,oneside,final]{book}
    87 }
     76% Specify the document class, default style attributes, page dimensions, etc.
     77% For hyperlinked PDF, suitable for viewing on a computer, use this:
     78\documentclass[letterpaper,12pt,titlepage,oneside,final]{book}
     79
     80% For PDF, suitable for double-sided printing, change the PrintVersion
     81% variable below to "true" and use this \documentclass line instead of the
     82% one above:
     83%\documentclass[letterpaper,12pt,titlepage,openright,twoside,final]{book}
     84
     85\usepackage{etoolbox}
    8886
    8987% Some LaTeX commands I define for my own nomenclature.
     
    9694% Anything defined here may be redefined by packages added below...
    9795
    98 % For a nomenclature (optional; available from ctan.org)
    99 %\usepackage{nomencl}
     96% This package allows if-then-else control structures.
     97\usepackage{ifthen}
     98\newboolean{PrintVersion}
     99\setboolean{PrintVersion}{false}
     100% CHANGE THIS VALUE TO "true" as necessary, to improve printed results for
     101% hard copies by overriding some options of the hyperref package, called below.
     102
     103%\usepackage{nomencl} % For a nomenclature (optional; available from ctan.org)
    100104% Lots of math symbols and environments
    101105\usepackage{amsmath,amssymb,amstext}
    102 % For including graphics (must match graphics driver)
    103 \usepackage{epic,eepic}
    104 \usepackage{graphicx}
     106% For including graphics N.B. pdftex graphics driver
     107\usepackage[pdftex]{graphicx}
    105108% Removes large sections of the document.
    106109\usepackage{comment}
    107110% Adds todos (Must be included after comment.)
    108111\usepackage{todonotes}
     112
    109113
    110114% Hyperlinks make it very easy to navigate an electronic document.
     
    113117% Use the "hyperref" package
    114118% N.B. HYPERREF MUST BE THE LAST PACKAGE LOADED; ADD ADDITIONAL PKGS ABOVE
    115 \usepackage[pagebackref=true]{hyperref}
     119\usepackage[pdftex,pagebackref=true]{hyperref} % with basic options
     120%\usepackage[pdftex,pagebackref=true]{hyperref}
    116121% N.B. pagebackref=true provides links back from the References to the body
    117122% text. This can cause trouble for printing.
     
    123128    pdffitwindow=false,     % window fit to page when opened
    124129    pdfstartview={FitH},    % fits the width of the page to the window
     130%    pdftitle={uWaterloo\ LaTeX\ Thesis\ Template}, % title: CHANGE THIS TEXT!
     131%    pdfauthor={Author},    % author: CHANGE THIS TEXT! and uncomment this line
     132%    pdfsubject={Subject},  % subject: CHANGE THIS TEXT! and uncomment this line
     133%    pdfkeywords={keyword1} {key2} {key3}, % optional list of keywords
    125134    pdfnewwindow=true,      % links in new window
    126135    colorlinks=true,        % false: boxed links; true: colored links
     136    linkcolor=blue,         % color of internal links
     137    citecolor=green,        % color of links to bibliography
     138    filecolor=magenta,      % color of file links
     139    urlcolor=cyan           % color of external links
    127140}
    128 \iftoggle{printversion}{
    129   \hypersetup{
    130     citecolor=black,        % colour of links to bibliography
    131     filecolor=black,        % colour of file links
    132     linkcolor=black,        % colour of internal links
    133     urlcolor=black,         % colour of external links
    134   }
    135 }{ % Digital Version
    136   \hypersetup{
    137     citecolor=green,
    138     filecolor=magenta,
    139     linkcolor=blue,
    140     urlcolor=cyan,
    141   }
    142 }
    143 
    144 \hypersetup{
    145   pdftitle={Exception Handling in Cforall},
    146   pdfauthor={Andrew James Beach},
    147   pdfsubject={Computer Science},
    148   pdfkeywords={programming languages} {exceptions}
    149       {language design} {language implementation},
    150 }
     141% for improved print quality, change some hyperref options
     142\ifthenelse{\boolean{PrintVersion}}{
     143\hypersetup{    % override some previously defined hyperref options
     144%    colorlinks,%
     145    citecolor=black,%
     146    filecolor=black,%
     147    linkcolor=black,%
     148    urlcolor=black}
     149}{} % end of ifthenelse (no else)
    151150
    152151% Exception to the rule of hyperref being the last add-on package
     
    218217\pdfstringdefDisableCommands{\def\Cpp{C++}}
    219218
    220 % Wrappers for inline code snippits.
    221 \newrobustcmd*\codeCFA[1]{\lstinline[language=CFA]{#1}}
    222 \newrobustcmd*\codeC[1]{\lstinline[language=C]{#1}}
    223 \newrobustcmd*\codeCpp[1]{\lstinline[language=C++]{#1}}
    224 \newrobustcmd*\codePy[1]{\lstinline[language=Python]{#1}}
    225 
    226219% Colour text, formatted in LaTeX style instead of TeX style.
    227220\newcommand*\colour[2]{{\color{#1}#2}}
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/links.hpp

    r5407cdc rfeacef9  
    117117        }
    118118
    119         unsigned long long ts() const {
     119        long long ts() const {
    120120                return before._links.ts;
    121121        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list.hpp

    r5407cdc rfeacef9  
    3939                while( __builtin_expect(ll.exchange(true),false) ) {
    4040                        while(ll.load(std::memory_order_relaxed))
    41                                 Pause();
     41                                asm volatile("pause");
    4242                }
    4343                /* paranoid */ assert(ll);
     
    9393                         && ready.compare_exchange_weak(copy, n + 1) )
    9494                                break;
    95                         Pause();
     95                        asm volatile("pause");
    9696                }
    9797
     
    133133                // Step 1 : make sure no writer are in the middle of the critical section
    134134                while(lock.load(std::memory_order_relaxed))
    135                         Pause();
     135                        asm volatile("pause");
    136136
    137137                // Fence needed because we don't want to start trying to acquire the lock
     
    195195                //   to simply lock their own lock and enter.
    196196                while(lock.load(std::memory_order_relaxed))
    197                         Pause();
     197                        asm volatile("pause");
    198198
    199199                // Step 2 : lock per-proc lock
     
    204204                for(uint_fast32_t i = 0; i < s; i++) {
    205205                        while(data[i].lock.load(std::memory_order_relaxed))
    206                                 Pause();
     206                                asm volatile("pause");
    207207                }
    208208
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/processor_list_good.cpp

    r5407cdc rfeacef9  
    2121                target = (target - (target % total)) + total;
    2222                while(waiting < target)
    23                         Pause();
     23                        asm volatile("pause");
    2424
    2525                assert(waiting < (1ul << 60));
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/randbit.cpp

    r5407cdc rfeacef9  
    123123                target = (target - (target % total)) + total;
    124124                while(waiting < target)
    125                         Pause();
     125                        asm volatile("pause");
    126126
    127127                assert(waiting < (1ul << 60));
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/relaxed_list.cpp

    r5407cdc rfeacef9  
    206206        std::cout << "Total ops     : " << ops << "(" << global.in << "i, " << global.out << "o, " << global.empty << "e)\n";
    207207        #ifndef NO_STATS
    208                 LIST_VARIANT<Node>::stats_print(std::cout, duration);
     208                LIST_VARIANT<Node>::stats_print(std::cout);
    209209        #endif
    210210}
     
    368368
    369369                for(Node * & node : nodes) {
    370                         node = nullptr;
    371                         while(!node) {
    372                                 node = list.pop();
    373                         }
     370                        node = list.pop();
     371                        assert(node);
    374372                        local.crc_out += node->value;
    375373                        local.out++;
     
    693691
    694692                                for(const auto & n : nodes) {
    695                                         local.valmax = std::max(local.valmax, size_t(n.value));
    696                                         local.valmin = std::min(local.valmin, size_t(n.value));
     693                                        local.valmax = max(local.valmax, size_t(n.value));
     694                                        local.valmin = min(local.valmin, size_t(n.value));
    697695                                }
    698696
     
    775773                                                try {
    776774                                                        arg = optarg = argv[optind];
    777                                                         nnodes = std::stoul(optarg, &len);
     775                                                        nnodes = stoul(optarg, &len);
    778776                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    779777                                                } catch(std::invalid_argument &) {
     
    794792                                                try {
    795793                                                        arg = optarg = argv[optind];
    796                                                         nnodes = std::stoul(optarg, &len);
     794                                                        nnodes = stoul(optarg, &len);
    797795                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    798796                                                } catch(std::invalid_argument &) {
     
    814812                                                try {
    815813                                                        arg = optarg = argv[optind];
    816                                                         nnodes = std::stoul(optarg, &len);
     814                                                        nnodes = stoul(optarg, &len);
    817815                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    818816                                                        nslots = nnodes;
     
    825823                                                try {
    826824                                                        arg = optarg = argv[optind];
    827                                                         nnodes = std::stoul(optarg, &len);
     825                                                        nnodes = stoul(optarg, &len);
    828826                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    829827                                                } catch(std::invalid_argument &) {
     
    833831                                                try {
    834832                                                        arg = optarg = argv[optind + 1];
    835                                                         nslots = std::stoul(optarg, &len);
     833                                                        nslots = stoul(optarg, &len);
    836834                                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    837835                                                } catch(std::invalid_argument &) {
     
    886884                        case 'd':
    887885                                try {
    888                                         duration = std::stod(optarg, &len);
     886                                        duration = stod(optarg, &len);
    889887                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    890888                                } catch(std::invalid_argument &) {
     
    895893                        case 't':
    896894                                try {
    897                                         nthreads = std::stoul(optarg, &len);
     895                                        nthreads = stoul(optarg, &len);
    898896                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    899897                                } catch(std::invalid_argument &) {
     
    904902                        case 'q':
    905903                                try {
    906                                         nqueues = std::stoul(optarg, &len);
     904                                        nqueues = stoul(optarg, &len);
    907905                                        if(len != arg.size()) { throw std::invalid_argument(""); }
    908906                                } catch(std::invalid_argument &) {
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi-packed.hpp

    r5407cdc rfeacef9  
    168168        for(int i = 0; i < width; i++) {
    169169                int idx = i % hwdith;
     170                std::cout << i << " -> " << idx + width << std::endl;
    170171                leafs[i].parent = &nodes[ idx ];
    171172        }
     
    173174        for(int i = 0; i < root; i++) {
    174175                int idx = (i / 2) + hwdith;
     176                std::cout << i + width << " -> " << idx + width << std::endl;
    175177                nodes[i].parent = &nodes[ idx ];
    176178        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/snzi.hpp

    r5407cdc rfeacef9  
    159159        std::cout << "SNZI: " << depth << "x" << width << "(" << mask - 1 << ") " << (sizeof(snzi_t::node) * (root + 1)) << " bytes" << std::endl;
    160160        for(int i = 0; i < root; i++) {
     161                std::cout << i << " -> " << (i / base) + width << std::endl;
    161162                nodes[i].parent = &nodes[(i / base) + width];
    162163        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/utils.hpp

    r5407cdc rfeacef9  
    1111#include <sys/sysinfo.h>
    1212
    13 // #include <x86intrin.h>
     13#include <x86intrin.h>
     14
     15// Barrier from
     16class barrier_t {
     17public:
     18        barrier_t(size_t total)
     19                : waiting(0)
     20                , total(total)
     21        {}
     22
     23        void wait(unsigned) {
     24                size_t target = waiting++;
     25                target = (target - (target % total)) + total;
     26                while(waiting < target)
     27                        asm volatile("pause");
     28
     29                assert(waiting < (1ul << 60));
     30        }
     31
     32private:
     33        std::atomic<size_t> waiting;
     34        size_t total;
     35};
    1436
    1537// class Random {
     
    80102};
    81103
    82 static inline long long int rdtscl(void) {
    83         #if defined( __i386 ) || defined( __x86_64 )
    84                 unsigned int lo, hi;
    85                 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    86                 return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
    87         #elif defined( __aarch64__ ) || defined( __arm__ )
    88                 // https://github.com/google/benchmark/blob/v1.1.0/src/cycleclock.h#L116
    89                 long long int virtual_timer_value;
    90                 asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
    91                 return virtual_timer_value;
    92         #else
    93                 #error unsupported hardware architecture
    94         #endif
    95 }
    96 
    97 #if defined( __i386 ) || defined( __x86_64 )
    98         #define Pause() __asm__ __volatile__ ( "pause" : : : )
    99 #elif defined( __ARM_ARCH )
    100         #define Pause() __asm__ __volatile__ ( "YIELD" : : : )
    101 #else
    102         #error unsupported architecture
    103 #endif
     104static inline long long rdtscl(void) {
     105    unsigned int lo, hi;
     106    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
     107    return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
     108}
    104109
    105110static inline void affinity(int tid) {
     
    190195}
    191196
    192 // Barrier from
    193 class barrier_t {
    194 public:
    195         barrier_t(size_t total)
    196                 : waiting(0)
    197                 , total(total)
    198         {}
    199 
    200         void wait(unsigned) {
    201                 size_t target = waiting++;
    202                 target = (target - (target % total)) + total;
    203                 while(waiting < target)
    204                         Pause();
    205 
    206                 assert(waiting < (1ul << 60));
    207         }
    208 
    209 private:
    210         std::atomic<size_t> waiting;
    211         size_t total;
    212 };
    213 
    214197struct spinlock_t {
    215198        std::atomic_bool ll = { false };
     
    218201                while( __builtin_expect(ll.exchange(true),false) ) {
    219202                        while(ll.load(std::memory_order_relaxed))
    220                                 Pause();
     203                                asm volatile("pause");
    221204                }
    222205        }
  • doc/theses/thierry_delisle_PhD/code/readyQ_proto/work_stealing.hpp

    r5407cdc rfeacef9  
    66#include <memory>
    77#include <mutex>
    8 #include <thread>
    98#include <type_traits>
    109
     
    1211#include "utils.hpp"
    1312#include "links.hpp"
    14 #include "links2.hpp"
    1513#include "snzi.hpp"
    1614
    17 // #include <x86intrin.h>
    18 
    1915using namespace std;
    20 
    21 static const long long lim = 2000;
    22 static const unsigned nqueues = 2;
    23 
    24 struct __attribute__((aligned(128))) timestamp_t {
    25         volatile unsigned long long val = 0;
    26 };
    27 
    28 template<typename node_t>
    29 struct __attribute__((aligned(128))) localQ_t {
    30         #ifdef NO_MPSC
    31                 intrusive_queue_t<node_t> list;
    32 
    33                 inline auto ts() { return list.ts(); }
    34                 inline auto lock() { return list.lock.lock(); }
    35                 inline auto try_lock() { return list.lock.try_lock(); }
    36                 inline auto unlock() { return list.lock.unlock(); }
    37 
    38                 inline auto push( node_t * node ) { return list.push( node ); }
    39                 inline auto pop() { return list.pop(); }
    40         #else
    41                 mpsc_queue<node_t> queue = {};
    42                 spinlock_t _lock = {};
    43 
    44                 inline auto ts() { auto h = queue.head(); return h ? h->_links.ts : 0ull; }
    45                 inline auto lock() { return _lock.lock(); }
    46                 inline auto try_lock() { return _lock.try_lock(); }
    47                 inline auto unlock() { return _lock.unlock(); }
    48 
    49                 inline auto push( node_t * node ) { return queue.push( node ); }
    50                 inline auto pop() { return queue.pop(); }
    51         #endif
    52 
    53 
    54 };
    5516
    5617template<typename node_t>
     
    6425
    6526        work_stealing(unsigned _numThreads, unsigned)
    66                 : numThreads(_numThreads * nqueues)
    67                 , lists(new localQ_t<node_t>[numThreads])
    68                 // , lists(new intrusive_queue_t<node_t>[numThreads])
    69                 , times(new timestamp_t[numThreads])
    70                 // , snzi( std::log2( numThreads / 2 ), 2 )
     27                : numThreads(_numThreads)
     28                , lists(new intrusive_queue_t<node_t>[numThreads])
     29                , snzi( std::log2( numThreads / 2 ), 2 )
    7130
    7231        {
     
    8140        __attribute__((noinline, hot)) void push(node_t * node) {
    8241                node->_links.ts = rdtscl();
    83                 // node->_links.ts = 1;
    84 
    85                 auto & list = *({
    86                         unsigned i;
    87                         #ifdef NO_MPSC
    88                                 do {
    89                         #endif
    90                                 tls.stats.push.attempt++;
    91                                 // unsigned r = tls.rng1.next();
    92                                 unsigned r = tls.it++;
    93                                 if(tls.my_queue == outside) {
    94                                         i = r % numThreads;
    95                                 } else {
    96                                         i = tls.my_queue + (r % nqueues);
     42                if( node->_links.hint > numThreads ) {
     43                        node->_links.hint = tls.rng.next() % numThreads;
     44                        tls.stat.push.nhint++;
     45                }
     46
     47                unsigned i = node->_links.hint;
     48                auto & list = lists[i];
     49                list.lock.lock();
     50
     51                if(list.push( node )) {
     52                        snzi.arrive(i);
     53                }
     54
     55                list.lock.unlock();
     56        }
     57
     58        __attribute__((noinline, hot)) node_t * pop() {
     59                node_t * node;
     60                while(true) {
     61                        if(!snzi.query()) {
     62                                return nullptr;
     63                        }
     64
     65                        {
     66                                unsigned i = tls.my_queue;
     67                                auto & list = lists[i];
     68                                if( list.ts() != 0 ) {
     69                                        list.lock.lock();
     70                                        if((node = try_pop(i))) {
     71                                                tls.stat.pop.local.success++;
     72                                                break;
     73                                        }
     74                                        else {
     75                                                tls.stat.pop.local.elock++;
     76                                        }
    9777                                }
    98                         #ifdef NO_MPSC
    99                                 } while(!lists[i].try_lock());
    100                         #endif
    101                         &lists[i];
    102                 });
    103 
    104                 list.push( node );
    105                 #ifdef NO_MPSC
    106                         list.unlock();
     78                                else {
     79                                        tls.stat.pop.local.espec++;
     80                                }
     81                        }
     82
     83                        tls.stat.pop.steal.tried++;
     84
     85                        int i = tls.rng.next() % numThreads;
     86                        auto & list = lists[i];
     87                        if( list.ts() == 0 ) {
     88                                tls.stat.pop.steal.empty++;
     89                                continue;
     90                        }
     91
     92                        if( !list.lock.try_lock() ) {
     93                                tls.stat.pop.steal.locked++;
     94                                continue;
     95                        }
     96
     97                        if((node = try_pop(i))) {
     98                                tls.stat.pop.steal.success++;
     99                                break;
     100                        }
     101                }
     102
     103                #if defined(READ)
     104                        const unsigned f = READ;
     105                        if(0 == (tls.it % f)) {
     106                                unsigned i = tls.it / f;
     107                                lists[i % numThreads].ts();
     108                        }
     109                        // lists[tls.it].ts();
     110                        tls.it++;
    107111                #endif
    108                 // tls.rng2.set_raw_state( tls.rng1.get_raw_state());
    109                 // count++;
    110                 tls.stats.push.success++;
    111         }
    112 
    113         __attribute__((noinline, hot)) node_t * pop() {
    114                 if(tls.my_queue != outside) {
    115                         // if( tls.myfriend == outside ) {
    116                         //      auto r  = tls.rng1.next();
    117                         //      tls.myfriend = r % numThreads;
    118                         //      // assert(lists[(tls.it % nqueues) + tls.my_queue].ts() >= lists[((tls.it + 1) % nqueues) + tls.my_queue].ts());
    119                         //      tls.mytime = std::min(lists[(tls.it % nqueues) + tls.my_queue].ts(), lists[((tls.it + 1) % nqueues) + tls.my_queue].ts());
    120                         //      // times[tls.myfriend].val = 0;
    121                         //      // lists[tls.myfriend].val = 0;
    122                         // }
    123                         // // else if(times[tls.myfriend].val == 0) {
    124                         // // else if(lists[tls.myfriend].val == 0) {
    125                         // else if(times[tls.myfriend].val < tls.mytime) {
    126                         // // else if(times[tls.myfriend].val < lists[(tls.it % nqueues) + tls.my_queue].ts()) {
    127                         //      node_t * n = try_pop(tls.myfriend, tls.stats.pop.help);
    128                         //      tls.stats.help++;
    129                         //      tls.myfriend = outside;
    130                         //      if(n) return n;
    131                         // }
    132                         // if( tls.myfriend == outside ) {
    133                         //      auto r  = tls.rng1.next();
    134                         //      tls.myfriend = r % numThreads;
    135                         //      tls.mytime = lists[((tls.it + 1) % nqueues) + tls.my_queue].ts();
    136                         // }
    137                         // else {
    138                         //      if(times[tls.myfriend].val + 1000 < tls.mytime) {
    139                         //              node_t * n = try_pop(tls.myfriend, tls.stats.pop.help);
    140                         //              tls.stats.help++;
    141                         //              if(n) return n;
    142                         //      }
    143                         //      tls.myfriend = outside;
    144                         // }
    145 
    146                         node_t * n = local();
    147                         if(n) return n;
    148                 }
    149 
    150                 // try steal
    151                 for(int i = 0; i < 25; i++) {
    152                         node_t * n = steal();
    153                         if(n) return n;
    154                 }
    155 
    156                 return search();
    157         }
    158 
    159 private:
    160         inline node_t * local() {
    161                 unsigned i = (--tls.it % nqueues) + tls.my_queue;
    162                 node_t * n = try_pop(i, tls.stats.pop.local);
    163                 if(n) return n;
    164                 i = (--tls.it % nqueues) + tls.my_queue;
    165                 return try_pop(i, tls.stats.pop.local);
    166         }
    167 
    168         inline node_t * steal() {
    169                 unsigned i = tls.rng2.prev() % numThreads;
    170                 return try_pop(i, tls.stats.pop.steal);
    171         }
    172 
    173         inline node_t * search() {
    174                 unsigned offset = tls.rng2.prev();
    175                 for(unsigned i = 0; i < numThreads; i++) {
    176                         unsigned idx = (offset + i) % numThreads;
    177                         node_t * thrd = try_pop(idx, tls.stats.pop.search);
    178                         if(thrd) {
    179                                 return thrd;
    180                         }
    181                 }
    182 
    183                 return nullptr;
    184         }
    185 
    186 private:
    187         struct attempt_stat_t {
    188                 std::size_t attempt = { 0 };
    189                 std::size_t elock   = { 0 };
    190                 std::size_t eempty  = { 0 };
    191                 std::size_t espec   = { 0 };
    192                 std::size_t success = { 0 };
    193         };
    194 
    195         node_t * try_pop(unsigned i, attempt_stat_t & stat) {
    196                 assert(i < numThreads);
     112
     113
     114                return node;
     115        }
     116
     117private:
     118        node_t * try_pop(unsigned i) {
    197119                auto & list = lists[i];
    198                 stat.attempt++;
    199 
    200                 // If the list is empty, don't try
    201                 if(list.ts() == 0) { stat.espec++; return nullptr; }
    202 
    203                 // If we can't get the lock, move on
    204                 if( !list.try_lock() ) { stat.elock++; return nullptr; }
    205120
    206121                // If list is empty, unlock and retry
    207122                if( list.ts() == 0 ) {
    208                         list.unlock();
    209                         stat.eempty++;
     123                        list.lock.unlock();
    210124                        return nullptr;
    211125                }
    212126
    213                 auto node = list.pop();
    214                 list.unlock();
    215                 stat.success++;
    216                 #ifdef NO_MPSC
    217                         // times[i].val = 1;
    218                         times[i].val = node.first->_links.ts;
    219                         // lists[i].val = node.first->_links.ts;
    220                         return node.first;
    221                 #else
    222                         times[i].val = node->_links.ts;
    223                         return node;
    224                 #endif
     127                        // Actually pop the list
     128                node_t * node;
     129                bool emptied;
     130                std::tie(node, emptied) = list.pop();
     131                assert(node);
     132
     133                if(emptied) {
     134                        snzi.depart(i);
     135                }
     136
     137                // Unlock and return
     138                list.lock.unlock();
     139                return node;
    225140        }
    226141
     
    229144
    230145        static std::atomic_uint32_t ticket;
    231         static const unsigned outside = 0xFFFFFFFF;
    232 
    233         static inline unsigned calc_preferred() {
    234                 unsigned t = ticket++;
    235                 if(t == 0) return outside;
    236                 unsigned i = (t - 1) * nqueues;
    237                 return i;
    238         }
    239 
    240146        static __attribute__((aligned(128))) thread_local struct TLS {
    241                 Random     rng1 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
    242                 Random     rng2 = { unsigned(std::hash<std::thread::id>{}(std::this_thread::get_id()) ^ rdtscl()) };
    243                 unsigned   it   = 0;
    244                 unsigned   my_queue = calc_preferred();
    245                 unsigned   myfriend = outside;
    246                 unsigned long long int mytime = 0;
     147                Random     rng = { int(rdtscl()) };
     148                unsigned   my_queue = ticket++;
    247149                #if defined(READ)
    248150                        unsigned it = 0;
     
    250152                struct {
    251153                        struct {
    252                                 std::size_t attempt = { 0 };
    253                                 std::size_t success = { 0 };
     154                                std::size_t nhint = { 0 };
    254155                        } push;
    255156                        struct {
    256                                 attempt_stat_t help;
    257                                 attempt_stat_t local;
    258                                 attempt_stat_t steal;
    259                                 attempt_stat_t search;
     157                                struct {
     158                                        std::size_t success = { 0 };
     159                                        std::size_t espec = { 0 };
     160                                        std::size_t elock = { 0 };
     161                                } local;
     162                                struct {
     163                                        std::size_t tried   = { 0 };
     164                                        std::size_t locked  = { 0 };
     165                                        std::size_t empty   = { 0 };
     166                                        std::size_t success = { 0 };
     167                                } steal;
    260168                        } pop;
    261                         std::size_t help = { 0 };
    262                 } stats;
     169                } stat;
    263170        } tls;
    264171
    265172private:
    266173        const unsigned numThreads;
    267         std::unique_ptr<localQ_t<node_t> []> lists;
    268         // std::unique_ptr<intrusive_queue_t<node_t> []> lists;
    269         std::unique_ptr<timestamp_t []> times;
    270         __attribute__((aligned(128))) std::atomic_size_t count;
     174        std::unique_ptr<intrusive_queue_t<node_t> []> lists;
     175        __attribute__((aligned(64))) snzi_t snzi;
    271176
    272177#ifndef NO_STATS
     
    274179        static struct GlobalStats {
    275180                struct {
    276                         std::atomic_size_t attempt = { 0 };
    277                         std::atomic_size_t success = { 0 };
     181                        std::atomic_size_t nhint = { 0 };
    278182                } push;
    279183                struct {
    280184                        struct {
    281                                 std::atomic_size_t attempt = { 0 };
    282                                 std::atomic_size_t elock   = { 0 };
    283                                 std::atomic_size_t eempty  = { 0 };
    284                                 std::atomic_size_t espec   = { 0 };
    285185                                std::atomic_size_t success = { 0 };
    286                         } help;
    287                         struct {
    288                                 std::atomic_size_t attempt = { 0 };
    289                                 std::atomic_size_t elock   = { 0 };
    290                                 std::atomic_size_t eempty  = { 0 };
    291                                 std::atomic_size_t espec   = { 0 };
    292                                 std::atomic_size_t success = { 0 };
     186                                std::atomic_size_t espec = { 0 };
     187                                std::atomic_size_t elock = { 0 };
    293188                        } local;
    294189                        struct {
    295                                 std::atomic_size_t attempt = { 0 };
    296                                 std::atomic_size_t elock   = { 0 };
    297                                 std::atomic_size_t eempty  = { 0 };
    298                                 std::atomic_size_t espec   = { 0 };
     190                                std::atomic_size_t tried   = { 0 };
     191                                std::atomic_size_t locked  = { 0 };
     192                                std::atomic_size_t empty   = { 0 };
    299193                                std::atomic_size_t success = { 0 };
    300194                        } steal;
    301                         struct {
    302                                 std::atomic_size_t attempt = { 0 };
    303                                 std::atomic_size_t elock   = { 0 };
    304                                 std::atomic_size_t eempty  = { 0 };
    305                                 std::atomic_size_t espec   = { 0 };
    306                                 std::atomic_size_t success = { 0 };
    307                         } search;
    308195                } pop;
    309                 std::atomic_size_t help = { 0 };
    310196        } global_stats;
    311197
    312198public:
    313199        static void stats_tls_tally() {
    314                 global_stats.push.attempt += tls.stats.push.attempt;
    315                 global_stats.push.success += tls.stats.push.success;
    316                 global_stats.pop.help  .attempt += tls.stats.pop.help  .attempt;
    317                 global_stats.pop.help  .elock   += tls.stats.pop.help  .elock  ;
    318                 global_stats.pop.help  .eempty  += tls.stats.pop.help  .eempty ;
    319                 global_stats.pop.help  .espec   += tls.stats.pop.help  .espec  ;
    320                 global_stats.pop.help  .success += tls.stats.pop.help  .success;
    321                 global_stats.pop.local .attempt += tls.stats.pop.local .attempt;
    322                 global_stats.pop.local .elock   += tls.stats.pop.local .elock  ;
    323                 global_stats.pop.local .eempty  += tls.stats.pop.local .eempty ;
    324                 global_stats.pop.local .espec   += tls.stats.pop.local .espec  ;
    325                 global_stats.pop.local .success += tls.stats.pop.local .success;
    326                 global_stats.pop.steal .attempt += tls.stats.pop.steal .attempt;
    327                 global_stats.pop.steal .elock   += tls.stats.pop.steal .elock  ;
    328                 global_stats.pop.steal .eempty  += tls.stats.pop.steal .eempty ;
    329                 global_stats.pop.steal .espec   += tls.stats.pop.steal .espec  ;
    330                 global_stats.pop.steal .success += tls.stats.pop.steal .success;
    331                 global_stats.pop.search.attempt += tls.stats.pop.search.attempt;
    332                 global_stats.pop.search.elock   += tls.stats.pop.search.elock  ;
    333                 global_stats.pop.search.eempty  += tls.stats.pop.search.eempty ;
    334                 global_stats.pop.search.espec   += tls.stats.pop.search.espec  ;
    335                 global_stats.pop.search.success += tls.stats.pop.search.success;
    336                 global_stats.help += tls.stats.help;
    337         }
    338 
    339         static void stats_print(std::ostream & os, double duration ) {
     200                global_stats.push.nhint += tls.stat.push.nhint;
     201                global_stats.pop.local.success += tls.stat.pop.local.success;
     202                global_stats.pop.local.espec   += tls.stat.pop.local.espec  ;
     203                global_stats.pop.local.elock   += tls.stat.pop.local.elock  ;
     204                global_stats.pop.steal.tried   += tls.stat.pop.steal.tried  ;
     205                global_stats.pop.steal.locked  += tls.stat.pop.steal.locked ;
     206                global_stats.pop.steal.empty   += tls.stat.pop.steal.empty  ;
     207                global_stats.pop.steal.success += tls.stat.pop.steal.success;
     208        }
     209
     210        static void stats_print(std::ostream & os ) {
    340211                std::cout << "----- Work Stealing Stats -----" << std::endl;
    341212
    342                 double push_suc = (100.0 * double(global_stats.push.success) / global_stats.push.attempt);
    343                 double push_len = double(global_stats.push.attempt     ) / global_stats.push.success;
    344                 os << "Push   Pick : " << push_suc << " %, len " << push_len << " (" << global_stats.push.attempt      << " / " << global_stats.push.success << ")\n";
    345 
    346                 double hlp_suc = (100.0 * double(global_stats.pop.help.success) / global_stats.pop.help.attempt);
    347                 double hlp_len = double(global_stats.pop.help.attempt     ) / global_stats.pop.help.success;
    348                 os << "Help        : " << hlp_suc << " %, len " << hlp_len << " (" << global_stats.pop.help.attempt      << " / " << global_stats.pop.help.success << ")\n";
    349                 os << "Help Fail   : " << global_stats.pop.help.espec << "s, " << global_stats.pop.help.eempty << "e, " << global_stats.pop.help.elock << "l\n";
    350 
    351                 double pop_suc = (100.0 * double(global_stats.pop.local.success) / global_stats.pop.local.attempt);
    352                 double pop_len = double(global_stats.pop.local.attempt     ) / global_stats.pop.local.success;
    353                 os << "Local       : " << pop_suc << " %, len " << pop_len << " (" << global_stats.pop.local.attempt      << " / " << global_stats.pop.local.success << ")\n";
    354                 os << "Local Fail  : " << global_stats.pop.local.espec << "s, " << global_stats.pop.local.eempty << "e, " << global_stats.pop.local.elock << "l\n";
    355 
    356                 double stl_suc = (100.0 * double(global_stats.pop.steal.success) / global_stats.pop.steal.attempt);
    357                 double stl_len = double(global_stats.pop.steal.attempt     ) / global_stats.pop.steal.success;
    358                 os << "Steal       : " << stl_suc << " %, len " << stl_len << " (" << global_stats.pop.steal.attempt      << " / " << global_stats.pop.steal.success << ")\n";
    359                 os << "Steal Fail  : " << global_stats.pop.steal.espec << "s, " << global_stats.pop.steal.eempty << "e, " << global_stats.pop.steal.elock << "l\n";
    360 
    361                 double srh_suc = (100.0 * double(global_stats.pop.search.success) / global_stats.pop.search.attempt);
    362                 double srh_len = double(global_stats.pop.search.attempt     ) / global_stats.pop.search.success;
    363                 os << "Search      : " << srh_suc << " %, len " << srh_len << " (" << global_stats.pop.search.attempt      << " / " << global_stats.pop.search.success << ")\n";
    364                 os << "Search Fail : " << global_stats.pop.search.espec << "s, " << global_stats.pop.search.eempty << "e, " << global_stats.pop.search.elock << "l\n";
    365                 os << "Helps       : " << std::setw(15) << std::scientific << global_stats.help / duration << "/sec (" << global_stats.help  << ")\n";
     213                double stealSucc = double(global_stats.pop.steal.success) / global_stats.pop.steal.tried;
     214                os << "Push to new Q : " << std::setw(15) << global_stats.push.nhint << "\n";
     215                os << "Local Pop     : " << std::setw(15) << global_stats.pop.local.success << "\n";
     216                os << "Steal Pop     : " << std::setw(15) << global_stats.pop.steal.success << "(" << global_stats.pop.local.espec << "s, " << global_stats.pop.local.elock << "l)\n";
     217                os << "Steal Success : " << std::setw(15) << stealSucc << "(" << global_stats.pop.steal.tried << " tries)\n";
     218                os << "Steal Fails   : " << std::setw(15) << global_stats.pop.steal.empty << "e, " << global_stats.pop.steal.locked << "l\n";
    366219        }
    367220private:
  • doc/user/figures/Cdecl.fig

    r5407cdc rfeacef9  
    1 #FIG 3.2  Produced by xfig version 3.2.7b
     1#FIG 3.2  Produced by xfig version 3.2.5b
    22Landscape
    33Center
    44Inches
    5 Letter
     5Letter 
    66100.00
    77Single
     
    19192 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
    2020         2850 1200 3600 1200 3600 1350 2850 1350 2850 1200
    21 4 1 0 50 -1 4 11 0.0000 2 120 105 3075 1335 1\001
    22 4 1 0 50 -1 4 11 0.0000 2 120 105 3225 1335 2\001
    23 4 1 0 50 -1 4 11 0.0000 2 120 105 3375 1335 3\001
    24 4 1 0 50 -1 4 11 0.0000 2 120 105 3525 1335 4\001
    25 4 1 0 50 -1 4 11 0.0000 2 120 105 2925 1335 0\001
     214 1 0 50 -1 4 11 0.0000 2 120 90 2925 1325 0\001
     224 1 0 50 -1 4 11 0.0000 2 120 90 3075 1325 1\001
     234 1 0 50 -1 4 11 0.0000 2 120 90 3225 1325 2\001
     244 1 0 50 -1 4 11 0.0000 2 120 90 3375 1325 3\001
     254 1 0 50 -1 4 11 0.0000 2 120 90 3525 1325 4\001
    2626-6
    27272 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
     
    5555        1 1 1.00 45.00 60.00
    5656         2550 1275 2850 1275
    57 4 1 0 50 -1 4 11 0.0000 2 120 105 1350 1650 0\001
    58 4 1 0 50 -1 4 11 0.0000 2 120 105 1500 1650 1\001
    59 4 1 0 50 -1 4 11 0.0000 2 120 105 1650 1650 2\001
    60 4 1 0 50 -1 4 11 0.0000 2 120 105 1800 1650 3\001
    61 4 1 0 50 -1 4 11 0.0000 2 120 105 1950 1650 4\001
     574 1 0 50 -1 4 11 0.0000 2 120 90 1350 1650 0\001
     584 1 0 50 -1 4 11 0.0000 2 120 90 1500 1650 1\001
     594 1 0 50 -1 4 11 0.0000 2 120 90 1650 1650 2\001
     604 1 0 50 -1 4 11 0.0000 2 120 90 1800 1650 3\001
     614 1 0 50 -1 4 11 0.0000 2 120 90 1950 1650 4\001
    62624 1 0 50 -1 4 11 0.0000 2 90 90 1200 1325 x\001
    63634 1 0 50 -1 4 11 0.0000 2 90 90 2400 1325 x\001
  • doc/user/user.tex

    r5407cdc rfeacef9  
    1111%% Created On       : Wed Apr  6 14:53:29 2016
    1212%% Last Modified By : Peter A. Buhr
    13 %% Last Modified On : Sun Apr 25 19:03:03 2021
    14 %% Update Count     : 4951
     13%% Last Modified On : Mon Feb 15 13:48:53 2021
     14%% Update Count     : 4452
    1515%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1616
     
    6666% math escape $...$ (dollar symbol)
    6767\input{common}                                          % common CFA document macros
    68 \setlength{\gcolumnposn}{3in}
    6968\CFAStyle                                                                                               % use default CFA format-style
    7069\lstset{language=CFA}                                                                   % CFA default lnaguage
    7170\lstnewenvironment{C++}[1][]                            % use C++ style
    72 {\lstset{language=C++,moredelim=**[is][\protect\color{red}]{®}{®},#1}}
     71{\lstset{language=C++,moredelim=**[is][\protect\color{red}]{@}{@},#1}}
    7372{}
    7473
     
    8281\newcommand{\Textbf}[2][red]{{\color{#1}{\textbf{#2}}}}
    8382\newcommand{\Emph}[2][red]{{\color{#1}\textbf{\emph{#2}}}}
    84 \newcommand{\R}[1]{{\color{red}#1}}
    85 \newcommand{\RB}[1]{\Textbf{#1}}
     83\newcommand{\R}[1]{\Textbf{#1}}
     84\newcommand{\RC}[1]{\Textbf{\LstBasicStyle{#1}}}
    8685\newcommand{\B}[1]{{\Textbf[blue]{#1}}}
    8786\newcommand{\G}[1]{{\Textbf[OliveGreen]{#1}}}
     
    177176int main( void ) {
    178177        int x = 0, y = 1, z = 2;
    179         ®printf( "%d %d %d\n", x, y, z );®
     178        @printf( "%d %d %d\n", x, y, z );@
    180179}
    181180\end{cfa}
     
    186185int main( void ) {
    187186        int x = 0, y = 1, z = 2;
    188         ®sout | x | y | z;®$\indexc{sout}$
     187        @sout | x | y | z;@$\indexc{sout}$
    189188}
    190189\end{cfa}
     
    195194int main() {
    196195        int x = 0, y = 1, z = 2;
    197         ®cout<<x<<" "<<y<<" "<<z<<endl;®
     196        @cout<<x<<" "<<y<<" "<<z<<endl;@
    198197}
    199198\end{cfa}
     
    225224\begin{tabular}{@{}rcccccccc@{}}
    226225                & 2021  & 2016  & 2011  & 2006  & 2001  & 1996  & 1991  & 1986  \\ \hline
    227 \RB{C}  & \RB{1}& \RB{2}& \RB{2}& \RB{1}& \RB{1}& \RB{1}& \RB{1}& \RB{1}\\
     226\R{C}   & \R{1} & \R{2} & \R{2} & \R{1} & \R{1} & \R{1} & \R{1} & \R{1} \\
    228227Java    & 2             & 1             & 1             & 2             & 3             & 28    & -             & -             \\
    229228Python  & 3             & 5             & 6             & 7             & 23    & 13    & -             & -             \\
     
    259258The signature feature of \CFA is \emph{\Index{overload}able} \Index{parametric-polymorphic} functions~\cite{forceone:impl,Cormack90,Duggan96} with functions generalized using a ©forall© clause (giving the language its name):
    260259\begin{cfa}
    261 ®forall( otype T )® T identity( T val ) { return val; }
     260@forall( otype T )@ T identity( T val ) { return val; }
    262261int forty_two = identity( 42 ); $\C{// T is bound to int, forty\_two == 42}$
    263262\end{cfa}
     
    323322Whereas, \CFA wraps each of these routines into one overloaded name ©abs©:
    324323\begin{cfa}
    325 char ®abs®( char );
    326 extern "C" { int ®abs®( int ); } $\C{// use default C routine for int}$
    327 long int ®abs®( long int );
    328 long long int ®abs®( long long int );
    329 float ®abs®( float );
    330 double ®abs®( double );
    331 long double ®abs®( long double );
    332 float _Complex ®abs®( float _Complex );
    333 double _Complex ®abs®( double _Complex );
    334 long double _Complex ®abs®( long double _Complex );
     324char @abs@( char );
     325extern "C" { int @abs@( int ); } $\C{// use default C routine for int}$
     326long int @abs@( long int );
     327long long int @abs@( long long int );
     328float @abs@( float );
     329double @abs@( double );
     330long double @abs@( long double );
     331float _Complex @abs@( float _Complex );
     332double _Complex @abs@( double _Complex );
     333long double _Complex @abs@( long double _Complex );
    335334\end{cfa}
    336335The problem is \Index{name clash} between the C name ©abs© and the \CFA names ©abs©, resulting in two name linkages\index{C linkage}: ©extern "C"© and ©extern "Cforall"© (default).
     
    359358The 2011 C standard plus GNU extensions.
    360359\item
    361 \Indexc[deletekeywords=inline]{-fgnu89-inline}\index{compilation option!-fgnu89-inline@{\lstinline[deletekeywords=inline]{-fgnu89-inline}}}
     360\Indexc[deletekeywords=inline]{-fgnu89-inline}\index{compilation option!-fgnu89-inline@{\lstinline[deletekeywords=inline]$-fgnu89-inline$}}
    362361Use the traditional GNU semantics for inline routines in C11 mode, which allows inline routines in header files.
    363362\end{description}
     
    531530Keyword clashes are accommodated by syntactic transformations using the \CFA backquote escape-mechanism:
    532531\begin{cfa}
    533 int ®``®otype = 3; $\C{// make keyword an identifier}$
    534 double ®``®forall = 3.5;
     532int @``@otype = 3; $\C{// make keyword an identifier}$
     533double @``@forall = 3.5;
    535534\end{cfa}
    536535
     
    543542// include file uses the CFA keyword "with".
    544543#if ! defined( with )                                                   $\C{// nesting ?}$
    545 #define with ®``®with                                                   $\C{// make keyword an identifier}$
     544#define with @``@with                                                   $\C{// make keyword an identifier}$
    546545#define __CFA_BFD_H__
    547546#endif
     
    561560Numeric constants are extended to allow \Index{underscore}s\index{constant!underscore} as a separator, \eg:
    562561\begin{cfa}
    563 2®_®147®_®483®_®648; $\C{// decimal constant}$
    564 56®_®ul; $\C{// decimal unsigned long constant}$
    565 0®_®377; $\C{// octal constant}$
    566 0x®_®ff®_®ff; $\C{// hexadecimal constant}$
    567 0x®_®ef3d®_®aa5c; $\C{// hexadecimal constant}$
    568 3.141®_®592®_®654; $\C{// floating constant}$
    569 10®_®e®_®+1®_®00; $\C{// floating constant}$
    570 0x®_®ff®_®ff®_®p®_®3; $\C{// hexadecimal floating}$
    571 0x®_®1.ffff®_®ffff®_®p®_®128®_®l; $\C{// hexadecimal floating long constant}$
    572 L®_®$"\texttt{\textbackslash{x}}$®_®$\texttt{ff}$®_®$\texttt{ee}"$; $\C{// wide character constant}$
     5622@_@147@_@483@_@648; $\C{// decimal constant}$
     56356@_@ul; $\C{// decimal unsigned long constant}$
     5640@_@377; $\C{// octal constant}$
     5650x@_@ff@_@ff; $\C{// hexadecimal constant}$
     5660x@_@ef3d@_@aa5c; $\C{// hexadecimal constant}$
     5673.141@_@592@_@654; $\C{// floating constant}$
     56810@_@e@_@+1@_@00; $\C{// floating constant}$
     5690x@_@ff@_@ff@_@p@_@3; $\C{// hexadecimal floating}$
     5700x@_@1.ffff@_@ffff@_@p@_@128@_@l; $\C{// hexadecimal floating long constant}$
     571L@_@$"\texttt{\textbackslash{x}}$@_@$\texttt{ff}$@_@$\texttt{ee}"$; $\C{// wide character constant}$
    573572\end{cfa}
    574573The rules for placement of underscores are:
     
    603602Floating exponentiation\index{exponentiation!floating} is performed using \Index{logarithm}s\index{exponentiation!logarithm}, so the exponent cannot be negative.
    604603\begin{cfa}
    605 sout | 1 ®\® 0 | 1 ®\® 1 | 2 ®\® 8 | -4 ®\® 3 | 5 ®\® 3 | 5 ®\® 32 | 5L ®\® 32 | 5L ®\® 64 | -4 ®\® -3 | -4.0 ®\® -3 | 4.0 ®\® 2.1
    606            | (1.0f+2.0fi) ®\® (3.0f+2.0fi);
    607 1 1 256 -64 125 ®0® 3273344365508751233 ®0® ®0® -0.015625 18.3791736799526 0.264715-1.1922i
     604sout | 1 @\@ 0 | 1 @\@ 1 | 2 @\@ 8 | -4 @\@ 3 | 5 @\@ 3 | 5 @\@ 32 | 5L @\@ 32 | 5L @\@ 64 | -4 @\@ -3 | -4.0 @\@ -3 | 4.0 @\@ 2.1
     605           | (1.0f+2.0fi) @\@ (3.0f+2.0fi);
     6061 1 256 -64 125 @0@ 3273344365508751233 @0@ @0@ -0.015625 18.3791736799526 0.264715-1.1922i
    608607\end{cfa}
    609608Note, ©5 \ 32© and ©5L \ 64© overflow, and ©-4 \ -3© is a fraction but stored in an integer so all three computations generate an integral zero.
     
    613612\begin{cfa}
    614613forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } )
    615 T ?®\®?( T ep, unsigned int y );
     614T ?@\@?( T ep, unsigned int y );
    616615forall( otype T | { void ?{}( T & this, one_t ); T ?*?( T, T ); } )
    617 T ?®\®?( T ep, unsigned long int y );
     616T ?@\@?( T ep, unsigned long int y );
    618617\end{cfa}
    619618The user type ©T© must define multiplication, one (©1©), and ©*©.
     
    625624
    626625
    627 %\subsection{\texorpdfstring{\protect\lstinline{if}/\protect\lstinline{while} Statement}{if Statement}}
     626%\subsection{\texorpdfstring{\protect\lstinline@if@/\protect\lstinline@while@ Statement}{if Statement}}
    628627\subsection{\texorpdfstring{\LstKeywordStyle{if} / \LstKeywordStyle{while} Statement}{if / while Statement}}
    629628
     
    631630Declarations in the ©do©-©while© condition are not useful because they appear after the loop body.}
    632631\begin{cfa}
    633 if ( ®int x = f()® ) ... $\C{// x != 0}$
    634 if ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$
    635 if ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$
    636 if ( ®struct S { int i; } x = { f() }; x.i < 4® ) $\C{// relational expression}$
    637 
    638 while ( ®int x = f()® ) ... $\C{// x != 0}$
    639 while ( ®int x = f(), y = g()® ) ... $\C{// x != 0 \&\& y != 0}$
    640 while ( ®int x = f(), y = g(); x < y® ) ... $\C{// relational expression}$
    641 while ( ®struct S { int i; } x = { f() }; x.i < 4® ) ... $\C{// relational expression}$
     632if ( @int x = f()@ ) ... $\C{// x != 0}$
     633if ( @int x = f(), y = g()@ ) ... $\C{// x != 0 \&\& y != 0}$
     634if ( @int x = f(), y = g(); x < y@ ) ... $\C{// relational expression}$
     635if ( @struct S { int i; } x = { f() }; x.i < 4@ ) $\C{// relational expression}$
     636
     637while ( @int x = f()@ ) ... $\C{// x != 0}$
     638while ( @int x = f(), y = g()@ ) ... $\C{// x != 0 \&\& y != 0}$
     639while ( @int x = f(), y = g(); x < y@ ) ... $\C{// relational expression}$
     640while ( @struct S { int i; } x = { f() }; x.i < 4@ ) ... $\C{// relational expression}$
    642641\end{cfa}
    643642Unless a relational expression is specified, each variable is compared not equal to 0, which is the standard semantics for the ©if©/©while© expression, and the results are combined using the logical ©&&© operator.
     
    646645
    647646
    648 %\section{\texorpdfstring{\protect\lstinline{case} Clause}{case Clause}}
     647%\section{\texorpdfstring{\protect\lstinline@case@ Clause}{case Clause}}
    649648\subsection{\texorpdfstring{\LstKeywordStyle{case} Clause}{case Clause}}
    650649\label{s:caseClause}
     
    659658\begin{cfa}
    660659switch ( i ) {
    661   case ®1, 3, 5®:
     660  case @1, 3, 5@:
    662661        ...
    663   case ®2, 4, 6®:
     662  case @2, 4, 6@:
    664663        ...
    665664}
     
    686685\end{cquote}
    687686In addition, subranges are allowed to specify case values.\footnote{
    688 gcc has the same mechanism but awkward syntax, \lstinline{2 ...42}, because a space is required after a number, otherwise the period is a decimal point.}
     687gcc has the same mechanism but awkward syntax, \lstinline@2 ...42@, because a space is required after a number, otherwise the period is a decimal point.}
    689688\begin{cfa}
    690689switch ( i ) {
    691   case ®1~5:® $\C{// 1, 2, 3, 4, 5}$
     690  case @1~5:@ $\C{// 1, 2, 3, 4, 5}$
    692691        ...
    693   case ®10~15:® $\C{// 10, 11, 12, 13, 14, 15}$
     692  case @10~15:@ $\C{// 10, 11, 12, 13, 14, 15}$
    694693        ...
    695694}
     
    697696Lists of subranges are also allowed.
    698697\begin{cfa}
    699 case ®1~5, 12~21, 35~42®:
    700 \end{cfa}
    701 
    702 
    703 %\section{\texorpdfstring{\protect\lstinline{switch} Statement}{switch Statement}}
     698case @1~5, 12~21, 35~42@:
     699\end{cfa}
     700
     701
     702%\section{\texorpdfstring{\protect\lstinline@switch@ Statement}{switch Statement}}
    704703\subsection{\texorpdfstring{\LstKeywordStyle{switch} Statement}{switch Statement}}
    705704
     
    741740if ( argc == 3 ) {
    742741        // open output file
    743         ®// open input file
    744 ®} else if ( argc == 2 ) {
    745         ®// open input file (duplicate)
    746 
    747 ®} else {
     742        @// open input file
     743@} else if ( argc == 2 ) {
     744        @// open input file (duplicate)
     745
     746@} else {
    748747        // usage message
    749748}
     
    756755\begin{cfa}
    757756switch ( i ) {
    758   ®case 1: case 3: case 5:®     // odd values
     757  @case 1: case 3: case 5:@     // odd values
    759758        // odd action
    760759        break;
    761   ®case 2: case 4: case 6:®     // even values
     760  @case 2: case 4: case 6:@     // even values
    762761        // even action
    763762        break;
     
    775774        if ( j < k ) {
    776775                ...
    777           ®case 1:®             // transfer into "if" statement
     776          @case 1:@             // transfer into "if" statement
    778777                ...
    779778        } // if
     
    781780        while ( j < 5 ) {
    782781                ...
    783           ®case 3:®             // transfer into "while" statement
     782          @case 3:@             // transfer into "while" statement
    784783                ...
    785784        } // while
     
    822821\begin{cfa}
    823822switch ( x ) {
    824         ®int y = 1;® $\C{// unreachable initialization}$
    825         ®x = 7;® $\C{// unreachable code without label/branch}$
     823        @int y = 1;@ $\C{// unreachable initialization}$
     824        @x = 7;@ $\C{// unreachable code without label/branch}$
    826825  case 0: ...
    827826        ...
    828         ®int z = 0;® $\C{// unreachable initialization, cannot appear after case}$
     827        @int z = 0;@ $\C{// unreachable initialization, cannot appear after case}$
    829828        z = 2;
    830829  case 1:
    831         ®x = z;® $\C{// without fall through, z is uninitialized}$
     830        @x = z;@ $\C{// without fall through, z is uninitialized}$
    832831}
    833832\end{cfa}
     
    861860Therefore, to preserve backwards compatibility, it is necessary to introduce a new kind of ©switch© statement, called ©choose©, with no implicit fall-through semantics and an explicit fall-through if the last statement of a case-clause ends with the new keyword ©fallthrough©/©fallthru©, \eg:
    862861\begin{cfa}
    863 ®choose® ( i ) {
     862@choose@ ( i ) {
    864863  case 1:  case 2:  case 3:
    865864        ...
    866         ®// implicit end of switch (break)
    867   ®case 5:
     865        @// implicit end of switch (break)
     866  @case 5:
    868867        ...
    869         ®fallthru®; $\C{// explicit fall through}$
     868        @fallthru@; $\C{// explicit fall through}$
    870869  case 7:
    871870        ...
    872         ®break® $\C{// explicit end of switch (redundant)}$
     871        @break@ $\C{// explicit end of switch (redundant)}$
    873872  default:
    874873        j = 3;
     
    891890\begin{cfa}
    892891switch ( x ) {
    893         ®int i = 0;® $\C{// allowed only at start}$
     892        @int i = 0;@ $\C{// allowed only at start}$
    894893  case 0:
    895894        ...
    896         ®int j = 0;® $\C{// disallowed}$
     895        @int j = 0;@ $\C{// disallowed}$
    897896  case 1:
    898897        {
    899                 ®int k = 0;® $\C{// allowed at different nesting levels}$
     898                @int k = 0;@ $\C{// allowed at different nesting levels}$
    900899                ...
    901           ®case 2:® $\C{// disallow case in nested statements}$
     900          @case 2:@ $\C{// disallow case in nested statements}$
    902901        }
    903902  ...
     
    916915  case 3:
    917916        if ( ... ) {
    918                 ... ®fallthru;® // goto case 4
     917                ... @fallthru;@ // goto case 4
    919918        } else {
    920919                ...
     
    931930choose ( ... ) {
    932931  case 3:
    933         ... ®fallthrough common;®
     932        ... @fallthrough common;@
    934933  case 4:
    935         ... ®fallthrough common;®
    936 
    937   ®common:® // below fallthrough
     934        ... @fallthrough common;@
     935
     936  @common:@ // below fallthrough
    938937                          // at case-clause level
    939938        ...     // common code for cases 3/4
     
    951950                for ( ... ) {
    952951                        // multi-level transfer
    953                         ... ®fallthru common;®
     952                        ... @fallthru common;@
    954953                }
    955954                ...
    956955        }
    957956        ...
    958   ®common:® // below fallthrough
     957  @common:@ // below fallthrough
    959958                          // at case-clause level
    960959\end{cfa}
     
    971970\hline
    972971\begin{cfa}
    973 while ®($\,$)® { sout | "empty"; break; }
    974 do { sout | "empty"; break; } while ®($\,$)®;
    975 for ®($\,$)® { sout | "empty"; break; }
    976 for ( ®0® ) { sout | "A"; } sout | "zero";
    977 for ( ®1® ) { sout | "A"; }
    978 for ( ®10® ) { sout | "A"; }
    979 for ( ®= 10® ) { sout | "A"; }
    980 for ( ®1 ~= 10 ~ 2® ) { sout | "B"; }
    981 for ( ®10 -~= 1 ~ 2® ) { sout | "C"; }
    982 for ( ®0.5 ~ 5.5® ) { sout | "D"; }
    983 for ( ®5.5 -~ 0.5® ) { sout | "E"; }
    984 for ( ®i; 10® ) { sout | i; }
    985 for ( ®i; = 10® ) { sout | i; }
    986 for ( ®i; 1 ~= 10 ~ 2® ) { sout | i; }
    987 for ( ®i; 10 -~= 1 ~ 2® ) { sout | i; }
    988 for ( ®i; 0.5 ~ 5.5® ) { sout | i; }
    989 for ( ®i; 5.5 -~ 0.5® ) { sout | i; }
    990 for ( ®ui; 2u ~= 10u ~ 2u® ) { sout | ui; }
    991 for ( ®ui; 10u -~= 2u ~ 2u® ) { sout | ui; }
     972while @($\,$)@ { sout | "empty"; break; }
     973do { sout | "empty"; break; } while @($\,$)@;
     974for @($\,$)@ { sout | "empty"; break; }
     975for ( @0@ ) { sout | "A"; } sout | "zero";
     976for ( @1@ ) { sout | "A"; }
     977for ( @10@ ) { sout | "A"; }
     978for ( @= 10@ ) { sout | "A"; }
     979for ( @1 ~= 10 ~ 2@ ) { sout | "B"; }
     980for ( @10 -~= 1 ~ 2@ ) { sout | "C"; }
     981for ( @0.5 ~ 5.5@ ) { sout | "D"; }
     982for ( @5.5 -~ 0.5@ ) { sout | "E"; }
     983for ( @i; 10@ ) { sout | i; }
     984for ( @i; = 10@ ) { sout | i; }
     985for ( @i; 1 ~= 10 ~ 2@ ) { sout | i; }
     986for ( @i; 10 -~= 1 ~ 2@ ) { sout | i; }
     987for ( @i; 0.5 ~ 5.5@ ) { sout | i; }
     988for ( @i; 5.5 -~ 0.5@ ) { sout | i; }
     989for ( @ui; 2u ~= 10u ~ 2u@ ) { sout | ui; }
     990for ( @ui; 10u -~= 2u ~ 2u@ ) { sout | ui; }
    992991enum { N = 10 };
    993 for ( ®N® ) { sout | "N"; }
    994 for ( ®i; N® ) { sout | i; }
    995 for ( ®i; N -~ 0® ) { sout | i; }
     992for ( @N@ ) { sout | "N"; }
     993for ( @i; N@ ) { sout | i; }
     994for ( @i; N -~ 0@ ) { sout | i; }
    996995const int start = 3, comp = 10, inc = 2;
    997 for ( ®i; start ~ comp ~ inc + 1® ) { sout | i; }
    998 for ( i; 1 ~ ®@® ) { if ( i > 10 ) break; sout | i; }
    999 for ( i; 10 -~ ®@® ) { if ( i < 0 ) break; sout | i; }
    1000 for ( i; 2 ~ ®@® ~ 2 ) { if ( i > 10 ) break; sout | i; }
    1001 for ( i; 2.1 ~ ®@® ~ ®@® ) { if ( i > 10.5 ) break; sout | i; i += 1.7; }
    1002 for ( i; 10 -~ ®@® ~ 2 ) { if ( i < 0 ) break; sout | i; }
    1003 for ( i; 12.1 ~ ®@® ~ ®@® ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; }
    1004 for ( i; 5 ®:® j; -5 ~ @ ) { sout | i | j; }
    1005 for ( i; 5 ®:® j; -5 -~ @ ) { sout | i | j; }
    1006 for ( i; 5 ®:® j; -5 ~ @ ~ 2 ) { sout | i | j; }
    1007 for ( i; 5 ®:® j; -5 -~ @ ~ 2 ) { sout | i | j; }
    1008 for ( i; 5 ®:® j; -5 ~ @ ) { sout | i | j; }
    1009 for ( i; 5 ®:® j; -5 -~ @ ) { sout | i | j; }
    1010 for ( i; 5 ®:® j; -5 ~ @ ~ 2 ) { sout | i | j; }
    1011 for ( i; 5 ®:® j; -5 -~ @ ~ 2 ) { sout | i | j; }
    1012 for ( i; 5 ®:® j; -5 -~ @ ~ 2 ®:® k; 1.5 ~ @ ) { sout | i | j | k; }
    1013 for ( i; 5 ®:® j; -5 -~ @ ~ 2 ®:® k; 1.5 ~ @ ) { sout | i | j | k; }
    1014 for ( i; 5 ®:® k; 1.5 ~ @ ®:® j; -5 -~ @ ~ 2 ) { sout | i | j | k; }
     996for ( @i; start ~ comp ~ inc + 1@ ) { sout | i; }
     997for ( i; 1 ~ $\R{@}$ ) { if ( i > 10 ) break; sout | i; }
     998for ( i; 10 -~ $\R{@}$ ) { if ( i < 0 ) break; sout | i; }
     999for ( i; 2 ~ $\R{@}$ ~ 2 ) { if ( i > 10 ) break; sout | i; }
     1000for ( i; 2.1 ~ $\R{@}$ ~ $\R{@}$ ) { if ( i > 10.5 ) break; sout | i; i += 1.7; }
     1001for ( i; 10 -~ $\R{@}$ ~ 2 ) { if ( i < 0 ) break; sout | i; }
     1002for ( i; 12.1 ~ $\R{@}$ ~ $\R{@}$ ) { if ( i < 2.5 ) break; sout | i; i -= 1.7; }
     1003for ( i; 5 @:@ j; -5 ~ $@$ ) { sout | i | j; }
     1004for ( i; 5 @:@ j; -5 -~ $@$ ) { sout | i | j; }
     1005for ( i; 5 @:@ j; -5 ~ $@$ ~ 2 ) { sout | i | j; }
     1006for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 ) { sout | i | j; }
     1007for ( i; 5 @:@ j; -5 ~ $@$ ) { sout | i | j; }
     1008for ( i; 5 @:@ j; -5 -~ $@$ ) { sout | i | j; }
     1009for ( i; 5 @:@ j; -5 ~ $@$ ~ 2 ) { sout | i | j; }
     1010for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 ) { sout | i | j; }
     1011for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 @:@ k; 1.5 ~ $@$ ) { sout | i | j | k; }
     1012for ( i; 5 @:@ j; -5 -~ $@$ ~ 2 @:@ k; 1.5 ~ $@$ ) { sout | i | j | k; }
     1013for ( i; 5 @:@ k; 1.5 ~ $@$ @:@ j; -5 -~ $@$ ~ 2 ) { sout | i | j | k; }
    10151014\end{cfa}
    10161015&
     
    10901089The loop index is polymorphic in the type of the comparison value N (when the start value is implicit) or the start value M.
    10911090\begin{cfa}
    1092 for ( i; ®5® )                                  $\C[2.5in]{// typeof(5) i; 5 is comparison value}$
    1093 for ( i; ®1.5®~5.5~0.5 )                $\C{// typeof(1.5) i; 1.5 is start value}$
     1091for ( i; @5@ )                                  $\C[2.5in]{// typeof(5) i; 5 is comparison value}$
     1092for ( i; @1.5@~5.5~0.5 )                $\C{// typeof(1.5) i; 1.5 is start value}$
    10941093\end{cfa}
    10951094\item
    10961095An empty conditional implies comparison value of ©1© (true).
    10971096\begin{cfa}
    1098 while ( ®/*empty*/®  )                  $\C{// while ( true )}$
    1099 for ( ®/*empty*/® )                    $\C{// for ( ; true; )}$
    1100 do ... while ( ®/*empty*/®  )    $\C{// do ... while ( true )}$
     1097while ( $\R{/*empty*/}$ )               $\C{// while ( true )}$
     1098for ( $\R{/*empty*/}$ )                 $\C{// for ( ; true; )}$
     1099do ... while ( $\R{/*empty*/}$ ) $\C{// do ... while ( true )}$
    11011100\end{cfa}
    11021101\item
    11031102A comparison N is implicit up-to exclusive range [0,N\R{)}.
    11041103\begin{cfa}
    1105 for ( ®5® )                                             $\C{// for ( typeof(5) i; i < 5; i += 1 )}$
     1104for ( @5@ )                                             $\C{// for ( typeof(5) i; i < 5; i += 1 )}$
    11061105\end{cfa}
    11071106\item
    11081107A comparison ©=© N is implicit up-to inclusive range [0,N\R{]}.
    11091108\begin{cfa}
    1110 for ( ®=®5 )                                    $\C{// for ( typeof(5) i; i <= 5; i += 1 )}$
     1109for ( @=@5 )                                    $\C{// for ( typeof(5) i; i <= 5; i += 1 )}$
    11111110\end{cfa}
    11121111\item
    11131112The up-to range M ©~©\index{~@©~©} N means exclusive range [M,N\R{)}.
    11141113\begin{cfa}
    1115 for ( 1®~®5 )                                   $\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$
     1114for ( 1@~@5 )                                   $\C{// for ( typeof(1) i = 1; i < 5; i += 1 )}$
    11161115\end{cfa}
    11171116\item
    11181117The up-to range M ©~=©\index{~=@©~=©} N means inclusive range [M,N\R{]}.
    11191118\begin{cfa}
    1120 for ( 1®~=®5 )                                  $\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$
     1119for ( 1@~=@5 )                                  $\C{// for ( typeof(1) i = 1; i <= 5; i += 1 )}$
    11211120\end{cfa}
    11221121\item
    11231122The down-to range M ©-~©\index{-~@©-~©} N means exclusive range [N,M\R{)}.
    11241123\begin{cfa}
    1125 for ( 1®-~®5 )                                  $\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$
     1124for ( 1@-~@5 )                                  $\C{// for ( typeof(1) i = 5; i > 0; i -= 1 )}$
    11261125\end{cfa}
    11271126\item
    11281127The down-to range M ©-~=©\index{-~=@©-~=©} N means inclusive range [N,M\R{]}.
    11291128\begin{cfa}
    1130 for ( 1®-~=®5 )                                 $\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$
     1129for ( 1@-~=@5 )                                 $\C{// for ( typeof(1) i = 5; i >= 0; i -= 1 )}$
    11311130\end{cfa}
    11321131\item
    11331132©@© means put nothing in this field.
    11341133\begin{cfa}
    1135 for ( 1~®@®~2 )                                 $\C{// for ( typeof(1) i = 1; /*empty*/; i += 2 )}$
     1134for ( 1~$\R{@}$~2 )                             $\C{// for ( typeof(1) i = 1; /*empty*/; i += 2 )}$
    11361135\end{cfa}
    11371136\item
    11381137©:© means start another index.
    11391138\begin{cfa}
    1140 for ( i; 5 ®:® j; 2~12~3 )              $\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}\CRT$
     1139for ( i; 5 @:@ j; 2~12~3 )              $\C{// for ( typeof(i) i = 1, j = 2; i < 5 \&\& j < 12; i += 1, j += 3 )}\CRT$
    11411140\end{cfa}
    11421141\end{itemize}
    11431142
    11441143
    1145 %\subsection{\texorpdfstring{Labelled \protect\lstinline{continue} / \protect\lstinline{break}}{Labelled continue / break}}
     1144%\subsection{\texorpdfstring{Labelled \protect\lstinline@continue@ / \protect\lstinline@break@}{Labelled continue / break}}
    11461145\subsection{\texorpdfstring{Labelled \LstKeywordStyle{continue} / \LstKeywordStyle{break} Statement}{Labelled continue / break Statement}}
    11471146
     
    11581157\begin{lrbox}{\myboxA}
    11591158\begin{cfa}[tabsize=3]
    1160 ®Compound:® {
    1161         ®Try:® try {
    1162                 ®For:® for ( ... ) {
    1163                         ®While:® while ( ... ) {
    1164                                 ®Do:® do {
    1165                                         ®If:® if ( ... ) {
    1166                                                 ®Switch:® switch ( ... ) {
     1159@Compound:@ {
     1160        @Try:@ try {
     1161                @For:@ for ( ... ) {
     1162                        @While:@ while ( ... ) {
     1163                                @Do:@ do {
     1164                                        @If:@ if ( ... ) {
     1165                                                @Switch:@ switch ( ... ) {
    11671166                                                        case 3:
    1168                                                                 ®break Compound®;
    1169                                                                 ®break Try®;
    1170                                                                 ®break For®;      /* or */  ®continue For®;
    1171                                                                 ®break While®;  /* or */  ®continue While®;
    1172                                                                 ®break Do®;      /* or */  ®continue Do®;
    1173                                                                 ®break If®;
    1174                                                                 ®break Switch®;
     1167                                                                @break Compound@;
     1168                                                                @break Try@;
     1169                                                                @break For@;      /* or */  @continue For@;
     1170                                                                @break While@;  /* or */  @continue While@;
     1171                                                                @break Do@;      /* or */  @continue Do@;
     1172                                                                @break If@;
     1173                                                                @break Switch@;
    11751174                                                        } // switch
    11761175                                                } else {
    1177                                                         ... ®break If®; ...     // terminate if
     1176                                                        ... @break If@; ...     // terminate if
    11781177                                                } // if
    11791178                                } while ( ... ); // do
    11801179                        } // while
    11811180                } // for
    1182         } ®finally® { // always executed
     1181        } @finally@ { // always executed
    11831182        } // try
    11841183} // compound
     
    11901189{
    11911190
    1192                 ®ForC:® for ( ... ) {
    1193                         ®WhileC:® while ( ... ) {
    1194                                 ®DoC:® do {
     1191                @ForC:@ for ( ... ) {
     1192                        @WhileC:@ while ( ... ) {
     1193                                @DoC:@ do {
    11951194                                        if ( ... ) {
    11961195                                                switch ( ... ) {
    11971196                                                        case 3:
    1198                                                                 ®goto Compound®;
    1199                                                                 ®goto Try®;
    1200                                                                 ®goto ForB®;      /* or */  ®goto ForC®;
    1201                                                                 ®goto WhileB®;  /* or */  ®goto WhileC®;
    1202                                                                 ®goto DoB®;      /* or */  ®goto DoC®;
    1203                                                                 ®goto If®;
    1204                                                                 ®goto Switch®;
    1205                                                         } ®Switch:® ;
     1197                                                                @goto Compound@;
     1198                                                                @goto Try@;
     1199                                                                @goto ForB@;      /* or */  @goto ForC@;
     1200                                                                @goto WhileB@;  /* or */  @goto WhileC@;
     1201                                                                @goto DoB@;      /* or */  @goto DoC@;
     1202                                                                @goto If@;
     1203                                                                @goto Switch@;
     1204                                                        } @Switch:@ ;
    12061205                                                } else {
    1207                                                         ... ®goto If®; ...      // terminate if
    1208                                                 } ®If:®;
    1209                                 } while ( ... ); ®DoB:® ;
    1210                         } ®WhileB:® ;
    1211                 } ®ForB:® ;
    1212 
    1213 
    1214 } ®Compound:® ;
     1206                                                        ... @goto If@; ...      // terminate if
     1207                                                } @If:@;
     1208                                } while ( ... ); @DoB:@ ;
     1209                        } @WhileB:@ ;
     1210                } @ForB:@ ;
     1211
     1212
     1213} @Compound:@ ;
    12151214\end{cfa}
    12161215\end{lrbox}
     
    12411240
    12421241
    1243 %\subsection{\texorpdfstring{\protect\lstinline{with} Statement}{with Statement}}
     1242%\subsection{\texorpdfstring{\protect\lstinline@with@ Statement}{with Statement}}
    12441243\subsection{\texorpdfstring{\LstKeywordStyle{with} Statement}{with Statement}}
    12451244\label{s:WithStatement}
     
    12561255\begin{cfa}
    12571256Person p
    1258 ®p.®name; ®p.®address; ®p.®sex; $\C{// access containing fields}$
     1257@p.@name; @p.@address; @p.@sex; $\C{// access containing fields}$
    12591258\end{cfa}
    12601259which extends to multiple levels of qualification for nested aggregates and multiple aggregates.
    12611260\begin{cfa}
    12621261struct Ticket { ... } t;
    1263 ®p.name®.first; ®p.address®.street;             $\C{// access nested fields}$
    1264 ®t.®departure; ®t.®cost;                                $\C{// access multiple aggregate}$
     1262@p.name@.first; @p.address@.street;             $\C{// access nested fields}$
     1263@t.@departure; @t.@cost;                                $\C{// access multiple aggregate}$
    12651264\end{cfa}
    12661265Repeated aggregate qualification is tedious and makes code difficult to read.
     
    12851284\begin{C++}
    12861285struct S {
    1287         char ®c®;   int ®i®;   double ®d®;
     1286        char @c@;   int @i@;   double @d@;
    12881287        void f( /* S * this */ ) {                              $\C{// implicit ``this'' parameter}$
    1289                 ®c®;   ®i®;   ®d®;                                      $\C{// this->c; this->i; this->d;}$
     1288                @c@;   @i@;   @d@;                                      $\C{// this->c; this->i; this->d;}$
    12901289        }
    12911290}
     
    12951294\begin{cfa}
    12961295struct T {
    1297         char ®m®;   int ®i®;   double ®n®;              $\C{// derived class variables}$
     1296        char @m@;   int @i@;   double @n@;              $\C{// derived class variables}$
    12981297};
    12991298struct S : public T {
    1300         char ®c®;   int ®i®;   double ®d®;              $\C{// class variables}$
    1301         void g( double ®d®, T & t ) {
    1302                 d;   ®t®.m;   ®t®.i;   ®t®.n;           $\C{// function parameter}$
    1303                 c;   i;   ®this->®d;   ®S::®d;          $\C{// class S variables}$
    1304                 m;   ®T::®i;   n;                                       $\C{// class T variables}$
     1299        char @c@;   int @i@;   double @d@;              $\C{// class variables}$
     1300        void g( double @d@, T & t ) {
     1301                d;   @t@.m;   @t@.i;   @t@.n;           $\C{// function parameter}$
     1302                c;   i;   @this->@d;   @S::@d;          $\C{// class S variables}$
     1303                m;   @T::@i;   n;                                       $\C{// class T variables}$
    13051304        }
    13061305};
     
    13121311Hence, the qualified fields become variables with the side-effect that it is simpler to write, easier to read, and optimize field references in a block.
    13131312\begin{cfa}
    1314 void f( S & this ) ®with ( this )® {            $\C{// with statement}$
    1315         ®c®;   ®i®;   ®d®;                                              $\C{// this.c, this.i, this.d}$
     1313void f( S & this ) @with ( this )@ {            $\C{// with statement}$
     1314        @c@;   @i@;   @d@;                                              $\C{// this.c, this.i, this.d}$
    13161315}
    13171316\end{cfa}
    13181317with the generality of opening multiple aggregate-parameters:
    13191318\begin{cfa}
    1320 void g( S & s, T & t ) ®with ( s, t )® {        $\C{// multiple aggregate parameters}$
    1321         c;   ®s.®i;   d;                                                $\C{// s.c, s.i, s.d}$
    1322         m;   ®t.®i;   n;                                                $\C{// t.m, t.i, t.n}$
     1319void g( S & s, T & t ) @with ( s, t )@ {        $\C{// multiple aggregate parameters}$
     1320        c;   @s.@i;   d;                                                $\C{// s.c, s.i, s.d}$
     1321        m;   @t.@i;   n;                                                $\C{// t.m, t.i, t.n}$
    13231322}
    13241323\end{cfa}
     
    13391338The difference between parallel and nesting occurs for fields with the same name and type:
    13401339\begin{cfa}
    1341 struct Q { int ®i®; int k; int ®m®; } q, w;
    1342 struct R { int ®i®; int j; double ®m®; } r, w;
     1340struct Q { int @i@; int k; int @m@; } q, w;
     1341struct R { int @i@; int j; double @m@; } r, w;
    13431342with ( r, q ) {
    13441343        j + k;                                                                  $\C{// unambiguous, r.j + q.k}$
     
    13731372\begin{cfa}
    13741373void ?{}( S & s, int i ) with ( s ) { $\C{// constructor}$
    1375         ®s.i = i;®  j = 3;  m = 5.5; $\C{// initialize fields}$
     1374        @s.i = i;@  j = 3;  m = 5.5; $\C{// initialize fields}$
    13761375}
    13771376\end{cfa}
     
    13861385and implicitly opened \emph{after} a function-body open, to give them higher priority:
    13871386\begin{cfa}
    1388 void ?{}( S & s, int ®i® ) with ( s ) ®with( $\emph{\R{params}}$ )® { // syntax not allowed, illustration only
    1389         s.i = ®i®; j = 3; m = 5.5;
     1387void ?{}( S & s, int @i@ ) with ( s ) @with( $\emph{\R{params}}$ )@ { // syntax not allowed, illustration only
     1388        s.i = @i@; j = 3; m = 5.5;
    13901389}
    13911390\end{cfa}
     
    14701469For example, a routine returning a \Index{pointer} to an array of integers is defined and used in the following way:
    14711470\begin{cfa}
    1472 int ®(*®f®())[®5®]® {...}; $\C{// definition}$
    1473  ... ®(*®f®())[®3®]® += 1; $\C{// usage}$
     1471int @(*@f@())[@5@]@ {...}; $\C{// definition}$
     1472 ... @(*@f@())[@3@]@ += 1; $\C{// usage}$
    14741473\end{cfa}
    14751474Essentially, the return type is wrapped around the routine name in successive layers (like an \Index{onion}).
     
    14871486\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c}{\textbf{C}}        \\
    14881487\begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}]
    1489 #[5] *# ®int® x1;
    1490 #* [5]# ®int® x2;
    1491 #[* [5] int]# f®( int p )®;
     1488#[5] *# @int@ x1;
     1489#* [5]# @int@ x2;
     1490#[* [5] int]# f@( int p )@;
    14921491\end{cfa}
    14931492&
    14941493\begin{cfa}[moredelim={**[is][\color{blue}]{\#}{\#}}]
    1495 ®int® #*# x1 #[5]#;
    1496 ®int® #(*#x2#)[5]#;
    1497 #int (*#f®( int p )®#)[5]#;
     1494@int@ #*# x1 #[5]#;
     1495@int@ #(*#x2#)[5]#;
     1496#int (*#f@( int p )@#)[5]#;
    14981497\end{cfa}
    14991498\end{tabular}
     
    15071506\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c}{\textbf{C}}        \\
    15081507\begin{cfa}
    1509 ®*® int x, y;
     1508@*@ int x, y;
    15101509\end{cfa}
    15111510&
    15121511\begin{cfa}
    1513 int ®*®x, ®*®y;
     1512int @*@x, @*@y;
    15141513\end{cfa}
    15151514\end{tabular}
     
    15201519\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c}{\textbf{C}}        \\
    15211520\begin{cfa}
    1522 ®*® int x;
     1521@*@ int x;
    15231522int y;
    15241523\end{cfa}
    15251524&
    15261525\begin{cfa}
    1527 int ®*®x, y;
     1526int @*@x, y;
    15281527
    15291528\end{cfa}
     
    16611660&
    16621661\begin{cfa}
    1663 int * ®const® x = (int *)100
     1662int * @const@ x = (int *)100
    16641663*x = 3;                 // implicit dereference
    1665 int * ®const® y = (int *)104;
     1664int * @const@ y = (int *)104;
    16661665*y = *x;                        // implicit dereference
    16671666\end{cfa}
     
    17011700\begin{tabular}{@{}l@{\hspace{2em}}l@{}}
    17021701\begin{cfa}
    1703 int x, y, ®*® p1, ®*® p2, ®**® p3;
    1704 p1 = ®&®x;     // p1 points to x
     1702int x, y, @*@ p1, @*@ p2, @**@ p3;
     1703p1 = @&@x;     // p1 points to x
    17051704p2 = p1;     // p2 points to x
    1706 p1 = ®&®y;     // p1 points to y
     1705p1 = @&@y;     // p1 points to y
    17071706p3 = &p2;  // p3 points to p2
    17081707\end{cfa}
     
    17301729\begin{cfa}
    17311730p1 = p2; $\C{// pointer address assignment}$
    1732 ®*®p2 = ®*®p1 + x; $\C{// pointed-to value assignment / operation}$
     1731@*@p2 = @*@p1 + x; $\C{// pointed-to value assignment / operation}$
    17331732\end{cfa}
    17341733The C semantics work well for situations where manipulation of addresses is the primary meaning and data is rarely accessed, such as storage management (©malloc©/©free©).
     
    17461745To support this common case, a reference type is introduced in \CFA, denoted by ©&©, which is the opposite dereference semantics to a pointer type, making the value at the pointed-to location the implicit semantics for dereferencing (similar but not the same as \CC \Index{reference type}s).
    17471746\begin{cfa}
    1748 int x, y, ®&® r1, ®&® r2, ®&&® r3;
    1749 ®&®r1 = &x; $\C{// r1 points to x}$
    1750 ®&®r2 = &r1; $\C{// r2 points to x}$
    1751 ®&®r1 = &y; $\C{// r1 points to y}$
    1752 ®&&®r3 = ®&®&r2; $\C{// r3 points to r2}$
     1747int x, y, @&@ r1, @&@ r2, @&&@ r3;
     1748@&@r1 = &x; $\C{// r1 points to x}$
     1749@&@r2 = &r1; $\C{// r2 points to x}$
     1750@&@r1 = &y; $\C{// r1 points to y}$
     1751@&&@r3 = @&@&r2; $\C{// r3 points to r2}$
    17531752r2 = ((r1 + r2) * (r3 - r1)) / (r3 - 15); $\C{// implicit dereferencing}$
    17541753\end{cfa}
     
    17571756One way to conceptualize a reference is via a rewrite rule, where the compiler inserts a dereference operator before the reference variable for each reference qualifier in a declaration, so the previous example becomes:
    17581757\begin{cfa}
    1759 ®*®r2 = ((®*®r1 + ®*®r2) ®*® (®**®r3 - ®*®r1)) / (®**®r3 - 15);
     1758@*@r2 = ((@*@r1 + @*@r2) @*@ (@**@r3 - @*@r1)) / (@**@r3 - 15);
    17601759\end{cfa}
    17611760When a reference operation appears beside a dereference operation, \eg ©&*©, they cancel out.
     
    17661765For a \CFA reference type, the cancellation on the left-hand side of assignment leaves the reference as an address (\Index{lvalue}):
    17671766\begin{cfa}
    1768 (&®*®)r1 = &x; $\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}$
     1767(&@*@)r1 = &x; $\C{// (\&*) cancel giving address in r1 not variable pointed-to by r1}$
    17691768\end{cfa}
    17701769Similarly, the address of a reference can be obtained for assignment or computation (\Index{rvalue}):
    17711770\begin{cfa}
    1772 (&(&®*®)®*®)r3 = &(&®*®)r2; $\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}$
     1771(&(&@*@)@*@)r3 = &(&@*@)r2; $\C{// (\&*) cancel giving address in r2, (\&(\&*)*) cancel giving address in r3}$
    17731772\end{cfa}
    17741773Cancellation\index{cancellation!pointer/reference}\index{pointer!cancellation} works to arbitrary depth.
     
    17931792const int cx = 5; $\C{// cannot change cx;}$
    17941793const int & cr = cx; $\C{// cannot change what cr points to}$
    1795 ®&®cr = &cx; $\C{// can change cr}$
     1794@&@cr = &cx; $\C{// can change cr}$
    17961795cr = 7; $\C{// error, cannot change cx}$
    17971796int & const rc = x; $\C{// must be initialized}$
    1798 ®&®rc = &x; $\C{// error, cannot change rc}$
     1797@&@rc = &x; $\C{// error, cannot change rc}$
    17991798const int & const crc = cx; $\C{// must be initialized}$
    18001799crc = 7; $\C{// error, cannot change cx}$
    1801 ®&®crc = &cx; $\C{// error, cannot change crc}$
     1800@&@crc = &cx; $\C{// error, cannot change crc}$
    18021801\end{cfa}
    18031802Hence, for type ©& const©, there is no pointer assignment, so ©&rc = &x© is disallowed, and \emph{the address value cannot be the null pointer unless an arbitrary pointer is coerced\index{coercion} into the reference}:
     
    18201819\multicolumn{1}{c@{\hspace{3em}}}{\textbf{\CFA}}        & \multicolumn{1}{c}{\textbf{C}}        \\
    18211820\begin{cfa}
    1822 ®const® * ®const® * const int ccp;
    1823 ®const® & ®const® & const int ccr;
     1821@const@ * @const@ * const int ccp;
     1822@const@ & @const@ & const int ccr;
    18241823\end{cfa}
    18251824&
    18261825\begin{cfa}
    1827 const int * ®const® * ®const® ccp;
     1826const int * @const@ * @const@ ccp;
    18281827
    18291828\end{cfa}
     
    18571856\begin{cfa}
    18581857int * p = &x; $\C{// assign address of x}$
    1859 ®int * p = x;® $\C{// assign value of x}$
     1858@int * p = x;@ $\C{// assign value of x}$
    18601859int & r = x; $\C{// must have address of x}$
    18611860\end{cfa}
     
    18811880When a pointer/reference parameter has a ©const© value (immutable), it is possible to pass literals and expressions.
    18821881\begin{cfa}
    1883 void f( ®const® int & cr );
    1884 void g( ®const® int * cp );
    1885 f( 3 );                   g( ®&®3 );
    1886 f( x + y );             g( ®&®(x + y) );
     1882void f( @const@ int & cr );
     1883void g( @const@ int * cp );
     1884f( 3 );                   g( @&@3 );
     1885f( x + y );             g( @&@(x + y) );
    18871886\end{cfa}
    18881887Here, the compiler passes the address to the literal 3 or the temporary for the expression ©x + y©, knowing the argument cannot be changed through the parameter.
     
    18951894void f( int & r );
    18961895void g( int * p );
    1897 f( 3 );                   g( ®&®3 ); $\C{// compiler implicit generates temporaries}$
    1898 f( x + y );             g( ®&®(x + y) ); $\C{// compiler implicit generates temporaries}$
     1896f( 3 );                   g( @&@3 ); $\C{// compiler implicit generates temporaries}$
     1897f( x + y );             g( @&@(x + y) ); $\C{// compiler implicit generates temporaries}$
    18991898\end{cfa}
    19001899Essentially, there is an implicit \Index{rvalue} to \Index{lvalue} conversion in this case.\footnote{
     
    19171916Instead, a routine object should be referenced by a ©const© reference:
    19181917\begin{cfa}
    1919 ®const® void (®&® fr)( int ) = f; $\C{// routine reference}$
     1918@const@ void (@&@ fr)( int ) = f; $\C{// routine reference}$
    19201919fr = ... $\C{// error, cannot change code}$
    19211920&fr = ...; $\C{// changing routine reference}$
     
    19791978\begin{cfa}
    19801979int x, &r = x, f( int p );
    1981 x = ®r® + f( ®r® ); $\C{// lvalue reference converts to rvalue}$
     1980x = @r@ + f( @r@ ); $\C{// lvalue reference converts to rvalue}$
    19821981\end{cfa}
    19831982An rvalue has no type qualifiers (©cv©), so the reference qualifiers are dropped.
    19841983
    19851984\item
    1986 lvalue to reference conversion: \lstinline[deletekeywords=lvalue]{lvalue-type cv1 T} converts to ©cv2 T &©, which allows implicitly converting variables to references.
    1987 \begin{cfa}
    1988 int x, &r = ®x®, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$
    1989 f( ®x® ); $\C{// lvalue variable (int) convert to reference (int \&)}$
     1985lvalue to reference conversion: \lstinline[deletekeywords=lvalue]@lvalue-type cv1 T@ converts to ©cv2 T &©, which allows implicitly converting variables to references.
     1986\begin{cfa}
     1987int x, &r = @x@, f( int & p ); $\C{// lvalue variable (int) convert to reference (int \&)}$
     1988f( @x@ ); $\C{// lvalue variable (int) convert to reference (int \&)}$
    19901989\end{cfa}
    19911990Conversion can restrict a type, where ©cv1© $\le$ ©cv2©, \eg passing an ©int© to a ©const volatile int &©, which has low cost.
     
    19971996\begin{cfa}
    19981997int x, & f( int & p );
    1999 f( ®x + 3® );   $\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}$
    2000 ®&f®(...) = &x; $\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT$
     1998f( @x + 3@ );   $\C[1.5in]{// rvalue parameter (int) implicitly converts to lvalue temporary reference (int \&)}$
     1999@&f@(...) = &x; $\C{// rvalue result (int \&) implicitly converts to lvalue temporary reference (int \&)}\CRT$
    20012000\end{cfa}
    20022001In both case, modifications to the temporary are inaccessible (\Index{warning}).
     
    21652164
    21662165
    2167 \section{Enumeration}
    2168 
    2169 An \newterm{enumeration} is a compile-time mechanism to alias names to constants, like ©typedef© is a mechanism to alias names to types.
    2170 Its purpose is to define a restricted-value type providing code-readability and maintenance -- changing an enum's value automatically updates all name usages during compilation.
    2171 
    2172 An enumeration type is a set of names, each called an \newterm{enumeration constant} (shortened to \newterm{enum}) aliased to a fixed value (constant).
    2173 \begin{cfa}
    2174 enum Days { Mon, Tue, Wed, Thu, Fri, Sat, Sun }; // enumeration type definition, set of 7 names & values
    2175 Days days = Mon; // enumeration type declaration and initialization
    2176 \end{cfa}
    2177 The set of enums are injected into the variable namespace at the definition scope.
    2178 Hence, enums may be overloaded with enum/variable/function names.
    2179 \begin{cfa}
    2180 enum Foo { Bar };
    2181 enum Goo { Bar };       $\C[1.75in]{// overload Foo.Bar}$
    2182 int Foo;                        $\C{// type/variable separate namespace}$
    2183 double Bar;                     $\C{// overload Foo.Bar, Goo.Bar}\CRT$
    2184 \end{cfa}
    2185 An anonymous enumeration injects enums with specific values into a scope.
    2186 \begin{cfa}
    2187 enum { Prime = 103, BufferSize = 1024 };
    2188 \end{cfa}
    2189 An enumeration is better than using C \Index{preprocessor} or constant declarations.
    2190 \begin{cquote}
    2191 \begin{tabular}{@{}l@{\hspace{4em}}l@{}}
    2192 \begin{cfa}
    2193 #define Mon 0
    2194 ...
    2195 #define Sun 6
    2196 \end{cfa}
    2197 &
    2198 \begin{cfa}
    2199 const int Mon = 0,
    2200                          ...,
    2201                          Sun = 6;
    2202 \end{cfa}
    2203 \end{tabular}
    2204 \end{cquote}
    2205 because the enumeration is succinct, has automatic numbering, can appear in ©case© labels, does not use storage, and is part of the language type-system.
    2206 Finally, the type of an enum is implicitly or explicitly specified and the constant value can be implicitly or explicitly specified.
    2207 Note, enum values may be repeated in an enumeration.
    2208 
    2209 
    2210 \subsection{Enum type}
    2211 
    2212 The type of enums can be any type, and an enum's value comes from this type.
    2213 Because an enum is a constant, it cannot appear in a mutable context, \eg ©Mon = Sun© is disallowed, and has no address (it is an rvalue).
    2214 Therefore, an enum is automatically converted to its constant's base-type, \eg comparing/printing an enum compares/prints its value rather than the enum name;
    2215 there is no mechanism to print the enum name.
    2216 
    2217 The default enum type is ©int©.
    2218 Hence, ©Days© is the set type ©Mon©, ©Tue©, ...\,, ©Sun©, while the type of each enum is ©int© and each enum represents a fixed integral value.
    2219 If no values are specified for an integral enum type, the enums are automatically numbered by one from left to right starting at zero.
    2220 Hence, the value of enum ©Mon© is 0, ©Tue© is 1, ...\,, ©Sun© is 6.
    2221 If an enum value is specified, numbering continues by one from that value for subsequent unnumbered enums.
    2222 If an enum value is an expression, the compiler performs constant-folding to obtain a constant value.
    2223 
    2224 \CFA allows other integral types with associated values.
    2225 \begin{cfa}
    2226 enum( ®char® ) Letter { A ®= 'A'®,  B,  C,  I ®= 'I'®,  J,  K };
    2227 enum( ®long long int® ) BigNum { X = 123_456_789_012_345,  Y = 345_012_789_456_123 };
    2228 \end{cfa}
    2229 For enumeration ©Letter©, enum ©A©'s value is explicitly set to ©'A'©, with ©B© and ©C© implicitly numbered with increasing values from ©'A'©, and similarly for enums ©I©, ©J©, and ©K©.
    2230 
    2231 Non-integral enum types must be explicitly initialized, \eg ©double© is not automatically numbered by one.
    2232 \begin{cfa}
    2233 // non-integral numeric
    2234 enum( ®double® ) Math { PI_2 = 1.570796, PI = 3.141597,  E = 2.718282 }
    2235 // pointer
    2236 enum( ®char *® ) Name { Fred = "Fred",  Mary = "Mary",  Jane = "Jane" };
    2237 int i, j, k;
    2238 enum( ®int *® ) ptr { I = &i,  J = &j,  K = &k };
    2239 enum( ®int &® ) ref { I = i,  J = j,  K = k };
    2240 // tuple
    2241 enum( ®[int, int]® ) { T = [ 1, 2 ] };
    2242 // function
    2243 void f() {...}   void g() {...}
    2244 enum( ®void (*)()® ) funs { F = f,  F = g };
    2245 // aggregate
    2246 struct S { int i, j; };
    2247 enum( ®S® ) s { A = { 3,  4 }, B = { 7,  8 } };
    2248 // enumeration
    2249 enum( ®Letter® ) Greek { Alph = A, Beta = B, /* more enums */  }; // alphabet intersection
    2250 \end{cfa}
    2251 Enumeration ©Greek© may have more or less enums than ©Letter©, but the enum values \emph{must} be from ©Letter©.
    2252 Therefore, ©Greek© enums are a subset of type ©Letter© and are type compatible with enumeration ©Letter©, but ©Letter© enums are not type compatible with enumeration ©Greek©.
    2253 
    2254 The following examples illustrate the difference between the enumeration type and the type of its enums.
    2255 \begin{cfa}
    2256 Math m = PI;    $\C[1.5in]{// allowed}$
    2257 double d = PI;  $\C{// allowed, conversion to base type}$
    2258 m = E;                  $\C{// allowed}$
    2259 m = Alph;               $\C{// {\color{red}disallowed}}$
    2260 m = 3.141597;   $\C{// {\color{red}disallowed}}$
    2261 d = m;                  $\C{// allowed}$
    2262 d = Alph;               $\C{// {\color{red}disallowed}}$
    2263 Letter l = A;   $\C{// allowed}$
    2264 Greek g = Alph; $\C{// allowed}$
    2265 l = Alph;               $\C{// allowed, conversion to base type}$
    2266 g = A;                  $\C{// {\color{red}disallowed}}\CRT$
    2267 \end{cfa}
    2268 
    2269 A constructor \emph{cannot} be used to initialize enums because a constructor executes at runtime.
    2270 A fallback is explicit C-style initialization using ©@=©.
    2271 \begin{cfa}
    2272 enum( struct vec3 ) Axis { Up @= { 1, 0, 0 }, Left @= { 0, 1, 0 }, Front @= { 0, 0, 1 } }
    2273 \end{cfa}
    2274 Finally, enumeration variables are assignable and comparable only if the appropriate operators are defined for its enum type.
    2275 
    2276 
    2277 \subsection{Inheritance}
    2278 
    2279 \Index{Plan-9}\index{inheritance!enumeration} inheritance may be used with enumerations.
    2280 \begin{cfa}
    2281 enum( char * ) Name2 { ®inline Name®, Jack = "Jack", Jill = "Jill" };
    2282 enum ®/* inferred */®  Name3 { ®inline Name2®, Sue = "Sue", Tom = "Tom" };
    2283 \end{cfa}
    2284 Enumeration ©Name2© inherits all the enums and their values from enumeration ©Name© by containment, and a ©Name© enumeration is a subtype of enumeration ©Name2©.
    2285 Note, enums must be unique in inheritance but enum values may be repeated.
    2286 The enum type for the inheriting type must be the same as the inherited type;
    2287 hence the enum type may be omitted for the inheriting enumeration and it is inferred from the inherited enumeration, as for ©Name3©.
    2288 When inheriting from integral types, automatic numbering may be used, so the inheritance placement left to right is important, \eg the placement of ©Sue© and ©Tom© before or after ©inline Name2©.
    2289 
    2290 Specifically, the inheritance relationship for ©Name©s is:
    2291 \begin{cfa}
    2292 Name $\(\subseteq\)$ Name2 $\(\subseteq\)$ Name3 $\(\subseteq\)$ const char * // enum type of Name
    2293 \end{cfa}
    2294 Hence, given
    2295 \begin{cfa}
    2296 void f( Name );
    2297 void g( Name2 );
    2298 void h( Name3 );
    2299 void j( const char * );
    2300 \end{cfa}
    2301 the following calls are valid
    2302 \begin{cfa}
    2303 f( Fred );
    2304 g( Fred );   g( Jill );
    2305 h( Fred );   h( Jill );   h( Sue );
    2306 j( Fred );    j( Jill );    j( Sue );    j( 'W' );
    2307 \end{cfa}
    2308 Note, the validity of calls is the same for call-by-reference as for call-by-value, and ©const© restrictions are the same as for other types.
    2309 
    2310 Enums cannot be created at runtime, so inheritence problems, such as contra-variance do not apply.
    2311 Only instances of the enum base-type may be created at runtime.
    2312 
    2313 \begin{comment}
    2314 The invariance of references, as I show at the bottom, is easy to overlook.  Not shown, but on the same topic, is that returns work in the opposite direction as parameters.  Hopefully our existing type rules already know both those facts, so that we'd only have to provide the rules that I suggest using the by-value parameters.
    2315 
    2316 The Fred, Jack, and Mary declarations are picked verbatim from our earlier whiteboard, just repeated here for reference.
    2317 
    2318 \begin{cfa}
    2319 // Fred is a subset of char *
    2320 enum( char *) Fred { A = "A", B = "B", C = "C" };
    2321 // Jack is a subset of Fred
    2322 enum( enum Fred ) Jack { W = A, Y = C};
    2323 // Mary is a superset of Fred
    2324 enum Mary { inline Fred, D = "hello" };
    2325 
    2326 // Demonstrating invariance of references
    2327 
    2328 [void] frcs( & * char x ) { char * x0 = x; x = "bye"; }
    2329 [void] frf ( & Fred   x ) { Fred   x0 = x; x = B;     }
    2330 [void] frj ( & Jack   x ) { Jack   x0 = x; x = W;     }
    2331 [void] frm ( & Mary   x ) { Mary   x0 = x; x = D;     }
    2332 
    2333 char * vcs;
    2334 Fred   vf;
    2335 Jack   vj;
    2336 Mary   vm;
    2337 
    2338 // all variant calls: bad  (here are noteworthy examples)
    2339              frcs( vf  );  // can't assign "bye" to vf
    2340              frm ( vf  );  // can't assign D     to vf
    2341              frf ( vj  );  // can't assign B     to vj
    2342 vf  = B    ; frj ( vf  );  // can't assign B     to frj.x0
    2343 vcs = "bye"; frf ( vcs );  // can't assign "bye" to frf.x0
    2344 \end{cfa}
    2345 
    2346 This example is really great. However, I think it's work explicitly doing one with ©const &©.
    2347 \end{comment}
    2348 
    2349 
    23502166\section{Routine Definition}
    23512167
    2352 \CFA supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax.
     2168\CFA also supports a new syntax for routine definition, as well as \Celeven and K\&R routine syntax.
    23532169The point of the new syntax is to allow returning multiple values from a routine~\cite{Galletly96,CLU}, \eg:
    23542170\begin{cfa}
    2355 ®[ int o1, int o2, char o3 ]® f( int i1, char i2, char i3 ) {
     2171@[ int o1, int o2, char o3 ]@ f( int i1, char i2, char i3 ) {
    23562172        $\emph{routine body}$
    23572173}
    23582174\end{cfa}
    23592175where routine ©f© has three output (return values) and three input parameters.
    2360 Existing C syntax cannot be extended with multiple return types because it is impossible to embed a single routine name within multiple return type-specifications.
     2176Existing C syntax cannot be extended with multiple return types because it is impossible to embed a single routine name within multiple return type specifications.
    23612177
    23622178In detail, the brackets, ©[]©, enclose the result type, where each return value is named and that name is a local variable of the particular return type.\footnote{
     
    23652181Declaration qualifiers can only appear at the start of a routine definition, \eg:
    23662182\begin{cfa}
    2367 ®extern® [ int x ] g( int y ) {$\,$}
     2183@extern@ [ int x ] g( int y ) {$\,$}
    23682184\end{cfa}
    23692185Lastly, if there are no output parameters or input parameters, the brackets and/or parentheses must still be specified;
     
    23842200int (*f(x))[ 5 ] int x; {}
    23852201\end{cfa}
    2386 The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter ©x© of type array of 5 integers.
     2202The string ``©int (*f(x))[ 5 ]©'' declares a K\&R style routine of type returning a pointer to an array of 5 integers, while the string ``©[ 5 ] int x©'' declares a \CFA style parameter x of type array of 5 integers.
    23872203Since the strings overlap starting with the open bracket, ©[©, there is an ambiguous interpretation for the string.
    23882204As well, \CFA-style declarations cannot be used to declare parameters for C-style routine-definitions because of the following ambiguity:
     
    24232239\begin{minipage}{\linewidth}
    24242240\begin{cfa}
    2425 ®[ int x, int y ]® f() {
     2241@[ int x, int y ]@ f() {
    24262242        int z;
    24272243        ... x = 0; ... y = z; ...
    2428         ®return;® $\C{// implicitly return x, y}$
     2244        @return;@ $\C{// implicitly return x, y}$
    24292245}
    24302246\end{cfa}
     
    27582574
    27592575int fred() {
    2760         s.t.c = ®S.®R;  // type qualification
    2761         struct ®S.®T t = { ®S.®R, 1, 2 };
    2762         enum ®S.®C c;
    2763         union ®S.T.®U u;
     2576        s.t.c = @S.@R;  // type qualification
     2577        struct @S.@T t = { @S.@R, 1, 2 };
     2578        enum @S.@C c;
     2579        union @S.T.@U u;
    27642580}
    27652581\end{cfa}
     
    27872603qsort( ia, size ); $\C{// sort ascending order using builtin ?<?}$
    27882604{
    2789         ®int ?<?( int x, int y ) { return x > y; }® $\C{// nested routine}$
     2605        @int ?<?( int x, int y ) { return x > y; }@ $\C{// nested routine}$
    27902606        qsort( ia, size ); $\C{// sort descending order by local redefinition}$
    27912607}
     
    27972613\begin{cfa}
    27982614[* [int]( int )] foo() { $\C{// int (* foo())( int )}$
    2799         int ®i® = 7;
     2615        int @i@ = 7;
    28002616        int bar( int p ) {
    2801                 ®i® += 1; $\C{// dependent on local variable}$
    2802                 sout | ®i®;
     2617                @i@ += 1; $\C{// dependent on local variable}$
     2618                sout | @i@;
    28032619        }
    28042620        return bar; $\C{// undefined because of local dependence}$
     
    28182634In C and \CFA, lists of elements appear in several contexts, such as the parameter list of a routine call.
    28192635\begin{cfa}
    2820 f( ®2, x, 3 + i® ); $\C{// element list}$
     2636f( @2, x, 3 + i@ ); $\C{// element list}$
    28212637\end{cfa}
    28222638A list of elements is called a \newterm{tuple}, and is different from a \Index{comma expression}.
     
    29312747In \CFA, it is possible to overcome this restriction by declaring a \newterm{tuple variable}.
    29322748\begin{cfa}
    2933 [int, int] ®qr® = div( 13, 5 ); $\C{// initialize tuple variable}$
    2934 printf( "%d %d\n", ®qr® ); $\C{// print quotient/remainder}$
     2749[int, int] @qr@ = div( 13, 5 ); $\C{// initialize tuple variable}$
     2750printf( "%d %d\n", @qr@ ); $\C{// print quotient/remainder}$
    29352751\end{cfa}
    29362752It is now possible to match the multiple return-values to a single variable, in much the same way as \Index{aggregation}.
     
    35963412\begin{cfa}
    35973413int x = 1, y = 2, z = 3;
    3598 sout | x ®|® y ®|® z;
     3414sout | x @|@ y @|@ z;
    35993415\end{cfa}
    36003416&
    36013417\begin{cfa}
    36023418
    3603 cout << x ®<< " "® << y ®<< " "® << z << endl;
     3419cout << x @<< " "@ << y @<< " "@ << z << endl;
    36043420\end{cfa}
    36053421&
     
    36103426\\
    36113427\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3612 1® ®2® ®3
     34281@ @2@ @3
    36133429\end{cfa}
    36143430&
    36153431\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3616 1® ®2® ®3
     34321@ @2@ @3
    36173433\end{cfa}
    36183434&
    36193435\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3620 1® ®2® ®3
     34361@ @2@ @3
    36213437\end{cfa}
    36223438\end{tabular}
    36233439\end{cquote}
    36243440The \CFA form has half the characters of the \CC form, and is similar to \Index*{Python} I/O with respect to implicit separators and newline.
    3625 Similar simplification occurs for \Index{tuple} I/O, which flattens the tuple and prints each value separated by ``\lstinline[showspaces=true]{, }''.
     3441Similar simplification occurs for \Index{tuple} I/O, which flattens the tuple and prints each value separated by ``\lstinline[showspaces=true]@, @''.
    36263442\begin{cfa}
    36273443[int, [ int, int ] ] t1 = [ 1, [ 2, 3 ] ], t2 = [ 4, [ 5, 6 ] ];
     
    36293445\end{cfa}
    36303446\begin{cfa}[showspaces=true,aboveskip=0pt]
    3631 1®, ®2®, ®3 4®, ®5®, ®6
     34471@, @2@, @3 4@, @5@, @6
    36323448\end{cfa}
    36333449Finally, \CFA uses the logical-or operator for I/O as it is the lowest-priority \emph{overloadable} operator, other than assignment.
     
    36383454&
    36393455\begin{cfa}
    3640 sout | x * 3 | y + 1 | z << 2 | x == y | ®(®x | y®)® | ®(®x || y®)® | ®(®x > z ? 1 : 2®)®;
     3456sout | x * 3 | y + 1 | z << 2 | x == y | @(@x | y@)@ | @(@x || y@)@ | @(@x > z ? 1 : 2@)@;
    36413457\end{cfa}
    36423458\\
     
    36443460&
    36453461\begin{cfa}
    3646 cout << x * 3 << y + 1 << ®(®z << 2®)® << ®(®x == y®)® << ®(®x | y®)® << ®(®x || y®)® << ®(®x > z ? 1 : 2®)® << endl;
     3462cout << x * 3 << y + 1 << @(@z << 2@)@ << @(@x == y@)@ << @(@x | y@)@ << @(@x || y@)@ << @(@x > z ? 1 : 2@)@ << endl;
    36473463\end{cfa}
    36483464\\
     
    36793495\\
    36803496\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3681 ®1® ®2.5® ®A®
     3497@1@ @2.5@ @A@
    36823498
    36833499
     
    36853501&
    36863502\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3687 ®1® ®2.5® ®A®
     3503@1@ @2.5@ @A@
    36883504
    36893505
     
    36913507&
    36923508\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3693 ®1®
    3694 ®2.5®
    3695 ®A®
     3509@1@
     3510@2.5@
     3511@A@
    36963512\end{cfa}
    36973513\end{tabular}
     
    37293545
    37303546\item
    3731 A separator does not appear before a C string starting with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \LstStringStyle{,.;!?)]\}\%\textcent\guillemotright}, where \LstStringStyle{\guillemotright} is a closing citation mark.
     3547A separator does not appear before a C string starting with the (extended) \Index*{ASCII}\index{ASCII!extended} characters: \LstStringStyle{,.;!?)]\}\%\textcent\guillemotright}, where \LstStringStyle{\guillemotright} a closing citation mark.
    37323548\begin{cfa}
    37333549sout | 1 | ", x" | 2 | ". x" | 3 | "; x" | 4 | "! x" | 5 | "? x" | 6 | "% x"
     
    37353551\end{cfa}
    37363552\begin{cfa}[showspaces=true]
    3737 1®,® x 2®.® x 3®;® x 4®!® x 5®?® x 6®%® x 7$\R{\LstStringStyle{\textcent}}$ x 8$\R{\LstStringStyle{\guillemotright}}$ x 9®)® x 10®]® x 11®}® x
     35531@,@ x 2@.@ x 3@;@ x 4@!@ x 5@?@ x 6@%@ x 7$\R{\LstStringStyle{\textcent}}$ x 8$\R{\LstStringStyle{\guillemotright}}$ x 9@)@ x 10@]@ x 11@}@ x
    37383554\end{cfa}
    37393555
     
    37423558%$
    37433559\begin{cfa}
    3744 sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $\LstStringStyle{\textdollar}$" | 5 | "x $\LstStringStyle{\textsterling}$" | 6 | "x $\LstStringStyle{\textyen}$"
     3560sout | "x (" | 1 | "x [" | 2 | "x {" | 3 | "x =" | 4 | "x $" | 5 | "x $\LstStringStyle{\textsterling}$" | 6 | "x $\LstStringStyle{\textyen}$"
    37453561           | 7 | "x $\LstStringStyle{\textexclamdown}$" | 8 | "x $\LstStringStyle{\textquestiondown}$" | 9 | "x $\LstStringStyle{\guillemotleft}$" | 10;
    37463562\end{cfa}
    37473563%$
    37483564\begin{cfa}[showspaces=true]
    3749 x ®(®1 x ®[®2 x ®{®3 x ®=®4 x $\LstStringStyle{\textdollar}$5 x $\R{\LstStringStyle{\textsterling}}$6 x $\R{\LstStringStyle{\textyen}}$7 x $\R{\LstStringStyle{\textexclamdown}}$8 x $\R{\LstStringStyle{\textquestiondown}}$9 x $\R{\LstStringStyle{\guillemotleft}}$10
     3565x @(@1 x @[@2 x @{@3 x @=@4 x $\LstStringStyle{\textdollar}$5 x $\R{\LstStringStyle{\textsterling}}$6 x $\R{\LstStringStyle{\textyen}}$7 x $\R{\LstStringStyle{\textexclamdown}}$8 x $\R{\LstStringStyle{\textquestiondown}}$9 x $\R{\LstStringStyle{\guillemotleft}}$10
    37503566\end{cfa}
    37513567%$
    37523568
    37533569\item
    3754 A separator does not appear before/after a C string starting/ending with the \Index*{ASCII} quote or whitespace characters: \lstinline[basicstyle=\tt,showspaces=true]{`'": \t\v\f\r\n}
     3570A seperator does not appear before/after a C string starting/ending with the \Index*{ASCII} quote or whitespace characters: \lstinline[basicstyle=\tt,showspaces=true]{`'": \t\v\f\r\n}
    37553571\begin{cfa}
    37563572sout | "x`" | 1 | "`x'" | 2 | "'x\"" | 3 | "\"x:" | 4 | ":x " | 5 | " x\t" | 6 | "\tx";
    37573573\end{cfa}
    37583574\begin{cfa}[showspaces=true,showtabs=true]
    3759 x®`®1®`®x$\R{\texttt{'}}$2$\R{\texttt{'}}$x$\R{\texttt{"}}$3$\R{\texttt{"}}$x®:®4®:®x® ®5® ®x®  ®6®     ®x
     3575x@`@1@`@x$\R{\texttt{'}}$2$\R{\texttt{'}}$x$\R{\texttt{"}}$3$\R{\texttt{"}}$x@:@4@:@x@ @5@ @x@  @6@     @x
    37603576\end{cfa}
    37613577
     
    37663582\end{cfa}
    37673583\begin{cfa}[showspaces=true,showtabs=true]
    3768 x (® ®1® ®) x 2® ®, x 3® ®:x:® ®4
     3584x (@ @1@ @) x 2@ @, x 3@ @:x:@ @4
    37693585\end{cfa}
    37703586\end{enumerate}
     
    37793595\Indexc{sepSet}\index{manipulator!sepSet@©sepSet©} and \Indexc{sep}\index{manipulator!sep@©sep©}/\Indexc{sepGet}\index{manipulator!sepGet@©sepGet©} set and get the separator string.
    37803596The separator string can be at most 16 characters including the ©'\0'© string terminator (15 printable characters).
    3781 \begin{cfa}[belowskip=0pt]
    3782 sepSet( sout, ", $\LstStringStyle{\textdollar}$" ); $\C{// set separator from " " to ", \$"}$
    3783 sout | 1 | 2 | 3 | " \"" | ®sep® | "\"";
    3784 \end{cfa}
    3785 \begin{cfa}[showspaces=true,aboveskip=0pt]
    3786 1®, $\LstStringStyle{\textdollar}$®2®, $\LstStringStyle{\textdollar}$®3 ®", $\LstStringStyle{\textdollar}$"®
    3787 \end{cfa}
     3597\begin{cfa}[escapechar=off,belowskip=0pt]
     3598sepSet( sout, ", $" ); $\C{// set separator from " " to ", \$"}$
     3599sout | 1 | 2 | 3 | " \"" | @sep@ | "\"";
     3600\end{cfa}
     3601%$
     3602\begin{cfa}[mathescape=off,showspaces=true,aboveskip=0pt]
     36031@, $@2@, $@3 @", $"@
     3604\end{cfa}
     3605%$
    37883606\begin{cfa}[belowskip=0pt]
    37893607sepSet( sout, " " ); $\C{// reset separator to " "}$
    3790 sout | 1 | 2 | 3 | " \"" | ®sepGet( sout )® | "\"";
     3608sout | 1 | 2 | 3 | " \"" | @sepGet( sout )@ | "\"";
    37913609\end{cfa}
    37923610\begin{cfa}[showspaces=true,aboveskip=0pt]
    3793 1® ®2® ®3 ®" "®
     36111@ @2@ @3 @" "@
    37943612\end{cfa}
    37953613©sepGet© can be used to store a separator and then restore it:
    37963614\begin{cfa}[belowskip=0pt]
    3797 char store[®sepSize®]; $\C{// sepSize is the maximum separator size}$
     3615char store[@sepSize@]; $\C{// sepSize is the maximum separator size}$
    37983616strcpy( store, sepGet( sout ) ); $\C{// copy current separator}$
    37993617sepSet( sout, "_" ); $\C{// change separator to underscore}$
     
    38013619\end{cfa}
    38023620\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3803 1®_®2®_®3
     36211@_@2@_@3
    38043622\end{cfa}
    38053623\begin{cfa}[belowskip=0pt]
     
    38083626\end{cfa}
    38093627\begin{cfa}[showspaces=true,aboveskip=0pt]
    3810 1® ®2® ®3
     36281@ @2@ @3
    38113629\end{cfa}
    38123630
     
    38163634\begin{cfa}[belowskip=0pt]
    38173635sepSetTuple( sout, " " ); $\C{// set tuple separator from ", " to " "}$
    3818 sout | t1 | t2 | " \"" | ®sepTuple® | "\"";
     3636sout | t1 | t2 | " \"" | @sepTuple@ | "\"";
    38193637\end{cfa}
    38203638\begin{cfa}[showspaces=true,aboveskip=0pt]
    3821 1 2 3 4 5 6 ®" "®
     36391 2 3 4 5 6 @" "@
    38223640\end{cfa}
    38233641\begin{cfa}[belowskip=0pt]
    38243642sepSetTuple( sout, ", " ); $\C{// reset tuple separator to ", "}$
    3825 sout | t1 | t2 | " \"" | ®sepGetTuple( sout )® | "\"";
     3643sout | t1 | t2 | " \"" | @sepGetTuple( sout )@ | "\"";
    38263644\end{cfa}
    38273645\begin{cfa}[showspaces=true,aboveskip=0pt]
    3828 1, 2, 3 4, 5, 6 ®", "®
     36461, 2, 3 4, 5, 6 @", "@
    38293647\end{cfa}
    38303648As for ©sepGet©, ©sepGetTuple© can be use to store a tuple separator and then restore it.
     
    38783696\end{cfa}
    38793697\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    3880 ® ®1 2 3® ®
     3698@ @1 2 3@ @
    38813699\end{cfa}
    38823700\end{enumerate}
     
    38983716For example, in:
    38993717\begin{cfa}
    3900 sin | i | ®nl® | j;
    3901 1 ®2®
     3718sin | i | @nl@ | j;
     37191 @2@
    390237203
    39033721\end{cfa}
     
    394037580b0 0b11011 0b11011 0b11011 0b11011
    39413759sout | bin( -27HH ) | bin( -27H ) | bin( -27 ) | bin( -27L );
    3942 0b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b®(58 1s)®100101
     37600b11100101 0b1111111111100101 0b11111111111111111111111111100101 0b@(58 1s)@100101
    39433761\end{cfa}
    39443762
     
    39763794
    39773795\item
    3978 \Indexc{eng}( floating-point )\index{manipulator!eng@©eng©} print value in engineering notation with exponent, which means the exponent is adjusted to a multiple of 3.
    3979 \begin{cfa}[belowskip=0pt]
    3980 sout | eng( 0.0 ) | eng( 27000.5 ) | eng( -27.5e7 );
    3981 0®e0® 27.0005®e3® -275®e6®
    3982 \end{cfa}
    3983 
    3984 \item
    3985 \Indexc{unit}( engineering-notation )\index{manipulator!unit@©unit©} print engineering exponent as a letter between the range $10^{-24}$ and $10^{24}$:
    3986 ©y© $\Rightarrow 10^{-24}$, ©z© $\Rightarrow 10^{-21}$, ©a© $\Rightarrow 10^{-18}$, ©f© $\Rightarrow 10^{-15}$, ©p© $\Rightarrow 10^{-12}$, ©n© $\Rightarrow 10^{-9}$, ©u© $\Rightarrow 10^{-6}$, ©m© $\Rightarrow 10^{-3}$, ©K© $\Rightarrow 10^{3}$, ©M© $\Rightarrow 10^{6}$, ©G© $\Rightarrow 10^{9}$, ©T© $\Rightarrow 10^{12}$, ©P© $\Rightarrow 10^{15}$, ©E© $\Rightarrow 10^{18}$, ©Z© $\Rightarrow 10^{21}$, ©Y© $\Rightarrow 10^{24}$.
    3987 For exponent $10^{0}$, no decimal point or letter is printed.
    3988 \begin{cfa}[belowskip=0pt]
    3989 sout | unit(eng( 0.0 )) | unit(eng( 27000.5 )) | unit(eng( -27.5e7 ));
    3990 0 27.0005®K® -275®M®
    3991 \end{cfa}
    3992 
    3993 \item
    39943796\Indexc{upcase}( bin / hex / floating-point )\index{manipulator!upcase@©upcase©} print letters in a value in upper case. Lower case is the default.
    39953797\begin{cfa}[belowskip=0pt]
    39963798sout | upcase( bin( 27 ) ) | upcase( hex( 27 ) ) | upcase( 27.5e-10 ) | upcase( hex( 27.5 ) );
    3997 0®B®11011 0®X®1®B® 2.75®E®-09 0®X®1.®B®8®P®+4
     37990@B@11011 0@X@1@B@ 2.75@E@-09 0@X@1.@B@8@P@+4
    39983800\end{cfa}
    39993801
     
    40113813\begin{cfa}[belowskip=0pt]
    40123814sout | 0. | nodp( 0. ) | 27.0 | nodp( 27.0 ) | nodp( 27.5 );
    4013 0.0 ®0® 27.0 ®27® 27.5
     38150.0 @0@ 27.0 @27@ 27.5
    40143816\end{cfa}
    40153817
     
    40183820\begin{cfa}[belowskip=0pt]
    40193821sout | sign( 27 ) | sign( -27 ) | sign( 27. ) | sign( -27. ) | sign( 27.5 ) | sign( -27.5 );
    4020 ®+®27 -27 ®+®27.0 -27.0 ®+®27.5 -27.5
    4021 \end{cfa}
    4022 
    4023 \item
    4024 \Indexc{wd}( minimum, value )\index{manipulator!wd@©wd©}, ©wd©( minimum, precision, value )
    4025 For all types, minimum is the number of printed characters.
     3822@+@27 -27 @+@27.0 -27.0 @+@27.5 -27.5
     3823\end{cfa}
     3824
     3825\item
     3826\Indexc{wd}©( unsigned char minimum, T val )©\index{manipulator!wd@©wd©}, ©wd( unsigned char minimum, unsigned char precision, T val )©
     3827For all types, ©minimum© is the minimum number of printed characters.
    40263828If the value is shorter than the minimum, it is padded on the right with spaces.
    40273829\begin{cfa}[belowskip=0pt]
     
    40313833\end{cfa}
    40323834\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4033 ®  ®34 ® ®34 34
    4034 ®  ®4.000000 ® ®4.000000 4.000000
    4035 ®  ®ab ® ®ab ab
    4036 \end{cfa}
    4037 If the value is larger, it is printed without truncation, ignoring the minimum.
     3835@  @34 @ @34 34
     3836@  @4.000000 @ @4.000000 4.000000
     3837@  @ab @ @ab ab
     3838\end{cfa}
     3839If the value is larger, it is printed without truncation, ignoring the ©minimum©.
    40383840\begin{cfa}[belowskip=0pt]
    40393841sout | wd( 4, 34567 ) | wd( 3, 34567 ) | wd( 2, 34567 );
     
    40423844\end{cfa}
    40433845\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4044 3456®7® 345®67® 34®567®
    4045 3456®.® 345®6.® 34®56.®
    4046 abcd®e® abc®de® ab®cde®
    4047 \end{cfa}
    4048 
    4049 For integer types, precision is the minimum number of printed digits.
     38463456@7@ 345@67@ 34@567@
     38473456@.@ 345@6.@ 34@56.@
     3848abcd@e@ abc@de@ ab@cde@
     3849\end{cfa}
     3850
     3851For integer types, ©precision© is the minimum number of printed digits.
    40503852If the value is shorter, it is padded on the left with leading zeros.
    40513853\begin{cfa}[belowskip=0pt]
     
    40533855\end{cfa}
    40543856\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4055  ®0®34     ®00®34 ®00000000®34
    4056 \end{cfa}
    4057 If the value is larger, it is printed without truncation, ignoring the precision.
     3857 @0@34     @00@34 @00000000@34
     3858\end{cfa}
     3859If the value is larger, it is printed without truncation, ignoring the ©precision©.
    40583860\begin{cfa}[belowskip=0pt]
    40593861sout | wd( 4,1, 3456 ) | wd( 8,2, 3456 ) | wd( 10,3, 3456 );
     
    406238643456     3456       3456
    40633865\end{cfa}
    4064 If precision is 0, nothing is printed for zero.
    4065 If precision is greater than the minimum, it becomes the minimum.
     3866If ©precision© is 0, nothing is printed for zero.
     3867If ©precision© is greater than the minimum, it becomes the minimum.
    40663868\begin{cfa}[belowskip=0pt]
    40673869sout | wd( 4,0, 0 ) | wd( 3,10, 34 );
    40683870\end{cfa}
    40693871\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4070 ®    ® ®00000000®34
    4071 \end{cfa}
    4072 For floating-point types, precision is the minimum number of digits after the decimal point.
     3872@    @ @00000000@34
     3873\end{cfa}
     3874For floating-point types, ©precision© is the minimum number of digits after the decimal point.
    40733875\begin{cfa}[belowskip=0pt]
    40743876sout | wd( 6,3, 27.5 ) | wd( 8,1, 27.5 ) | wd( 8,0, 27.5 ) | wd( 3,8, 27.5 );
    40753877\end{cfa}
    40763878\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4077 27.®500®     27.®5®      28. 27.®50000000®
    4078 \end{cfa}
    4079 For the C-string type, precision is the maximum number of printed characters, so the string is truncated if it exceeds the maximum.
     387927.@500@     27.@5@      28. 27.@50000000@
     3880\end{cfa}
     3881For the C-string type, ©precision© is the maximum number of printed characters, so the string is truncated if it exceeds the maximum.
    40803882\begin{cfa}[belowskip=0pt]
    40813883sout | wd( 6,8, "abcd" ) | wd( 6,8, "abcdefghijk" ) | wd( 6,3, "abcd" );
     
    40863888
    40873889\item
    4088 \begin{sloppypar}
    4089 \Indexc{ws}( minimum, significant, floating-point )\index{manipulator!ws@©ws©}
    4090 For floating-point types, minimum is the same as for manipulator ©wd©, but significant is the maximum number of significant digits to be printed for both the integer and fractions (versus only the fraction for ©wd©).
    4091 If a value's significant digits is greater than significant, the last significant digit is rounded up.
    4092 \end{sloppypar}
     3890\Indexc{ws( unsigned char minimum, unsigned char significant, floating-point )}\index{manipulator!ws@©ws©}
     3891For floating-point type, ©minimum© is the same as for manipulator ©wd©, but ©significant© is the maximum number of significant digits to be printed for both the integer and fractions (versus only the fraction for ©wd©).
     3892If a value's significant digits is greater than ©significant©, the last significant digit is rounded up.
    40933893\begin{cfa}[belowskip=0pt]
    40943894sout | ws(6,6, 234.567) | ws(6,5, 234.567) | ws(6,4, 234.567) | ws(6,3, 234.567);
    40953895\end{cfa}
    40963896\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4097 234.567 234.5®7®  234.®6®    23®5®
    4098 \end{cfa}
    4099 If a value's magnitude is greater than significant, the value is printed in scientific notation with the specified number of significant digits.
     3897234.567 234.5@7@  234.@6@    23@5@
     3898\end{cfa}
     3899If a value's magnitude is greater than ©significant©, the value is printed in scientific notation with the specified number of significant digits.
    41003900\begin{cfa}[belowskip=0pt]
    41013901sout | ws(6,6, 234567.) | ws(6,5, 234567.) | ws(6,4, 234567.) | ws(6,3, 234567.);
    41023902\end{cfa}
    41033903\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4104 234567. 2.3457®e+05® 2.346®e+05® 2.35®e+05®
    4105 \end{cfa}
    4106 If significant is greater than minimum, it defines the number of printed characters.
     3904234567. 2.3457@e+05@ 2.346@e+05@ 2.35@e+05@
     3905\end{cfa}
     3906If ©significant© is greater than ©minimum©, it defines the number of printed characters.
    41073907\begin{cfa}[belowskip=0pt]
    41083908sout | ws(3,6, 234567.) | ws(4,6, 234567.) | ws(5,6, 234567.) | ws(6,6, 234567.);
     
    41183918\end{cfa}
    41193919\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4120 27®  ® 27.000000  27.500000  027  27.500®    ®
     392027@  @ 27.000000  27.500000  027  27.500@    @
    41213921\end{cfa}
    41223922
     
    41253925\begin{cfa}[belowskip=0pt]
    41263926sout | pad0( wd( 4, 27 ) ) | pad0( wd( 4,3, 27 ) ) | pad0( wd( 8,3, 27.5 ) );
    4127 ®00®27  ®0®27 ®00®27.500
     3927@00@27  @0@27 @00@27.500
    41283928\end{cfa}
    41293929\end{enumerate}
     
    41893989
    41903990The format of numeric input values in the same as C constants without a trailing type suffix, as the input value-type is denoted by the input variable.
    4191 For ©bool© type, the constants are ©true© and ©false©.
     3991For ©_Bool© type, the constants are ©true© and ©false©.
    41923992For integral types, any number of digits, optionally preceded by a sign (©+© or ©-©), where a
    41933993\begin{itemize}
     
    42104010\begin{enumerate}
    42114011\item
    4212 \Indexc{skip}( pattern )\index{manipulator!skip@©skip©}, ©skip©( length )
    4213 The pattern is composed of white-space and non-white-space characters, where \emph{any} white-space character matches 0 or more input white-space characters (hence, consecutive white-space characters in the pattern are combined), and each non-white-space character matches exactly with an input character.
    4214 The length is composed of the next $N$ characters, including the newline character.
     4012\Indexc{skip( const char * pattern )}\index{manipulator!skip@©skip©} / ©skip( unsigned int length )© / ©const char * pattern©
     4013The argument defines a ©pattern© or ©length©.
     4014The ©pattern© is composed of white-space and non-white-space characters, where \emph{any} white-space character matches 0 or more input white-space characters (hence, consecutive white-space characters in the pattern are combined), and each non-white-space character matches exactly with an input character.
     4015The ©length© is composed of the next $N$ characters, including the newline character.
    42154016If the match successes, the input characters are discarded, and input continues with the next character.
    42164017If the match fails, the input characters are left unread.
     
    42204021\end{cfa}
    42214022\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4222 ®abc   ®
    4223 ®abc  ®
    4224 ®xx®
    4225 \end{cfa}
    4226 
    4227 \item
    4228 \Indexc{wdi}( maximum, reference-value )\index{manipulator!wdi@©wdi©}
    4229 For all types except ©char©, maximum is the maximum number of characters read for the current operation.
     4023@abc   @
     4024@abc  @
     4025@xx@
     4026\end{cfa}
     4027
     4028\item
     4029\Indexc{wdi}©( unsigned int maximum, T & val )©\index{manipulator!wdi@©wdi©}
     4030For all types except ©char©, ©maximum© is the maximum number of characters read for the current operation.
    42304031\begin{cfa}[belowskip=0pt]
    42314032char s[10];   int i;   double d;   
     
    42334034\end{cfa}
    42344035\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4235 ®abcd1233.456E+2®
     4036@abcd1233.456E+2@
    42364037\end{cfa}
    42374038Note, input ©wdi© cannot be overloaded with output ©wd© because both have the same parameters but return different types.
     
    42394040
    42404041\item
    4241 \Indexc{ignore}( reference-value )\index{manipulator!ignore@©ignore©}
     4042\Indexc{ignore( T & val )}\index{manipulator!ignore@©ignore©}
    42424043For all types, the data is read from the stream depending on the argument type but ignored, \ie it is not stored in the argument.
    42434044\begin{cfa}[belowskip=0pt]
     
    42464047\end{cfa}
    42474048\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4248 ®  -75.35e-4® 25
    4249 \end{cfa}
    4250 
    4251 \item
    4252 \Indexc{incl}( scanset, input-string )\index{manipulator!incl@©incl©}
    4253 For C-string types, the scanset matches any number of characters \emph{in} the set.
    4254 Matching characters are read into the C input-string and null terminated.
     4049@  -75.35e-4@ 25
     4050\end{cfa}
     4051
     4052\item
     4053\Indexc{incl( const char * scanset, char * s )}\index{manipulator!incl@©incl©}
     4054For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{in} the set.
     4055Matching characters are read into the C string and null terminated.
    42554056\begin{cfa}[belowskip=0pt]
    42564057char s[10];
     
    42584059\end{cfa}
    42594060\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4260 ®bca®xyz
    4261 \end{cfa}
    4262 
    4263 \item
    4264 \Indexc{excl}( scanset, input-string )\index{manipulator!excl@©excl©}
    4265 For C-string types, the scanset matches any number of characters \emph{not in} the set.
    4266 Non-matching characters are read into the C input-string and null terminated.
     4061@bca@xyz
     4062\end{cfa}
     4063
     4064\item
     4065\Indexc{excl( const char * scanset, char * s )}\index{manipulator!excl@©excl©}
     4066For the C-string type, the argument defines a ©scanset© that matches any number of characters \emph{not in} the set.
     4067Non-matching characters are read into the C string and null terminated.
    42674068\begin{cfa}[belowskip=0pt]
    42684069char s[10];
     
    42704071\end{cfa}
    42714072\begin{cfa}[showspaces=true,aboveskip=0pt,belowskip=0pt]
    4272 ®xyz®bca
     4073@xyz@bca
    42734074\end{cfa}
    42744075\end{enumerate}
    42754076
    42764077
    4277 \subsection{Concurrent Stream Access}
    4278 
    4279 When a stream is shared by multiple threads, input or output characters can be intermixed or cause failure.
    4280 For example, if two threads execute the following:
    4281 \begin{cfa}
    4282 $\emph{thread\(_1\)}$ : sout | "abc " | "def ";
    4283 $\emph{thread\(_2\)}$ : sout | "uvw " | "xyz ";
    4284 \end{cfa}
    4285 possible outputs are:
    4286 \begin{cquote}
    4287 \begin{tabular}{@{}l|l|l|l|l@{}}
    4288 \begin{cfa}
    4289 abc def
    4290 uvw xyz
    4291 \end{cfa}
    4292 &
    4293 \begin{cfa}
    4294 abc uvw xyz
    4295 def
    4296 \end{cfa}
    4297 &
    4298 \begin{cfa}
    4299 uvw abc xyz def
    4300 
    4301 \end{cfa}
    4302 &
    4303 \begin{cfa}
    4304 abuvwc dexf
    4305 yz
    4306 \end{cfa}
    4307 &
    4308 \begin{cfa}
    4309 uvw abc def
    4310 xyz
    4311 \end{cfa}
    4312 \end{tabular}
    4313 \end{cquote}
    4314 Concurrent operations can even corrupt the internal state of the stream resulting in failure.
    4315 As a result, some form of mutual exclusion is required for concurrent stream access.
    4316 
    4317 A coarse-grained solution is to perform all stream operations via a single thread or within a monitor providing the necessary mutual exclusion for the stream.
    4318 A fine-grained solution is to have a lock for each stream, which is acquired and released around stream operations by each thread.
    4319 \CFA provides a fine-grained solution where a \Index{recursive lock} is acquired and released indirectly via a manipulator ©acquire© or instantiating an \Index{RAII} type specific for the kind of stream: ©osacquire©\index{ostream@©ostream©!osacquire@©osacquire©} for output streams and ©isacquire©\index{isacquire@©isacquire©}\index{istream@©istream©!isacquire@©isacquire©} for input streams.
    4320 
    4321 The common usage is manipulator ©acquire©\index{ostream@©ostream©!acquire@©acquire©} to lock a stream during a single cascaded I/O expression, with the manipulator appearing as the first item in a cascade list, \eg:
    4322 \begin{cfa}
    4323 $\emph{thread\(_1\)}$ : sout | ®acquire® | "abc " | "def ";   // manipulator
    4324 $\emph{thread\(_2\)}$ : sout | ®acquire® | "uvw " | "xyz ";
    4325 \end{cfa}
    4326 Now, the order of the thread execution is still non-deterministic, but the output is constrained to two possible lines in either order.
    4327 \begin{cquote}
    4328 \def\VRfont{\fontfamily{pcr}\upshape\selectfont}
    4329 \begin{tabular}{@{}l|l@{}}
    4330 \begin{cfa}
    4331 abc def
    4332 uvw xyz
    4333 \end{cfa}
    4334 &
    4335 \begin{cfa}
    4336 uvw xyz
    4337 abc def
    4338 \end{cfa}
    4339 \end{tabular}
    4340 \end{cquote}
    4341 In summary, the stream lock is acquired by the ©acquire© manipulator and implicitly released at the end of the cascaded I/O expression ensuring all operations in the expression occur atomically.
    4342 
    4343 To lock a stream across multiple I/O operations, an object of type ©osacquire© or ©isacquire© is declared to implicitly acquire/release the stream lock providing mutual exclusion for the object's duration, \eg:
    4344 \begin{cfa}
    4345 {       // acquire sout for block duration
    4346         ®osacquire® acq = { sout };                             $\C{// named stream locker}$
    4347         sout | 1;
    4348         sout | ®acquire® | 2 | 3;                               $\C{// unnecessary, but ok to acquire and release again}$
    4349         sout | 4;
    4350 }       // implicitly release the lock when "acq" is deallocated
    4351 \end{cfa}
    4352 Note, the unnecessary ©acquire© manipulator works because the recursive stream-lock can be acquired/released multiple times by the owner thread.
    4353 Hence, calls to functions that also acquire a stream lock for their output do not result in \Index{deadlock}.
    4354 
    4355 The previous values written by threads 1 and 2 can be read in concurrently:
    4356 \begin{cfa}
    4357 {       // acquire sin lock for block duration
    4358         ®isacquire acq = { sin };®                              $\C{// named stream locker}$
    4359         int x, y, z, w;
    4360         sin | x;
    4361         sin | ®acquire® | y | z;                                $\C{// unnecessary, but ok to acquire and release again}$
    4362         sin | w;
    4363 }       // implicitly release the lock when "acq" is deallocated
    4364 \end{cfa}
    4365 Again, the order of the reading threads is non-deterministic.
    4366 Note, non-deterministic reading is rare.
    4367 
    4368 \Textbf{WARNING:} The general problem of \Index{nested locking} can occur if routines are called in an I/O sequence that block, \eg:
    4369 \begin{cfa}
    4370 sout | ®acquire® | "data:" | rtn( mon );        $\C{// mutex call on monitor}$
    4371 \end{cfa}
    4372 If the thread executing the I/O expression blocks in the monitor with the ©sout© lock, other threads writing to ©sout© also block until the thread holding the lock is unblocked and releases it.
    4373 This scenario can lead to \Index{deadlock}, if the thread that is going to unblock the thread waiting in the monitor first writes to ©sout© (deadly embrace).
    4374 To prevent nested locking, a simple precaution is to factor out the blocking call from the expression, \eg:
    4375 \begin{cfa}
    4376 int ®data® = rtn( mon );
    4377 sout | acquire | "data:" | ®data®;
    4378 \end{cfa}
    4379 
    4380 \Textbf{WARNING:} ©printf©\index{printf@©printf©}, ©scanf©\index{scanf@©scanf©} and their derivatives are unsafe when used with user-level threading, as in \CFA.
    4381 These stream routines use kernel-thread locking (©futex©\index{futex@©futex©}), which block kernel threads, to prevent interleaving of I/O.
    4382 However, the following simple example illustrates how a deadlock can occur (other complex scenarios are possible).
    4383 Assume a single kernel thread and two user-level threads calling ©printf©.
    4384 One user-level thread acquires the I/O lock and is time-sliced while performing ©printf©.
    4385 The other user-level thread then starts execution, calls ©printf©, and blocks the only kernel thread because it cannot acquire the I/O lock.
    4386 It does not help if the kernel lock is multiple acquisition, \ie, the lock owner can acquire it multiple times, because it then results in two user threads in the ©printf© critical section, corrupting the stream.
    4387 
    4388 
    4389 \begin{comment}
    43904078\section{Types}
    43914079
     
    44664154process((int) s); // type is converted, no function is called
    44674155\end{cfa}
    4468 \end{comment}
    44694156
    44704157
     
    46004287In C, the integer constants 0 and 1 suffice because the integer promotion rules can convert them to any arithmetic type, and the rules for pointer expressions treat constant expressions evaluating to 0 as a special case.
    46014288However, user-defined arithmetic types often need the equivalent of a 1 or 0 for their functions or operators, polymorphic functions often need 0 and 1 constants of a type matching their polymorphic parameters, and user-defined pointer-like types may need a null value.
    4602 Defining special constants for a user-defined type is more efficient than defining a conversion to the type from ©bool©.
     4289Defining special constants for a user-defined type is more efficient than defining a conversion to the type from ©_Bool©.
    46034290
    46044291Why just 0 and 1? Why not other integers? No other integers have special status in C.
     
    46824369\begin{table}[hbt]
    46834370\centering
    4684 \begin{tabular}{@{}l@{\hspace{\parindentlnth}}l@{\hspace{\parindentlnth}}l@{}}
    4685 \begin{tabular}{@{}ll@{}}
    4686 ©?[?]©  & subscripting \impl{?[?]}                                      \\
    4687 ©?()©   & function call \impl{?()}                                      \\
    4688 ©?++©   & postfix increment \impl{?++}                          \\
    4689 ©?--©   & postfix decrement \impl{?--}                          \\
    4690 ©++?©   & prefix increment \impl{++?}                           \\
    4691 ©--?©   & prefix decrement \impl{--?}                           \\
    4692 ©*?©    & dereference \impl{*?}                                         \\
    4693 ©+?©    & unary plus \impl{+?}                                          \\
    4694 ©-?©    & arithmetic negation \impl{-?}                         \\
    4695 ©~?©    & bitwise negation \impl{~?}                            \\
    4696 ©!?©    & logical complement \impl{"!?}                         \\
    4697 ©?\?©   & exponentiation \impl{?\?}                                     \\
    4698 ©?*?©   & multiplication \impl{?*?}                                     \\
    4699 ©?/?©   & division \impl{?/?}                                           \\
    4700 ©?%?©   & remainder \impl{?%?}                                          \\
    4701 \end{tabular}
    4702 &
    4703 \begin{tabular}{@{}ll@{}}
    4704 ©?+?©   & addition \impl{?+?}                                           \\
    4705 ©?-?©   & subtraction \impl{?-?}                                        \\
    4706 ©?<<?©  & left shift \impl{?<<?}                                        \\
    4707 ©?>>?©  & right shift \impl{?>>?}                                       \\
    4708 ©?<?©   & less than \impl{?<?}                                          \\
    4709 ©?<=?©  & less than or equal \impl{?<=?}                        \\
    4710 ©?>=?©  & greater than or equal \impl{?>=?}                     \\
    4711 ©?>?©   & greater than \impl{?>?}                                       \\
    4712 ©?==?©  & equality \impl{?==?}                                          \\
    4713 ©?!=?©  & inequality \impl{?"!=?}                                       \\
    4714 ©?&?©   & bitwise AND \impl{?&?}                                        \\
    4715 ©?^?©   & exclusive OR \impl{?^?}                                       \\
    4716 ©?|?©   & inclusive OR \impl{?"|?}                                      \\
    4717                                                                                                         \\
    4718                                                                                                         \\
    4719 \end{tabular}
    4720 &
    4721 \begin{tabular}{@{}ll@{}}
    4722 ©?=?©   & simple assignment \impl{?=?}                          \\
    4723 ©?\=?©  & exponentiation assignment \impl{?\=?}         \\
    4724 ©?*=?©  & multiplication assignment \impl{?*=?}         \\
    4725 ©?/=?©  & division assignment \impl{?/=?}                       \\
    4726 ©?%=?©  & remainder assignment \impl{?%=?}                      \\
    4727 ©?+=?©  & addition assignment \impl{?+=?}                       \\
    4728 ©?-=?©  & subtraction assignment \impl{?-=?}            \\
    4729 ©?<<=?© & left-shift assignment \impl{?<<=?}            \\
    4730 ©?>>=?© & right-shift assignment \impl{?>>=?}           \\
    4731 ©?&=?©  & bitwise AND assignment \impl{?&=?}            \\
    4732 ©?^=?©  & exclusive OR assignment \impl{?^=?}           \\
    4733 ©?|=?©  & inclusive OR assignment \impl{?"|=?}          \\
    4734                                                                                                         \\
    4735                                                                                                         \\
    4736                                                                                                         \\
    4737 \end{tabular}
    4738 \end{tabular}
     4371\input{../refrat/operidents}
    47394372\caption{Operator Identifiers}
    47404373\label{opids}
     
    48244457For example, given
    48254458\begin{cfa}
    4826 auto j = ®...®
     4459auto j = @...@
    48274460\end{cfa}
    48284461and the need to write a routine to compute using ©j©
    48294462\begin{cfa}
    4830 void rtn( ®...® parm );
     4463void rtn( @...@ parm );
    48314464rtn( j );
    48324465\end{cfa}
     
    50654698\begin{figure}
    50664699\begin{cfa}
    5067 #include <fstream.hfa>
    5068 #include ®<coroutine.hfa>®
    5069 
    5070 ®coroutine® Fibonacci {
     4700#include <fstream>
     4701#include <coroutine>
     4702
     4703coroutine Fibonacci {
    50714704        int fn; $\C{// used for communication}$
    50724705};
    5073 
    5074 void main( Fibonacci & fib ) with( fib ) { $\C{// called on first resume}$
     4706void ?{}( Fibonacci * this ) {
     4707        this->fn = 0;
     4708}
     4709void main( Fibonacci * this ) {
    50754710        int fn1, fn2; $\C{// retained between resumes}$
    5076         fn = 0;  fn1 = fn; $\C{// 1st case}$
    5077         ®suspend;® $\C{// restart last resume}$
    5078         fn = 1;  fn2 = fn1;  fn1 = fn; $\C{// 2nd case}$
    5079         ®suspend;® $\C{// restart last resume}$
    5080         for () {
    5081                 fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn; $\C{// general case}$
    5082                 ®suspend;® $\C{// restart last resume}$
    5083         }
    5084 }
    5085 int next( Fibonacci & fib ) with( fib ) {
    5086         ®resume( fib );® $\C{// restart last suspend}$
    5087         return fn;
     4711        this->fn = 0; $\C{// case 0}$
     4712        fn1 = this->fn;
     4713        suspend(); $\C{// return to last resume}$
     4714
     4715        this->fn = 1; $\C{// case 1}$
     4716        fn2 = fn1;
     4717        fn1 = this->fn;
     4718        suspend(); $\C{// return to last resume}$
     4719
     4720        for ( ;; ) { $\C{// general case}$
     4721                this->fn = fn1 + fn2;
     4722                fn2 = fn1;
     4723                fn1 = this->fn;
     4724                suspend(); $\C{// return to last resume}$
     4725        } // for
     4726}
     4727int next( Fibonacci * this ) {
     4728        resume( this ); $\C{// transfer to last suspend}$
     4729        return this->fn;
    50884730}
    50894731int main() {
    50904732        Fibonacci f1, f2;
    5091         for ( 10 ) { $\C{// print N Fibonacci values}$
    5092                 sout | next( f1 ) | next( f2 );
    5093         }
    5094 }
    5095 \end{cfa}
    5096 \vspace*{-5pt}
     4733        for ( int i = 1; i <= 10; i += 1 ) {
     4734                sout | next( &f1 ) | ' ' | next( &f2 );
     4735        } // for
     4736}
     4737\end{cfa}
    50974738\caption{Fibonacci Coroutine}
    50984739\label{f:FibonacciCoroutine}
     
    51204761\begin{figure}
    51214762\begin{cfa}
    5122 #include <fstream.hfa>
    5123 #include ®<thread.hfa>®
    5124 
    5125 ®monitor® AtomicCnt { int counter; };
    5126 void ?{}( AtomicCnt & c, int init = 0 ) with(c) { counter = init; }
    5127 int inc( AtomicCnt & ®mutex® c, int inc = 1 ) with(c) { return counter += inc; }
    5128 int dec( AtomicCnt & ®mutex® c, int dec = 1 ) with(c) { return counter -= dec; }
    5129 forall( ostype & | ostream( ostype ) ) { $\C{// print any stream}$
    5130         ostype & ?|?( ostype & os, AtomicCnt c ) { return os | c.counter; }
    5131         void ?|?( ostype & os, AtomicCnt c ) { (ostype &)(os | c.counter); ends( os ); }
    5132 }
    5133 
    5134 AtomicCnt global; $\C{// shared}$
     4763#include <fstream>
     4764#include <kernel>
     4765#include <monitor>
     4766#include <thread>
     4767
     4768monitor global_t {
     4769        int value;
     4770};
     4771
     4772void ?{}(global_t * this) {
     4773        this->value = 0;
     4774}
     4775
     4776static global_t global;
     4777
     4778void increment3( global_t * mutex this ) {
     4779        this->value += 1;
     4780}
     4781void increment2( global_t * mutex this ) {
     4782        increment3( this );
     4783}
     4784void increment( global_t * mutex this ) {
     4785        increment2( this );
     4786}
    51354787
    51364788thread MyThread {};
    5137 void main( MyThread & ) {
    5138         for ( i; 100_000 ) {
    5139                 inc( global );
    5140                 dec( global );
     4789
     4790void main( MyThread* this ) {
     4791        for(int i = 0; i < 1_000_000; i++) {
     4792                increment( &global );
    51414793        }
    51424794}
    5143 int main() {
    5144         enum { Threads = 4 };
    5145         processor p[Threads - 1]; $\C{// + starting processor}$
     4795int main(int argc, char* argv[]) {
     4796        processor p;
    51464797        {
    5147                 MyThread t[Threads];
     4798                MyThread f[4];
    51484799        }
    5149         sout | global; $\C{// print 0}$
     4800        sout | global.value;
    51504801}
    51514802\end{cfa}
    51524803\caption{Atomic-Counter Monitor}
    5153 \label{f:AtomicCounterMonitor}
     4804\caption{f:AtomicCounterMonitor}
    51544805\end{figure}
    51554806
     
    66146265
    66156266C has a number of syntax ambiguities, which are resolved by taking the longest sequence of overlapping characters that constitute a token.
    6616 For example, the program fragment ©x+++++y© is parsed as \lstinline[showspaces=true]{x ++ ++ + y} because operator tokens ©++© and ©+© overlap.
    6617 Unfortunately, the longest sequence violates a constraint on increment operators, even though the parse \lstinline[showspaces=true]{x ++ + ++ y} might yield a correct expression.
     6267For example, the program fragment ©x+++++y© is parsed as \lstinline[showspaces=true]@x ++ ++ + y@ because operator tokens ©++© and ©+© overlap.
     6268Unfortunately, the longest sequence violates a constraint on increment operators, even though the parse \lstinline[showspaces=true]@x ++ + ++ y@ might yield a correct expression.
    66186269Hence, C programmers are aware that spaces have to added to disambiguate certain syntactic cases.
    66196270
     
    66356286requiring arbitrary whitespace look-ahead for the routine-call parameter-list to disambiguate.
    66366287However, the dereference operator \emph{must} have a parameter/argument to dereference ©*?(...)©.
    6637 Hence, always interpreting the string ©*?()© as \lstinline[showspaces=true]{* ?()} does not preclude any meaningful program.
     6288Hence, always interpreting the string ©*?()© as \lstinline[showspaces=true]@* ?()@ does not preclude any meaningful program.
    66386289
    66396290The remaining cases are with the increment/decrement operators and conditional expression, \eg:
     
    67436394\begin{cfa}
    67446395int i; $\C{// forward definition}$
    6745 int *j = ®&i®; $\C{// forward reference, valid in C, invalid in \CFA}$
     6396int *j = @&i@; $\C{// forward reference, valid in C, invalid in \CFA}$
    67466397int i = 0; $\C{// definition}$
    67476398\end{cfa}
     
    67516402struct X { int i; struct X *next; };
    67526403static struct X a; $\C{// forward definition}$
    6753 static struct X b = { 0, ®&a® };$\C{// forward reference, valid in C, invalid in \CFA}$
     6404static struct X b = { 0, @&a@ };$\C{// forward reference, valid in C, invalid in \CFA}$
    67546405static struct X a = { 1, &b }; $\C{// definition}$
    67556406\end{cfa}
     
    67646415\item[Change:] have ©struct© introduce a scope for nested types:
    67656416\begin{cfa}
    6766 enum ®Colour® { R, G, B, Y, C, M };
     6417enum @Colour@ { R, G, B, Y, C, M };
    67676418struct Person {
    6768         enum ®Colour® { R, G, B };      $\C[7cm]{// nested type}$
     6419        enum @Colour@ { R, G, B };      $\C[7cm]{// nested type}$
    67696420        struct Face { $\C{// nested type}$
    6770                 ®Colour® Eyes, Hair; $\C{// type defined outside (1 level)}$
     6421                @Colour@ Eyes, Hair; $\C{// type defined outside (1 level)}$
    67716422        };
    6772         ®.Colour® shirt; $\C{// type defined outside (top level)}$
    6773         ®Colour® pants; $\C{// type defined same level}$
     6423        @.Colour@ shirt; $\C{// type defined outside (top level)}$
     6424        @Colour@ pants; $\C{// type defined same level}$
    67746425        Face looks[10]; $\C{// type defined same level}$
    67756426};
    6776 ®Colour® c = R; $\C{// type/enum defined same level}$
    6777 Person®.Colour® pc = Person®.®R;$\C{// type/enum defined inside}$
    6778 Person®.®Face pretty; $\C{// type defined inside}\CRT$
     6427@Colour@ c = R; $\C{// type/enum defined same level}$
     6428Person@.Colour@ pc = Person@.@R;$\C{// type/enum defined inside}$
     6429Person@.@Face pretty; $\C{// type defined inside}\CRT$
    67796430\end{cfa}
    67806431In C, the name of the nested types belongs to the same scope as the name of the outermost enclosing structure, \ie the nested types are hoisted to the scope of the outer-most type, which is not useful and confusing.
     
    68516502\label{s:CFAKeywords}
    68526503
    6853 \CFA introduces the following new \Index{keyword}s, which cannot be used as identifiers.
     6504\CFA introduces the following new keywords.
    68546505
    68556506\begin{cquote}
    6856 \begin{tabular}{@{}lllllll@{}}
    6857 \begin{tabular}{@{}l@{}}
    6858 \Indexc{basetypeof}             \\
    6859 \Indexc{choose}                 \\
    6860 \Indexc{coroutine}              \\
    6861 \Indexc{disable}                \\
    6862 \end{tabular}
    6863 &
    6864 \begin{tabular}{@{}l@{}}
    6865 \Indexc{enable}                 \\
    6866 \Indexc{exception}              \\
    6867 \Indexc{fallthrough}    \\
    6868 \Indexc{fallthru}               \\
    6869 \end{tabular}
    6870 &
    6871 \begin{tabular}{@{}l@{}}
    6872 \Indexc{finally}                \\
    6873 \Indexc{fixup}                  \\
    6874 \Indexc{forall}                 \\
    6875 \Indexc{generator}              \\
    6876 \end{tabular}
    6877 &
    6878 \begin{tabular}{@{}l@{}}
    6879 \Indexc{int128}                 \\
    6880 \Indexc{monitor}                \\
    6881 \Indexc{mutex}                  \\
    6882 \Indexc{one_t}                  \\
    6883 \end{tabular}
    6884 &
    6885 \begin{tabular}{@{}l@{}}
    6886 \Indexc{report}                 \\
    6887 \Indexc{suspend}                \\
    6888 \Indexc{throw}                  \\
    6889 \Indexc{throwResume}    \\
    6890 \end{tabular}
    6891 &
    6892 \begin{tabular}{@{}l@{}}
    6893 \Indexc{trait}                  \\
    6894 \Indexc{try}                    \\
    6895 \Indexc{virtual}                \\
    6896 \Indexc{waitfor}                \\
    6897 \end{tabular}
    6898 &
    6899 \begin{tabular}{@{}l@{}}
    6900 \Indexc{when}                   \\
    6901 \Indexc{with}                   \\
    6902 \Indexc{zero_t}                 \\
    6903                                                 \\
    6904 \end{tabular}
    6905 \end{tabular}
     6507\input{../refrat/keywords}
    69066508\end{cquote}
    6907 \CFA introduces the following new \Index{quasi-keyword}s, which can be used as identifiers.
    6908 \begin{cquote}
    6909 \begin{tabular}{@{}ll@{}}
    6910 \begin{tabular}{@{}l@{}}
    6911 \Indexc{catch}                  \\
    6912 \Indexc{catchResume}    \\
    6913 \Indexc{finally}                \\
    6914 \end{tabular}
    6915 &
    6916 \begin{tabular}{@{}l@{}}
    6917 \Indexc{fixup}                  \\
    6918 \Indexc{or}                             \\
    6919 \Indexc{timeout}                \\
    6920 \end{tabular}
    6921 \end{tabular}
    6922 \end{cquote}
     6509
    69236510
    69246511\section{Standard Headers}
     
    70796666// assume ?|? operator for printing an S
    70806667
    7081 S & sp = *®new®( 3 );                                                   $\C{// call constructor after allocation}$
     6668S & sp = *@new@( 3 );                                                   $\C{// call constructor after allocation}$
    70826669sout | sp.i;
    7083 ®delete®( &sp );
    7084 
    7085 S * spa = ®anew®( 10, 5 );                                              $\C{// allocate array and initialize each array element}$
     6670@delete@( &sp );
     6671
     6672S * spa = @anew@( 10, 5 );                                              $\C{// allocate array and initialize each array element}$
    70866673for ( i; 10 ) sout | spa[i] | nonl;
    70876674sout | nl;
    7088 ®adelete®( 10, spa );
     6675@adelete@( 10, spa );
    70896676\end{cfa}
    70906677Allocation routines ©new©/©anew© allocate a variable/array and initialize storage using the allocated type's constructor.
     
    73226909[ int, long double ] remquo( long double, long double );
    73236910
     6911float div( float, float, int * );$\indexc{div}$ $\C{// alternative name for remquo}$
     6912double div( double, double, int * );
     6913long double div( long double, long double, int * );
    73246914[ int, float ] div( float, float );
    73256915[ int, double ] div( double, double );
     
    73826972long double _Complex log( long double _Complex );
    73836973
    7384 int log2( unsigned int );$\indexc{log2}$
    7385 long int log2( unsigned long int );
    7386 long long int log2( unsigned long long int )
    7387 float log2( float );
     6974float log2( float );$\indexc{log2}$
    73886975double log2( double );
    73896976long double log2( long double );
     
    75677154\leavevmode
    75687155\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    7569 // n / align * align
    7570 signed char floor( signed char n, signed char align );
    7571 unsigned char floor( unsigned char n, unsigned char align );
    7572 short int floor( short int n, short int align );
    7573 unsigned short int floor( unsigned short int n, unsigned short int align );
    7574 int floor( int n, int align );
    7575 unsigned int floor( unsigned int n, unsigned int align );
    7576 long int floor( long int n, long int align );
    7577 unsigned long int floor( unsigned long int n, unsigned long int align );
    7578 long long int floor( long long int n, long long int align );
    7579 unsigned long long int floor( unsigned long long int n, unsigned long long int align );
    7580 
    7581 // (n + (align - 1)) / align
    7582 signed char ceiling_div( signed char n, char align );
    7583 unsigned char ceiling_div( unsigned char n, unsigned char align );
    7584 short int ceiling_div( short int n, short int align );
    7585 unsigned short int ceiling_div( unsigned short int n, unsigned short int align );
    7586 int ceiling_div( int n, int align );
    7587 unsigned int ceiling_div( unsigned int n, unsigned int align );
    7588 long int ceiling_div( long int n, long int align );
    7589 unsigned long int ceiling_div( unsigned long int n, unsigned long int align );
    7590 long long int ceiling_div( long long int n, long long int align );
    7591 unsigned long long int ceiling_div( unsigned long long int n, unsigned long long int align );
    7592 
    7593 // floor( n + (n % align != 0 ? align - 1 : 0), align )
    7594 signed char ceiling( signed char n, signed char align );
    7595 unsigned char ceiling( unsigned char n, unsigned char align );
    7596 short int ceiling( short int n, short int align );
    7597 unsigned short int ceiling( unsigned short int n, unsigned short int align );
    7598 int ceiling( int n, int align );
    7599 unsigned int ceiling( unsigned int n, unsigned int align );
    7600 long int ceiling( long int n, long int align );
    7601 unsigned long int ceiling( unsigned long int n, unsigned long int align );
    7602 long long int ceiling( long long int n, long long int align );
    7603 unsigned long long int ceiling( unsigned long long int n, unsigned long long int align );
    7604 
    76057156float floor( float );$\indexc{floor}$
    76067157double floor( double );
     
    76987249
    76997250
    7700 %\subsection{\texorpdfstring{\protect\lstinline{Duration}}{Duration}}
     7251%\subsection{\texorpdfstring{\protect\lstinline@Duration@}{Duration}}
    77017252\subsection{\texorpdfstring{\LstBasicStyle{Duration}}{Duration}}
    77027253\label{s:Duration}
     
    77057256\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    77067257struct Duration {
    7707         int64_t tn; $\C{// nanoseconds}$
     7258        int64_t tv; $\C{// nanoseconds}$
    77087259};
    77097260
    77107261void ?{}( Duration & dur );
    77117262void ?{}( Duration & dur, zero_t );
    7712 void ?{}( Duration & dur, timeval t )
    7713 void ?{}( Duration & dur, timespec t )
    77147263
    77157264Duration ?=?( Duration & dur, zero_t );
    7716 Duration ?=?( Duration & dur, timeval t )
    7717 Duration ?=?( Duration & dur, timespec t )
    77187265
    77197266Duration +?( Duration rhs );
     
    77377284Duration ?%=?( Duration & lhs, Duration rhs );
    77387285
    7739 bool ?==?( Duration lhs, zero_t );
    7740 bool ?!=?( Duration lhs, zero_t );
    7741 bool ?<? ( Duration lhs, zero_t );
    7742 bool ?<=?( Duration lhs, zero_t );
    7743 bool ?>? ( Duration lhs, zero_t );
    7744 bool ?>=?( Duration lhs, zero_t );
    7745 
    7746 bool ?==?( Duration lhs, Duration rhs );
    7747 bool ?!=?( Duration lhs, Duration rhs );
    7748 bool ?<? ( Duration lhs, Duration rhs );
    7749 bool ?<=?( Duration lhs, Duration rhs );
    7750 bool ?>? ( Duration lhs, Duration rhs );
    7751 bool ?>=?( Duration lhs, Duration rhs );
     7286_Bool ?==?( Duration lhs, Duration rhs );
     7287_Bool ?!=?( Duration lhs, Duration rhs );
     7288_Bool ?<? ( Duration lhs, Duration rhs );
     7289_Bool ?<=?( Duration lhs, Duration rhs );
     7290_Bool ?>? ( Duration lhs, Duration rhs );
     7291_Bool ?>=?( Duration lhs, Duration rhs );
     7292
     7293_Bool ?==?( Duration lhs, zero_t );
     7294_Bool ?!=?( Duration lhs, zero_t );
     7295_Bool ?<? ( Duration lhs, zero_t );
     7296_Bool ?<=?( Duration lhs, zero_t );
     7297_Bool ?>? ( Duration lhs, zero_t );
     7298_Bool ?>=?( Duration lhs, zero_t );
    77527299
    77537300Duration abs( Duration rhs );
     
    77767323int64_t ?`w( Duration dur );
    77777324
    7778 double ?`dns( Duration dur );
    7779 double ?`dus( Duration dur );
    7780 double ?`dms( Duration dur );
    7781 double ?`ds( Duration dur );
    7782 double ?`dm( Duration dur );
    7783 double ?`dh( Duration dur );
    7784 double ?`dd( Duration dur );
    7785 double ?`dw( Duration dur );
    7786 
    77877325Duration max( Duration lhs, Duration rhs );
    77887326Duration min( Duration lhs, Duration rhs );
    7789 
    7790 forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype & os, Duration dur );
    7791 \end{cfa}
    7792 
    7793 
    7794 %\subsection{\texorpdfstring{\protect\lstinline{timeval}}{timeval}}
     7327\end{cfa}
     7328
     7329
     7330%\subsection{\texorpdfstring{\protect\lstinline@\timeval@}{timeval}}
    77957331\subsection{\texorpdfstring{\LstBasicStyle{timeval}}{timeval}}
    77967332\label{s:timeval}
     
    77997335\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    78007336void ?{}( timeval & t );
    7801 void ?{}( timeval & t, zero_t );
    78027337void ?{}( timeval & t, time_t sec, suseconds_t usec );
    78037338void ?{}( timeval & t, time_t sec );
     7339void ?{}( timeval & t, zero_t );
    78047340void ?{}( timeval & t, Time time );
    78057341
     
    78077343timeval ?+?( timeval & lhs, timeval rhs );
    78087344timeval ?-?( timeval & lhs, timeval rhs );
    7809 bool ?==?( timeval lhs, timeval rhs );
    7810 bool ?!=?( timeval lhs, timeval rhs );
    7811 \end{cfa}
    7812 
    7813 
    7814 %\subsection{\texorpdfstring{\protect\lstinline{timespec}}{timespec}}
     7345_Bool ?==?( timeval lhs, timeval rhs );
     7346_Bool ?!=?( timeval lhs, timeval rhs );
     7347\end{cfa}
     7348
     7349
     7350%\subsection{\texorpdfstring{\protect\lstinline@timespec@}{timespec}}
    78157351\subsection{\texorpdfstring{\LstBasicStyle{timespec}}{timespec}}
    78167352\label{s:timespec}
     
    78197355\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    78207356void ?{}( timespec & t );
    7821 void ?{}( timespec & t, zero_t );
    78227357void ?{}( timespec & t, time_t sec, __syscall_slong_t nsec );
    78237358void ?{}( timespec & t, time_t sec );
     7359void ?{}( timespec & t, zero_t );
    78247360void ?{}( timespec & t, Time time );
    78257361
     
    78277363timespec ?+?( timespec & lhs, timespec rhs );
    78287364timespec ?-?( timespec & lhs, timespec rhs );
    7829 bool ?==?( timespec lhs, timespec rhs );
    7830 bool ?!=?( timespec lhs, timespec rhs );
    7831 \end{cfa}
    7832 
    7833 
    7834 %\subsection{\texorpdfstring{\protect\lstinline{itimerval}}{itimerval}}
     7365_Bool ?==?( timespec lhs, timespec rhs );
     7366_Bool ?!=?( timespec lhs, timespec rhs );
     7367\end{cfa}
     7368
     7369
     7370%\subsection{\texorpdfstring{\protect\lstinline@itimerval@}{itimerval}}
    78357371\subsection{\texorpdfstring{\LstBasicStyle{itimerval}}{itimerval}}
    78367372\label{s:itimerval}
     
    78437379
    78447380
    7845 %\subsection{\texorpdfstring{\protect\lstinline{Time}}{Time}}
     7381%\subsection{\texorpdfstring{\protect\lstinline@Time@}{Time}}
    78467382\subsection{\texorpdfstring{\LstBasicStyle{Time}}{Time}}
    78477383\label{s:Time}
     
    78507386\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    78517387struct Time {
    7852         uint64_t tn; $\C{// nanoseconds since UNIX epoch}$
     7388        uint64_t tv; $\C{// nanoseconds since UNIX epoch}$
    78537389};
    78547390
    78557391void ?{}( Time & time );
    78567392void ?{}( Time & time, zero_t );
     7393
     7394Time ?=?( Time & time, zero_t );
     7395
    78577396void ?{}( Time & time, timeval t );
     7397Time ?=?( Time & time, timeval t );
     7398
    78587399void ?{}( Time & time, timespec t );
    7859 
    7860 Time ?=?( Time & time, zero_t );
    7861 Time ?=?( Time & time, timeval t );
    78627400Time ?=?( Time & time, timespec t );
    78637401
     
    78697407Time ?-?( Time lhs, Duration rhs );
    78707408Time ?-=?( Time & lhs, Duration rhs );
    7871 bool ?==?( Time lhs, Time rhs );
    7872 bool ?!=?( Time lhs, Time rhs );
    7873 bool ?<?( Time lhs, Time rhs );
    7874 bool ?<=?( Time lhs, Time rhs );
    7875 bool ?>?( Time lhs, Time rhs );
    7876 bool ?>=?( Time lhs, Time rhs );
    7877 
    7878 int64_t ?`ns( Time t );
     7409_Bool ?==?( Time lhs, Time rhs );
     7410_Bool ?!=?( Time lhs, Time rhs );
     7411_Bool ?<?( Time lhs, Time rhs );
     7412_Bool ?<=?( Time lhs, Time rhs );
     7413_Bool ?>?( Time lhs, Time rhs );
     7414_Bool ?>=?( Time lhs, Time rhs );
    78797415
    78807416char * yy_mm_dd( Time time, char * buf );
    7881 char * ?`ymd( Time time, char * buf ); // short form
     7417char * ?`ymd( Time time, char * buf ) { // short form
     7418        return yy_mm_dd( time, buf );
     7419} // ymd
    78827420
    78837421char * mm_dd_yy( Time time, char * buf );
    7884 char * ?`mdy( Time time, char * buf ); // short form
     7422char * ?`mdy( Time time, char * buf ) { // short form
     7423        return mm_dd_yy( time, buf );
     7424} // mdy
    78857425
    78867426char * dd_mm_yy( Time time, char * buf );
    7887 char * ?`dmy( Time time, char * buf ); // short form
     7427char * ?`dmy( Time time, char * buf ) { // short form
     7428        return dd_mm_yy( time, buf );;
     7429} // dmy
    78887430
    78897431size_t strftime( char * buf, size_t size, const char * fmt, Time time );
    7890 
    7891 forall( ostype & | ostream( ostype ) ) ostype & ?|?( ostype & os, Time time );
     7432forall( dtype ostype | ostream( ostype ) ) ostype & ?|?( ostype & os, Time time );
    78927433\end{cfa}
    78937434
     
    79097450
    79107451
    7911 %\subsection{\texorpdfstring{\protect\lstinline{Clock}}{Clock}}
     7452%\subsection{\texorpdfstring{\protect\lstinline@Clock@}{Clock}}
    79127453\subsection{\texorpdfstring{\LstBasicStyle{Clock}}{Clock}}
    79137454\label{s:Clock}
     
    79157456\leavevmode
    79167457\begin{cfa}[aboveskip=0pt,belowskip=0pt]
    7917 struct Clock { $\C{// virtual clock}$
    7918         Duration offset; $\C{// offset from computer real-time}$
     7458struct Clock {
     7459        Duration offset; $\C{// for virtual clock: contains offset from real-time}$
     7460        int clocktype; $\C{// implementation only -1 (virtual), CLOCK\_REALTIME}$
    79197461};
    79207462
    7921 void ?{}( Clock & clk ); $\C{// create no offset}$
    7922 void ?{}( Clock & clk, Duration adj ); $\C{// create with offset}$
    7923 void reset( Clock & clk, Duration adj ); $\C{// change offset}$
    7924 
    7925 Duration resolutionHi(); $\C{// clock resolution in nanoseconds (fine)}$
    7926 Duration resolution(); $\C{// clock resolution without nanoseconds (coarse)}$
    7927 
    7928 Time timeHiRes(); $\C{// real time with nanoseconds}$
    7929 Time time(); $\C{// real time without nanoseconds}$
    7930 Time time( Clock & clk ); $\C{// real time for given clock}$
    7931 Time ?()( Clock & clk ); $\C{//\ \ \ \ alternative syntax}$
    7932 timeval time( Clock & clk ); $\C{// convert to C time format}$
    7933 tm time( Clock & clk );
    7934 Duration processor(); $\C{// non-monotonic duration of kernel thread}$
    7935 Duration program(); $\C{// non-monotonic duration of program CPU}$
    7936 Duration boot(); $\C{// monotonic duration since computer boot}$
     7463void resetClock( Clock & clk );
     7464void resetClock( Clock & clk, Duration adj );
     7465void ?{}( Clock & clk );
     7466void ?{}( Clock & clk, Duration adj );
     7467
     7468Duration getResNsec(); $\C{// with nanoseconds}$
     7469Duration getRes(); $\C{// without nanoseconds}$
     7470
     7471Time getTimeNsec(); $\C{// with nanoseconds}$
     7472Time getTime(); $\C{// without nanoseconds}$
     7473Time getTime( Clock & clk );
     7474Time ?()( Clock & clk );
     7475timeval getTime( Clock & clk );
     7476tm getTime( Clock & clk );
    79377477\end{cfa}
    79387478
     
    81057645forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype * os, Int mp );
    81067646\end{cfa}
    8107 \VRef[Figure]{f:MultiPrecisionFactorials} shows \CFA and C factorial programs using the GMP interfaces.
     7647
     7648The following factorial programs contrast using GMP with the \CFA and C interfaces, where the output from these programs appears in \VRef[Figure]{f:MultiPrecisionFactorials}.
    81087649(Compile with flag \Indexc{-lgmp} to link with the GMP library.)
    8109 
    8110 \begin{figure}
    81117650\begin{cquote}
    81127651\begin{tabular}{@{}l@{\hspace{\parindentlnth}}|@{\hspace{\parindentlnth}}l@{}}
    8113 \multicolumn{1}{@{}c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}} & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}@{}}   \\
     7652\multicolumn{1}{c|@{\hspace{\parindentlnth}}}{\textbf{\CFA}}    & \multicolumn{1}{@{\hspace{\parindentlnth}}c}{\textbf{C}}      \\
    81147653\hline
    81157654\begin{cfa}
     
    81207659
    81217660        sout | 0 | fact;
    8122         for ( i; 40 ) {
     7661        for ( unsigned int i = 1; i <= 40; i += 1 ) {
    81237662                fact *= i;
    81247663                sout | i | fact;
     
    81307669#include <gmp.h>$\indexc{gmp.h}$
    81317670int main( void ) {
    8132         ®gmp_printf®( "Factorial Numbers\n" );
    8133         ®mpz_t® fact;
    8134         ®mpz_init_set_ui®( fact, 1 );
    8135         ®gmp_printf®( "%d %Zd\n", 0, fact );
     7671        @gmp_printf@( "Factorial Numbers\n" );
     7672        @mpz_t@ fact;
     7673        @mpz_init_set_ui@( fact, 1 );
     7674        @gmp_printf@( "%d %Zd\n", 0, fact );
    81367675        for ( unsigned int i = 1; i <= 40; i += 1 ) {
    8137                 ®mpz_mul_ui®( fact, fact, i );
    8138                 ®gmp_printf®( "%d %Zd\n", i, fact );
     7676                @mpz_mul_ui@( fact, fact, i );
     7677                @gmp_printf@( "%d %Zd\n", i, fact );
    81397678        }
    81407679}
     
    81427681\end{tabular}
    81437682\end{cquote}
    8144 \small
     7683
     7684\begin{figure}
    81457685\begin{cfa}
    81467686Factorial Numbers
  • example/io/batch-readv.c

    r5407cdc rfeacef9  
    6666}
    6767
    68 uint64_t timeHiRes() {
     68uint64_t getTimeNsec() {
    6969        timespec curr;
    7070        clock_gettime( CLOCK_REALTIME, &curr );
     
    163163
    164164        printf("Running for %f second, reading %d bytes in batches of %d\n", duration, buflen, batch);
    165         uint64_t start = timeHiRes();
    166         uint64_t end   = timeHiRes();
    167         uint64_t prev  = timeHiRes();
     165        uint64_t start = getTimeNsec();
     166        uint64_t end   = getTimeNsec();
     167        uint64_t prev  = getTimeNsec();
    168168        for(;;) {
    169169                submit_and_drain(&iov, batch);
    170                 end = timeHiRes();
     170                end = getTimeNsec();
    171171                uint64_t delta = end - start;
    172172                if( to_fseconds(end - prev) > 0.1 ) {
  • libcfa/configure.ac

    r5407cdc rfeacef9  
    169169AH_TEMPLATE([CFA_HAVE_IOSQE_FIXED_FILE],[Defined if io_uring support is present when compiling libcfathread and supports the flag FIXED_FILE.])
    170170AH_TEMPLATE([CFA_HAVE_IOSQE_IO_DRAIN],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_DRAIN.])
     171AH_TEMPLATE([CFA_HAVE_IOSQE_ASYNC],[Defined if io_uring support is present when compiling libcfathread and supports the flag ASYNC.])
    171172AH_TEMPLATE([CFA_HAVE_IOSQE_IO_LINK],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_LINK.])
    172173AH_TEMPLATE([CFA_HAVE_IOSQE_IO_HARDLINK],[Defined if io_uring support is present when compiling libcfathread and supports the flag IO_HARDLINK.])
    173 AH_TEMPLATE([CFA_HAVE_IOSQE_ASYNC],[Defined if io_uring support is present when compiling libcfathread and supports the flag ASYNC.])
    174 AH_TEMPLATE([CFA_HAVE_IOSQE_BUFFER_SELECT],[Defined if io_uring support is present when compiling libcfathread and supports the flag BUFFER_SELEC.])
    175174AH_TEMPLATE([CFA_HAVE_SPLICE_F_FD_IN_FIXED],[Defined if io_uring support is present when compiling libcfathread and supports the flag SPLICE_F_FD_IN_FIXED.])
    176175AH_TEMPLATE([CFA_HAVE_IORING_SETUP_ATTACH_WQ],[Defined if io_uring support is present when compiling libcfathread and supports the flag IORING_SETUP_ATTACH_WQ.])
     
    183182
    184183define(ioring_ops, [IORING_OP_NOP,IORING_OP_READV,IORING_OP_WRITEV,IORING_OP_FSYNC,IORING_OP_READ_FIXED,IORING_OP_WRITE_FIXED,IORING_OP_POLL_ADD,IORING_OP_POLL_REMOVE,IORING_OP_SYNC_FILE_RANGE,IORING_OP_SENDMSG,IORING_OP_RECVMSG,IORING_OP_TIMEOUT,IORING_OP_TIMEOUT_REMOVE,IORING_OP_ACCEPT,IORING_OP_ASYNC_CANCEL,IORING_OP_LINK_TIMEOUT,IORING_OP_CONNECT,IORING_OP_FALLOCATE,IORING_OP_OPENAT,IORING_OP_CLOSE,IORING_OP_FILES_UPDATE,IORING_OP_STATX,IORING_OP_READ,IORING_OP_WRITE,IORING_OP_FADVISE,IORING_OP_MADVISE,IORING_OP_SEND,IORING_OP_RECV,IORING_OP_OPENAT2,IORING_OP_EPOLL_CTL,IORING_OP_SPLICE,IORING_OP_PROVIDE_BUFFERS,IORING_OP_REMOVE_BUFFER,IORING_OP_TEE])
    185 define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_IO_LINK,IOSQE_IO_HARDLINK,IOSQE_ASYNC,IOSQE_BUFFER_SELECT,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ])
     184define(ioring_flags, [IOSQE_FIXED_FILE,IOSQE_IO_DRAIN,IOSQE_ASYNC,IOSQE_IO_LINK,IOSQE_IO_HARDLINK,SPLICE_F_FD_IN_FIXED,IORING_SETUP_ATTACH_WQ])
    186185
    187186define(ioring_from_decls, [
  • libcfa/prelude/builtins.c

    r5407cdc rfeacef9  
    99// Author           : Peter A. Buhr
    1010// Created On       : Fri Jul 21 16:21:03 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 13 17:26:32 2021
    13 // Update Count     : 117
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Oct 27 14:42:00 2020
     13// Update Count     : 111
    1414//
    1515
     
    125125} // distribution
    126126
    127 #define __CFA_BASE_COMP_1__() if ( x == 1 ) return 1
    128 #define __CFA_BASE_COMP_2__() if ( x == 2 ) return x << (y - 1)
     127#define __CFA_BASE_COMP_1__() if ( ep == 1 ) return 1
     128#define __CFA_BASE_COMP_2__() if ( ep == 2 ) return ep << (y - 1)
    129129#define __CFA_EXP_OVERFLOW__() if ( y >= sizeof(y) * CHAR_BIT ) return 0
    130130
     
    134134        __CFA_BASE_COMP_2__();                                                          /* special case, positive shifting for integral types */ \
    135135        __CFA_EXP_OVERFLOW__();                                                         /* immediate overflow, negative exponent > 2^size-1 */ \
    136         typeof(x) op = 1;                                                                       /* accumulate odd product */ \
     136        typeof(ep) op = 1;                                                                      /* accumulate odd product */ \
    137137        for ( ; y > 1; y >>= 1 ) {                                                      /* squaring exponentiation, O(log2 y) */ \
    138                 if ( (y & 1) == 1 ) op = op * x;                                /* odd ? */ \
    139                 x = x * x; \
     138                if ( (y & 1) == 1 ) op = op * ep;                               /* odd ? */ \
     139                ep = ep * ep; \
    140140        } \
    141         return x * op
     141        return ep * op
    142142
    143143static inline {
    144         long int ?\?( int x, unsigned int y ) { __CFA_EXP__(); }
    145         long int ?\?( long int x, unsigned long int y ) { __CFA_EXP__(); }
    146         long long int ?\?( long long int x, unsigned long long int y ) { __CFA_EXP__(); }
     144        long int ?\?( int ep, unsigned int y ) { __CFA_EXP__(); }
     145        long int ?\?( long int ep, unsigned long int y ) { __CFA_EXP__(); }
    147146        // unsigned computation may be faster and larger
    148         unsigned long int ?\?( unsigned int x, unsigned int y ) { __CFA_EXP__(); }
    149         unsigned long int ?\?( unsigned long int x, unsigned long int y ) { __CFA_EXP__(); }
    150         unsigned long long int ?\?( unsigned long long int x, unsigned long long int y ) { __CFA_EXP__(); }
     147        unsigned long int ?\?( unsigned int ep, unsigned int y ) { __CFA_EXP__(); }
     148        unsigned long int ?\?( unsigned long int ep, unsigned long int y ) { __CFA_EXP__(); }
    151149} // distribution
    152150
     
    159157
    160158static inline forall( OT | { void ?{}( OT & this, one_t ); OT ?*?( OT, OT ); } ) {
    161         OT ?\?( OT x, unsigned int y ) { __CFA_EXP__(); }
    162         OT ?\?( OT x, unsigned long int y ) { __CFA_EXP__(); }
    163         OT ?\?( OT x, unsigned long long int y ) { __CFA_EXP__(); }
     159        OT ?\?( OT ep, unsigned int y ) { __CFA_EXP__(); }
     160        OT ?\?( OT ep, unsigned long int y ) { __CFA_EXP__(); }
    164161} // distribution
    165162
     
    169166
    170167static inline {
    171         long int ?\=?( int & x, unsigned int y ) { x = x \ y; return x; }
    172168        long int ?\=?( long int & x, unsigned long int y ) { x = x \ y; return x; }
    173         long long int ?\=?( long long int & x, unsigned long long int y ) { x = x \ y; return x; }
    174         unsigned long int ?\=?( unsigned int & x, unsigned int y ) { x = x \ y; return x; }
    175169        unsigned long int ?\=?( unsigned long int & x, unsigned long int y ) { x = x \ y; return x; }
    176         unsigned long long int ?\=?( unsigned long long int & x, unsigned long long int y ) { x = x \ y; return x; }
     170        int ?\=?( int & x, unsigned long int y ) { x = x \ y; return x; }
     171        unsigned int ?\=?( unsigned int & x, unsigned long int y ) { x = x \ y; return x; }
    177172} // distribution
    178173
  • libcfa/prelude/defines.hfa.in

    r5407cdc rfeacef9  
    149149
    150150/* Defined if io_uring support is present when compiling libcfathread and
    151    supports the flag BUFFER_SELEC. */
    152 #undef CFA_HAVE_IOSQE_BUFFER_SELECT
    153 
    154 /* Defined if io_uring support is present when compiling libcfathread and
    155151   supports the flag FIXED_FILE. */
    156152#undef CFA_HAVE_IOSQE_FIXED_FILE
  • libcfa/src/Makefile.am

    r5407cdc rfeacef9  
    1111## Created On       : Sun May 31 08:54:01 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Sat Apr 24 09:09:56 2021
    14 ## Update Count     : 254
     13## Last Modified On : Wed Dec  9 22:46:14 2020
     14## Update Count     : 250
    1515###############################################################################
    1616
     
    5656        bits/queue.hfa \
    5757        bits/sequence.hfa \
    58         containers/array.hfa \
    5958        concurrency/iofwd.hfa \
    6059        containers/list.hfa \
    61         containers/queueLockFree.hfa \
    6260        containers/stackLockFree.hfa \
    6361        vec/vec.hfa \
     
    6967        common.hfa \
    7068        fstream.hfa \
    71         strstream.hfa \
    7269        heap.hfa \
    7370        iostream.hfa \
  • libcfa/src/bits/debug.hfa

    r5407cdc rfeacef9  
    101101        __CFADBG_PRINT_GROUP_##group(__cfaabi_bits_print_buffer(STDERR_FILENO, __VA_ARGS__))
    102102#define __cfadbg_print_buffer_decl(group, ...) \
    103         __CFADBG_PRINT_GROUP_##group(char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( STDERR_FILENO, __dbg_text, __dbg_len ))
     103        __CFADBG_PRINT_GROUP_##group(char __dbg_text[256]; int __dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write( __dbg_text, __dbg_len ))
    104104#define __cfadbg_print_buffer_local(group, ...) \
    105105        __CFADBG_PRINT_GROUP_##group(__dbg_len = snprintf( __dbg_text, 256, __VA_ARGS__ ); __cfaabi_bits_write(STDERR_FILENO, __dbg_text, __dbg_len))
  • libcfa/src/bits/defs.hfa

    r5407cdc rfeacef9  
    7474        #error unsupported architecture
    7575#endif
    76 
    77 #define CFA_IO_LAZY (1_l64u << 32_l64u)
  • libcfa/src/bits/locks.hfa

    r5407cdc rfeacef9  
    3737        extern "C" {
    3838                extern void disable_interrupts() OPTIONAL_THREAD;
    39                 extern void enable_interrupts( bool poll = true ) OPTIONAL_THREAD;
     39                extern void enable_interrupts_noPoll() OPTIONAL_THREAD;
    4040
    4141                #ifdef __CFA_DEBUG__
     
    5757                        __cfaabi_dbg_record_lock( this, caller );
    5858                } else {
    59                         enable_interrupts( false );
     59                        enable_interrupts_noPoll();
    6060                }
    6161                return result;
     
    9090        static inline void unlock( __spinlock_t & this ) {
    9191                __atomic_clear( &this.lock, __ATOMIC_RELEASE );
    92                 enable_interrupts( false );
     92                enable_interrupts_noPoll();
    9393        }
    9494#endif
  • libcfa/src/bits/queue.hfa

    r5407cdc rfeacef9  
    1515        };
    1616
    17         static inline {
     17        inline {
    1818                // wrappers to make Collection have T
    1919                T & head( Queue(T) & q ) with( q ) {
     
    154154        struct QueueIter {
    155155                inline ColIter;                                                                 // Plan 9 inheritance
    156         };
     156        };     
    157157
    158         static inline {
     158        inline {
    159159                void ?{}( QueueIter(T) & qi ) with( qi ) {
    160160                        ((ColIter &)qi){};
  • libcfa/src/bits/weakso_locks.cfa

    r5407cdc rfeacef9  
    1818#include "bits/weakso_locks.hfa"
    1919
    20 void  ?{}( blocking_lock &, bool, bool ) {}
    21 void ^?{}( blocking_lock & ) {}
     20void  ?{}( blocking_lock & this, bool multi_acquisition, bool strict_owner ) {}
     21void ^?{}( blocking_lock & this ) {}
    2222
    23 void lock( blocking_lock & ) {}
    24 bool try_lock( blocking_lock & ) { return false; }
    25 void unlock( blocking_lock & ) {}
    26 void on_notify( blocking_lock &, struct $thread * ) {}
    27 size_t on_wait( blocking_lock & ) { return 0; }
    28 void on_wakeup( blocking_lock &, size_t ) {}
    29 size_t wait_count( blocking_lock & ) { return 0; }
     23void lock( blocking_lock & this ) {}
     24bool try_lock( blocking_lock & this ) { return false; }
     25void unlock( blocking_lock & this ) {}
     26void on_notify( blocking_lock & this, struct $thread * t ) {}
     27void on_wait( blocking_lock & this ) {}
     28size_t wait_count( blocking_lock & this ) { return 0; }
     29void set_recursion_count( blocking_lock & this, size_t recursion ) {}
     30size_t get_recursion_count( blocking_lock & this ) { return 0; }
  • libcfa/src/bits/weakso_locks.hfa

    r5407cdc rfeacef9  
    5656void unlock( blocking_lock & this ) OPTIONAL_THREAD;
    5757void on_notify( blocking_lock & this, struct $thread * t ) OPTIONAL_THREAD;
    58 size_t on_wait( blocking_lock & this ) OPTIONAL_THREAD;
    59 void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD;
     58void on_wait( blocking_lock & this ) OPTIONAL_THREAD;
    6059size_t wait_count( blocking_lock & this ) OPTIONAL_THREAD;
     60void set_recursion_count( blocking_lock & this, size_t recursion ) OPTIONAL_THREAD;
     61size_t get_recursion_count( blocking_lock & this ) OPTIONAL_THREAD;
    6162
    6263//----------
     
    6869static inline void  ?{}( multiple_acquisition_lock & this ) {((blocking_lock &)this){ true, false };}
    6970static inline void ^?{}( multiple_acquisition_lock & this ) {}
    70 static inline void   lock     ( multiple_acquisition_lock & this ) { lock    ( (blocking_lock &)this ); }
    71 static inline bool   try_lock ( multiple_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); }
    72 static inline void   unlock   ( multiple_acquisition_lock & this ) { unlock  ( (blocking_lock &)this ); }
    73 static inline size_t on_wait  ( multiple_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); }
    74 static inline void   on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
     71static inline void   lock     ( multiple_acquisition_lock & this ) { lock   ( (blocking_lock &)this ); }
     72static inline void   unlock   ( multiple_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); }
     73static inline void   on_wait  ( multiple_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); }
    7574static inline void   on_notify( multiple_acquisition_lock & this, struct $thread * t ){ on_notify( (blocking_lock &)this, t ); }
     75static inline void   set_recursion_count( multiple_acquisition_lock & this, size_t recursion ){ set_recursion_count( (blocking_lock &)this, recursion ); }
     76static inline size_t get_recursion_count( multiple_acquisition_lock & this ){ return get_recursion_count( (blocking_lock &)this ); }
  • libcfa/src/clock.hfa

    r5407cdc rfeacef9  
    1010// Created On       : Thu Apr 12 14:36:06 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sun Apr 18 08:12:16 2021
    13 // Update Count     : 28
     12// Last Modified On : Mon Jan  6 12:49:58 2020
     13// Update Count     : 9
    1414//
    1515
     
    2727//######################### Clock #########################
    2828
    29 struct Clock {                                                                                  // virtual clock
    30         // private
    31         Duration offset;                                                                        // offset from computer real-time
     29struct Clock {                                                                                  // private
     30        Duration offset;                                                                        // for virtual clock: contains offset from real-time
    3231};
    3332
    3433static inline {
    35         void reset( Clock & clk, Duration adj ) with( clk ) { // change offset
     34        void resetClock( Clock & clk, Duration adj ) with( clk ) {
    3635                offset = adj + __timezone`s;                                    // timezone (global) is (UTC - local time) in seconds
    37         } // reset
     36        } // resetClock
    3837
    39         void ?{}( Clock & clk ) { reset( clk, (Duration){ 0 } ); } // create no offset
    40         void ?{}( Clock & clk, Duration adj ) { reset( clk, adj ); } // create with offset
     38        void ?{}( Clock & clk, Duration adj ) { resetClock( clk, adj ); }
    4139
    42         // System-wide clock that measures real, i.e., wall-clock) time. This clock is affected by discontinuous jumps in
    43         // the system time. For example, manual changes of the clock, and incremental adjustments performed by adjtime(3)
    44         // and NTP (daylight saving (Fall back).
    45         Duration resolutionHi() {                                                       // clock resolution in nanoseconds (fine)
     40        Duration getResNsec() {
    4641                struct timespec res;
    4742                clock_getres( CLOCK_REALTIME, &res );
    4843                return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns;
    49         } // resolutionHi
     44        } // getRes
    5045
    51         Duration resolution() {                                                         // clock resolution without nanoseconds (coarse)
     46        Duration getRes() {
    5247                struct timespec res;
    5348                clock_getres( CLOCK_REALTIME_COARSE, &res );
    5449                return ((int64_t)res.tv_sec * TIMEGRAN + res.tv_nsec)`ns;
    55         } // resolution
     50        } // getRes
    5651
    57         Time timeHiRes() {                                                                      // real time with nanoseconds
     52        Time getTimeNsec() {                                                            // with nanoseconds
    5853                timespec curr;
    5954                clock_gettime( CLOCK_REALTIME, &curr );
    6055                return (Time){ curr };
    61         } // timeHiRes
     56        } // getTimeNsec
    6257
    63         Time time() {                                                                           // real time without nanoseconds
     58        Time getTime() {                                                                        // without nanoseconds
    6459                timespec curr;
    6560                clock_gettime( CLOCK_REALTIME_COARSE, &curr );
    6661                curr.tv_nsec = 0;
    6762                return (Time){ curr };
    68         } // time
     63        } // getTime
    6964
    70         Time time( Clock & clk ) with( clk ) {                          // real time for given clock
    71                 return time() + offset;
    72         } // time
     65        Time getTime( Clock & clk ) with( clk ) {
     66                return getTime() + offset;
     67        } // getTime
    7368
    7469        Time ?()( Clock & clk ) with( clk ) {                           // alternative syntax
    75                 return time() + offset;
    76         } // ?()
     70                return getTime() + offset;
     71        } // getTime
    7772
    78         timeval time( Clock & clk ) {                                           // convert to C time format
     73        timeval getTime( Clock & clk ) {
    7974                return (timeval){ clk() };
    80         } // time
     75        } // getTime
    8176
    82         tm time( Clock & clk ) with( clk ) {
     77        tm getTime( Clock & clk ) with( clk ) {
    8378                tm ret;
    84                 localtime_r( time( clk ).tv_sec, &ret );
     79                localtime_r( getTime( clk ).tv_sec, &ret );
    8580                return ret;
    86         } // time
     81        } // getTime
    8782
    88         // CFA processor CPU-time watch that ticks when the processor (kernel thread) is running. This watch is affected by
    89         // discontinuous jumps when the OS is not running the kernal thread. A duration is returned because the value is
    90         // relative and cannot be converted to real-time (wall-clock) time.
    91         Duration processor() {                                                          // non-monotonic duration of kernel thread
     83        Time getCPUTime() {
    9284                timespec ts;
    9385                clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts );
    94                 return (Duration){ ts };
    95         } // processor
    96 
    97         // Program CPU-time watch measures CPU time consumed by all processors (kernel threads) in the UNIX process.  This
    98         // watch is affected by discontinuous jumps when the OS is not running the kernel threads. A duration is returned
    99         // because the value is relative and cannot be converted to real-time (wall-clock) time.
    100         Duration program() {                                                            // non-monotonic duration of program CPU
    101                 timespec ts;
    102                 clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &ts );
    103                 return (Duration){ ts };
    104         } // program
    105 
    106         // Monotonic duration from machine boot and including system suspension. This watch is unaffected by discontinuous
    107         // jumps resulting from manual changes of the clock, and incremental adjustments performed by adjtime(3) and NTP
    108         // (Fall back). A duration is returned because the value is relative and cannot be converted to real-time
    109         // (wall-clock) time.
    110         Duration boot() {                                                                       // monotonic duration since computer boot
    111                 timespec ts;
    112                 clock_gettime( CLOCK_BOOTTIME, &ts );
    113                 return (Duration){ ts };
    114         } // boot
     86                return (Time){ ts };
     87    } // getCPUTime
    11588} // distribution
    11689
  • libcfa/src/concurrency/alarm.cfa

    r5407cdc rfeacef9  
    1515
    1616#define __cforall_thread__
    17 // #define __CFA_DEBUG_PRINT_PREEMPTION__
    1817
    1918#include <errno.h>
     
    108107                bool first = ! & alarms`first;
    109108
    110                 __cfadbg_print_safe( preemption, " KERNEL: alarm inserting %p (%lu).\n", this, this->alarm.tn );
    111109                insert( &alarms, this );
    112110                if( first ) {
     
    116114        unlock( event_kernel->lock );
    117115        this->set = true;
    118         enable_interrupts();
     116        enable_interrupts( __cfaabi_dbg_ctx );
    119117}
    120118
     
    127125        }
    128126        unlock( event_kernel->lock );
    129         enable_interrupts();
     127        enable_interrupts( __cfaabi_dbg_ctx );
    130128        this->set = false;
    131129}
  • libcfa/src/concurrency/clib/cfathread.cfa

    r5407cdc rfeacef9  
    1414//
    1515
    16 #include "fstream.hfa"
    17 #include "locks.hfa"
    1816#include "kernel.hfa"
    19 #include "stats.hfa"
    2017#include "thread.hfa"
    21 #include "time.hfa"
    2218
    23 #include "cfathread.h"
     19thread CRunner {
     20        void (*themain)( CRunner * );
     21};
    2422
    25 extern void ?{}(processor &, const char[], cluster &, $thread *);
    26 extern "C" {
    27       extern void __cfactx_invoke_thread(void (*main)(void *), void * this);
     23static void ?{}( CRunner & this, void (*themain)( CRunner * ) ) {
     24        this.themain = themain;
    2825}
    2926
    30 //================================================================================
    31 // Thread run y the C Interface
    32 
    33 struct cfathread_object {
    34         $thread self;
    35         void * (*themain)( void * );
    36         void * arg;
    37         void * ret;
    38 };
    39 void main(cfathread_object & this);
    40 void ^?{}(cfathread_object & mutex this);
    41 
    42 static inline $thread * get_thread( cfathread_object & this ) { return &this.self; }
    43 
    44 typedef ThreadCancelled(cfathread_object) cfathread_exception;
    45 typedef ThreadCancelled_vtable(cfathread_object) cfathread_vtable;
    46 
    47 void defaultResumptionHandler(ThreadCancelled(cfathread_object) & except) {
    48         abort | "A thread was cancelled";
     27void main( CRunner & this ) {
     28        this.themain( &this );
    4929}
    5030
    51 cfathread_vtable _cfathread_vtable_instance;
     31processor * procs = 0p;
     32int proc_cnt = 1;
    5233
    53 cfathread_vtable & const _default_vtable = _cfathread_vtable_instance;
    54 
    55 cfathread_vtable const & get_exception_vtable(cfathread_exception *) {
    56         return _cfathread_vtable_instance;
    57 }
    58 
    59 static void ?{}( cfathread_object & this, cluster & cl, void *(*themain)( void * ), void * arg ) {
    60         this.themain = themain;
    61         this.arg = arg;
    62         (this.self){"C-thread", cl};
    63         __thrd_start(this, main);
    64 }
    65 
    66 void ^?{}(cfathread_object & mutex this) {
    67         ^(this.self){};
    68 }
    69 
    70 void main( cfathread_object & this ) {
    71         __attribute__((unused)) void * const thrd_obj = (void*)&this;
    72         __attribute__((unused)) void * const thrd_hdl = (void*)active_thread();
    73         /* paranoid */ verify( thrd_obj == thrd_hdl );
    74 
    75         this.ret = this.themain( this.arg );
    76 }
    77 
    78 //================================================================================
    79 // Special Init Thread responsible for the initialization or processors
    80 struct __cfainit {
    81         $thread self;
    82         void (*init)( void * );
    83         void * arg;
    84 };
    85 void main(__cfainit & this);
    86 void ^?{}(__cfainit & mutex this);
    87 
    88 static inline $thread * get_thread( __cfainit & this ) { return &this.self; }
    89 
    90 typedef ThreadCancelled(__cfainit) __cfainit_exception;
    91 typedef ThreadCancelled_vtable(__cfainit) __cfainit_vtable;
    92 
    93 void defaultResumptionHandler(ThreadCancelled(__cfainit) & except) {
    94         abort | "The init thread was cancelled";
    95 }
    96 
    97 __cfainit_vtable ___cfainit_vtable_instance;
    98 
    99 __cfainit_vtable const & get_exception_vtable(__cfainit_exception *) {
    100         return ___cfainit_vtable_instance;
    101 }
    102 
    103 static void ?{}( __cfainit & this, void (*init)( void * ), void * arg ) {
    104         this.init = init;
    105         this.arg = arg;
    106         (this.self){"Processir Init"};
    107 
    108         // Don't use __thrd_start! just prep the context manually
    109         $thread * this_thrd = get_thread(this);
    110         void (*main_p)(__cfainit &) = main;
    111 
    112         disable_interrupts();
    113         __cfactx_start(main_p, get_coroutine(this), this, __cfactx_invoke_thread);
    114 
    115         this_thrd->context.[SP, FP] = this_thrd->self_cor.context.[SP, FP];
    116         /* paranoid */ verify( this_thrd->context.SP );
    117 
    118         this_thrd->state = Ready;
    119         enable_interrupts();
    120 }
    121 
    122 void ^?{}(__cfainit & mutex this) {
    123         ^(this.self){};
    124 }
    125 
    126 void main( __cfainit & this ) {
    127         __attribute__((unused)) void * const thrd_obj = (void*)&this;
    128         __attribute__((unused)) void * const thrd_hdl = (void*)active_thread();
    129         /* paranoid */ verify( thrd_obj == thrd_hdl );
    130 
    131         this.init( this.arg );
    132 }
    133 
    134 //================================================================================
    135 // Main Api
    13634extern "C" {
    137         int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) {
    138                 *cl = new();
    139                 return 0;
     35        //--------------------
     36        // Basic thread management
     37        CRunner * cfathread_create( void (*main)( CRunner * ) ) {
     38                return new( main );
    14039        }
    14140
    142         cfathread_cluster_t cfathread_cluster_self(void) {
    143                 return active_cluster();
    144         }
    145 
    146         int cfathread_cluster_print_stats( cfathread_cluster_t cl ) {
    147                 #if !defined(__CFA_NO_STATISTICS__)
    148                         print_stats_at_exit( *cl, CFA_STATS_READY_Q | CFA_STATS_IO );
    149                         print_stats_now( *cl, CFA_STATS_READY_Q | CFA_STATS_IO );
    150                 #endif
    151                 return 0;
    152         }
    153 
    154         int cfathread_cluster_add_worker(cfathread_cluster_t cl, pthread_t* tid, void (*init_routine) (void *), void * arg) {
    155                 __cfainit * it = 0p;
    156                 if(init_routine) {
    157                         it = alloc();
    158                         (*it){init_routine, arg};
    159                 }
    160                 processor * proc = alloc();
    161                 (*proc){ "C-processor", *cl, get_thread(*it) };
    162 
    163                 // Wait for the init thread to return before continuing
    164                 if(it) {
    165                         ^(*it){};
    166                         free(it);
    167                 }
    168 
    169                 if(tid) *tid = proc->kernel_thread;
    170                 return 0;
    171         }
    172 
    173         int cfathread_cluster_pause (cfathread_cluster_t) {
    174                 abort | "Pausing clusters is not supported";
    175                 exit(1);
    176         }
    177 
    178         int cfathread_cluster_resume(cfathread_cluster_t) {
    179                 abort | "Resuming clusters is not supported";
    180                 exit(1);
    181         }
    182 
    183         //--------------------
    184         // Thread attributes
    185         int cfathread_attr_init(cfathread_attr_t *attr) __attribute__((nonnull (1))) {
    186                 attr->cl = active_cluster();
    187                 return 0;
    188         }
    189 
    190         //--------------------
    191         // Thread
    192         int cfathread_create( cfathread_t * handle, const cfathread_attr_t * attr, void *(*main)( void * ), void * arg ) __attribute__((nonnull (1))) {
    193                 cluster * cl = attr ? attr->cl : active_cluster();
    194                 cfathread_t thrd = alloc();
    195                 (*thrd){ *cl, main, arg };
    196                 *handle = thrd;
    197                 return 0;
    198         }
    199 
    200         int cfathread_join( cfathread_t thrd, void ** retval ) {
    201                 void * ret = join( *thrd ).ret;
    202                 ^( *thrd ){};
    203                 free(thrd);
    204                 if(retval) {
    205                         *retval = ret;
    206                 }
    207                 return 0;
    208         }
    209 
    210         int cfathread_get_errno(void) {
    211                 return errno;
    212         }
    213 
    214         cfathread_t cfathread_self(void) {
    215                 return (cfathread_t)active_thread();
    216         }
    217 
    218         int cfathread_usleep(useconds_t usecs) {
    219                 sleep(usecs`us);
    220                 return 0;
    221         }
    222 
    223         int cfathread_sleep(unsigned int secs) {
    224                 sleep(secs`s);
    225                 return 0;
     41        void cfathread_join( CRunner * thrd ) {
     42                delete( thrd );
    22643        }
    22744
     
    23047        }
    23148
    232         void cfathread_unpark( cfathread_t thrd ) {
     49        void cfathread_unpark( CRunner * thrd ) {
    23350                unpark( *thrd );
    23451        }
     
    23855        }
    23956
    240         typedef struct cfathread_mutex * cfathread_mutex_t;
     57        //--------------------
     58        // Basic kernel features
     59        void cfathread_setproccnt( int ncnt ) {
     60                assert( ncnt >= 1 );
     61                adelete( procs );
    24162
    242         //--------------------
    243         // Mutex
    244         struct cfathread_mutex {
    245                 fast_lock impl;
    246         };
    247         int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict) __attribute__((nonnull (1))) { *mut = new(); return 0; }
    248         int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1))) { delete( *mut ); return 0; }
    249         int cfathread_mutex_lock   (cfathread_mutex_t *mut) __attribute__((nonnull (1))) { lock( (*mut)->impl ); return 0; }
    250         int cfathread_mutex_unlock (cfathread_mutex_t *mut) __attribute__((nonnull (1))) { unlock( (*mut)->impl ); return 0; }
    251         int cfathread_mutex_trylock(cfathread_mutex_t *mut) __attribute__((nonnull (1))) {
    252                 bool ret = try_lock( (*mut)->impl );
    253                 if( ret ) return 0;
    254                 else return EBUSY;
    255         }
    256 
    257         //--------------------
    258         // Condition
    259         struct cfathread_condition {
    260                 condition_variable(fast_lock) impl;
    261         };
    262         int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict) __attribute__((nonnull (1))) { *cond = new(); return 0; }
    263         int cfathread_cond_signal(cfathread_cond_t *cond) __attribute__((nonnull (1)))  { notify_one( (*cond)->impl ); return 0; }
    264         int cfathread_cond_wait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut) __attribute__((nonnull (1,2))) { wait( (*cond)->impl, (*mut)->impl ); return 0; }
    265         int cfathread_cond_timedwait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut, const struct timespec *restrict abstime) __attribute__((nonnull (1,2,3))) {
    266                 Time t = { *abstime };
    267                 if( wait( (*cond)->impl, (*mut)->impl, t ) ) {
    268                         return 0;
    269                 }
    270                 errno = ETIMEDOUT;
    271                 return ETIMEDOUT;
     63                proc_cnt = ncnt - 1;
     64                procs = anew(proc_cnt);
    27265        }
    27366}
    274 
    275 #include <iofwd.hfa>
    276 
    277 extern "C" {
    278         #include <unistd.h>
    279         #include <sys/types.h>
    280         #include <sys/socket.h>
    281 
    282         //--------------------
    283         // IO operations
    284         int cfathread_socket(int domain, int type, int protocol) {
    285                 return socket(domain, type, protocol);
    286         }
    287         int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) {
    288                 return bind(socket, address, address_len);
    289         }
    290 
    291         int cfathread_listen(int socket, int backlog) {
    292                 return listen(socket, backlog);
    293         }
    294 
    295         int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) {
    296                 return cfa_accept4(socket, address, address_len, 0, CFA_IO_LAZY);
    297         }
    298 
    299         int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) {
    300                 return cfa_connect(socket, address, address_len, CFA_IO_LAZY);
    301         }
    302 
    303         int cfathread_dup(int fildes) {
    304                 return dup(fildes);
    305         }
    306 
    307         int cfathread_close(int fildes) {
    308                 return cfa_close(fildes, CFA_IO_LAZY);
    309         }
    310 
    311         ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags) {
    312                 return cfa_sendmsg(socket, message, flags, CFA_IO_LAZY);
    313         }
    314 
    315         ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte) {
    316                 // Use send rather then write for socket since it's faster
    317                 return cfa_send(fildes, buf, nbyte, 0, CFA_IO_LAZY);
    318         }
    319 
    320         ssize_t cfathread_recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len)  {
    321                 struct iovec iov;
    322                 iov.iov_base = buffer;
    323                 iov.iov_len = length;
    324 
    325                 struct msghdr msg;
    326                 msg.msg_name = address;
    327                 msg.msg_namelen = address_len ? (socklen_t)*address_len : (socklen_t)0;
    328                 msg.msg_iov = &iov;
    329                 msg.msg_iovlen = 1;
    330                 msg.msg_control = 0p;
    331                 msg.msg_controllen = 0;
    332 
    333                 ssize_t ret = cfa_recvmsg(socket, &msg, flags, CFA_IO_LAZY);
    334 
    335                 if(address_len) *address_len = msg.msg_namelen;
    336                 return ret;
    337         }
    338 
    339         ssize_t cfathread_read(int fildes, void *buf, size_t nbyte) {
    340                 // Use recv rather then read for socket since it's faster
    341                 return cfa_recv(fildes, buf, nbyte, 0, CFA_IO_LAZY);
    342         }
    343 
    344 }
  • libcfa/src/concurrency/clib/cfathread.h

    r5407cdc rfeacef9  
    1414//
    1515
     16#include "stddef.h"
     17#include "invoke.h"
     18
    1619#if defined(__cforall) || defined(__cplusplus)
    1720extern "C" {
    1821#endif
    19         #include <asm/types.h>
    20         #include <errno.h>
    21         #include <unistd.h>
    22 
     22        //--------------------
     23        // Basic types
     24        struct cfathread_CRunner_t;
     25        typedef struct cfathread_CRunner_t * cfathread_t;
    2326
    2427        //--------------------
    25         // Basic types
    26 
    27         typedef struct cluster * cfathread_cluster_t;
    28 
    29         int cfathread_cluster_create(cfathread_cluster_t * cluster);
    30         cfathread_cluster_t cfathread_cluster_self(void);
    31         int cfathread_cluster_print_stats(cfathread_cluster_t cluster);
    32         int cfathread_cluster_add_worker(cfathread_cluster_t cluster, pthread_t* tid, void (*init_routine) (void *), void * arg);
    33         int cfathread_cluster_pause (cfathread_cluster_t cluster);
    34         int cfathread_cluster_resume(cfathread_cluster_t cluster);
    35 
    36         //--------------------
    37         // thread attribute
    38         typedef struct cfathread_attr {
    39                 cfathread_cluster_t cl;
    40         } cfathread_attr_t;
    41 
    42         int cfathread_attr_init(cfathread_attr_t * attr) __attribute__((nonnull (1)));
    43         static inline int cfathread_attr_destroy(cfathread_attr_t * attr) __attribute__((nonnull (1)));
    44         static inline int cfathread_attr_destroy(cfathread_attr_t * attr) { return 0; }
    45         static inline int cfathread_attr_setbackground(cfathread_attr_t * attr, int background) __attribute__((nonnull (1)));
    46         static inline int cfathread_attr_setbackground(cfathread_attr_t * attr, int background) { return 0; }
    47         static inline int cfathread_attr_setcluster(cfathread_attr_t * attr, cfathread_cluster_t cl) __attribute__((nonnull (1)));
    48         static inline int cfathread_attr_setcluster(cfathread_attr_t * attr, cfathread_cluster_t cl) { attr->cl = cl; return 0; }
    49 
    50         //--------------------
    51         // thread type
    52         struct cfathread_object;
    53         typedef struct cfathread_object * cfathread_t;
    54 
    55         int cfathread_create( cfathread_t * h, const cfathread_attr_t * a, void *(*main)( void * ), void * arg ) __attribute__((nonnull (1)));
    56         int cfathread_join( cfathread_t, void ** retval );
    57 
    58         int cfathread_get_errno(void);
    59         cfathread_t cfathread_self(void);
    60 
    61         int cfathread_usleep(useconds_t usecs);
    62         int cfathread_sleep(unsigned int secs);
     28        // Basic thread support
     29        cfathread_t cfathread_create( void (*main)( cfathread_t ) );
     30        void cfathread_join( cfathread_t );
    6331
    6432        void cfathread_park( void );
     
    6735
    6836        //--------------------
    69         // mutex and condition
    70         struct timespec;
     37        // Basic kernel features
     38        void cfathread_setproccnt( int );
    7139
    72         typedef struct cfathread_mutex_attr {
    73         } cfathread_mutexattr_t;
    74         typedef struct cfathread_mutex * cfathread_mutex_t;
    75         int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict attr) __attribute__((nonnull (1)));
    76         int cfathread_mutex_destroy(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
    77         int cfathread_mutex_lock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
    78         int cfathread_mutex_trylock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
    79         int cfathread_mutex_unlock(cfathread_mutex_t *mut) __attribute__((nonnull (1)));
    80 
    81         typedef struct cfathread_cond_attr {
    82         } cfathread_condattr_t;
    83         typedef struct cfathread_condition * cfathread_cond_t;
    84         int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict attr) __attribute__((nonnull (1)));
    85         int cfathread_cond_wait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut) __attribute__((nonnull (1,2)));
    86         int cfathread_cond_timedwait(cfathread_cond_t *restrict cond, cfathread_mutex_t *restrict mut, const struct timespec *restrict abstime) __attribute__((nonnull (1,2,3)));
    87         int cfathread_cond_signal(cfathread_cond_t *cond) __attribute__((nonnull (1)));
    88 
    89         //--------------------
    90         // IO operations
    91         struct sockaddr;
    92         struct msghdr;
    93         int cfathread_socket(int domain, int type, int protocol);
    94         int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len);
    95         int cfathread_listen(int socket, int backlog);
    96         int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);
    97         int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len);
    98         int cfathread_dup(int fildes);
    99         int cfathread_close(int fildes);
    100         ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags);
    101         ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte);
    102         ssize_t cfathread_recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len);
    103         ssize_t cfathread_read(int fildes, void *buf, size_t nbyte);
    10440
    10541#if defined(__cforall) || defined(__cplusplus)
  • libcfa/src/concurrency/coroutine.cfa

    r5407cdc rfeacef9  
    4646
    4747//-----------------------------------------------------------------------------
     48FORALL_DATA_INSTANCE(CoroutineCancelled, (coroutine_t &), (coroutine_t))
     49
     50forall(T &)
     51void mark_exception(CoroutineCancelled(T) *) {}
     52
    4853forall(T &)
    4954void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
     
    6065// This code should not be inlined. It is the error path on resume.
    6166forall(T & | is_coroutine(T))
    62 void __cfaehm_cancelled_coroutine(
    63                 T & cor, $coroutine * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ) {
     67void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ) {
    6468        verify( desc->cancellation );
    6569        desc->state = Cancelled;
     
    6872        // TODO: Remove explitate vtable set once trac#186 is fixed.
    6973        CoroutineCancelled(T) except;
    70         except.virtual_table = &_default_vtable;
     74        except.virtual_table = &get_exception_vtable(&except);
    7175        except.the_coroutine = &cor;
    7276        except.the_exception = except;
    73         // Why does this need a cast?
    74         throwResume (CoroutineCancelled(T) &)except;
     77        throwResume except;
    7578
    7679        except->virtual_table->free( except );
     
    145148// Part of the Public API
    146149// Not inline since only ever called once per coroutine
    147 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })
     150forall(T & | is_coroutine(T))
    148151void prime(T& cor) {
    149152        $coroutine* this = get_coroutine(cor);
     
    193196
    194197void __stack_clean  ( __stack_info_t * this ) {
     198        size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t);
    195199        void * storage = this->storage->limit;
    196200
    197201        #if CFA_COROUTINE_USE_MMAP
    198                 size_t size = ((intptr_t)this->storage->base) - ((intptr_t)this->storage->limit) + sizeof(__stack_t);
    199202                storage = (void *)(((intptr_t)storage) - __page_size);
    200203                if(munmap(storage, size + __page_size) == -1) {
  • libcfa/src/concurrency/coroutine.hfa

    r5407cdc rfeacef9  
    2222//-----------------------------------------------------------------------------
    2323// Exception thrown from resume when a coroutine stack is cancelled.
    24 EHM_FORALL_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (
     24FORALL_DATA_EXCEPTION(CoroutineCancelled, (coroutine_t &), (coroutine_t)) (
    2525        coroutine_t * the_coroutine;
    2626        exception_t * the_exception;
     
    6060//-----------------------------------------------------------------------------
    6161// Public coroutine API
    62 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })
     62forall(T & | is_coroutine(T))
    6363void prime(T & cor);
    6464
     
    130130
    131131forall(T & | is_coroutine(T))
    132 void __cfaehm_cancelled_coroutine(
    133         T & cor, $coroutine * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) );
     132void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc );
    134133
    135134// Resume implementation inlined for performance
    136 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); })
     135forall(T & | is_coroutine(T))
    137136static inline T & resume(T & cor) {
    138137        // optimization : read TLS once and reuse it
     
    164163        $ctx_switch( src, dst );
    165164        if ( unlikely(dst->cancellation) ) {
    166                 __cfaehm_cancelled_coroutine( cor, dst, _default_vtable );
     165                __cfaehm_cancelled_coroutine( cor, dst );
    167166        }
    168167
  • libcfa/src/concurrency/future.hfa

    r5407cdc rfeacef9  
    3737
    3838                // Fulfil the future, returns whether or not someone was unblocked
    39                 $thread * fulfil( future(T) & this, T result ) {
     39                bool fulfil( future(T) & this, T result ) {
    4040                        this.result = result;
    4141                        return fulfil( (future_t&)this );
     
    9696                bool fulfil( multi_future(T) & this, T result ) {
    9797                        this.result = result;
    98                         return fulfil( (future_t&)this ) != 0p;
     98                        return fulfil( (future_t&)this );
    9999                }
    100100
  • libcfa/src/concurrency/invoke.c

    r5407cdc rfeacef9  
    3434
    3535extern void disable_interrupts() OPTIONAL_THREAD;
    36 extern void enable_interrupts( _Bool poll );
     36extern void enable_interrupts( __cfaabi_dbg_ctx_param );
    3737
    3838void __cfactx_invoke_coroutine(
     
    8282) {
    8383        // Officially start the thread by enabling preemption
    84         enable_interrupts( true );
     84        enable_interrupts( __cfaabi_dbg_ctx );
    8585
    8686        // Call the main of the thread
  • libcfa/src/concurrency/invoke.h

    r5407cdc rfeacef9  
    148148                struct $thread * prev;
    149149                volatile unsigned long long ts;
    150                 unsigned preferred;
     150                int preferred;
    151151        };
    152152
     
    200200                } node;
    201201
    202                 struct processor * last_proc;
    203 
    204202                #if defined( __CFA_WITH_VERIFY__ )
    205203                        void * canary;
     
    226224                }
    227225
    228                 static inline $thread * volatile & ?`next ( $thread * this )  __attribute__((const)) {
    229                         return this->seqable.next;
    230                 }
    231 
    232226                static inline $thread *& Back( $thread * this ) __attribute__((const)) {
    233227                        return this->seqable.back;
  • libcfa/src/concurrency/io.cfa

    r5407cdc rfeacef9  
    3232        extern "C" {
    3333                #include <sys/syscall.h>
    34                 #include <sys/eventfd.h>
    3534
    3635                #include <linux/io_uring.h>
     
    4039        #include "kernel.hfa"
    4140        #include "kernel/fwd.hfa"
    42         #include "kernel_private.hfa"
    4341        #include "io/types.hfa"
    4442
     
    8179        };
    8280
    83         static $io_context * __ioarbiter_allocate( $io_arbiter & this, __u32 idxs[], __u32 want );
    84         static void __ioarbiter_submit( $io_context * , __u32 idxs[], __u32 have, bool lazy );
    85         static void __ioarbiter_flush ( $io_context & );
    86         static inline void __ioarbiter_notify( $io_context & ctx );
     81        // returns true of acquired as leader or second leader
     82        static inline bool try_lock( __leaderlock_t & this ) {
     83                const uintptr_t thrd = 1z | (uintptr_t)active_thread();
     84                bool block;
     85                disable_interrupts();
     86                for() {
     87                        struct $thread * expected = this.value;
     88                        if( 1p != expected && 0p != expected ) {
     89                                /* paranoid */ verify( thrd != (uintptr_t)expected ); // We better not already be the next leader
     90                                enable_interrupts( __cfaabi_dbg_ctx );
     91                                return false;
     92                        }
     93                        struct $thread * desired;
     94                        if( 0p == expected ) {
     95                                // If the lock isn't locked acquire it, no need to block
     96                                desired = 1p;
     97                                block = false;
     98                        }
     99                        else {
     100                                // If the lock is already locked try becomming the next leader
     101                                desired = (struct $thread *)thrd;
     102                                block = true;
     103                        }
     104                        if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break;
     105                }
     106                if( block ) {
     107                        enable_interrupts( __cfaabi_dbg_ctx );
     108                        park();
     109                        disable_interrupts();
     110                }
     111                return true;
     112        }
     113
     114        static inline bool next( __leaderlock_t & this ) {
     115                /* paranoid */ verify( ! __preemption_enabled() );
     116                struct $thread * nextt;
     117                for() {
     118                        struct $thread * expected = this.value;
     119                        /* paranoid */ verify( (1 & (uintptr_t)expected) == 1 ); // The lock better be locked
     120
     121                        struct $thread * desired;
     122                        if( 1p == expected ) {
     123                                // No next leader, just unlock
     124                                desired = 0p;
     125                                nextt   = 0p;
     126                        }
     127                        else {
     128                                // There is a next leader, remove but keep locked
     129                                desired = 1p;
     130                                nextt   = (struct $thread *)(~1z & (uintptr_t)expected);
     131                        }
     132                        if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break;
     133                }
     134
     135                if(nextt) {
     136                        unpark( nextt );
     137                        enable_interrupts( __cfaabi_dbg_ctx );
     138                        return true;
     139                }
     140                enable_interrupts( __cfaabi_dbg_ctx );
     141                return false;
     142        }
     143
     144//=============================================================================================
     145// I/O Syscall
     146//=============================================================================================
     147        static int __io_uring_enter( struct __io_data & ring, unsigned to_submit, bool get ) {
     148                bool need_sys_to_submit = false;
     149                bool need_sys_to_complete = false;
     150                unsigned flags = 0;
     151
     152                TO_SUBMIT:
     153                if( to_submit > 0 ) {
     154                        if( !(ring.ring_flags & IORING_SETUP_SQPOLL) ) {
     155                                need_sys_to_submit = true;
     156                                break TO_SUBMIT;
     157                        }
     158                        if( (*ring.submit_q.flags) & IORING_SQ_NEED_WAKEUP ) {
     159                                need_sys_to_submit = true;
     160                                flags |= IORING_ENTER_SQ_WAKEUP;
     161                        }
     162                }
     163
     164                if( get && !(ring.ring_flags & IORING_SETUP_SQPOLL) ) {
     165                        flags |= IORING_ENTER_GETEVENTS;
     166                        if( (ring.ring_flags & IORING_SETUP_IOPOLL) ) {
     167                                need_sys_to_complete = true;
     168                        }
     169                }
     170
     171                int ret = 0;
     172                if( need_sys_to_submit || need_sys_to_complete ) {
     173                        __cfadbg_print_safe(io_core, "Kernel I/O : IO_URING enter %d %u %u\n", ring.fd, to_submit, flags);
     174                        ret = syscall( __NR_io_uring_enter, ring.fd, to_submit, 0, flags, (sigset_t *)0p, _NSIG / 8);
     175                        __cfadbg_print_safe(io_core, "Kernel I/O : IO_URING %d returned %d\n", ring.fd, ret);
     176
     177                        if( ret < 0 ) {
     178                                switch((int)errno) {
     179                                case EAGAIN:
     180                                case EINTR:
     181                                case EBUSY:
     182                                        ret = -1;
     183                                        break;
     184                                default:
     185                                        abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) );
     186                                }
     187                        }
     188                }
     189
     190                // Memory barrier
     191                __atomic_thread_fence( __ATOMIC_SEQ_CST );
     192                return ret;
     193        }
     194
    87195//=============================================================================================
    88196// I/O Polling
    89197//=============================================================================================
    90         static inline unsigned __flush( struct $io_context & );
    91         static inline __u32 __release_sqes( struct $io_context & );
    92         extern void __kernel_unpark( $thread * thrd );
    93 
    94         bool __cfa_io_drain( processor * proc ) {
     198        static unsigned __collect_submitions( struct __io_data & ring );
     199        static __u32 __release_consumed_submission( struct __io_data & ring );
     200        static inline void __clean( volatile struct io_uring_sqe * sqe );
     201
     202        // Process a single completion message from the io_uring
     203        // This is NOT thread-safe
     204        static inline void process( volatile struct io_uring_cqe & cqe ) {
     205                struct io_future_t * future = (struct io_future_t *)(uintptr_t)cqe.user_data;
     206                __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future );
     207
     208                fulfil( *future, cqe.res );
     209        }
     210
     211        static [int, bool] __drain_io( & struct __io_data ring ) {
    95212                /* paranoid */ verify( ! __preemption_enabled() );
    96                 /* paranoid */ verify( ready_schedule_islocked() );
    97                 /* paranoid */ verify( proc );
    98                 /* paranoid */ verify( proc->io.ctx );
     213
     214                unsigned to_submit = 0;
     215                if( ring.poller_submits ) {
     216                        // If the poller thread also submits, then we need to aggregate the submissions which are ready
     217                        to_submit = __collect_submitions( ring );
     218                }
     219
     220                int ret = __io_uring_enter(ring, to_submit, true);
     221                if( ret < 0 ) {
     222                        return [0, true];
     223                }
     224
     225                // update statistics
     226                if (to_submit > 0) {
     227                        __STATS__( true,
     228                                if( to_submit > 0 ) {
     229                                        io.submit_q.submit_avg.rdy += to_submit;
     230                                        io.submit_q.submit_avg.csm += ret;
     231                                        io.submit_q.submit_avg.cnt += 1;
     232                                }
     233                        )
     234                }
     235
     236                __atomic_thread_fence( __ATOMIC_SEQ_CST );
     237
     238                // Release the consumed SQEs
     239                __release_consumed_submission( ring );
    99240
    100241                // Drain the queue
    101                 $io_context * ctx = proc->io.ctx;
    102                 unsigned head = *ctx->cq.head;
    103                 unsigned tail = *ctx->cq.tail;
    104                 const __u32 mask = *ctx->cq.mask;
     242                unsigned head = *ring.completion_q.head;
     243                unsigned tail = *ring.completion_q.tail;
     244                const __u32 mask = *ring.completion_q.mask;
     245
     246                // Nothing was new return 0
     247                if (head == tail) {
     248                        return [0, to_submit > 0];
     249                }
    105250
    106251                __u32 count = tail - head;
    107                 __STATS__( false, io.calls.drain++; io.calls.completed += count; )
    108 
    109                 if(count == 0) return false;
    110 
     252                /* paranoid */ verify( count != 0 );
    111253                for(i; count) {
    112254                        unsigned idx = (head + i) & mask;
    113                         volatile struct io_uring_cqe & cqe = ctx->cq.cqes[idx];
     255                        volatile struct io_uring_cqe & cqe = ring.completion_q.cqes[idx];
    114256
    115257                        /* paranoid */ verify(&cqe);
    116258
    117                         struct io_future_t * future = (struct io_future_t *)(uintptr_t)cqe.user_data;
    118                         __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future );
    119 
    120                         __kernel_unpark( fulfil( *future, cqe.res, false ) );
    121                 }
    122 
    123                 __cfadbg_print_safe(io, "Kernel I/O : %u completed\n", count);
     259                        process( cqe );
     260                }
    124261
    125262                // Mark to the kernel that the cqe has been seen
    126263                // Ensure that the kernel only sees the new value of the head index after the CQEs have been read.
    127                 __atomic_store_n( ctx->cq.head, head + count, __ATOMIC_SEQ_CST );
    128 
    129                 /* paranoid */ verify( ready_schedule_islocked() );
    130                 /* paranoid */ verify( ! __preemption_enabled() );
    131 
    132                 return true;
    133         }
    134 
    135         void __cfa_io_flush( processor * proc ) {
    136                 /* paranoid */ verify( ! __preemption_enabled() );
    137                 /* paranoid */ verify( proc );
    138                 /* paranoid */ verify( proc->io.ctx );
    139 
    140                 $io_context & ctx = *proc->io.ctx;
    141 
    142                 __ioarbiter_flush( ctx );
    143 
    144                 __STATS__( true, io.calls.flush++; )
    145                 int ret = syscall( __NR_io_uring_enter, ctx.fd, ctx.sq.to_submit, 0, 0, (sigset_t *)0p, _NSIG / 8);
    146                 if( ret < 0 ) {
    147                         switch((int)errno) {
    148                         case EAGAIN:
    149                         case EINTR:
    150                         case EBUSY:
     264                __atomic_fetch_add( ring.completion_q.head, count, __ATOMIC_SEQ_CST );
     265
     266                return [count, count > 0 || to_submit > 0];
     267        }
     268
     269        void main( $io_ctx_thread & this ) {
     270                __ioctx_register( this );
     271
     272                __cfadbg_print_safe(io_core, "Kernel I/O : IO poller %d (%p) ready\n", this.ring->fd, &this);
     273
     274                const int reset_cnt = 5;
     275                int reset = reset_cnt;
     276                // Then loop until we need to start
     277                LOOP:
     278                while(!__atomic_load_n(&this.done, __ATOMIC_SEQ_CST)) {
     279                        // Drain the io
     280                        int count;
     281                        bool again;
     282                        disable_interrupts();
     283                                [count, again] = __drain_io( *this.ring );
     284
     285                                if(!again) reset--;
     286
    151287                                // Update statistics
    152                                 __STATS__( false, io.calls.errors.busy ++; )
    153                                 return;
    154                         default:
    155                                 abort( "KERNEL ERROR: IO_URING SYSCALL - (%d) %s\n", (int)errno, strerror(errno) );
    156                         }
    157                 }
    158 
    159                 __cfadbg_print_safe(io, "Kernel I/O : %u submitted to io_uring %d\n", ret, ctx.fd);
    160                 __STATS__( true, io.calls.submitted += ret; )
    161                 /* paranoid */ verify( ctx.sq.to_submit <= *ctx.sq.num );
    162                 /* paranoid */ verify( ctx.sq.to_submit >= ret );
    163 
    164                 ctx.sq.to_submit -= ret;
    165 
    166                 /* paranoid */ verify( ctx.sq.to_submit <= *ctx.sq.num );
    167 
    168                 // Release the consumed SQEs
    169                 __release_sqes( ctx );
    170 
    171                 /* paranoid */ verify( ! __preemption_enabled() );
    172 
    173                 ctx.proc->io.pending = false;
     288                                __STATS__( true,
     289                                        io.complete_q.completed_avg.val += count;
     290                                        io.complete_q.completed_avg.cnt += 1;
     291                                )
     292                        enable_interrupts( __cfaabi_dbg_ctx );
     293
     294                        // If we got something, just yield and check again
     295                        if(reset > 1) {
     296                                yield();
     297                                continue LOOP;
     298                        }
     299
     300                        // We alread failed to find completed entries a few time.
     301                        if(reset == 1) {
     302                                // Rearm the context so it can block
     303                                // but don't block right away
     304                                // we need to retry one last time in case
     305                                // something completed *just now*
     306                                __ioctx_prepare_block( this );
     307                                continue LOOP;
     308                        }
     309
     310                                __STATS__( false,
     311                                        io.complete_q.blocks += 1;
     312                                )
     313                                __cfadbg_print_safe(io_core, "Kernel I/O : Parking io poller %d (%p)\n", this.ring->fd, &this);
     314
     315                                // block this thread
     316                                wait( this.sem );
     317
     318                        // restore counter
     319                        reset = reset_cnt;
     320                }
     321
     322                __cfadbg_print_safe(io_core, "Kernel I/O : Fast poller %d (%p) stopping\n", this.ring->fd, &this);
     323
     324                __ioctx_unregister( this );
    174325        }
    175326
     
    193344//         head and tail must be fully filled and shouldn't ever be touched again.
    194345//
    195         //=============================================================================================
    196         // Allocation
    197         // for user's convenience fill the sqes from the indexes
    198         static inline void __fill(struct io_uring_sqe * out_sqes[], __u32 want, __u32 idxs[], struct $io_context * ctx)  {
    199                 struct io_uring_sqe * sqes = ctx->sq.sqes;
    200                 for(i; want) {
    201                         __cfadbg_print_safe(io, "Kernel I/O : filling loop\n");
    202                         out_sqes[i] = &sqes[idxs[i]];
    203                 }
    204         }
    205 
    206         // Try to directly allocate from the a given context
    207         // Not thread-safe
    208         static inline bool __alloc(struct $io_context * ctx, __u32 idxs[], __u32 want) {
    209                 __sub_ring_t & sq = ctx->sq;
    210                 const __u32 mask  = *sq.mask;
    211                 __u32 fhead = sq.free_ring.head;    // get the current head of the queue
    212                 __u32 ftail = sq.free_ring.tail;    // get the current tail of the queue
    213 
    214                 // If we don't have enough sqes, fail
    215                 if((ftail - fhead) < want) { return false; }
    216 
    217                 // copy all the indexes we want from the available list
    218                 for(i; want) {
    219                         __cfadbg_print_safe(io, "Kernel I/O : allocating loop\n");
    220                         idxs[i] = sq.free_ring.array[(fhead + i) & mask];
    221                 }
    222 
    223                 // Advance the head to mark the indexes as consumed
    224                 __atomic_store_n(&sq.free_ring.head, fhead + want, __ATOMIC_RELEASE);
    225 
    226                 // return success
    227                 return true;
    228         }
    229346
    230347        // Allocate an submit queue entry.
     
    233350        // for convenience, return both the index and the pointer to the sqe
    234351        // sqe == &sqes[idx]
    235         struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) {
    236                 __cfadbg_print_safe(io, "Kernel I/O : attempting to allocate %u\n", want);
    237 
    238                 disable_interrupts();
    239                 processor * proc = __cfaabi_tls.this_processor;
    240                 $io_context * ctx = proc->io.ctx;
    241                 /* paranoid */ verify( __cfaabi_tls.this_processor );
    242                 /* paranoid */ verify( ctx );
    243 
    244                 __cfadbg_print_safe(io, "Kernel I/O : attempting to fast allocation\n");
    245 
    246                 // We can proceed to the fast path
    247                 if( __alloc(ctx, idxs, want) ) {
    248                         // Allocation was successful
    249                         __STATS__( true, io.alloc.fast += 1; )
    250                         enable_interrupts();
    251 
    252                         __cfadbg_print_safe(io, "Kernel I/O : fast allocation successful from ring %d\n", ctx->fd);
    253 
    254                         __fill( sqes, want, idxs, ctx );
    255                         return ctx;
    256                 }
    257                 // The fast path failed, fallback
    258                 __STATS__( true, io.alloc.fail += 1; )
    259 
    260                 // Fast path failed, fallback on arbitration
    261                 __STATS__( true, io.alloc.slow += 1; )
    262                 enable_interrupts();
    263 
    264                 $io_arbiter * ioarb = proc->cltr->io.arbiter;
    265                 /* paranoid */ verify( ioarb );
    266 
    267                 __cfadbg_print_safe(io, "Kernel I/O : falling back on arbiter for allocation\n");
    268 
    269                 struct $io_context * ret = __ioarbiter_allocate(*ioarb, idxs, want);
    270 
    271                 __cfadbg_print_safe(io, "Kernel I/O : slow allocation completed from ring %d\n", ret->fd);
    272 
    273                 __fill( sqes, want, idxs,ret );
    274                 return ret;
    275         }
    276 
    277 
    278         //=============================================================================================
    279         // submission
    280         static inline void __submit( struct $io_context * ctx, __u32 idxs[], __u32 have, bool lazy) {
    281                 // We can proceed to the fast path
    282                 // Get the right objects
    283                 __sub_ring_t & sq = ctx->sq;
    284                 const __u32 mask  = *sq.mask;
    285                 __u32 tail = *sq.kring.tail;
    286 
    287                 // Add the sqes to the array
    288                 for( i; have ) {
    289                         __cfadbg_print_safe(io, "Kernel I/O : __submit loop\n");
    290                         sq.kring.array[ (tail + i) & mask ] = idxs[i];
    291                 }
    292 
    293                 // Make the sqes visible to the submitter
    294                 __atomic_store_n(sq.kring.tail, tail + have, __ATOMIC_RELEASE);
    295                 sq.to_submit++;
    296 
    297                 ctx->proc->io.pending = true;
    298                 ctx->proc->io.dirty   = true;
    299                 if(sq.to_submit > 30 || !lazy) {
    300                         __cfa_io_flush( ctx->proc );
    301                 }
    302         }
    303 
    304         void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) {
    305                 __cfadbg_print_safe(io, "Kernel I/O : attempting to submit %u (%s)\n", have, lazy ? "lazy" : "eager");
    306 
    307                 disable_interrupts();
    308                 processor * proc = __cfaabi_tls.this_processor;
    309                 $io_context * ctx = proc->io.ctx;
    310                 /* paranoid */ verify( __cfaabi_tls.this_processor );
    311                 /* paranoid */ verify( ctx );
    312 
    313                 // Can we proceed to the fast path
    314                 if( ctx == inctx )              // We have the right instance?
     352        [* volatile struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ) {
     353                /* paranoid */ verify( data != 0 );
     354
     355                // Prepare the data we need
     356                __attribute((unused)) int len   = 0;
     357                __attribute((unused)) int block = 0;
     358                __u32 cnt = *ring.submit_q.num;
     359                __u32 mask = *ring.submit_q.mask;
     360
     361                __u32 off = thread_rand();
     362
     363                // Loop around looking for an available spot
     364                for() {
     365                        // Look through the list starting at some offset
     366                        for(i; cnt) {
     367                                __u64 expected = 3;
     368                                __u32 idx = (i + off) & mask; // Get an index from a random
     369                                volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx];
     370                                volatile __u64 * udata = &sqe->user_data;
     371
     372                                // Allocate the entry by CASing the user_data field from 0 to the future address
     373                                if( *udata == expected &&
     374                                        __atomic_compare_exchange_n( udata, &expected, data, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) )
     375                                {
     376                                        // update statistics
     377                                        __STATS__( false,
     378                                                io.submit_q.alloc_avg.val   += len;
     379                                                io.submit_q.alloc_avg.block += block;
     380                                                io.submit_q.alloc_avg.cnt   += 1;
     381                                        )
     382
     383                                        // debug log
     384                                        __cfadbg_print_safe( io, "Kernel I/O : allocated [%p, %u] for %p (%p)\n", sqe, idx, active_thread(), (void*)data );
     385
     386                                        // Success return the data
     387                                        return [sqe, idx];
     388                                }
     389                                verify(expected != data);
     390
     391                                // This one was used
     392                                len ++;
     393                        }
     394
     395                        block++;
     396
     397                        yield();
     398                }
     399        }
     400
     401        static inline __u32 __submit_to_ready_array( struct __io_data & ring, __u32 idx, const __u32 mask ) {
     402                /* paranoid */ verify( idx <= mask   );
     403                /* paranoid */ verify( idx != -1ul32 );
     404
     405                // We need to find a spot in the ready array
     406                __attribute((unused)) int len   = 0;
     407                __attribute((unused)) int block = 0;
     408                __u32 ready_mask = ring.submit_q.ready_cnt - 1;
     409
     410                __u32 off = thread_rand();
     411
     412                __u32 picked;
     413                LOOKING: for() {
     414                        for(i; ring.submit_q.ready_cnt) {
     415                                picked = (i + off) & ready_mask;
     416                                __u32 expected = -1ul32;
     417                                if( __atomic_compare_exchange_n( &ring.submit_q.ready[picked], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) {
     418                                        break LOOKING;
     419                                }
     420                                verify(expected != idx);
     421
     422                                len ++;
     423                        }
     424
     425                        block++;
     426
     427                        __u32 released = __release_consumed_submission( ring );
     428                        if( released == 0 ) {
     429                                yield();
     430                        }
     431                }
     432
     433                // update statistics
     434                __STATS__( false,
     435                        io.submit_q.look_avg.val   += len;
     436                        io.submit_q.look_avg.block += block;
     437                        io.submit_q.look_avg.cnt   += 1;
     438                )
     439
     440                return picked;
     441        }
     442
     443        void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1))) {
     444                __io_data & ring = *ctx->thrd.ring;
     445
    315446                {
    316                         __submit(ctx, idxs, have, lazy);
    317 
    318                         // Mark the instance as no longer in-use, re-enable interrupts and return
    319                         __STATS__( true, io.submit.fast += 1; )
    320                         enable_interrupts();
    321 
    322                         __cfadbg_print_safe(io, "Kernel I/O : submitted on fast path\n");
    323                         return;
    324                 }
    325 
    326                 // Fast path failed, fallback on arbitration
    327                 __STATS__( true, io.submit.slow += 1; )
    328                 enable_interrupts();
    329 
    330                 __cfadbg_print_safe(io, "Kernel I/O : falling back on arbiter for submission\n");
    331 
    332                 __ioarbiter_submit(inctx, idxs, have, lazy);
    333         }
    334 
    335         //=============================================================================================
    336         // Flushing
     447                        __attribute__((unused)) volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx];
     448                        __cfadbg_print_safe( io,
     449                                "Kernel I/O : submitting %u (%p) for %p\n"
     450                                "    data: %p\n"
     451                                "    opcode: %s\n"
     452                                "    fd: %d\n"
     453                                "    flags: %d\n"
     454                                "    prio: %d\n"
     455                                "    off: %p\n"
     456                                "    addr: %p\n"
     457                                "    len: %d\n"
     458                                "    other flags: %d\n"
     459                                "    splice fd: %d\n"
     460                                "    pad[0]: %llu\n"
     461                                "    pad[1]: %llu\n"
     462                                "    pad[2]: %llu\n",
     463                                idx, sqe,
     464                                active_thread(),
     465                                (void*)sqe->user_data,
     466                                opcodes[sqe->opcode],
     467                                sqe->fd,
     468                                sqe->flags,
     469                                sqe->ioprio,
     470                                (void*)sqe->off,
     471                                (void*)sqe->addr,
     472                                sqe->len,
     473                                sqe->accept_flags,
     474                                sqe->splice_fd_in,
     475                                sqe->__pad2[0],
     476                                sqe->__pad2[1],
     477                                sqe->__pad2[2]
     478                        );
     479                }
     480
     481
     482                // Get now the data we definetely need
     483                volatile __u32 * const tail = ring.submit_q.tail;
     484                const __u32 mask  = *ring.submit_q.mask;
     485
     486                // There are 2 submission schemes, check which one we are using
     487                if( ring.poller_submits ) {
     488                        // If the poller thread submits, then we just need to add this to the ready array
     489                        __submit_to_ready_array( ring, idx, mask );
     490
     491                        post( ctx->thrd.sem );
     492
     493                        __cfadbg_print_safe( io, "Kernel I/O : Added %u to ready for %p\n", idx, active_thread() );
     494                }
     495                else if( ring.eager_submits ) {
     496                        __attribute__((unused)) __u32 picked = __submit_to_ready_array( ring, idx, mask );
     497
     498                        #if defined(LEADER_LOCK)
     499                                if( !try_lock(ring.submit_q.submit_lock) ) {
     500                                        __STATS__( false,
     501                                                io.submit_q.helped += 1;
     502                                        )
     503                                        return;
     504                                }
     505                                /* paranoid */ verify( ! __preemption_enabled() );
     506                                __STATS__( true,
     507                                        io.submit_q.leader += 1;
     508                                )
     509                        #else
     510                                for() {
     511                                        yield();
     512
     513                                        if( try_lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2) ) {
     514                                                __STATS__( false,
     515                                                        io.submit_q.leader += 1;
     516                                                )
     517                                                break;
     518                                        }
     519
     520                                        // If some one else collected our index, we are done
     521                                        #warning ABA problem
     522                                        if( ring.submit_q.ready[picked] != idx ) {
     523                                                __STATS__( false,
     524                                                        io.submit_q.helped += 1;
     525                                                )
     526                                                return;
     527                                        }
     528
     529                                        __STATS__( false,
     530                                                io.submit_q.busy += 1;
     531                                        )
     532                                }
     533                        #endif
     534
     535                        // We got the lock
     536                        // Collect the submissions
     537                        unsigned to_submit = __collect_submitions( ring );
     538
     539                        // Actually submit
     540                        int ret = __io_uring_enter( ring, to_submit, false );
     541
     542                        #if defined(LEADER_LOCK)
     543                                /* paranoid */ verify( ! __preemption_enabled() );
     544                                next(ring.submit_q.submit_lock);
     545                        #else
     546                                unlock(ring.submit_q.submit_lock);
     547                        #endif
     548                        if( ret < 0 ) {
     549                                return;
     550                        }
     551
     552                        // Release the consumed SQEs
     553                        __release_consumed_submission( ring );
     554
     555                        // update statistics
     556                        __STATS__( false,
     557                                io.submit_q.submit_avg.rdy += to_submit;
     558                                io.submit_q.submit_avg.csm += ret;
     559                                io.submit_q.submit_avg.cnt += 1;
     560                        )
     561
     562                        __cfadbg_print_safe( io, "Kernel I/O : submitted %u (among %u) for %p\n", idx, ret, active_thread() );
     563                }
     564                else
     565                {
     566                        // get mutual exclusion
     567                        #if defined(LEADER_LOCK)
     568                                while(!try_lock(ring.submit_q.submit_lock));
     569                        #else
     570                                lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2);
     571                        #endif
     572
     573                        /* paranoid */ verifyf( ring.submit_q.sqes[ idx ].user_data != 3ul64,
     574                        /* paranoid */  "index %u already reclaimed\n"
     575                        /* paranoid */  "head %u, prev %u, tail %u\n"
     576                        /* paranoid */  "[-0: %u,-1: %u,-2: %u,-3: %u]\n",
     577                        /* paranoid */  idx,
     578                        /* paranoid */  *ring.submit_q.head, ring.submit_q.prev_head, *tail
     579                        /* paranoid */  ,ring.submit_q.array[ ((*ring.submit_q.head) - 0) & (*ring.submit_q.mask) ]
     580                        /* paranoid */  ,ring.submit_q.array[ ((*ring.submit_q.head) - 1) & (*ring.submit_q.mask) ]
     581                        /* paranoid */  ,ring.submit_q.array[ ((*ring.submit_q.head) - 2) & (*ring.submit_q.mask) ]
     582                        /* paranoid */  ,ring.submit_q.array[ ((*ring.submit_q.head) - 3) & (*ring.submit_q.mask) ]
     583                        /* paranoid */ );
     584
     585                        // Append to the list of ready entries
     586
     587                        /* paranoid */ verify( idx <= mask );
     588                        ring.submit_q.array[ (*tail) & mask ] = idx;
     589                        __atomic_fetch_add(tail, 1ul32, __ATOMIC_SEQ_CST);
     590
     591                        // Submit however, many entries need to be submitted
     592                        int ret = __io_uring_enter( ring, 1, false );
     593                        if( ret < 0 ) {
     594                                switch((int)errno) {
     595                                default:
     596                                        abort( "KERNEL ERROR: IO_URING SUBMIT - %s\n", strerror(errno) );
     597                                }
     598                        }
     599
     600                        /* paranoid */ verify(ret == 1);
     601
     602                        // update statistics
     603                        __STATS__( false,
     604                                io.submit_q.submit_avg.csm += 1;
     605                                io.submit_q.submit_avg.cnt += 1;
     606                        )
     607
     608                        {
     609                                __attribute__((unused)) volatile __u32 * const head = ring.submit_q.head;
     610                                __attribute__((unused)) __u32 last_idx = ring.submit_q.array[ ((*head) - 1) & mask ];
     611                                __attribute__((unused)) volatile struct io_uring_sqe * sqe = &ring.submit_q.sqes[last_idx];
     612
     613                                __cfadbg_print_safe( io,
     614                                        "Kernel I/O : last submitted is %u (%p)\n"
     615                                        "    data: %p\n"
     616                                        "    opcode: %s\n"
     617                                        "    fd: %d\n"
     618                                        "    flags: %d\n"
     619                                        "    prio: %d\n"
     620                                        "    off: %p\n"
     621                                        "    addr: %p\n"
     622                                        "    len: %d\n"
     623                                        "    other flags: %d\n"
     624                                        "    splice fd: %d\n"
     625                                        "    pad[0]: %llu\n"
     626                                        "    pad[1]: %llu\n"
     627                                        "    pad[2]: %llu\n",
     628                                        last_idx, sqe,
     629                                        (void*)sqe->user_data,
     630                                        opcodes[sqe->opcode],
     631                                        sqe->fd,
     632                                        sqe->flags,
     633                                        sqe->ioprio,
     634                                        (void*)sqe->off,
     635                                        (void*)sqe->addr,
     636                                        sqe->len,
     637                                        sqe->accept_flags,
     638                                        sqe->splice_fd_in,
     639                                        sqe->__pad2[0],
     640                                        sqe->__pad2[1],
     641                                        sqe->__pad2[2]
     642                                );
     643                        }
     644
     645                        __atomic_thread_fence( __ATOMIC_SEQ_CST );
     646                        // Release the consumed SQEs
     647
     648                        __release_consumed_submission( ring );
     649                        // ring.submit_q.sqes[idx].user_data = 3ul64;
     650
     651                        #if defined(LEADER_LOCK)
     652                                next(ring.submit_q.submit_lock);
     653                        #else
     654                                unlock(ring.submit_q.submit_lock);
     655                        #endif
     656
     657                        __cfadbg_print_safe( io, "Kernel I/O : submitted %u for %p\n", idx, active_thread() );
     658                }
     659        }
     660
     661        // #define PARTIAL_SUBMIT 32
     662
     663        // go through the list of submissions in the ready array and moved them into
     664        // the ring's submit queue
     665        static unsigned __collect_submitions( struct __io_data & ring ) {
     666                /* paranoid */ verify( ring.submit_q.ready != 0p );
     667                /* paranoid */ verify( ring.submit_q.ready_cnt > 0 );
     668
     669                unsigned to_submit = 0;
     670                __u32 tail = *ring.submit_q.tail;
     671                const __u32 mask = *ring.submit_q.mask;
     672                #if defined(PARTIAL_SUBMIT)
     673                        #if defined(LEADER_LOCK)
     674                                #error PARTIAL_SUBMIT and LEADER_LOCK cannot co-exist
     675                        #endif
     676                        const __u32 cnt = ring.submit_q.ready_cnt > PARTIAL_SUBMIT ? PARTIAL_SUBMIT : ring.submit_q.ready_cnt;
     677                        const __u32 offset = ring.submit_q.prev_ready;
     678                        ring.submit_q.prev_ready += cnt;
     679                #else
     680                        const __u32 cnt = ring.submit_q.ready_cnt;
     681                        const __u32 offset = 0;
     682                #endif
     683
     684                // Go through the list of ready submissions
     685                for( c; cnt ) {
     686                        __u32 i = (offset + c) % ring.submit_q.ready_cnt;
     687
     688                        // replace any submission with the sentinel, to consume it.
     689                        __u32 idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED);
     690
     691                        // If it was already the sentinel, then we are done
     692                        if( idx == -1ul32 ) continue;
     693
     694                        // If we got a real submission, append it to the list
     695                        ring.submit_q.array[ (tail + to_submit) & mask ] = idx & mask;
     696                        to_submit++;
     697                }
     698
     699                // Increment the tail based on how many we are ready to submit
     700                __atomic_fetch_add(ring.submit_q.tail, to_submit, __ATOMIC_SEQ_CST);
     701
     702                return to_submit;
     703        }
     704
    337705        // Go through the ring's submit queue and release everything that has already been consumed
    338706        // by io_uring
    339         // This cannot be done by multiple threads
    340         static __u32 __release_sqes( struct $io_context & ctx ) {
    341                 const __u32 mask = *ctx.sq.mask;
    342 
     707        static __u32 __release_consumed_submission( struct __io_data & ring ) {
     708                const __u32 smask = *ring.submit_q.mask;
     709
     710                // We need to get the lock to copy the old head and new head
     711                if( !try_lock(ring.submit_q.release_lock __cfaabi_dbg_ctx2) ) return 0;
    343712                __attribute__((unused))
    344                 __u32 ctail = *ctx.sq.kring.tail;    // get the current tail of the queue
    345                 __u32 chead = *ctx.sq.kring.head;        // get the current head of the queue
    346                 __u32 phead = ctx.sq.kring.released; // get the head the last time we were here
    347 
    348                 __u32 ftail = ctx.sq.free_ring.tail;  // get the current tail of the queue
     713                __u32 ctail = *ring.submit_q.tail;        // get the current tail of the queue
     714                __u32 chead = *ring.submit_q.head;              // get the current head of the queue
     715                __u32 phead = ring.submit_q.prev_head;  // get the head the last time we were here
     716                ring.submit_q.prev_head = chead;                // note up to were we processed
     717                unlock(ring.submit_q.release_lock);
    349718
    350719                // the 3 fields are organized like this diagram
     
    365734                __u32 count = chead - phead;
    366735
    367                 if(count == 0) {
    368                         return 0;
    369                 }
    370 
    371736                // We acquired an previous-head/current-head range
    372737                // go through the range and release the sqes
    373738                for( i; count ) {
    374                         __cfadbg_print_safe(io, "Kernel I/O : release loop\n");
    375                         __u32 idx = ctx.sq.kring.array[ (phead + i) & mask ];
    376                         ctx.sq.free_ring.array[ (ftail + i) & mask ] = idx;
    377                 }
    378 
    379                 ctx.sq.kring.released = chead;          // note up to were we processed
    380                 __atomic_store_n(&ctx.sq.free_ring.tail, ftail + count, __ATOMIC_SEQ_CST);
    381 
    382                 __ioarbiter_notify(ctx);
    383 
     739                        __u32 idx = ring.submit_q.array[ (phead + i) & smask ];
     740
     741                        /* paranoid */ verify( 0 != ring.submit_q.sqes[ idx ].user_data );
     742                        __clean( &ring.submit_q.sqes[ idx ] );
     743                }
    384744                return count;
    385745        }
    386746
    387 //=============================================================================================
    388 // I/O Arbiter
    389 //=============================================================================================
    390         static inline void block(__outstanding_io_queue & queue, __outstanding_io & item) {
    391                 // Lock the list, it's not thread safe
    392                 lock( queue.lock __cfaabi_dbg_ctx2 );
    393                 {
    394                         // Add our request to the list
    395                         add( queue.queue, item );
    396 
    397                         // Mark as pending
    398                         __atomic_store_n( &queue.empty, false, __ATOMIC_SEQ_CST );
    399                 }
    400                 unlock( queue.lock );
    401 
    402                 wait( item.sem );
    403         }
    404 
    405         static inline bool empty(__outstanding_io_queue & queue ) {
    406                 return __atomic_load_n( &queue.empty, __ATOMIC_SEQ_CST);
    407         }
    408 
    409         static $io_context * __ioarbiter_allocate( $io_arbiter & this, __u32 idxs[], __u32 want ) {
    410                 __cfadbg_print_safe(io, "Kernel I/O : arbiter allocating\n");
    411 
    412                 __STATS__( false, io.alloc.block += 1; )
    413 
    414                 // No one has any resources left, wait for something to finish
    415                 // We need to add ourself to a list of pending allocs and wait for an answer
    416                 __pending_alloc pa;
    417                 pa.idxs = idxs;
    418                 pa.want = want;
    419 
    420                 block(this.pending, (__outstanding_io&)pa);
    421 
    422                 return pa.ctx;
    423 
    424         }
    425 
    426         static void __ioarbiter_notify( $io_arbiter & this, $io_context * ctx ) {
    427                 /* paranoid */ verify( !empty(this.pending.queue) );
    428 
    429                 lock( this.pending.lock __cfaabi_dbg_ctx2 );
    430                 {
    431                         while( !empty(this.pending.queue) ) {
    432                                 __cfadbg_print_safe(io, "Kernel I/O : notifying\n");
    433                                 __u32 have = ctx->sq.free_ring.tail - ctx->sq.free_ring.head;
    434                                 __pending_alloc & pa = (__pending_alloc&)head( this.pending.queue );
    435 
    436                                 if( have > pa.want ) goto DONE;
    437                                 drop( this.pending.queue );
    438 
    439                                 /* paranoid */__attribute__((unused)) bool ret =
    440 
    441                                 __alloc(ctx, pa.idxs, pa.want);
    442 
    443                                 /* paranoid */ verify( ret );
    444 
    445                                 pa.ctx = ctx;
    446 
    447                                 post( pa.sem );
    448                         }
    449 
    450                         this.pending.empty = true;
    451                         DONE:;
    452                 }
    453                 unlock( this.pending.lock );
    454         }
    455 
    456         static void __ioarbiter_notify( $io_context & ctx ) {
    457                 if(!empty( ctx.arbiter->pending )) {
    458                         __ioarbiter_notify( *ctx.arbiter, &ctx );
    459                 }
    460         }
    461 
    462         // Simply append to the pending
    463         static void __ioarbiter_submit( $io_context * ctx, __u32 idxs[], __u32 have, bool lazy ) {
    464                 __cfadbg_print_safe(io, "Kernel I/O : submitting %u from the arbiter to context %u\n", have, ctx->fd);
    465 
    466                 __cfadbg_print_safe(io, "Kernel I/O : waiting to submit %u\n", have);
    467 
    468                 __external_io ei;
    469                 ei.idxs = idxs;
    470                 ei.have = have;
    471                 ei.lazy = lazy;
    472 
    473                 block(ctx->ext_sq, (__outstanding_io&)ei);
    474 
    475                 __cfadbg_print_safe(io, "Kernel I/O : %u submitted from arbiter\n", have);
    476         }
    477 
    478         static void __ioarbiter_flush( $io_context & ctx ) {
    479                 if(!empty( ctx.ext_sq )) {
    480                         __STATS__( false, io.flush.external += 1; )
    481 
    482                         __cfadbg_print_safe(io, "Kernel I/O : arbiter flushing\n");
    483 
    484                         lock( ctx.ext_sq.lock __cfaabi_dbg_ctx2 );
    485                         {
    486                                 while( !empty(ctx.ext_sq.queue) ) {
    487                                         __external_io & ei = (__external_io&)drop( ctx.ext_sq.queue );
    488 
    489                                         __submit(&ctx, ei.idxs, ei.have, ei.lazy);
    490 
    491                                         post( ei.sem );
    492                                 }
    493 
    494                                 ctx.ext_sq.empty = true;
    495                         }
    496                         unlock(ctx.ext_sq.lock );
    497                 }
     747        void __sqe_clean( volatile struct io_uring_sqe * sqe ) {
     748                __clean( sqe );
     749        }
     750
     751        static inline void __clean( volatile struct io_uring_sqe * sqe ) {
     752                // If we are in debug mode, thrash the fields to make sure we catch reclamation errors
     753                __cfaabi_dbg_debug_do(
     754                        memset(sqe, 0xde, sizeof(*sqe));
     755                        sqe->opcode = (sizeof(opcodes) / sizeof(const char *)) - 1;
     756                );
     757
     758                // Mark the entry as unused
     759                __atomic_store_n(&sqe->user_data, 3ul64, __ATOMIC_SEQ_CST);
    498760        }
    499761#endif
  • libcfa/src/concurrency/io/call.cfa.in

    r5407cdc rfeacef9  
    5454                        | IOSQE_IO_DRAIN
    5555                #endif
     56                #if defined(CFA_HAVE_IOSQE_ASYNC)
     57                        | IOSQE_ASYNC
     58                #endif
     59        ;
     60
     61        static const __u32 LINK_FLAGS = 0
    5662                #if defined(CFA_HAVE_IOSQE_IO_LINK)
    5763                        | IOSQE_IO_LINK
     
    6066                        | IOSQE_IO_HARDLINK
    6167                #endif
    62                 #if defined(CFA_HAVE_IOSQE_ASYNC)
    63                         | IOSQE_ASYNC
    64                 #endif
    65                 #if defined(CFA_HAVE_IOSQE_BUFFER_SELECTED)
    66                         | IOSQE_BUFFER_SELECTED
    67                 #endif
    6868        ;
    6969
     
    7474        ;
    7575
    76         extern struct $io_context * cfa_io_allocate(struct io_uring_sqe * out_sqes[], __u32 out_idxs[], __u32 want)  __attribute__((nonnull (1,2)));
    77         extern void cfa_io_submit( struct $io_context * in_ctx, __u32 in_idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1,2)));
     76        extern [* volatile struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data );
     77        extern void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1)));
     78
     79        static inline io_context * __get_io_context( void ) {
     80                cluster * cltr = active_cluster();
     81
     82                /* paranoid */ verifyf( cltr, "No active cluster for io operation\\n");
     83                assertf( cltr->io.cnt > 0, "Cluster %p has no default io contexts and no context was specified\\n", cltr );
     84
     85                /* paranoid */ verifyf( cltr->io.ctxs, "default io contexts for cluster %p are missing\\n", cltr);
     86                return &cltr->io.ctxs[ thread_rand() % cltr->io.cnt ];
     87        }
    7888#endif
    7989
     
    8898
    8999extern "C" {
    90         #include <asm/types.h>
     100        #include <sys/types.h>
    91101        #include <sys/socket.h>
    92102        #include <sys/syscall.h>
     
    132142        extern int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    133143
    134         extern ssize_t splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags);
     144        extern ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);
    135145        extern ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);
    136146}
     
    185195                return ', '.join(args_a)
    186196
    187 AsyncTemplate = """inline void async_{name}(io_future_t & future, {params}, __u64 submit_flags) {{
     197AsyncTemplate = """inline void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context) {{
    188198        #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_{op})
    189199                ssize_t res = {name}({args});
     
    195205                }}
    196206        #else
     207                // we don't support LINK yet
     208                if( 0 != (submit_flags & LINK_FLAGS) ) {{
     209                        errno = ENOTSUP; return -1;
     210                }}
     211
     212                if( !context ) {{
     213                        context = __get_io_context();
     214                }}
     215                if(cancellation) {{
     216                        cancellation->target = (__u64)(uintptr_t)&future;
     217                }}
     218
    197219                __u8 sflags = REGULAR_FLAGS & submit_flags;
     220                struct __io_data & ring = *context->thrd.ring;
     221
    198222                __u32 idx;
    199223                struct io_uring_sqe * sqe;
    200                 struct $io_context * ctx = cfa_io_allocate( &sqe, &idx, 1 );
     224                [(volatile struct io_uring_sqe *) sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&future );
    201225
    202226                sqe->opcode = IORING_OP_{op};
    203                 sqe->user_data = (uintptr_t)&future;
    204227                sqe->flags = sflags;
    205228                sqe->ioprio = 0;
     
    215238                asm volatile("": : :"memory");
    216239
    217                 verify( sqe->user_data == (uintptr_t)&future );
    218                 cfa_io_submit( ctx, &idx, 1, 0 != (submit_flags & CFA_IO_LAZY) );
     240                verify( sqe->user_data == (__u64)(uintptr_t)&future );
     241                __submit( context, idx );
    219242        #endif
    220243}}"""
    221244
    222 SyncTemplate = """{ret} cfa_{name}({params}, __u64 submit_flags) {{
     245SyncTemplate = """{ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {{
     246        if( timeout >= 0 ) {{
     247                errno = ENOTSUP;
     248                return -1;
     249        }}
    223250        io_future_t future;
    224251
    225         async_{name}( future, {args}, submit_flags );
     252        async_{name}( future, {args}, submit_flags, cancellation, context );
    226253
    227254        wait( future );
     
    238265                'fd'  : 'fd',
    239266                'off' : 'offset',
    240                 'addr': '(uintptr_t)iov',
     267                'addr': '(__u64)iov',
    241268                'len' : 'iovcnt',
    242269        }, define = 'CFA_HAVE_PREADV2'),
     
    245272                'fd'  : 'fd',
    246273                'off' : 'offset',
    247                 'addr': '(uintptr_t)iov',
     274                'addr': '(__u64)iov',
    248275                'len' : 'iovcnt'
    249276        }, define = 'CFA_HAVE_PWRITEV2'),
     
    257284                'addr': 'fd',
    258285                'len': 'op',
    259                 'off': '(uintptr_t)event'
     286                'off': '(__u64)event'
    260287        }),
    261288        # CFA_HAVE_IORING_OP_SYNC_FILE_RANGE
     
    269296        Call('SENDMSG', 'ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags)', {
    270297                'fd': 'sockfd',
    271                 'addr': '(uintptr_t)(struct msghdr *)msg',
     298                'addr': '(__u64)(struct msghdr *)msg',
    272299                'len': '1',
    273300                'msg_flags': 'flags'
     
    276303        Call('RECVMSG', 'ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags)', {
    277304                'fd': 'sockfd',
    278                 'addr': '(uintptr_t)(struct msghdr *)msg',
     305                'addr': '(__u64)(struct msghdr *)msg',
    279306                'len': '1',
    280307                'msg_flags': 'flags'
     
    283310        Call('SEND', 'ssize_t send(int sockfd, const void *buf, size_t len, int flags)', {
    284311                'fd': 'sockfd',
    285                 'addr': '(uintptr_t)buf',
     312                'addr': '(__u64)buf',
    286313                'len': 'len',
    287314                'msg_flags': 'flags'
     
    290317        Call('RECV', 'ssize_t recv(int sockfd, void *buf, size_t len, int flags)', {
    291318                'fd': 'sockfd',
    292                 'addr': '(uintptr_t)buf',
     319                'addr': '(__u64)buf',
    293320                'len': 'len',
    294321                'msg_flags': 'flags'
     
    297324        Call('ACCEPT', 'int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)', {
    298325                'fd': 'sockfd',
    299                 'addr': '(uintptr_t)addr',
    300                 'addr2': '(uintptr_t)addrlen',
     326                'addr': '(__u64)addr',
     327                'addr2': '(__u64)addrlen',
    301328                'accept_flags': 'flags'
    302329        }),
     
    304331        Call('CONNECT', 'int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)', {
    305332                'fd': 'sockfd',
    306                 'addr': '(uintptr_t)addr',
     333                'addr': '(__u64)addr',
    307334                'off': 'addrlen'
    308335        }),
     
    310337        Call('FALLOCATE', 'int fallocate(int fd, int mode, off_t offset, off_t len)', {
    311338                'fd': 'fd',
    312                 'addr': '(uintptr_t)len',
     339                'addr': '(__u64)len',
    313340                'len': 'mode',
    314341                'off': 'offset'
     
    323350        # CFA_HAVE_IORING_OP_MADVISE
    324351        Call('MADVISE', 'int madvise(void *addr, size_t length, int advice)', {
    325                 'addr': '(uintptr_t)addr',
     352                'addr': '(__u64)addr',
    326353                'len': 'length',
    327354                'fadvise_advice': 'advice'
     
    330357        Call('OPENAT', 'int openat(int dirfd, const char *pathname, int flags, mode_t mode)', {
    331358                'fd': 'dirfd',
    332                 'addr': '(uintptr_t)pathname',
     359                'addr': '(__u64)pathname',
    333360                'len': 'mode',
    334361                'open_flags': 'flags;'
     
    339366                'addr': 'pathname',
    340367                'len': 'sizeof(*how)',
    341                 'off': '(uintptr_t)how',
     368                'off': '(__u64)how',
    342369        }, define = 'CFA_HAVE_OPENAT2'),
    343370        # CFA_HAVE_IORING_OP_CLOSE
     
    348375        Call('STATX', 'int statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf)', {
    349376                'fd': 'dirfd',
    350                 'off': '(uintptr_t)statxbuf',
     377                'off': '(__u64)statxbuf',
    351378                'addr': 'pathname',
    352379                'len': 'mask',
     
    356383        Call('READ', 'ssize_t read(int fd, void * buf, size_t count)', {
    357384                'fd': 'fd',
    358                 'addr': '(uintptr_t)buf',
     385                'addr': '(__u64)buf',
    359386                'len': 'count'
    360387        }),
     
    362389        Call('WRITE', 'ssize_t write(int fd, void * buf, size_t count)', {
    363390                'fd': 'fd',
    364                 'addr': '(uintptr_t)buf',
     391                'addr': '(__u64)buf',
    365392                'len': 'count'
    366393        }),
    367394        # CFA_HAVE_IORING_OP_SPLICE
    368         Call('SPLICE', 'ssize_t splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags)', {
     395        Call('SPLICE', 'ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags)', {
    369396                'splice_fd_in': 'fd_in',
    370397                'splice_off_in': 'off_in ? (__u64)*off_in : (__u64)-1',
     
    388415        if c.define:
    389416                print("""#if defined({define})
    390         {ret} cfa_{name}({params}, __u64 submit_flags);
     417        {ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    391418#endif""".format(define=c.define,ret=c.ret, name=c.name, params=c.params))
    392419        else:
    393                 print("{ret} cfa_{name}({params}, __u64 submit_flags);"
     420                print("{ret} cfa_{name}({params}, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);"
    394421                .format(ret=c.ret, name=c.name, params=c.params))
    395422
     
    399426        if c.define:
    400427                print("""#if defined({define})
    401         void async_{name}(io_future_t & future, {params}, __u64 submit_flags);
     428        void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context);
    402429#endif""".format(define=c.define,name=c.name, params=c.params))
    403430        else:
    404                 print("void async_{name}(io_future_t & future, {params}, __u64 submit_flags);"
     431                print("void async_{name}(io_future_t & future, {params}, int submit_flags, io_cancellation * cancellation, io_context * context);"
    405432                .format(name=c.name, params=c.params))
    406433print("\n")
     
    447474
    448475print("""
     476//-----------------------------------------------------------------------------
     477bool cancel(io_cancellation & this) {
     478        #if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_ASYNC_CANCEL)
     479                return false;
     480        #else
     481                io_future_t future;
     482
     483                io_context * context = __get_io_context();
     484
     485                __u8 sflags = 0;
     486                struct __io_data & ring = *context->thrd.ring;
     487
     488                __u32 idx;
     489                volatile struct io_uring_sqe * sqe;
     490                [sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&future );
     491
     492                sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
     493                sqe->opcode = IORING_OP_ASYNC_CANCEL;
     494                sqe->flags = sflags;
     495                sqe->addr = this.target;
     496
     497                verify( sqe->user_data == (__u64)(uintptr_t)&future );
     498                __submit( context, idx );
     499
     500                wait(future);
     501
     502                if( future.result == 0 ) return true; // Entry found
     503                if( future.result == -EALREADY) return true; // Entry found but in progress
     504                if( future.result == -ENOENT ) return false; // Entry not found
     505                return false;
     506        #endif
     507}
     508
    449509//-----------------------------------------------------------------------------
    450510// Check if a function is has asynchronous
  • libcfa/src/concurrency/io/setup.cfa

    r5407cdc rfeacef9  
    2626
    2727#if !defined(CFA_HAVE_LINUX_IO_URING_H)
     28        void __kernel_io_startup() {
     29                // Nothing to do without io_uring
     30        }
     31
     32        void __kernel_io_shutdown() {
     33                // Nothing to do without io_uring
     34        }
     35
    2836        void ?{}(io_context_params & this) {}
    2937
    30         void  ?{}($io_context & this, struct cluster & cl) {}
    31         void ^?{}($io_context & this) {}
    32 
    33         void __cfa_io_start( processor * proc ) {}
    34         void __cfa_io_flush( processor * proc ) {}
    35         void __cfa_io_stop ( processor * proc ) {}
    36 
    37         $io_arbiter * create(void) { return 0p; }
    38         void destroy($io_arbiter *) {}
     38        void ?{}(io_context & this, struct cluster & cl) {}
     39        void ?{}(io_context & this, struct cluster & cl, const io_context_params & params) {}
     40
     41        void ^?{}(io_context & this) {}
     42        void ^?{}(io_context & this, bool cluster_context) {}
     43
     44        void register_fixed_files( io_context &, int *, unsigned ) {}
     45        void register_fixed_files( cluster    &, int *, unsigned ) {}
    3946
    4047#else
     
    6168        void ?{}(io_context_params & this) {
    6269                this.num_entries = 256;
     70                this.num_ready = 256;
     71                this.submit_aff = -1;
     72                this.eager_submits = false;
     73                this.poller_submits = false;
     74                this.poll_submit = false;
     75                this.poll_complete = false;
    6376        }
    6477
     
    93106
    94107//=============================================================================================
     108// I/O Startup / Shutdown logic + Master Poller
     109//=============================================================================================
     110
     111        // IO Master poller loop forward
     112        static void * iopoll_loop( __attribute__((unused)) void * args );
     113
     114        static struct {
     115                      pthread_t  thrd;    // pthread handle to io poller thread
     116                      void *     stack;   // pthread stack for io poller thread
     117                      int        epollfd; // file descriptor to the epoll instance
     118                volatile     bool run;     // Whether or not to continue
     119                volatile     bool stopped; // Whether the poller has finished running
     120                volatile uint64_t epoch;   // Epoch used for memory reclamation
     121        } iopoll;
     122
     123        void __kernel_io_startup(void) {
     124                __cfadbg_print_safe(io_core, "Kernel : Creating EPOLL instance\n" );
     125
     126                iopoll.epollfd = epoll_create1(0);
     127                if (iopoll.epollfd == -1) {
     128                        abort( "internal error, epoll_create1\n");
     129                }
     130
     131                __cfadbg_print_safe(io_core, "Kernel : Starting io poller thread\n" );
     132
     133                iopoll.stack   = __create_pthread( &iopoll.thrd, iopoll_loop, 0p );
     134                iopoll.run     = true;
     135                iopoll.stopped = false;
     136                iopoll.epoch   = 0;
     137        }
     138
     139        void __kernel_io_shutdown(void) {
     140                // Notify the io poller thread of the shutdown
     141                iopoll.run = false;
     142                sigval val = { 1 };
     143                pthread_sigqueue( iopoll.thrd, SIGUSR1, val );
     144
     145                // Wait for the io poller thread to finish
     146
     147                __destroy_pthread( iopoll.thrd, iopoll.stack, 0p );
     148
     149                int ret = close(iopoll.epollfd);
     150                if (ret == -1) {
     151                        abort( "internal error, close epoll\n");
     152                }
     153
     154                // Io polling is now fully stopped
     155
     156                __cfadbg_print_safe(io_core, "Kernel : IO poller stopped\n" );
     157        }
     158
     159        static void * iopoll_loop( __attribute__((unused)) void * args ) {
     160                __processor_id_t id;
     161                id.full_proc = false;
     162                id.id = doregister(&id);
     163                __cfaabi_tls.this_proc_id = &id;
     164                __cfadbg_print_safe(io_core, "Kernel : IO poller thread starting\n" );
     165
     166                // Block signals to control when they arrive
     167                sigset_t mask;
     168                sigfillset(&mask);
     169                if ( pthread_sigmask( SIG_BLOCK, &mask, 0p ) == -1 ) {
     170                abort( "internal error, pthread_sigmask" );
     171                }
     172
     173                sigdelset( &mask, SIGUSR1 );
     174
     175                // Create sufficient events
     176                struct epoll_event events[10];
     177                // Main loop
     178                while( iopoll.run ) {
     179                        __cfadbg_print_safe(io_core, "Kernel I/O - epoll : waiting on io_uring contexts\n");
     180
     181                        // increment the epoch to notify any deleters we are starting a new cycle
     182                        __atomic_fetch_add(&iopoll.epoch, 1, __ATOMIC_SEQ_CST);
     183
     184                        // Wait for events
     185                        int nfds = epoll_pwait( iopoll.epollfd, events, 10, -1, &mask );
     186
     187                        __cfadbg_print_safe(io_core, "Kernel I/O - epoll : %d io contexts events, waking up\n", nfds);
     188
     189                        // Check if an error occured
     190                        if (nfds == -1) {
     191                                if( errno == EINTR ) continue;
     192                                abort( "internal error, pthread_sigmask" );
     193                        }
     194
     195                        for(i; nfds) {
     196                                $io_ctx_thread * io_ctx = ($io_ctx_thread *)(uintptr_t)events[i].data.u64;
     197                                /* paranoid */ verify( io_ctx );
     198                                __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Unparking io poller %d (%p)\n", io_ctx->ring->fd, io_ctx);
     199                                #if !defined( __CFA_NO_STATISTICS__ )
     200                                        __cfaabi_tls.this_stats = io_ctx->self.curr_cluster->stats;
     201                                #endif
     202
     203                                eventfd_t v;
     204                                eventfd_read(io_ctx->ring->efd, &v);
     205
     206                                post( io_ctx->sem );
     207                        }
     208                }
     209
     210                __atomic_store_n(&iopoll.stopped, true, __ATOMIC_SEQ_CST);
     211
     212                __cfadbg_print_safe(io_core, "Kernel : IO poller thread stopping\n" );
     213                unregister(&id);
     214                return 0p;
     215        }
     216
     217//=============================================================================================
    95218// I/O Context Constrution/Destruction
    96219//=============================================================================================
    97220
    98 
    99 
    100         static void __io_uring_setup ( $io_context & this, const io_context_params & params_in, int procfd );
    101         static void __io_uring_teardown( $io_context & this );
    102         static void __epoll_register($io_context & ctx);
    103         static void __epoll_unregister($io_context & ctx);
    104         void __ioarbiter_register( $io_arbiter & mutex, $io_context & ctx );
    105         void __ioarbiter_unregister( $io_arbiter & mutex, $io_context & ctx );
    106 
    107         void ?{}($io_context & this, processor * proc, struct cluster & cl) {
    108                 /* paranoid */ verify( cl.io.arbiter );
    109                 this.proc = proc;
    110                 this.arbiter = cl.io.arbiter;
    111                 this.ext_sq.empty = true;
    112                 (this.ext_sq.queue){};
    113                 __io_uring_setup( this, cl.io.params, proc->idle );
    114                 __cfadbg_print_safe(io_core, "Kernel I/O : Created ring for io_context %u (%p)\n", this.fd, &this);
    115         }
    116 
    117         void ^?{}($io_context & this) {
    118                 __cfadbg_print_safe(io_core, "Kernel I/O : tearing down io_context %u\n", this.fd);
    119 
    120                 __io_uring_teardown( this );
    121                 __cfadbg_print_safe(io_core, "Kernel I/O : Destroyed ring for io_context %u\n", this.fd);
     221        void ?{}($io_ctx_thread & this, struct cluster & cl) { (this.self){ "IO Poller", cl }; }
     222        void main( $io_ctx_thread & this );
     223        static inline $thread * get_thread( $io_ctx_thread & this ) { return &this.self; }
     224        void ^?{}( $io_ctx_thread & mutex this ) {}
     225
     226        static void __io_create ( __io_data & this, const io_context_params & params_in );
     227        static void __io_destroy( __io_data & this );
     228
     229        void ?{}(io_context & this, struct cluster & cl, const io_context_params & params) {
     230                (this.thrd){ cl };
     231                this.thrd.ring = malloc();
     232                __cfadbg_print_safe(io_core, "Kernel I/O : Creating ring for io_context %p\n", &this);
     233                __io_create( *this.thrd.ring, params );
     234
     235                __cfadbg_print_safe(io_core, "Kernel I/O : Starting poller thread for io_context %p\n", &this);
     236                this.thrd.done = false;
     237                __thrd_start( this.thrd, main );
     238
     239                __cfadbg_print_safe(io_core, "Kernel I/O : io_context %p ready\n", &this);
     240        }
     241
     242        void ?{}(io_context & this, struct cluster & cl) {
     243                io_context_params params;
     244                (this){ cl, params };
     245        }
     246
     247        void ^?{}(io_context & this, bool cluster_context) {
     248                __cfadbg_print_safe(io_core, "Kernel I/O : tearing down io_context %p\n", &this);
     249
     250                // Notify the thread of the shutdown
     251                __atomic_store_n(&this.thrd.done, true, __ATOMIC_SEQ_CST);
     252
     253                // If this is an io_context within a cluster, things get trickier
     254                $thread & thrd = this.thrd.self;
     255                if( cluster_context ) {
     256                        // We are about to do weird things with the threads
     257                        // we don't need interrupts to complicate everything
     258                        disable_interrupts();
     259
     260                        // Get cluster info
     261                        cluster & cltr = *thrd.curr_cluster;
     262                        /* paranoid */ verify( cltr.idles.total == 0 || &cltr == mainCluster );
     263                        /* paranoid */ verify( !ready_mutate_islocked() );
     264
     265                        // We need to adjust the clean-up based on where the thread is
     266                        if( thrd.state == Ready || thrd.preempted != __NO_PREEMPTION ) {
     267                                // This is the tricky case
     268                                // The thread was preempted or ready to run and now it is on the ready queue
     269                                // but the cluster is shutting down, so there aren't any processors to run the ready queue
     270                                // the solution is to steal the thread from the ready-queue and pretend it was blocked all along
     271
     272                                ready_schedule_lock();
     273                                        // The thread should on the list
     274                                        /* paranoid */ verify( thrd.link.next != 0p );
     275
     276                                        // Remove the thread from the ready queue of this cluster
     277                                        // The thread should be the last on the list
     278                                        __attribute__((unused)) bool removed = remove_head( &cltr, &thrd );
     279                                        /* paranoid */ verify( removed );
     280                                        thrd.link.next = 0p;
     281                                        thrd.link.prev = 0p;
     282
     283                                        // Fixup the thread state
     284                                        thrd.state = Blocked;
     285                                        thrd.ticket = TICKET_BLOCKED;
     286                                        thrd.preempted = __NO_PREEMPTION;
     287
     288                                ready_schedule_unlock();
     289
     290                                // Pretend like the thread was blocked all along
     291                        }
     292                        // !!! This is not an else if !!!
     293                        // Ok, now the thread is blocked (whether we cheated to get here or not)
     294                        if( thrd.state == Blocked ) {
     295                                // This is the "easy case"
     296                                // The thread is parked and can easily be moved to active cluster
     297                                verify( thrd.curr_cluster != active_cluster() || thrd.curr_cluster == mainCluster );
     298                                thrd.curr_cluster = active_cluster();
     299
     300                                // unpark the fast io_poller
     301                                unpark( &thrd );
     302                        }
     303                        else {
     304                                // The thread is in a weird state
     305                                // I don't know what to do here
     306                                abort("io_context poller thread is in unexpected state, cannot clean-up correctly\n");
     307                        }
     308
     309                        // The weird thread kidnapping stuff is over, restore interrupts.
     310                        enable_interrupts( __cfaabi_dbg_ctx );
     311                } else {
     312                        post( this.thrd.sem );
     313                }
     314
     315                ^(this.thrd){};
     316                __cfadbg_print_safe(io_core, "Kernel I/O : Stopped poller thread for io_context %p\n", &this);
     317
     318                __io_destroy( *this.thrd.ring );
     319                __cfadbg_print_safe(io_core, "Kernel I/O : Destroyed ring for io_context %p\n", &this);
     320
     321                free(this.thrd.ring);
     322        }
     323
     324        void ^?{}(io_context & this) {
     325                ^(this){ false };
    122326        }
    123327
     
    125329        extern void __enable_interrupts_hard();
    126330
    127         static void __io_uring_setup( $io_context & this, const io_context_params & params_in, int procfd ) {
     331        static void __io_create( __io_data & this, const io_context_params & params_in ) {
    128332                // Step 1 : call to setup
    129333                struct io_uring_params params;
    130334                memset(&params, 0, sizeof(params));
    131                 // if( params_in.poll_submit   ) params.flags |= IORING_SETUP_SQPOLL;
    132                 // if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL;
     335                if( params_in.poll_submit   ) params.flags |= IORING_SETUP_SQPOLL;
     336                if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL;
    133337
    134338                __u32 nentries = params_in.num_entries != 0 ? params_in.num_entries : 256;
     
    136340                        abort("ERROR: I/O setup 'num_entries' must be a power of 2\n");
    137341                }
     342                if( params_in.poller_submits && params_in.eager_submits ) {
     343                        abort("ERROR: I/O setup 'poller_submits' and 'eager_submits' cannot be used together\n");
     344                }
    138345
    139346                int fd = syscall(__NR_io_uring_setup, nentries, &params );
     
    143350
    144351                // Step 2 : mmap result
    145                 struct __sub_ring_t & sq = this.sq;
    146                 struct __cmp_ring_t & cq = this.cq;
     352                memset( &this, 0, sizeof(struct __io_data) );
     353                struct __submition_data  & sq = this.submit_q;
     354                struct __completion_data & cq = this.completion_q;
    147355
    148356                // calculate the right ring size
     
    193401                // Get the pointers from the kernel to fill the structure
    194402                // submit queue
    195                 sq.kring.head  = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
    196                 sq.kring.tail  = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
    197                 sq.kring.array = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
    198                 sq.mask        = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
    199                 sq.num         = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
    200                 sq.flags       = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
    201                 sq.dropped     = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
    202 
    203                 sq.kring.released = 0;
    204 
    205                 sq.free_ring.head = 0;
    206                 sq.free_ring.tail = *sq.num;
    207                 sq.free_ring.array = alloc( *sq.num, 128`align );
    208                 for(i; (__u32)*sq.num) {
    209                         sq.free_ring.array[i] = i;
    210                 }
    211 
    212                 sq.to_submit = 0;
     403                sq.head    = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
     404                sq.tail    = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
     405                sq.mask    = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
     406                sq.num     = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
     407                sq.flags   = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
     408                sq.dropped = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
     409                sq.array   = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
     410                sq.prev_head = *sq.head;
     411
     412                {
     413                        const __u32 num = *sq.num;
     414                        for( i; num ) {
     415                                __sqe_clean( &sq.sqes[i] );
     416                        }
     417                }
     418
     419                (sq.submit_lock){};
     420                (sq.release_lock){};
     421
     422                if( params_in.poller_submits || params_in.eager_submits ) {
     423                        /* paranoid */ verify( is_pow2( params_in.num_ready ) || (params_in.num_ready < 8) );
     424                        sq.ready_cnt = max( params_in.num_ready, 8 );
     425                        sq.ready = alloc( sq.ready_cnt, 64`align );
     426                        for(i; sq.ready_cnt) {
     427                                sq.ready[i] = -1ul32;
     428                        }
     429                        sq.prev_ready = 0;
     430                }
     431                else {
     432                        sq.ready_cnt = 0;
     433                        sq.ready = 0p;
     434                        sq.prev_ready = 0;
     435                }
    213436
    214437                // completion queue
     
    223446                // io_uring_register is so f*cking slow on some machine that it
    224447                // will never succeed if preemption isn't hard blocked
    225                 __cfadbg_print_safe(io_core, "Kernel I/O : registering %d for completion with ring %d\n", procfd, fd);
    226 
    227448                __disable_interrupts_hard();
    228449
    229                 int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &procfd, 1);
     450                int efd = eventfd(0, 0);
     451                if (efd < 0) {
     452                        abort("KERNEL ERROR: IO_URING EVENTFD - %s\n", strerror(errno));
     453                }
     454
     455                int ret = syscall( __NR_io_uring_register, fd, IORING_REGISTER_EVENTFD, &efd, 1);
    230456                if (ret < 0) {
    231457                        abort("KERNEL ERROR: IO_URING EVENTFD REGISTER - %s\n", strerror(errno));
     
    233459
    234460                __enable_interrupts_hard();
    235 
    236                 __cfadbg_print_safe(io_core, "Kernel I/O : registered %d for completion with ring %d\n", procfd, fd);
    237461
    238462                // some paranoid checks
     
    244468                /* paranoid */ verifyf( (*sq.mask) == ((*sq.num) - 1ul32), "IO_URING Expected mask to be %u (%u entries), was %u", (*sq.num) - 1ul32, *sq.num, *sq.mask );
    245469                /* paranoid */ verifyf( (*sq.num) >= nentries, "IO_URING Expected %u entries, got %u", nentries, *sq.num );
    246                 /* paranoid */ verifyf( (*sq.kring.head) == 0, "IO_URING Expected head to be 0, got %u", *sq.kring.head );
    247                 /* paranoid */ verifyf( (*sq.kring.tail) == 0, "IO_URING Expected tail to be 0, got %u", *sq.kring.tail );
     470                /* paranoid */ verifyf( (*sq.head) == 0, "IO_URING Expected head to be 0, got %u", *sq.head );
     471                /* paranoid */ verifyf( (*sq.tail) == 0, "IO_URING Expected tail to be 0, got %u", *sq.tail );
    248472
    249473                // Update the global ring info
    250                 this.ring_flags = 0;
     474                this.ring_flags = params.flags;
    251475                this.fd         = fd;
    252         }
    253 
    254         static void __io_uring_teardown( $io_context & this ) {
     476                this.efd        = efd;
     477                this.eager_submits  = params_in.eager_submits;
     478                this.poller_submits = params_in.poller_submits;
     479        }
     480
     481        static void __io_destroy( __io_data & this ) {
    255482                // Shutdown the io rings
    256                 struct __sub_ring_t & sq = this.sq;
    257                 struct __cmp_ring_t & cq = this.cq;
     483                struct __submition_data  & sq = this.submit_q;
     484                struct __completion_data & cq = this.completion_q;
    258485
    259486                // unmap the submit queue entries
     
    270497                // close the file descriptor
    271498                close(this.fd);
    272 
    273                 free( this.sq.free_ring.array ); // Maybe null, doesn't matter
    274         }
    275 
    276         void __cfa_io_start( processor * proc ) {
    277                 proc->io.ctx = alloc();
    278                 (*proc->io.ctx){proc, *proc->cltr};
    279         }
    280         void __cfa_io_stop ( processor * proc ) {
    281                 ^(*proc->io.ctx){};
    282                 free(proc->io.ctx);
     499                close(this.efd);
     500
     501                free( this.submit_q.ready ); // Maybe null, doesn't matter
    283502        }
    284503
     
    286505// I/O Context Sleep
    287506//=============================================================================================
    288         // static inline void __epoll_ctl($io_context & ctx, int op, const char * error) {
    289         //      struct epoll_event ev;
    290         //      ev.events = EPOLLIN | EPOLLONESHOT;
    291         //      ev.data.u64 = (__u64)&ctx;
    292         //      int ret = epoll_ctl(iopoll.epollfd, op, ctx.efd, &ev);
    293         //      if (ret < 0) {
    294         //              abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) );
    295         //      }
    296         // }
    297 
    298         // static void __epoll_register($io_context & ctx) {
    299         //      __epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD");
    300         // }
    301 
    302         // static void __epoll_unregister($io_context & ctx) {
    303         //      // Read the current epoch so we know when to stop
    304         //      size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST);
    305 
    306         //      // Remove the fd from the iopoller
    307         //      __epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE");
    308 
    309         //      // Notify the io poller thread of the shutdown
    310         //      iopoll.run = false;
    311         //      sigval val = { 1 };
    312         //      pthread_sigqueue( iopoll.thrd, SIGUSR1, val );
    313 
    314         //      // Make sure all this is done
    315         //      __atomic_thread_fence(__ATOMIC_SEQ_CST);
    316 
    317         //      // Wait for the next epoch
    318         //      while(curr == iopoll.epoch && !iopoll.stopped) Pause();
    319         // }
    320 
    321         // void __ioctx_prepare_block($io_context & ctx) {
    322         //      __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.fd, &ctx);
    323         //      __epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM");
    324         // }
    325 
     507        static inline void __ioctx_epoll_ctl($io_ctx_thread & ctx, int op, const char * error) {
     508                struct epoll_event ev;
     509                ev.events = EPOLLIN | EPOLLONESHOT;
     510                ev.data.u64 = (__u64)&ctx;
     511                int ret = epoll_ctl(iopoll.epollfd, op, ctx.ring->efd, &ev);
     512                if (ret < 0) {
     513                        abort( "KERNEL ERROR: EPOLL %s - (%d) %s\n", error, (int)errno, strerror(errno) );
     514                }
     515        }
     516
     517        void __ioctx_register($io_ctx_thread & ctx) {
     518                __ioctx_epoll_ctl(ctx, EPOLL_CTL_ADD, "ADD");
     519        }
     520
     521        void __ioctx_prepare_block($io_ctx_thread & ctx) {
     522                __cfadbg_print_safe(io_core, "Kernel I/O - epoll : Re-arming io poller %d (%p)\n", ctx.ring->fd, &ctx);
     523                __ioctx_epoll_ctl(ctx, EPOLL_CTL_MOD, "REARM");
     524        }
     525
     526        void __ioctx_unregister($io_ctx_thread & ctx) {
     527                // Read the current epoch so we know when to stop
     528                size_t curr = __atomic_load_n(&iopoll.epoch, __ATOMIC_SEQ_CST);
     529
     530                // Remove the fd from the iopoller
     531                __ioctx_epoll_ctl(ctx, EPOLL_CTL_DEL, "REMOVE");
     532
     533                // Notify the io poller thread of the shutdown
     534                iopoll.run = false;
     535                sigval val = { 1 };
     536                pthread_sigqueue( iopoll.thrd, SIGUSR1, val );
     537
     538                // Make sure all this is done
     539                __atomic_thread_fence(__ATOMIC_SEQ_CST);
     540
     541                // Wait for the next epoch
     542                while(curr == iopoll.epoch && !iopoll.stopped) Pause();
     543        }
    326544
    327545//=============================================================================================
    328546// I/O Context Misc Setup
    329547//=============================================================================================
    330         void ?{}( $io_arbiter & this ) {
    331                 this.pending.empty = true;
    332         }
    333 
    334         void ^?{}( $io_arbiter & this ) {}
    335 
    336         $io_arbiter * create(void) {
    337                 return new();
    338         }
    339         void destroy($io_arbiter * arbiter) {
    340                 delete(arbiter);
    341         }
    342 
    343 //=============================================================================================
    344 // I/O Context Misc Setup
    345 //=============================================================================================
    346 
     548        void register_fixed_files( io_context & ctx, int * files, unsigned count ) {
     549                int ret = syscall( __NR_io_uring_register, ctx.thrd.ring->fd, IORING_REGISTER_FILES, files, count );
     550                if( ret < 0 ) {
     551                        abort( "KERNEL ERROR: IO_URING REGISTER - (%d) %s\n", (int)errno, strerror(errno) );
     552                }
     553
     554                __cfadbg_print_safe( io_core, "Kernel I/O : Performed io_register for %p, returned %d\n", active_thread(), ret );
     555        }
     556
     557        void register_fixed_files( cluster & cltr, int * files, unsigned count ) {
     558                for(i; cltr.io.cnt) {
     559                        register_fixed_files( cltr.io.ctxs[i], files, count );
     560                }
     561        }
    347562#endif
  • libcfa/src/concurrency/io/types.hfa

    r5407cdc rfeacef9  
    2222
    2323#include "bits/locks.hfa"
    24 #include "bits/queue.hfa"
    2524#include "kernel/fwd.hfa"
    2625
    2726#if defined(CFA_HAVE_LINUX_IO_URING_H)
    28         #include "bits/sequence.hfa"
    29         #include "monitor.hfa"
     27        #define LEADER_LOCK
     28        struct __leaderlock_t {
     29                struct $thread * volatile value;        // ($thread) next_leader | (bool:1) is_locked
     30        };
    3031
    31         struct processor;
    32         monitor $io_arbiter;
     32        static inline void ?{}( __leaderlock_t & this ) { this.value = 0p; }
    3333
    3434        //-----------------------------------------------------------------------
    3535        // Ring Data structure
    36       struct __sub_ring_t {
    37                 struct {
    38                         // Head and tail of the ring (associated with array)
    39                         volatile __u32 * head;   // one passed last index consumed by the kernel
    40                         volatile __u32 * tail;   // one passed last index visible to the kernel
    41                         volatile __u32 released; // one passed last index released back to the free list
     36      struct __submition_data {
     37                // Head and tail of the ring (associated with array)
     38                volatile __u32 * head;
     39                volatile __u32 * tail;
     40                volatile __u32 prev_head;
    4241
    43                         // The actual kernel ring which uses head/tail
    44                         // indexes into the sqes arrays
    45                         __u32 * array;
    46                 } kring;
    47 
    48                 struct {
    49                         volatile __u32 head;
    50                         volatile __u32 tail;
    51                         // The ring which contains free allocations
    52                         // indexes into the sqes arrays
    53                         __u32 * array;
    54                 } free_ring;
    55 
    56                 // number of sqes to submit on next system call.
    57                 __u32 to_submit;
     42                // The actual kernel ring which uses head/tail
     43                // indexes into the sqes arrays
     44                __u32 * array;
    5845
    5946                // number of entries and mask to go with it
     
    6148                const __u32 * mask;
    6249
    63                 // Submission flags, currently only IORING_SETUP_SQPOLL
     50                // Submission flags (Not sure what for)
    6451                __u32 * flags;
    6552
    66                 // number of sqes not submitted
    67                 // From documentation : [dropped] is incremented for each invalid submission queue entry encountered in the ring buffer.
     53                // number of sqes not submitted (whatever that means)
    6854                __u32 * dropped;
    6955
     56                // Like head/tail but not seen by the kernel
     57                volatile __u32 * ready;
     58                __u32 ready_cnt;
     59                __u32 prev_ready;
     60
     61                #if defined(LEADER_LOCK)
     62                        __leaderlock_t submit_lock;
     63                #else
     64                        __spinlock_t submit_lock;
     65                #endif
     66                __spinlock_t  release_lock;
     67
    7068                // A buffer of sqes (not the actual ring)
    71                 struct io_uring_sqe * sqes;
     69                volatile struct io_uring_sqe * sqes;
    7270
    7371                // The location and size of the mmaped area
     
    7674        };
    7775
    78         struct __cmp_ring_t {
     76        struct __completion_data {
    7977                // Head and tail of the ring
    8078                volatile __u32 * head;
     
    8583                const __u32 * num;
    8684
    87                 // I don't know what this value is for
     85                // number of cqes not submitted (whatever that means)
    8886                __u32 * overflow;
    8987
     
    9694        };
    9795
    98         struct __outstanding_io {
    99                 inline Colable;
    100                 single_sem sem;
    101         };
    102         static inline __outstanding_io *& Next( __outstanding_io * n ) { return (__outstanding_io *)Next( (Colable *)n ); }
    103 
    104         struct __outstanding_io_queue {
    105                 __spinlock_t lock;
    106                 Queue(__outstanding_io) queue;
    107                 volatile bool empty;
    108         };
    109 
    110         struct __external_io {
    111                 inline __outstanding_io;
    112                 __u32 * idxs;
    113                 __u32 have;
    114                 bool lazy;
    115         };
    116 
    117 
    118         struct __attribute__((aligned(128))) $io_context {
    119                 $io_arbiter * arbiter;
    120                 processor * proc;
    121 
    122                 __outstanding_io_queue ext_sq;
    123 
    124                 struct __sub_ring_t sq;
    125                 struct __cmp_ring_t cq;
     96        struct __io_data {
     97                struct __submition_data submit_q;
     98                struct __completion_data completion_q;
    12699                __u32 ring_flags;
    127100                int fd;
    128         };
    129 
    130         struct __pending_alloc {
    131                 inline __outstanding_io;
    132                 __u32 * idxs;
    133                 __u32 want;
    134                 $io_context * ctx;
    135         };
    136 
    137         struct __attribute__((aligned(128))) $io_arbiter {
    138                 __outstanding_io_queue pending;
     101                int efd;
     102                bool eager_submits:1;
     103                bool poller_submits:1;
    139104        };
    140105
     
    168133        #endif
    169134
    170         // void __ioctx_prepare_block($io_context & ctx);
     135        struct $io_ctx_thread;
     136        void __ioctx_register($io_ctx_thread & ctx);
     137        void __ioctx_unregister($io_ctx_thread & ctx);
     138        void __ioctx_prepare_block($io_ctx_thread & ctx);
     139        void __sqe_clean( volatile struct io_uring_sqe * sqe );
    171140#endif
    172141
     
    179148
    180149static inline {
    181         $thread * fulfil( io_future_t & this, __s32 result, bool do_unpark = true ) {
     150        bool fulfil( io_future_t & this, __s32 result ) {
    182151                this.result = result;
    183                 return fulfil(this.self, do_unpark);
     152                return fulfil(this.self);
    184153        }
    185154
  • libcfa/src/concurrency/iofwd.hfa

    r5407cdc rfeacef9  
    1818#include <unistd.h>
    1919extern "C" {
    20         #include <asm/types.h>
     20        #include <sys/types.h>
    2121        #if CFA_HAVE_LINUX_IO_URING_H
    2222                #include <linux/io_uring.h>
     
    4848struct cluster;
    4949struct io_future_t;
    50 struct $io_context;
     50struct io_context;
     51struct io_cancellation;
    5152
    5253struct iovec;
     
    5455struct sockaddr;
    5556struct statx;
    56 struct epoll_event;
    57 
    58 struct io_uring_sqe;
    59 
    60 //----------
    61 // underlying calls
    62 extern struct $io_context * cfa_io_allocate(struct io_uring_sqe * out_sqes[], __u32 out_idxs[], __u32 want)  __attribute__((nonnull (1,2)));
    63 extern void cfa_io_submit( struct $io_context * in_ctx, __u32 in_idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1,2)));
    6457
    6558//----------
    6659// synchronous calls
    6760#if defined(CFA_HAVE_PREADV2)
    68         extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
     61        extern ssize_t cfa_preadv2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    6962#endif
    7063#if defined(CFA_HAVE_PWRITEV2)
    71         extern ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
     64        extern ssize_t cfa_pwritev2(int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    7265#endif
    73 extern int cfa_fsync(int fd, __u64 submit_flags);
    74 extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags);
    75 extern int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags);
    76 extern  ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags);
    77 extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags, __u64 submit_flags);
    78 extern ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags);
    79 extern ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags, __u64 submit_flags);
    80 extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);
    81 extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);
    82 extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, __u64 submit_flags);
    83 extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, __u64 submit_flags);
    84 extern int cfa_madvise(void *addr, size_t length, int advice, __u64 submit_flags);
    85 extern int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags);
     66extern int cfa_fsync(int fd, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     67extern int cfa_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     68extern 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);
     69extern  ssize_t cfa_sendmsg(int sockfd, const struct msghdr *msg, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     70extern ssize_t cfa_recvmsg(int sockfd, struct msghdr *msg, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     71extern ssize_t cfa_send(int sockfd, const void *buf, size_t len, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     72extern ssize_t cfa_recv(int sockfd, void *buf, size_t len, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     73extern int cfa_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     74extern int cfa_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     75extern int cfa_fallocate(int fd, int mode, off_t offset, off_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     76extern int cfa_posix_fadvise(int fd, off_t offset, off_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     77extern int cfa_madvise(void *addr, size_t length, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     78extern int cfa_openat(int dirfd, const char *pathname, int flags, mode_t mode, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    8679#if defined(CFA_HAVE_OPENAT2)
    87         extern int cfa_openat2(int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags);
     80        extern int cfa_openat2(int dirfd, const char *pathname, struct open_how * how, size_t size, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    8881#endif
    89 extern int cfa_close(int fd, __u64 submit_flags);
     82extern int cfa_close(int fd, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    9083#if defined(CFA_HAVE_STATX)
    91         extern int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);
     84        extern int cfa_statx(int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    9285#endif
    93 extern ssize_t cfa_read(int fd, void * buf, size_t count, __u64 submit_flags);
    94 extern ssize_t cfa_write(int fd, void * buf, size_t count, __u64 submit_flags);
    95 extern ssize_t cfa_splice(int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags);
    96 extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);
     86extern ssize_t cfa_read(int fd, void * buf, size_t count, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     87extern ssize_t cfa_write(int fd, void * buf, size_t count, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     88extern ssize_t cfa_splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
     89extern ssize_t cfa_tee(int fd_in, int fd_out, size_t len, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context);
    9790
    9891//----------
    9992// asynchronous calls
    10093#if defined(CFA_HAVE_PREADV2)
    101         extern void async_preadv2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
     94        extern void async_preadv2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
    10295#endif
    10396#if defined(CFA_HAVE_PWRITEV2)
    104         extern void async_pwritev2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, __u64 submit_flags);
     97        extern void async_pwritev2(io_future_t & future, int fd, const struct iovec *iov, int iovcnt, off_t offset, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
    10598#endif
    106 extern void async_fsync(io_future_t & future, int fd, __u64 submit_flags);
    107 extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event *event, __u64 submit_flags);
    108 extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, __u64 submit_flags);
    109 extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr *msg, int flags, __u64 submit_flags);
    110 extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr *msg, int flags, __u64 submit_flags);
    111 extern void async_send(io_future_t & future, int sockfd, const void *buf, size_t len, int flags, __u64 submit_flags);
    112 extern void async_recv(io_future_t & future, int sockfd, void *buf, size_t len, int flags, __u64 submit_flags);
    113 extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, __u64 submit_flags);
    114 extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, __u64 submit_flags);
    115 extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, __u64 submit_flags);
    116 extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, __u64 submit_flags);
    117 extern void async_madvise(io_future_t & future, void *addr, size_t length, int advice, __u64 submit_flags);
    118 extern void async_openat(io_future_t & future, int dirfd, const char *pathname, int flags, mode_t mode, __u64 submit_flags);
     99extern void async_fsync(io_future_t & future, int fd, int submit_flags, io_cancellation * cancellation, io_context * context);
     100extern void async_epoll_ctl(io_future_t & future, int epfd, int op, int fd, struct epoll_event *event, int submit_flags, io_cancellation * cancellation, io_context * context);
     101extern void async_sync_file_range(io_future_t & future, int fd, off64_t offset, off64_t nbytes, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
     102extern void async_sendmsg(io_future_t & future, int sockfd, const struct msghdr *msg, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
     103extern void async_recvmsg(io_future_t & future, int sockfd, struct msghdr *msg, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
     104extern void async_send(io_future_t & future, int sockfd, const void *buf, size_t len, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
     105extern void async_recv(io_future_t & future, int sockfd, void *buf, size_t len, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
     106extern void async_accept4(io_future_t & future, int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
     107extern void async_connect(io_future_t & future, int sockfd, const struct sockaddr *addr, socklen_t addrlen, int submit_flags, io_cancellation * cancellation, io_context * context);
     108extern void async_fallocate(io_future_t & future, int fd, int mode, off_t offset, off_t len, int submit_flags, io_cancellation * cancellation, io_context * context);
     109extern void async_posix_fadvise(io_future_t & future, int fd, off_t offset, off_t len, int advice, int submit_flags, io_cancellation * cancellation, io_context * context);
     110extern void async_madvise(io_future_t & future, void *addr, size_t length, int advice, int submit_flags, io_cancellation * cancellation, io_context * context);
     111extern void async_openat(io_future_t & future, int dirfd, const char *pathname, int flags, mode_t mode, int submit_flags, io_cancellation * cancellation, io_context * context);
    119112#if defined(CFA_HAVE_OPENAT2)
    120         extern void async_openat2(io_future_t & future, int dirfd, const char *pathname, struct open_how * how, size_t size, __u64 submit_flags);
     113        extern void async_openat2(io_future_t & future, int dirfd, const char *pathname, struct open_how * how, size_t size, int submit_flags, io_cancellation * cancellation, io_context * context);
    121114#endif
    122 extern void async_close(io_future_t & future, int fd, __u64 submit_flags);
     115extern void async_close(io_future_t & future, int fd, int submit_flags, io_cancellation * cancellation, io_context * context);
    123116#if defined(CFA_HAVE_STATX)
    124         extern void async_statx(io_future_t & future, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, __u64 submit_flags);
     117        extern void async_statx(io_future_t & future, int dirfd, const char *pathname, int flags, unsigned int mask, struct statx *statxbuf, int submit_flags, io_cancellation * cancellation, io_context * context);
    125118#endif
    126 void async_read(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);
    127 extern void async_write(io_future_t & future, int fd, void * buf, size_t count, __u64 submit_flags);
    128 extern void async_splice(io_future_t & future, int fd_in, __off64_t *off_in, int fd_out, __off64_t *off_out, size_t len, unsigned int flags, __u64 submit_flags);
    129 extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, __u64 submit_flags);
     119void async_read(io_future_t & future, int fd, void * buf, size_t count, int submit_flags, io_cancellation * cancellation, io_context * context);
     120extern void async_write(io_future_t & future, int fd, void * buf, size_t count, int submit_flags, io_cancellation * cancellation, io_context * context);
     121extern void async_splice(io_future_t & future, int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
     122extern void async_tee(io_future_t & future, int fd_in, int fd_out, size_t len, unsigned int flags, int submit_flags, io_cancellation * cancellation, io_context * context);
    130123
    131124
     
    133126// Check if a function is blocks a only the user thread
    134127bool has_user_level_blocking( fptr_t func );
     128
     129//-----------------------------------------------------------------------------
     130void register_fixed_files( io_context & ctx , int * files, unsigned count );
     131void register_fixed_files( cluster    & cltr, int * files, unsigned count );
  • libcfa/src/concurrency/kernel.cfa

    r5407cdc rfeacef9  
    2222#include <signal.h>
    2323#include <unistd.h>
    24 extern "C" {
    25         #include <sys/eventfd.h>
    26 }
    2724
    2825//CFA Includes
     
    3431#include "invoke.h"
    3532
    36 #if !defined(__CFA_NO_STATISTICS__)
    37         #define __STATS( ...) __VA_ARGS__
    38 #else
    39         #define __STATS( ...)
    40 #endif
    4133
    4234//-----------------------------------------------------------------------------
     
    115107static $thread * __next_thread(cluster * this);
    116108static $thread * __next_thread_slow(cluster * this);
    117 static inline bool __must_unpark( $thread * thrd ) __attribute((nonnull(1)));
    118109static void __run_thread(processor * this, $thread * dst);
    119110static void __wake_one(cluster * cltr);
    120111
    121 static void mark_idle (__cluster_proc_list & idles, processor & proc);
    122 static void mark_awake(__cluster_proc_list & idles, processor & proc);
    123 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list idles );
    124 
    125 extern void __cfa_io_start( processor * );
    126 extern bool __cfa_io_drain( processor * );
    127 extern void __cfa_io_flush( processor * );
    128 extern void __cfa_io_stop ( processor * );
    129 static inline bool __maybe_io_drain( processor * );
    130 
    131 extern void __disable_interrupts_hard();
    132 extern void __enable_interrupts_hard();
    133 
    134 static inline void __disable_interrupts_checked() {
    135         /* paranoid */ verify( __preemption_enabled() );
    136         disable_interrupts();
    137         /* paranoid */ verify( ! __preemption_enabled() );
    138 }
    139 
    140 static inline void __enable_interrupts_checked( bool poll = true ) {
    141         /* paranoid */ verify( ! __preemption_enabled() );
    142         enable_interrupts( poll );
    143         /* paranoid */ verify( __preemption_enabled() );
    144 }
     112static void push  (__cluster_idles & idles, processor & proc);
     113static void remove(__cluster_idles & idles, processor & proc);
     114static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles );
     115
    145116
    146117//=============================================================================================
     
    158129        verify(this);
    159130
    160         __cfa_io_start( this );
    161 
    162131        __cfadbg_print_safe(runtime_core, "Kernel : core %p starting\n", this);
    163132        #if !defined(__CFA_NO_STATISTICS__)
     
    171140                preemption_scope scope = { this };
    172141
    173                 __STATS( unsigned long long last_tally = rdtscl(); )
    174 
    175                 // if we need to run some special setup, now is the time to do it.
    176                 if(this->init.thrd) {
    177                         this->init.thrd->curr_cluster = this->cltr;
    178                         __run_thread(this, this->init.thrd);
    179                 }
     142                #if !defined(__CFA_NO_STATISTICS__)
     143                        unsigned long long last_tally = rdtscl();
     144                #endif
     145
    180146
    181147                __cfadbg_print_safe(runtime_core, "Kernel : core %p started\n", this);
     
    184150                MAIN_LOOP:
    185151                for() {
    186                         // Check if there is pending io
    187                         __maybe_io_drain( this );
    188 
    189152                        // Try to get the next thread
    190153                        readyThread = __next_thread( this->cltr );
    191154
    192155                        if( !readyThread ) {
    193                                 __cfa_io_flush( this );
    194156                                readyThread = __next_thread_slow( this->cltr );
    195157                        }
     
    205167
    206168                                // Push self to idle stack
    207                                 mark_idle(this->cltr->procs, * this);
     169                                push(this->cltr->idles, * this);
    208170
    209171                                // Confirm the ready-queue is empty
     
    211173                                if( readyThread ) {
    212174                                        // A thread was found, cancel the halt
    213                                         mark_awake(this->cltr->procs, * this);
     175                                        remove(this->cltr->idles, * this);
    214176
    215177                                        #if !defined(__CFA_NO_STATISTICS__)
     
    227189                                #endif
    228190
    229                                 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
    230 
    231                                 __disable_interrupts_hard();
    232                                 eventfd_t val;
    233                                 eventfd_read( this->idle, &val );
    234                                 __enable_interrupts_hard();
     191                                wait( this->idle );
    235192
    236193                                #if !defined(__CFA_NO_STATISTICS__)
     
    241198
    242199                                // We were woken up, remove self from idle
    243                                 mark_awake(this->cltr->procs, * this);
     200                                remove(this->cltr->idles, * this);
    244201
    245202                                // DON'T just proceed, start looking again
     
    248205
    249206                        /* paranoid */ verify( readyThread );
    250 
    251                         // Reset io dirty bit
    252                         this->io.dirty = false;
    253207
    254208                        // We found a thread run it
     
    265219                                }
    266220                        #endif
    267 
    268                         if(this->io.pending && !this->io.dirty) {
    269                                 __cfa_io_flush( this );
    270                         }
    271 
    272                 //      SEARCH: {
    273                 //              /* paranoid */ verify( ! __preemption_enabled() );
    274                 //              /* paranoid */ verify( kernelTLS().this_proc_id );
    275 
    276                 //              // First, lock the scheduler since we are searching for a thread
    277 
    278                 //              // Try to get the next thread
    279                 //              ready_schedule_lock();
    280                 //              readyThread = pop_fast( this->cltr );
    281                 //              ready_schedule_unlock();
    282                 //              if(readyThread) {  break SEARCH; }
    283 
    284                 //              // If we can't find a thread, might as well flush any outstanding I/O
    285                 //              if(this->io.pending) { __cfa_io_flush( this ); }
    286 
    287                 //              // Spin a little on I/O, just in case
    288                 //              for(25) {
    289                 //                      __maybe_io_drain( this );
    290                 //                      ready_schedule_lock();
    291                 //                      readyThread = pop_fast( this->cltr );
    292                 //                      ready_schedule_unlock();
    293                 //                      if(readyThread) {  break SEARCH; }
    294                 //              }
    295 
    296                 //              // no luck, try stealing a few times
    297                 //              for(25) {
    298                 //                      if( __maybe_io_drain( this ) ) {
    299                 //                              ready_schedule_lock();
    300                 //                              readyThread = pop_fast( this->cltr );
    301                 //                      } else {
    302                 //                              ready_schedule_lock();
    303                 //                              readyThread = pop_slow( this->cltr );
    304                 //                      }
    305                 //                      ready_schedule_unlock();
    306                 //                      if(readyThread) {  break SEARCH; }
    307                 //              }
    308 
    309                 //              // still no luck, search for a thread
    310                 //              ready_schedule_lock();
    311                 //              readyThread = pop_search( this->cltr );
    312                 //              ready_schedule_unlock();
    313                 //              if(readyThread) { break SEARCH; }
    314 
    315                 //              // Don't block if we are done
    316                 //              if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    317 
    318                 //              __STATS( __tls_stats()->ready.sleep.halts++; )
    319 
    320                 //              // Push self to idle stack
    321                 //              mark_idle(this->cltr->procs, * this);
    322 
    323                 //              // Confirm the ready-queue is empty
    324                 //              __maybe_io_drain( this );
    325                 //              ready_schedule_lock();
    326                 //              readyThread = pop_search( this->cltr );
    327                 //              ready_schedule_unlock();
    328 
    329                 //              if( readyThread ) {
    330                 //                      // A thread was found, cancel the halt
    331                 //                      mark_awake(this->cltr->procs, * this);
    332 
    333                 //                      __STATS( __tls_stats()->ready.sleep.cancels++; )
    334 
    335                 //                      // continue the main loop
    336                 //                      break SEARCH;
    337                 //              }
    338 
    339                 //              __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl()); )
    340                 //              __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle);
    341 
    342                 //              // __disable_interrupts_hard();
    343                 //              eventfd_t val;
    344                 //              eventfd_read( this->idle, &val );
    345                 //              // __enable_interrupts_hard();
    346 
    347                 //              __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl()); )
    348 
    349                 //              // We were woken up, remove self from idle
    350                 //              mark_awake(this->cltr->procs, * this);
    351 
    352                 //              // DON'T just proceed, start looking again
    353                 //              continue MAIN_LOOP;
    354                 //      }
    355 
    356                 // RUN_THREAD:
    357                 //      /* paranoid */ verify( kernelTLS().this_proc_id );
    358                 //      /* paranoid */ verify( ! __preemption_enabled() );
    359                 //      /* paranoid */ verify( readyThread );
    360 
    361                 //      // Reset io dirty bit
    362                 //      this->io.dirty = false;
    363 
    364                 //      // We found a thread run it
    365                 //      __run_thread(this, readyThread);
    366 
    367                 //      // Are we done?
    368                 //      if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
    369 
    370                 //      #if !defined(__CFA_NO_STATISTICS__)
    371                 //              unsigned long long curr = rdtscl();
    372                 //              if(curr > (last_tally + 500000000)) {
    373                 //                      __tally_stats(this->cltr->stats, __cfaabi_tls.this_stats);
    374                 //                      last_tally = curr;
    375                 //              }
    376                 //      #endif
    377 
    378                 //      if(this->io.pending && !this->io.dirty) {
    379                 //              __cfa_io_flush( this );
    380                 //      }
    381 
    382                 //      // Check if there is pending io
    383                 //      __maybe_io_drain( this );
    384221                }
    385222
     
    387224        }
    388225
    389         __cfa_io_stop( this );
    390 
    391226        post( this->terminated );
    392 
    393227
    394228        if(this == mainProcessor) {
     
    413247        /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next );
    414248        __builtin_prefetch( thrd_dst->context.SP );
    415 
    416         __cfadbg_print_safe(runtime_core, "Kernel : core %p running thread %p (%s)\n", this, thrd_dst, thrd_dst->self_cor.name);
    417249
    418250        $coroutine * proc_cor = get_coroutine(this->runner);
     
    465297                if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) {
    466298                        // The thread was preempted, reschedule it and reset the flag
    467                         schedule_thread$( thrd_dst );
     299                        __schedule_thread( thrd_dst );
    468300                        break RUNNING;
    469301                }
     
    486318                                break RUNNING;
    487319                        case TICKET_UNBLOCK:
    488                                 #if !defined(__CFA_NO_STATISTICS__)
    489                                         __tls_stats()->ready.threads.threads++;
    490                                         __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );
    491                                 #endif
    492320                                // This is case 2, the racy case, someone tried to run this thread before it finished blocking
    493321                                // In this case, just run it again.
     
    502330        proc_cor->state = Active;
    503331
    504         __cfadbg_print_safe(runtime_core, "Kernel : core %p finished running thread %p\n", this, thrd_dst);
    505 
    506         #if !defined(__CFA_NO_STATISTICS__)
    507                 __tls_stats()->ready.threads.threads--;
    508                 __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", this );
    509         #endif
    510 
    511332        /* paranoid */ verify( ! __preemption_enabled() );
    512333}
     
    518339        $thread * thrd_src = kernelTLS().this_thread;
    519340
    520         __STATS( thrd_src->last_proc = kernelTLS().this_processor; )
     341        #if !defined(__CFA_NO_STATISTICS__)
     342                struct processor * last_proc = kernelTLS().this_processor;
     343        #endif
    521344
    522345        // Run the thread on this processor
     
    537360
    538361        #if !defined(__CFA_NO_STATISTICS__)
    539                 /* paranoid */ verify( thrd_src->last_proc != 0p );
    540                 if(thrd_src->last_proc != kernelTLS().this_processor) {
     362                if(last_proc != kernelTLS().this_processor) {
    541363                        __tls_stats()->ready.threads.migration++;
    542364                }
     
    551373// Scheduler routines
    552374// KERNEL ONLY
    553 static void __schedule_thread( $thread * thrd ) {
     375void __schedule_thread( $thread * thrd ) {
    554376        /* paranoid */ verify( ! __preemption_enabled() );
    555377        /* paranoid */ verify( kernelTLS().this_proc_id );
    556         /* paranoid */ verify( ready_schedule_islocked());
    557378        /* paranoid */ verify( thrd );
    558379        /* paranoid */ verify( thrd->state != Halted );
     
    570391        if (thrd->preempted == __NO_PREEMPTION) thrd->state = Ready;
    571392
    572         // Dereference the thread now because once we push it, there is not guaranteed it's still valid.
    573         struct cluster * cl = thrd->curr_cluster;
    574         __STATS(bool outside = thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )
    575 
    576         // push the thread to the cluster ready-queue
    577         push( cl, thrd );
    578 
    579         // variable thrd is no longer safe to use
    580         thrd = 0xdeaddeaddeaddeadp;
    581 
    582         // wake the cluster using the save variable.
    583         __wake_one( cl );
    584 
    585         #if !defined(__CFA_NO_STATISTICS__)
    586                 if( kernelTLS().this_stats ) {
    587                         __tls_stats()->ready.threads.threads++;
    588                         if(outside) {
    589                                 __tls_stats()->ready.threads.extunpark++;
    590                         }
    591                         __push_stat( __tls_stats(), __tls_stats()->ready.threads.threads, false, "Processor", kernelTLS().this_processor );
    592                 }
    593                 else {
    594                         __atomic_fetch_add(&cl->stats->ready.threads.threads, 1, __ATOMIC_RELAXED);
    595                         __atomic_fetch_add(&cl->stats->ready.threads.extunpark, 1, __ATOMIC_RELAXED);
    596                         __push_stat( cl->stats, cl->stats->ready.threads.threads, true, "Cluster", cl );
    597                 }
    598         #endif
    599 
    600         /* paranoid */ verify( ready_schedule_islocked());
    601         /* paranoid */ verify( ! __preemption_enabled() );
    602 }
    603 
    604 void schedule_thread$( $thread * thrd ) {
    605393        ready_schedule_lock();
    606                 __schedule_thread( thrd );
     394                // Dereference the thread now because once we push it, there is not guaranteed it's still valid.
     395                struct cluster * cl = thrd->curr_cluster;
     396
     397                // push the thread to the cluster ready-queue
     398                push( cl, thrd );
     399
     400                // variable thrd is no longer safe to use
     401
     402                // wake the cluster using the save variable.
     403                __wake_one( cl );
    607404        ready_schedule_unlock();
     405
     406        /* paranoid */ verify( ! __preemption_enabled() );
    608407}
    609408
     
    614413
    615414        ready_schedule_lock();
    616                 $thread * thrd = pop_fast( this );
     415                $thread * thrd = pop( this );
    617416        ready_schedule_unlock();
    618417
     
    628427
    629428        ready_schedule_lock();
    630                 $thread * thrd;
    631                 for(25) {
    632                         thrd = pop_slow( this );
    633                         if(thrd) goto RET;
    634                 }
    635                 thrd = pop_search( this );
    636 
    637                 RET:
     429                $thread * thrd = pop_slow( this );
    638430        ready_schedule_unlock();
    639431
     
    643435}
    644436
    645 static inline bool __must_unpark( $thread * thrd ) {
     437void unpark( $thread * thrd ) {
     438        if( !thrd ) return;
     439
    646440        int old_ticket = __atomic_fetch_add(&thrd->ticket, 1, __ATOMIC_SEQ_CST);
    647441        switch(old_ticket) {
    648442                case TICKET_RUNNING:
    649443                        // Wake won the race, the thread will reschedule/rerun itself
    650                         return false;
     444                        break;
    651445                case TICKET_BLOCKED:
    652446                        /* paranoid */ verify( ! thrd->preempted != __NO_PREEMPTION );
    653447                        /* paranoid */ verify( thrd->state == Blocked );
    654                         return true;
     448
     449                        {
     450                                /* paranoid */ verify( publicTLS_get(this_proc_id) );
     451                                bool full = publicTLS_get(this_proc_id)->full_proc;
     452                                if(full) disable_interrupts();
     453
     454                                /* paranoid */ verify( ! __preemption_enabled() );
     455
     456                                // Wake lost the race,
     457                                __schedule_thread( thrd );
     458
     459                                /* paranoid */ verify( ! __preemption_enabled() );
     460
     461                                if(full) enable_interrupts( __cfaabi_dbg_ctx );
     462                                /* paranoid */ verify( publicTLS_get(this_proc_id) );
     463                        }
     464
     465                        break;
    655466                default:
    656467                        // This makes no sense, something is wrong abort
     
    659470}
    660471
    661 void __kernel_unpark( $thread * thrd ) {
    662         /* paranoid */ verify( ! __preemption_enabled() );
    663         /* paranoid */ verify( ready_schedule_islocked());
    664 
    665         if( !thrd ) return;
    666 
    667         if(__must_unpark(thrd)) {
    668                 // Wake lost the race,
    669                 __schedule_thread( thrd );
    670         }
    671 
    672         /* paranoid */ verify( ready_schedule_islocked());
    673         /* paranoid */ verify( ! __preemption_enabled() );
    674 }
    675 
    676 void unpark( $thread * thrd ) {
    677         if( !thrd ) return;
    678 
    679         if(__must_unpark(thrd)) {
    680                 disable_interrupts();
    681                         // Wake lost the race,
    682                         schedule_thread$( thrd );
    683                 enable_interrupts(false);
    684         }
    685 }
    686 
    687472void park( void ) {
    688         __disable_interrupts_checked();
    689                 /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION );
    690                 returnToKernel();
    691         __enable_interrupts_checked();
     473        /* paranoid */ verify( __preemption_enabled() );
     474        disable_interrupts();
     475        /* paranoid */ verify( ! __preemption_enabled() );
     476        /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION );
     477
     478        returnToKernel();
     479
     480        /* paranoid */ verify( ! __preemption_enabled() );
     481        enable_interrupts( __cfaabi_dbg_ctx );
     482        /* paranoid */ verify( __preemption_enabled() );
    692483
    693484}
     
    729520// KERNEL ONLY
    730521bool force_yield( __Preemption_Reason reason ) {
    731         __disable_interrupts_checked();
    732                 $thread * thrd = kernelTLS().this_thread;
    733                 /* paranoid */ verify(thrd->state == Active);
    734 
    735                 // SKULLDUGGERY: It is possible that we are preempting this thread just before
    736                 // it was going to park itself. If that is the case and it is already using the
    737                 // intrusive fields then we can't use them to preempt the thread
    738                 // If that is the case, abandon the preemption.
    739                 bool preempted = false;
    740                 if(thrd->link.next == 0p) {
    741                         preempted = true;
    742                         thrd->preempted = reason;
    743                         returnToKernel();
    744                 }
    745         __enable_interrupts_checked( false );
     522        /* paranoid */ verify( __preemption_enabled() );
     523        disable_interrupts();
     524        /* paranoid */ verify( ! __preemption_enabled() );
     525
     526        $thread * thrd = kernelTLS().this_thread;
     527        /* paranoid */ verify(thrd->state == Active);
     528
     529        // SKULLDUGGERY: It is possible that we are preempting this thread just before
     530        // it was going to park itself. If that is the case and it is already using the
     531        // intrusive fields then we can't use them to preempt the thread
     532        // If that is the case, abandon the preemption.
     533        bool preempted = false;
     534        if(thrd->link.next == 0p) {
     535                preempted = true;
     536                thrd->preempted = reason;
     537                returnToKernel();
     538        }
     539
     540        /* paranoid */ verify( ! __preemption_enabled() );
     541        enable_interrupts_noPoll();
     542        /* paranoid */ verify( __preemption_enabled() );
     543
    746544        return preempted;
    747545}
     
    759557        unsigned idle;
    760558        unsigned total;
    761         [idle, total, p] = query_idles(this->procs);
     559        [idle, total, p] = query(this->idles);
    762560
    763561        // If no one is sleeping, we are done
     
    765563
    766564        // We found a processor, wake it up
    767         eventfd_t val;
    768         val = 1;
    769         eventfd_write( p->idle, val );
     565        post( p->idle );
    770566
    771567        #if !defined(__CFA_NO_STATISTICS__)
    772                 if( kernelTLS().this_stats ) {
    773                         __tls_stats()->ready.sleep.wakes++;
    774                 }
    775                 else {
    776                         __atomic_fetch_add(&this->stats->ready.sleep.wakes, 1, __ATOMIC_RELAXED);
    777                 }
     568                __tls_stats()->ready.sleep.wakes++;
    778569        #endif
    779570
     
    788579        __cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
    789580
    790         __disable_interrupts_checked();
     581        disable_interrupts();
    791582                /* paranoid */ verify( ! __preemption_enabled() );
    792                 eventfd_t val;
    793                 val = 1;
    794                 eventfd_write( this->idle, val );
    795         __enable_interrupts_checked();
    796 }
    797 
    798 static void mark_idle(__cluster_proc_list & this, processor & proc) {
     583                post( this->idle );
     584        enable_interrupts( __cfaabi_dbg_ctx );
     585}
     586
     587static void push  (__cluster_idles & this, processor & proc) {
    799588        /* paranoid */ verify( ! __preemption_enabled() );
    800589        lock( this );
    801590                this.idle++;
    802591                /* paranoid */ verify( this.idle <= this.total );
    803                 remove(proc);
    804                 insert_first(this.idles, proc);
     592
     593                insert_first(this.list, proc);
    805594        unlock( this );
    806595        /* paranoid */ verify( ! __preemption_enabled() );
    807596}
    808597
    809 static void mark_awake(__cluster_proc_list & this, processor & proc) {
     598static void remove(__cluster_idles & this, processor & proc) {
    810599        /* paranoid */ verify( ! __preemption_enabled() );
    811600        lock( this );
    812601                this.idle--;
    813602                /* paranoid */ verify( this.idle >= 0 );
     603
    814604                remove(proc);
    815                 insert_last(this.actives, proc);
    816605        unlock( this );
    817606        /* paranoid */ verify( ! __preemption_enabled() );
    818607}
    819608
    820 static [unsigned idle, unsigned total, * processor] query_idles( & __cluster_proc_list this ) {
    821         /* paranoid */ verify( ! __preemption_enabled() );
    822         /* paranoid */ verify( ready_schedule_islocked() );
    823 
     609static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) {
    824610        for() {
    825611                uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
     
    827613                unsigned idle    = this.idle;
    828614                unsigned total   = this.total;
    829                 processor * proc = &this.idles`first;
     615                processor * proc = &this.list`first;
    830616                // Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it
    831617                asm volatile("": : :"memory");
     
    833619                return [idle, total, proc];
    834620        }
    835 
    836         /* paranoid */ verify( ready_schedule_islocked() );
    837         /* paranoid */ verify( ! __preemption_enabled() );
    838621}
    839622
     
    881664// Kernel Utilities
    882665//=============================================================================================
    883 #if defined(CFA_HAVE_LINUX_IO_URING_H)
    884 #include "io/types.hfa"
    885 #endif
    886 
    887 static inline bool __maybe_io_drain( processor * proc ) {
    888         bool ret = false;
    889         #if defined(CFA_HAVE_LINUX_IO_URING_H)
    890                 __cfadbg_print_safe(runtime_core, "Kernel : core %p checking io for ring %d\n", proc, proc->io.ctx->fd);
    891 
    892                 // Check if we should drain the queue
    893                 $io_context * ctx = proc->io.ctx;
    894                 unsigned head = *ctx->cq.head;
    895                 unsigned tail = *ctx->cq.tail;
    896                 if(head == tail) return false;
    897                 ready_schedule_lock();
    898                 ret = __cfa_io_drain( proc );
    899                 ready_schedule_unlock();
    900         #endif
    901         return ret;
    902 }
    903 
    904666//-----------------------------------------------------------------------------
    905667// Debug
     
    929691                __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this );
    930692        }
     693
     694        extern int __print_alarm_stats;
     695        void print_alarm_stats() {
     696                __print_alarm_stats = -1;
     697        }
    931698#endif
    932699// Local Variables: //
  • libcfa/src/concurrency/kernel.hfa

    r5407cdc rfeacef9  
    2828}
    2929
     30//-----------------------------------------------------------------------------
     31// Underlying Locks
    3032#ifdef __CFA_WITH_VERIFY__
    3133        extern bool __cfaabi_dbg_in_kernel();
    3234#endif
    3335
    34 //-----------------------------------------------------------------------------
    35 // I/O
    36 struct cluster;
    37 struct $io_context;
    38 struct $io_arbiter;
    39 
    40 struct io_context_params {
    41         int num_entries;
    42 };
    43 
    44 void  ?{}(io_context_params & this);
     36extern "C" {
     37        char * strerror(int);
     38}
     39#define CHECKED(x) { int err = x; if( err != 0 ) abort("KERNEL ERROR: Operation \"" #x "\" return error %d - %s\n", err, strerror(err)); }
     40
     41struct __bin_sem_t {
     42        pthread_mutex_t         lock;
     43        pthread_cond_t          cond;
     44        int                     val;
     45};
     46
     47static inline void ?{}(__bin_sem_t & this) with( this ) {
     48        // Create the mutex with error checking
     49        pthread_mutexattr_t mattr;
     50        pthread_mutexattr_init( &mattr );
     51        pthread_mutexattr_settype( &mattr, PTHREAD_MUTEX_ERRORCHECK_NP);
     52        pthread_mutex_init(&lock, &mattr);
     53
     54        pthread_cond_init (&cond, (const pthread_condattr_t *)0p);  // workaround trac#208: cast should not be required
     55        val = 0;
     56}
     57
     58static inline void ^?{}(__bin_sem_t & this) with( this ) {
     59        CHECKED( pthread_mutex_destroy(&lock) );
     60        CHECKED( pthread_cond_destroy (&cond) );
     61}
     62
     63static inline void wait(__bin_sem_t & this) with( this ) {
     64        verify(__cfaabi_dbg_in_kernel());
     65        CHECKED( pthread_mutex_lock(&lock) );
     66                while(val < 1) {
     67                        pthread_cond_wait(&cond, &lock);
     68                }
     69                val -= 1;
     70        CHECKED( pthread_mutex_unlock(&lock) );
     71}
     72
     73static inline bool post(__bin_sem_t & this) with( this ) {
     74        bool needs_signal = false;
     75
     76        CHECKED( pthread_mutex_lock(&lock) );
     77                if(val < 1) {
     78                        val += 1;
     79                        pthread_cond_signal(&cond);
     80                        needs_signal = true;
     81                }
     82        CHECKED( pthread_mutex_unlock(&lock) );
     83
     84        return needs_signal;
     85}
     86
     87#undef CHECKED
     88
    4589
    4690//-----------------------------------------------------------------------------
     
    5195struct __processor_id_t {
    5296        unsigned id:24;
     97        bool full_proc:1;
    5398
    5499        #if !defined(__CFA_NO_STATISTICS__)
     
    69114        struct cluster * cltr;
    70115
    71         // Ready Queue state per processor
    72         struct {
    73                 unsigned short its;
    74                 unsigned short itr;
    75                 unsigned id;
    76                 unsigned target;
    77                 unsigned long long int cutoff;
    78         } rdq;
    79 
    80116        // Set to true to notify the processor should terminate
    81117        volatile bool do_terminate;
     
    89125        // Handle to pthreads
    90126        pthread_t kernel_thread;
    91 
    92         struct {
    93                 $io_context * ctx;
    94                 bool pending;
    95                 bool dirty;
    96         } io;
    97127
    98128        // Preemption data
     
    104134
    105135        // Idle lock (kernel semaphore)
    106         int idle;
     136        __bin_sem_t idle;
    107137
    108138        // Termination synchronisation (user semaphore)
     
    114144        // Link lists fields
    115145        DLISTED_MGD_IMPL_IN(processor)
    116 
    117         // special init fields
    118         // This is needed for memcached integration
    119         // once memcached experiments are done this should probably be removed
    120         // it is not a particularly safe scheme as it can make processors less homogeneous
    121         struct {
    122                 $thread * thrd;
    123         } init;
    124146
    125147        #if !defined(__CFA_NO_STATISTICS__)
     
    137159void ^?{}(processor & this);
    138160
    139 static inline void  ?{}(processor & this)                        { this{ "Anonymous Processor", *mainCluster}; }
    140 static inline void  ?{}(processor & this, struct cluster & cltr) { this{ "Anonymous Processor", cltr}; }
    141 static inline void  ?{}(processor & this, const char name[])     { this{name, *mainCluster}; }
     161static inline void  ?{}(processor & this)                    { this{ "Anonymous Processor", *mainCluster}; }
     162static inline void  ?{}(processor & this, struct cluster & cltr)    { this{ "Anonymous Processor", cltr}; }
     163static inline void  ?{}(processor & this, const char name[]) { this{name, *mainCluster }; }
    142164
    143165DLISTED_MGD_IMPL_OUT(processor)
    144166
    145167//-----------------------------------------------------------------------------
     168// I/O
     169struct __io_data;
     170
     171// IO poller user-thread
     172// Not using the "thread" keyword because we want to control
     173// more carefully when to start/stop it
     174struct $io_ctx_thread {
     175        struct __io_data * ring;
     176        single_sem sem;
     177        volatile bool done;
     178        $thread self;
     179};
     180
     181
     182struct io_context {
     183        $io_ctx_thread thrd;
     184};
     185
     186struct io_context_params {
     187        int num_entries;
     188        int num_ready;
     189        int submit_aff;
     190        bool eager_submits:1;
     191        bool poller_submits:1;
     192        bool poll_submit:1;
     193        bool poll_complete:1;
     194};
     195
     196void  ?{}(io_context_params & this);
     197
     198void  ?{}(io_context & this, struct cluster & cl);
     199void  ?{}(io_context & this, struct cluster & cl, const io_context_params & params);
     200void ^?{}(io_context & this);
     201
     202struct io_cancellation {
     203        __u64 target;
     204};
     205
     206static inline void  ?{}(io_cancellation & this) { this.target = -1u; }
     207static inline void ^?{}(io_cancellation &) {}
     208bool cancel(io_cancellation & this);
     209
     210//-----------------------------------------------------------------------------
    146211// Cluster Tools
    147212
    148 // Intrusives lanes which are used by the ready queue
     213// Intrusives lanes which are used by the relaxed ready queue
    149214struct __attribute__((aligned(128))) __intrusive_lane_t;
    150215void  ?{}(__intrusive_lane_t & this);
    151216void ^?{}(__intrusive_lane_t & this);
    152217
    153 // Aligned timestamps which are used by the relaxed ready queue
    154 struct __attribute__((aligned(128))) __timestamp_t;
    155 void  ?{}(__timestamp_t & this);
    156 void ^?{}(__timestamp_t & this);
     218// Counter used for wether or not the lanes are all empty
     219struct __attribute__((aligned(128))) __snzi_node_t;
     220struct __snzi_t {
     221        unsigned mask;
     222        int root;
     223        __snzi_node_t * nodes;
     224};
     225
     226void  ?{}( __snzi_t & this, unsigned depth );
     227void ^?{}( __snzi_t & this );
    157228
    158229//TODO adjust cache size to ARCHITECTURE
    159230// Structure holding the relaxed ready queue
    160231struct __ready_queue_t {
     232        // Data tracking how many/which lanes are used
     233        // Aligned to 128 for cache locality
     234        __snzi_t snzi;
     235
    161236        // Data tracking the actual lanes
    162237        // On a seperate cacheline from the used struct since
     
    167242                __intrusive_lane_t * volatile data;
    168243
    169                 // Array of times
    170                 __timestamp_t * volatile tscs;
    171 
    172244                // Number of lanes (empty or not)
    173245                volatile size_t count;
     
    179251
    180252// Idle Sleep
    181 struct __cluster_proc_list {
     253struct __cluster_idles {
    182254        // Spin lock protecting the queue
    183255        volatile uint64_t lock;
     
    190262
    191263        // List of idle processors
    192         dlist(processor, processor) idles;
    193 
    194         // List of active processors
    195         dlist(processor, processor) actives;
     264        dlist(processor, processor) list;
    196265};
    197266
     
    209278
    210279        // List of idle processors
    211         __cluster_proc_list procs;
     280        __cluster_idles idles;
    212281
    213282        // List of threads
     
    223292
    224293        struct {
    225                 $io_arbiter * arbiter;
    226                 io_context_params params;
     294                io_context * ctxs;
     295                unsigned cnt;
    227296        } io;
    228297
  • libcfa/src/concurrency/kernel/fwd.hfa

    r5407cdc rfeacef9  
    108108
    109109        extern void disable_interrupts();
    110         extern void enable_interrupts( bool poll = false );
     110        extern void enable_interrupts_noPoll();
     111        extern void enable_interrupts( __cfaabi_dbg_ctx_param );
    111112
    112113        extern "Cforall" {
     
    219220                        // Mark as fulfilled, wake thread if needed
    220221                        // return true if a thread was unparked
    221                         $thread * post(oneshot & this, bool do_unpark = true) {
     222                        bool post(oneshot & this) {
    222223                                struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
    223                                 if( got == 0p ) return 0p;
    224                                 if(do_unpark) unpark( got );
    225                                 return got;
     224                                if( got == 0p ) return false;
     225                                unpark( got );
     226                                return true;
    226227                        }
    227228                }
     
    335336                        // from the server side, mark the future as fulfilled
    336337                        // delete it if needed
    337                         $thread * fulfil( future_t & this, bool do_unpark = true ) {
     338                        bool fulfil( future_t & this ) {
    338339                                for() {
    339340                                        struct oneshot * expected = this.ptr;
     
    343344                                                #pragma GCC diagnostic ignored "-Wfree-nonheap-object"
    344345                                        #endif
    345                                                 if( expected == 3p ) { free( &this ); return 0p; }
     346                                                if( expected == 3p ) { free( &this ); return false; }
    346347                                        #if defined(__GNUC__) && __GNUC__ >= 7
    347348                                                #pragma GCC diagnostic pop
     
    355356                                        struct oneshot * want = expected == 0p ? 1p : 2p;
    356357                                        if(__atomic_compare_exchange_n(&this.ptr, &expected, want, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    357                                                 if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return 0p; }
    358                                                 $thread * ret = post( *expected, do_unpark );
     358                                                if( expected == 0p ) { /* paranoid */ verify( this.ptr == 1p); return false; }
     359                                                bool ret = post( *expected );
    359360                                                __atomic_store_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
    360361                                                return ret;
     
    402403                                        __VA_ARGS__ \
    403404                                } \
    404                                 if( !(in_kernel) ) enable_interrupts(); \
     405                                if( !(in_kernel) ) enable_interrupts( __cfaabi_dbg_ctx ); \
    405406                        }
    406407                #else
  • libcfa/src/concurrency/kernel/startup.cfa

    r5407cdc rfeacef9  
    2222extern "C" {
    2323      #include <limits.h>       // PTHREAD_STACK_MIN
    24         #include <sys/eventfd.h>  // eventfd
    2524      #include <sys/mman.h>     // mprotect
    2625      #include <sys/resource.h> // getrlimit
     
    7372static void __kernel_first_resume( processor * this );
    7473static void __kernel_last_resume ( processor * this );
    75 static void init(processor & this, const char name[], cluster & _cltr, $thread * initT);
     74static void init(processor & this, const char name[], cluster & _cltr);
    7675static void deinit(processor & this);
    7776static void doregister( struct cluster & cltr );
     
    9089extern void __kernel_alarm_startup(void);
    9190extern void __kernel_alarm_shutdown(void);
     91extern void __kernel_io_startup (void);
     92extern void __kernel_io_shutdown(void);
    9293
    9394//-----------------------------------------------------------------------------
     
    101102KERNEL_STORAGE($thread,              mainThread);
    102103KERNEL_STORAGE(__stack_t,            mainThreadCtx);
     104KERNEL_STORAGE(io_context,           mainPollerThread);
    103105KERNEL_STORAGE(__scheduler_RWLock_t, __scheduler_lock);
    104106#if !defined(__CFA_NO_STATISTICS__)
     
    196198
    197199        void ?{}(processor & this) with( this ) {
     200                ( this.idle ){};
    198201                ( this.terminated ){};
    199202                ( this.runner ){};
    200                 init( this, "Main Processor", *mainCluster, 0p );
     203                init( this, "Main Processor", *mainCluster );
    201204                kernel_thread = pthread_self();
    202205
     
    223226        __kernel_alarm_startup();
    224227
     228        // Start IO
     229        __kernel_io_startup();
     230
    225231        // Add the main thread to the ready queue
    226232        // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread
    227         schedule_thread$(mainThread);
     233        __schedule_thread(mainThread);
    228234
    229235        // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX
     
    235241        // THE SYSTEM IS NOW COMPLETELY RUNNING
    236242
     243
     244        // SKULLDUGGERY: The constructor for the mainCluster will call alloc with a dimension of 0
     245        // malloc *can* return a non-null value, we should free it if that is the case
     246        free( mainCluster->io.ctxs );
     247
     248        // Now that the system is up, finish creating systems that need threading
     249        mainCluster->io.ctxs = (io_context *)&storage_mainPollerThread;
     250        mainCluster->io.cnt  = 1;
     251        (*mainCluster->io.ctxs){ *mainCluster };
     252
    237253        __cfadbg_print_safe(runtime_core, "Kernel : Started\n--------------------------------------------------\n\n");
    238254
    239255        /* paranoid */ verify( ! __preemption_enabled() );
    240         enable_interrupts();
     256        enable_interrupts( __cfaabi_dbg_ctx );
    241257        /* paranoid */ verify( __preemption_enabled() );
    242258
     
    244260
    245261static void __kernel_shutdown(void) {
     262        //Before we start shutting things down, wait for systems that need threading to shutdown
     263        ^(*mainCluster->io.ctxs){};
     264        mainCluster->io.cnt  = 0;
     265        mainCluster->io.ctxs = 0p;
     266
    246267        /* paranoid */ verify( __preemption_enabled() );
    247268        disable_interrupts();
     
    262283        __kernel_alarm_shutdown();
    263284
    264         #if !defined( __CFA_NO_STATISTICS__ )
    265                 __stats_t * st = (__stats_t *)& storage_mainProcStats;
    266                 __tally_stats(mainCluster->stats, st);
    267                 if( 0 != mainProcessor->print_stats ) {
    268                         __print_stats( st, mainProcessor->print_stats, "Processor ", mainProcessor->name, (void*)mainProcessor );
    269                 }
    270                 #if defined(CFA_STATS_ARRAY)
    271                         __flush_stat( st, "Processor", mainProcessor );
    272                 #endif
    273         #endif
     285        // Stop IO
     286        __kernel_io_shutdown();
    274287
    275288        // Destroy the main processor and its context in reverse order of construction
     
    351364                        __print_stats( &local_stats, proc->print_stats, "Processor ", proc->name, (void*)proc );
    352365                }
    353                 #if defined(CFA_STATS_ARRAY)
    354                         __flush_stat( &local_stats, "Processor", proc );
    355                 #endif
    356366        #endif
    357367
     
    447457        link.next = 0p;
    448458        link.prev = 0p;
    449         link.preferred = -1u;
    450         last_proc = 0p;
    451459        #if defined( __CFA_WITH_VERIFY__ )
    452460                canary = 0x0D15EA5E0D15EA5Ep;
     
    468476}
    469477
    470 static void init(processor & this, const char name[], cluster & _cltr, $thread * initT) with( this ) {
     478static void init(processor & this, const char name[], cluster & _cltr) with( this ) {
    471479        this.name = name;
    472480        this.cltr = &_cltr;
    473         this.rdq.its = 0;
    474         this.rdq.itr = 0;
    475         this.rdq.id  = -1u;
    476         this.rdq.target = -1u;
    477         this.rdq.cutoff = -1ull;
     481        full_proc = true;
    478482        do_terminate = false;
    479483        preemption_alarm = 0p;
    480484        pending_preemption = false;
    481485
    482         this.io.ctx = 0p;
    483         this.io.pending = false;
    484         this.io.dirty   = false;
    485 
    486         this.init.thrd = initT;
    487 
    488         this.idle = eventfd(0, 0);
    489         if (idle < 0) {
    490                 abort("KERNEL ERROR: PROCESSOR EVENTFD - %s\n", strerror(errno));
    491         }
    492 
    493486        #if !defined(__CFA_NO_STATISTICS__)
    494487                print_stats = 0;
     
    496489        #endif
    497490
    498         // Register and Lock the RWlock so no-one pushes/pops while we are changing the queue
    499         uint_fast32_t last_size = ready_mutate_register((__processor_id_t*)&this);
    500                 this.cltr->procs.total += 1u;
    501                 insert_last(this.cltr->procs.actives, this);
     491        lock( this.cltr->idles );
     492                int target = this.cltr->idles.total += 1u;
     493        unlock( this.cltr->idles );
     494
     495        id = doregister((__processor_id_t*)&this);
     496
     497        // Lock the RWlock so no-one pushes/pops while we are changing the queue
     498        uint_fast32_t last_size = ready_mutate_lock();
    502499
    503500                // Adjust the ready queue size
    504                 ready_queue_grow( cltr );
     501                ready_queue_grow( cltr, target );
    505502
    506503        // Unlock the RWlock
     
    512509// Not a ctor, it just preps the destruction but should not destroy members
    513510static void deinit(processor & this) {
     511        lock( this.cltr->idles );
     512                int target = this.cltr->idles.total -= 1u;
     513        unlock( this.cltr->idles );
     514
    514515        // Lock the RWlock so no-one pushes/pops while we are changing the queue
    515516        uint_fast32_t last_size = ready_mutate_lock();
    516                 this.cltr->procs.total -= 1u;
    517                 remove(this);
    518517
    519518                // Adjust the ready queue size
    520                 ready_queue_shrink( this.cltr );
    521 
    522         // Unlock the RWlock and unregister: we don't need the read_lock any more
    523         ready_mutate_unregister((__processor_id_t*)&this, last_size );
    524 
    525         close(this.idle);
    526 }
    527 
    528 void ?{}(processor & this, const char name[], cluster & _cltr, $thread * initT) {
     519                ready_queue_shrink( this.cltr, target );
     520
     521        // Unlock the RWlock
     522        ready_mutate_unlock( last_size );
     523
     524        // Finally we don't need the read_lock any more
     525        unregister((__processor_id_t*)&this);
     526}
     527
     528void ?{}(processor & this, const char name[], cluster & _cltr) {
     529        ( this.idle ){};
    529530        ( this.terminated ){};
    530531        ( this.runner ){};
    531532
    532533        disable_interrupts();
    533                 init( this, name, _cltr, initT );
    534         enable_interrupts();
     534                init( this, name, _cltr );
     535        enable_interrupts( __cfaabi_dbg_ctx );
    535536
    536537        __cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this);
    537538
    538539        this.stack = __create_pthread( &this.kernel_thread, __invoke_processor, (void *)&this );
    539 }
    540 
    541 void ?{}(processor & this, const char name[], cluster & _cltr) {
    542         (this){name, _cltr, 0p};
     540
    543541}
    544542
     
    559557        disable_interrupts();
    560558                deinit( this );
    561         enable_interrupts();
     559        enable_interrupts( __cfaabi_dbg_ctx );
    562560}
    563561
    564562//-----------------------------------------------------------------------------
    565563// Cluster
    566 static void ?{}(__cluster_proc_list & this) {
     564static void ?{}(__cluster_idles & this) {
    567565        this.lock  = 0;
    568566        this.idle  = 0;
    569567        this.total = 0;
     568        (this.list){};
    570569}
    571570
     
    583582        threads{ __get };
    584583
    585         io.arbiter = create();
    586         io.params = io_params;
    587 
    588584        doregister(this);
    589585
     
    593589
    594590                // Adjust the ready queue size
    595                 ready_queue_grow( &this );
     591                ready_queue_grow( &this, 0 );
    596592
    597593        // Unlock the RWlock
    598594        ready_mutate_unlock( last_size );
    599         enable_interrupts( false ); // Don't poll, could be in main cluster
     595        enable_interrupts_noPoll(); // Don't poll, could be in main cluster
     596
     597
     598        this.io.cnt  = num_io;
     599        this.io.ctxs = aalloc(num_io);
     600        for(i; this.io.cnt) {
     601                (this.io.ctxs[i]){ this, io_params };
     602        }
    600603}
    601604
    602605void ^?{}(cluster & this) {
    603         destroy(this.io.arbiter);
     606        for(i; this.io.cnt) {
     607                ^(this.io.ctxs[i]){ true };
     608        }
     609        free(this.io.ctxs);
    604610
    605611        // Lock the RWlock so no-one pushes/pops while we are changing the queue
     
    608614
    609615                // Adjust the ready queue size
    610                 ready_queue_shrink( &this );
     616                ready_queue_shrink( &this, 0 );
    611617
    612618        // Unlock the RWlock
    613619        ready_mutate_unlock( last_size );
    614         enable_interrupts( false ); // Don't poll, could be in main cluster
     620        enable_interrupts_noPoll(); // Don't poll, could be in main cluster
    615621
    616622        #if !defined(__CFA_NO_STATISTICS__)
     
    618624                        __print_stats( this.stats, this.print_stats, "Cluster", this.name, (void*)&this );
    619625                }
    620                 #if defined(CFA_STATS_ARRAY)
    621                         __flush_stat( this.stats, "Cluster", &this );
    622                 #endif
    623626                free( this.stats );
    624627        #endif
     
    733736}
    734737
     738
    735739#if defined(__CFA_WITH_VERIFY__)
    736740static bool verify_fwd_bck_rng(void) {
  • libcfa/src/concurrency/kernel_private.hfa

    r5407cdc rfeacef9  
    2929extern "C" {
    3030        void disable_interrupts() OPTIONAL_THREAD;
    31         void enable_interrupts( bool poll = true );
    32 }
    33 
    34 void schedule_thread$( $thread * ) __attribute__((nonnull (1)));
     31        void enable_interrupts_noPoll();
     32        void enable_interrupts( __cfaabi_dbg_ctx_param );
     33}
     34
     35void __schedule_thread( $thread * )
     36#if defined(NDEBUG) || (!defined(__CFA_DEBUG__) && !defined(__CFA_VERIFY__))
     37        __attribute__((nonnull (1)))
     38#endif
     39;
    3540
    3641extern bool __preemption_enabled();
     
    7277//-----------------------------------------------------------------------------
    7378// I/O
    74 $io_arbiter * create(void);
    75 void destroy($io_arbiter *);
     79void ^?{}(io_context & this, bool );
    7680
    7781//=======================================================================
    7882// Cluster lock API
    7983//=======================================================================
     84// Cells use by the reader writer lock
     85// while not generic it only relies on a opaque pointer
     86struct __attribute__((aligned(128))) __scheduler_lock_id_t {
     87        // Spin lock used as the underlying lock
     88        volatile bool lock;
     89
     90        // Handle pointing to the proc owning this cell
     91        // Used for allocating cells and debugging
     92        __processor_id_t * volatile handle;
     93
     94        #ifdef __CFA_WITH_VERIFY__
     95                // Debug, check if this is owned for reading
     96                bool owned;
     97        #endif
     98};
     99
     100static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
     101
    80102// Lock-Free registering/unregistering of threads
    81103// Register a processor to a given cluster and get its unique id in return
    82 void register_proc_id( struct __processor_id_t * );
     104unsigned doregister( struct __processor_id_t * proc );
    83105
    84106// Unregister a processor from a given cluster using its id, getting back the original pointer
    85 void unregister_proc_id( struct __processor_id_t * proc );
     107void     unregister( struct __processor_id_t * proc );
     108
     109//-----------------------------------------------------------------------
     110// Cluster idle lock/unlock
     111static inline void lock(__cluster_idles & this) {
     112        for() {
     113                uint64_t l = this.lock;
     114                if(
     115                        (0 == (l % 2))
     116                        && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
     117                ) return;
     118                Pause();
     119        }
     120}
     121
     122static inline void unlock(__cluster_idles & this) {
     123        /* paranoid */ verify( 1 == (this.lock % 2) );
     124        __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
     125}
    86126
    87127//=======================================================================
     
    111151        __atomic_store_n(ll, (bool)false, __ATOMIC_RELEASE);
    112152}
    113 
    114 // Cells use by the reader writer lock
    115 // while not generic it only relies on a opaque pointer
    116 struct __attribute__((aligned(128))) __scheduler_lock_id_t {
    117         // Spin lock used as the underlying lock
    118         volatile bool lock;
    119 
    120         // Handle pointing to the proc owning this cell
    121         // Used for allocating cells and debugging
    122         __processor_id_t * volatile handle;
    123 
    124         #ifdef __CFA_WITH_VERIFY__
    125                 // Debug, check if this is owned for reading
    126                 bool owned;
    127         #endif
    128 };
    129 
    130 static_assert( sizeof(struct __scheduler_lock_id_t) <= __alignof(struct __scheduler_lock_id_t));
    131153
    132154//-----------------------------------------------------------------------
     
    224246void ready_mutate_unlock( uint_fast32_t /* value returned by lock */ );
    225247
    226 //-----------------------------------------------------------------------
    227 // Lock-Free registering/unregistering of threads
    228 // Register a processor to a given cluster and get its unique id in return
    229 // For convenience, also acquires the lock
    230 static inline uint_fast32_t ready_mutate_register( struct __processor_id_t * proc ) {
    231         register_proc_id( proc );
    232         return ready_mutate_lock();
    233 }
    234 
    235 // Unregister a processor from a given cluster using its id, getting back the original pointer
    236 // assumes the lock is acquired
    237 static inline void ready_mutate_unregister( struct __processor_id_t * proc, uint_fast32_t last_s ) {
    238         ready_mutate_unlock( last_s );
    239         unregister_proc_id( proc );
    240 }
    241 
    242 //-----------------------------------------------------------------------
    243 // Cluster idle lock/unlock
    244 static inline void lock(__cluster_proc_list & this) {
    245         /* paranoid */ verify( ! __preemption_enabled() );
    246 
    247         // Start by locking the global RWlock so that we know no-one is
    248         // adding/removing processors while we mess with the idle lock
    249         ready_schedule_lock();
    250 
    251         // Simple counting lock, acquired, acquired by incrementing the counter
    252         // to an odd number
    253         for() {
    254                 uint64_t l = this.lock;
    255                 if(
    256                         (0 == (l % 2))
    257                         && __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
    258                 ) return;
    259                 Pause();
    260         }
    261 
    262         /* paranoid */ verify( ! __preemption_enabled() );
    263 }
    264 
    265 static inline void unlock(__cluster_proc_list & this) {
    266         /* paranoid */ verify( ! __preemption_enabled() );
    267 
    268         /* paranoid */ verify( 1 == (this.lock % 2) );
    269         // Simple couting lock, release by incrementing to an even number
    270         __atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
    271 
    272         // Release the global lock, which we acquired when locking
    273         ready_schedule_unlock();
    274 
    275         /* paranoid */ verify( ! __preemption_enabled() );
    276 }
    277 
    278248//=======================================================================
    279249// Ready-Queue API
     250//-----------------------------------------------------------------------
     251// pop thread from the ready queue of a cluster
     252// returns 0p if empty
     253__attribute__((hot)) bool query(struct cluster * cltr);
     254
    280255//-----------------------------------------------------------------------
    281256// push thread onto a ready queue for a cluster
    282257// returns true if the list was previously empty, false otherwise
    283 __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd);
    284 
    285 //-----------------------------------------------------------------------
    286 // pop thread from the local queues of a cluster
     258__attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd);
     259
     260//-----------------------------------------------------------------------
     261// pop thread from the ready queue of a cluster
    287262// returns 0p if empty
    288263// May return 0p spuriously
    289 __attribute__((hot)) struct $thread * pop_fast(struct cluster * cltr);
    290 
    291 //-----------------------------------------------------------------------
    292 // pop thread from any ready queue of a cluster
    293 // returns 0p if empty
    294 // May return 0p spuriously
    295 __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr);
    296 
    297 //-----------------------------------------------------------------------
    298 // search all ready queues of a cluster for any thread
     264__attribute__((hot)) struct $thread * pop(struct cluster * cltr);
     265
     266//-----------------------------------------------------------------------
     267// pop thread from the ready queue of a cluster
    299268// returns 0p if empty
    300269// guaranteed to find any threads added before this call
    301 __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr);
     270__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr);
     271
     272//-----------------------------------------------------------------------
     273// remove thread from the ready queue of a cluster
     274// returns bool if it wasn't found
     275bool remove_head(struct cluster * cltr, struct $thread * thrd);
    302276
    303277//-----------------------------------------------------------------------
    304278// Increase the width of the ready queue (number of lanes) by 4
    305 void ready_queue_grow  (struct cluster * cltr);
     279void ready_queue_grow  (struct cluster * cltr, int target);
    306280
    307281//-----------------------------------------------------------------------
    308282// Decrease the width of the ready queue (number of lanes) by 4
    309 void ready_queue_shrink(struct cluster * cltr);
     283void ready_queue_shrink(struct cluster * cltr, int target);
    310284
    311285
  • libcfa/src/concurrency/locks.cfa

    r5407cdc rfeacef9  
    134134        lock( lock __cfaabi_dbg_ctx2 );
    135135        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
    136         /* paranoid */ verifyf( owner == active_thread() || !strict_owner , "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this );
    137         /* paranoid */ verifyf( recursion_count == 1 || multi_acquisition, "Thread %p attempted to release owner lock %p which is not recursive but has a recursive count of %zu", active_thread(), &this, recursion_count );
     136        /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this );
    138137
    139138        // if recursion count is zero release lock and set new owner if one is waiting
     
    147146size_t wait_count( blocking_lock & this ) with( this ) {
    148147        return wait_count;
     148}
     149
     150void set_recursion_count( blocking_lock & this, size_t recursion ) with( this ) {
     151        recursion_count = recursion;
     152}
     153
     154size_t get_recursion_count( blocking_lock & this ) with( this ) {
     155        return recursion_count;
    149156}
    150157
     
    166173}
    167174
    168 size_t on_wait( blocking_lock & this ) with( this ) {
     175void on_wait( blocking_lock & this ) with( this ) {
    169176        lock( lock __cfaabi_dbg_ctx2 );
    170177        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
    171178        /* paranoid */ verifyf( owner == active_thread() || !strict_owner, "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this );
    172179
    173         size_t ret = recursion_count;
    174 
    175180        pop_and_set_new_owner( this );
    176181        unlock( lock );
    177         return ret;
    178 }
    179 
    180 void on_wakeup( blocking_lock & this, size_t recursion ) with( this ) {
    181         recursion_count = recursion;
    182182}
    183183
     
    274274        }
    275275
    276         bool empty( condition_variable(L) & this ) with(this) {
    277                 lock( lock __cfaabi_dbg_ctx2 );
    278                 bool ret = empty(blocked_threads);
    279                 unlock( lock );
    280                 return ret;
    281         }
     276        bool empty( condition_variable(L) & this ) with(this) { return empty(blocked_threads); }
    282277
    283278        int counter( condition_variable(L) & this ) with(this) { return count; }
     
    290285                if (i->lock) {
    291286                        // if lock was passed get recursion count to reset to after waking thread
    292                         recursion_count = on_wait( *i->lock );
     287                        recursion_count = get_recursion_count(*i->lock);
     288                        on_wait( *i->lock );
    293289                }
    294290                return recursion_count;
     
    305301
    306302                // resets recursion count here after waking
    307                 if (i.lock) on_wakeup(*i.lock, recursion_count);
     303                if (i.lock) set_recursion_count(*i.lock, recursion_count);
    308304        }
    309305
     
    327323
    328324                // resets recursion count here after waking
    329                 if (info.lock) on_wakeup(*info.lock, recursion_count);
     325                if (info.lock) set_recursion_count(*info.lock, recursion_count);
    330326        }
    331327
     
    377373}
    378374
    379 $thread * V (semaphore & this, const bool doUnpark ) with( this ) {
     375bool V(semaphore & this) with( this ) {
    380376        $thread * thrd = 0p;
    381377        lock( lock __cfaabi_dbg_ctx2 );
     
    389385
    390386        // make new owner
    391         if( doUnpark ) unpark( thrd );
    392 
    393         return thrd;
    394 }
    395 
    396 bool V(semaphore & this) with( this ) {
    397         $thread * thrd = V(this, true);
     387        unpark( thrd );
     388
    398389        return thrd != 0p;
    399390}
  • libcfa/src/concurrency/locks.hfa

    r5407cdc rfeacef9  
    2020
    2121#include "bits/weakso_locks.hfa"
    22 #include "containers/queueLockFree.hfa"
    23 
    24 #include "thread.hfa"
    2522
    2623#include "time_t.hfa"
    2724#include "time.hfa"
    28 
    29 //-----------------------------------------------------------------------------
    30 // Semaphores
    31 
    32 // '0-nary' semaphore
    33 // Similar to a counting semaphore except the value of one is never reached
    34 // as a consequence, a V() that would bring the value to 1 *spins* until
    35 // a P consumes it
    36 struct Semaphore0nary {
    37         __spinlock_t lock; // needed to protect
    38         mpsc_queue($thread) queue;
    39 };
    40 
    41 static inline bool P(Semaphore0nary & this, $thread * thrd) {
    42         /* paranoid */ verify(!(thrd->seqable.next));
    43         /* paranoid */ verify(!(thrd`next));
    44 
    45         push(this.queue, thrd);
    46         return true;
    47 }
    48 
    49 static inline bool P(Semaphore0nary & this) {
    50     $thread * thrd = active_thread();
    51     P(this, thrd);
    52     park();
    53     return true;
    54 }
    55 
    56 static inline $thread * V(Semaphore0nary & this, bool doUnpark = true) {
    57         $thread * next;
    58         lock(this.lock __cfaabi_dbg_ctx2);
    59                 for (;;) {
    60                         next = pop(this.queue);
    61                         if (next) break;
    62                         Pause();
    63                 }
    64         unlock(this.lock);
    65 
    66         if (doUnpark) unpark(next);
    67         return next;
    68 }
    69 
    70 // Wrapper used on top of any sempahore to avoid potential locking
    71 struct BinaryBenaphore {
    72         volatile ssize_t counter;
    73 };
    74 
    75 static inline {
    76         void ?{}(BinaryBenaphore & this) { this.counter = 0; }
    77         void ?{}(BinaryBenaphore & this, zero_t) { this.counter = 0; }
    78         void ?{}(BinaryBenaphore & this, one_t ) { this.counter = 1; }
    79 
    80         // returns true if no blocking needed
    81         bool P(BinaryBenaphore & this) {
    82                 return __atomic_fetch_sub(&this.counter, 1, __ATOMIC_SEQ_CST) > 0;
    83         }
    84 
    85         bool tryP(BinaryBenaphore & this) {
    86                 ssize_t c = this.counter;
    87                 return (c >= 1) && __atomic_compare_exchange_n(&this.counter, &c, c-1, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
    88         }
    89 
    90         // returns true if notify needed
    91         bool V(BinaryBenaphore & this) {
    92                 ssize_t c = 0;
    93                 for () {
    94                         if (__atomic_compare_exchange_n(&this.counter, &c, c+1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
    95                                 if (c == 0) return true;
    96                                 /* paranoid */ verify(c < 0);
    97                                 return false;
    98                         } else {
    99                                 if (c == 1) return true;
    100                                 /* paranoid */ verify(c < 1);
    101                                 Pause();
    102                         }
    103                 }
    104         }
    105 }
    106 
    107 // Binary Semaphore based on the BinaryBenaphore on top of the 0-nary Semaphore
    108 struct ThreadBenaphore {
    109         BinaryBenaphore ben;
    110         Semaphore0nary  sem;
    111 };
    112 
    113 static inline void ?{}(ThreadBenaphore & this) {}
    114 static inline void ?{}(ThreadBenaphore & this, zero_t) { (this.ben){ 0 }; }
    115 static inline void ?{}(ThreadBenaphore & this, one_t ) { (this.ben){ 1 }; }
    116 
    117 static inline bool P(ThreadBenaphore & this)              { return P(this.ben) ? false : P(this.sem); }
    118 static inline bool tryP(ThreadBenaphore & this)           { return tryP(this.ben); }
    119 static inline bool P(ThreadBenaphore & this, bool wait)   { return wait ? P(this) : tryP(this); }
    120 
    121 static inline $thread * V(ThreadBenaphore & this, bool doUnpark = true) {
    122         if (V(this.ben)) return 0p;
    123         return V(this.sem, doUnpark);
    124 }
    125 
    126 //-----------------------------------------------------------------------------
    127 // Semaphore
    128 struct semaphore {
    129         __spinlock_t lock;
    130         int count;
    131         __queue_t($thread) waiting;
    132 };
    133 
    134 void  ?{}(semaphore & this, int count = 1);
    135 void ^?{}(semaphore & this);
    136 bool   P (semaphore & this);
    137 bool   V (semaphore & this);
    138 bool   V (semaphore & this, unsigned count);
    139 $thread * V (semaphore & this, bool );
    14025
    14126//----------
     
    14631static inline void  ?{}( single_acquisition_lock & this ) {((blocking_lock &)this){ false, false };}
    14732static inline void ^?{}( single_acquisition_lock & this ) {}
    148 static inline void   lock     ( single_acquisition_lock & this ) { lock    ( (blocking_lock &)this ); }
    149 static inline bool   try_lock ( single_acquisition_lock & this ) { return try_lock( (blocking_lock &)this ); }
    150 static inline void   unlock   ( single_acquisition_lock & this ) { unlock  ( (blocking_lock &)this ); }
    151 static inline size_t on_wait  ( single_acquisition_lock & this ) { return on_wait ( (blocking_lock &)this ); }
    152 static inline void   on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    153 static inline void   on_notify( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
     33static inline void   lock      ( single_acquisition_lock & this ) { lock   ( (blocking_lock &)this ); }
     34static inline void   unlock    ( single_acquisition_lock & this ) { unlock ( (blocking_lock &)this ); }
     35static inline void   on_wait   ( single_acquisition_lock & this ) { on_wait( (blocking_lock &)this ); }
     36static inline void   on_notify ( single_acquisition_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
     37static inline void   set_recursion_count( single_acquisition_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }
     38static inline size_t get_recursion_count( single_acquisition_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }
    15439
    15540//----------
     
    16045static inline void  ?{}( owner_lock & this ) {((blocking_lock &)this){ true, true };}
    16146static inline void ^?{}( owner_lock & this ) {}
    162 static inline void   lock     ( owner_lock & this ) { lock    ( (blocking_lock &)this ); }
    163 static inline bool   try_lock ( owner_lock & this ) { return try_lock( (blocking_lock &)this ); }
    164 static inline void   unlock   ( owner_lock & this ) { unlock  ( (blocking_lock &)this ); }
    165 static inline size_t on_wait  ( owner_lock & this ) { return on_wait ( (blocking_lock &)this ); }
    166 static inline void   on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
     47static inline void   lock     ( owner_lock & this ) { lock   ( (blocking_lock &)this ); }
     48static inline void   unlock   ( owner_lock & this ) { unlock ( (blocking_lock &)this ); }
     49static inline void   on_wait  ( owner_lock & this ) { on_wait( (blocking_lock &)this ); }
    16750static inline void   on_notify( owner_lock & this, struct $thread * t ) { on_notify( (blocking_lock &)this, t ); }
    168 
    169 struct fast_lock {
    170         $thread * volatile owner;
    171         ThreadBenaphore sem;
    172 };
    173 
    174 static inline bool $try_lock(fast_lock & this, $thread * thrd) {
    175     $thread * exp = 0p;
    176     return __atomic_compare_exchange_n(&this.owner, &exp, thrd, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED);
    177 }
    178 
    179 static inline void lock( fast_lock & this ) __attribute__((artificial));
    180 static inline void lock( fast_lock & this ) {
    181         $thread * thrd = active_thread();
    182         /* paranoid */verify(thrd != this.owner);
    183 
    184         for (;;) {
    185                 if ($try_lock(this, thrd)) return;
    186                 P(this.sem);
    187         }
    188 }
    189 
    190 static inline bool try_lock( fast_lock & this ) __attribute__((artificial));
    191 static inline bool try_lock ( fast_lock & this ) {
    192         $thread * thrd = active_thread();
    193         /* paranoid */ verify(thrd != this.owner);
    194         return $try_lock(this, thrd);
    195 }
    196 
    197 static inline $thread * unlock( fast_lock & this ) __attribute__((artificial));
    198 static inline $thread * unlock( fast_lock & this ) {
    199         /* paranoid */ verify(active_thread() == this.owner);
    200 
    201         // open 'owner' before unlocking anyone
    202         // so new and unlocked threads don't park incorrectly.
    203         // This may require additional fencing on ARM.
    204         this.owner = 0p;
    205 
    206         return V(this.sem);
    207 }
    208 
    209 static inline size_t on_wait( fast_lock & this ) { unlock(this); return 0; }
    210 static inline void on_wakeup( fast_lock & this, size_t ) { lock(this); }
    211 static inline void on_notify( fast_lock &, struct $thread * t ) { unpark(t); }
    212 
    213 struct mcs_node {
    214         mcs_node * volatile next;
    215         single_sem sem;
    216 };
    217 
    218 static inline void ?{}(mcs_node & this) { this.next = 0p; }
    219 
    220 static inline mcs_node * volatile & ?`next ( mcs_node * node ) {
    221         return node->next;
    222 }
    223 
    224 struct mcs_lock {
    225         mcs_queue(mcs_node) queue;
    226 };
    227 
    228 static inline void lock(mcs_lock & l, mcs_node & n) {
    229         if(push(l.queue, &n))
    230                 wait(n.sem);
    231 }
    232 
    233 static inline void unlock(mcs_lock & l, mcs_node & n) {
    234         mcs_node * next = advance(l.queue, &n);
    235         if(next) post(next->sem);
    236 }
     51static inline void   set_recursion_count( owner_lock & this, size_t recursion ) { set_recursion_count( (blocking_lock &)this, recursion ); }
     52static inline size_t get_recursion_count( owner_lock & this ) { return get_recursion_count( (blocking_lock &)this ); }
    23753
    23854//-----------------------------------------------------------------------------
     
    24359
    24460        // For synchronization locks to use when releasing
    245         size_t on_wait( L & );
     61        void on_wait( L & );
     62
     63        // to get recursion count for cond lock to reset after waking
     64        size_t get_recursion_count( L & );
    24665
    24766        // to set recursion count after getting signalled;
    248         void on_wakeup( L &, size_t recursion );
     67        void set_recursion_count( L &, size_t recursion );
    24968};
    25069
     
    300119        bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time );
    301120}
     121
     122//-----------------------------------------------------------------------------
     123// Semaphore
     124struct semaphore {
     125        __spinlock_t lock;
     126        int count;
     127        __queue_t($thread) waiting;
     128};
     129
     130void  ?{}(semaphore & this, int count = 1);
     131void ^?{}(semaphore & this);
     132bool   P (semaphore & this);
     133bool   V (semaphore & this);
     134bool   V (semaphore & this, unsigned count);
  • libcfa/src/concurrency/monitor.hfa

    r5407cdc rfeacef9  
    6161static inline forall( T & | sized(T) | { void ^?{}( T & mutex ); } )
    6262void delete( T * th ) {
    63         if(th) ^(*th){};
     63        ^(*th){};
    6464        free( th );
    6565}
  • libcfa/src/concurrency/preemption.cfa

    r5407cdc rfeacef9  
    1515
    1616#define __cforall_thread__
    17 // #define __CFA_DEBUG_PRINT_PREEMPTION__
    1817
    1918#include "preemption.hfa"
     
    2928#include "kernel_private.hfa"
    3029
    31 
    3230#if !defined(__CFA_DEFAULT_PREEMPTION__)
    3331#define __CFA_DEFAULT_PREEMPTION__ 10`ms
    3432#endif
    3533
    36 __attribute__((weak)) Duration default_preemption() {
    37         const char * preempt_rate_s = getenv("CFA_DEFAULT_PREEMPTION");
    38         if(!preempt_rate_s) {
    39                 __cfadbg_print_safe(preemption, "No CFA_DEFAULT_PREEMPTION in ENV\n");
    40                 return __CFA_DEFAULT_PREEMPTION__;
    41         }
    42 
    43         char * endptr = 0p;
    44         long int preempt_rate_l = strtol(preempt_rate_s, &endptr, 10);
    45         if(preempt_rate_l < 0 || preempt_rate_l > 65535) {
    46                 __cfadbg_print_safe(preemption, "CFA_DEFAULT_PREEMPTION out of range : %ld\n", preempt_rate_l);
    47                 return __CFA_DEFAULT_PREEMPTION__;
    48         }
    49         if('\0' != *endptr) {
    50                 __cfadbg_print_safe(preemption, "CFA_DEFAULT_PREEMPTION not a decimal number : %s\n", preempt_rate_s);
    51                 return __CFA_DEFAULT_PREEMPTION__;
    52         }
    53 
    54         return preempt_rate_l`ms;
     34Duration default_preemption() __attribute__((weak)) {
     35        return __CFA_DEFAULT_PREEMPTION__;
    5536}
    5637
     
    11798        //Loop throught every thing expired
    11899        while( node = get_expired( alarms, currtime ) ) {
    119                 __cfadbg_print_buffer_decl( preemption, " KERNEL: preemption tick %lu\n", currtime.tn);
     100                // __cfaabi_dbg_print_buffer_decl( " KERNEL: preemption tick.\n" );
    120101                Duration period = node->period;
    121102                if( period == 0) {
     
    123104                }
    124105
    125                 __cfadbg_print_buffer_local( preemption, " KERNEL: alarm ticking node %p.\n", node );
    126 
    127 
    128106                // Check if this is a kernel
    129107                if( node->type == Kernel ) {
     
    131109                }
    132110                else if( node->type == User ) {
    133                         __cfadbg_print_buffer_local( preemption, " KERNEL: alarm unparking %p.\n", node->thrd );
    134111                        timeout( node->thrd );
    135112                }
     
    140117                // Check if this is a periodic alarm
    141118                if( period > 0 ) {
    142                         __cfadbg_print_buffer_local( preemption, " KERNEL: alarm period is %lu.\n", period`ns );
     119                        // __cfaabi_dbg_print_buffer_local( " KERNEL: alarm period is %lu.\n", period.tv );
    143120                        node->alarm = currtime + period;    // Alarm is periodic, add currtime to it (used cached current time)
    144121                        insert( alarms, node );             // Reinsert the node for the next time it triggers
     
    148125        // If there are still alarms pending, reset the timer
    149126        if( & (*alarms)`first ) {
     127                __cfadbg_print_buffer_decl(preemption, " KERNEL: @%ju(%ju) resetting alarm to %ju.\n", currtime.tv, __kernel_get_time().tv, (alarms->head->alarm - currtime).tv);
    150128                Duration delta = (*alarms)`first.alarm - currtime;
    151129                Duration capped = max(delta, 50`us);
     130                // itimerval tim  = { caped };
     131                // __cfaabi_dbg_print_buffer_local( "    Values are %lu, %lu, %lu %lu.\n", delta.tv, caped.tv, tim.it_value.tv_sec, tim.it_value.tv_usec);
     132
    152133                __kernel_set_timer( capped );
    153134        }
     
    315296        // Enable interrupts by decrementing the counter
    316297        // If counter reaches 0, execute any pending __cfactx_switch
    317         void enable_interrupts( bool poll ) {
     298        void enable_interrupts( __cfaabi_dbg_ctx_param ) {
    318299                // Cache the processor now since interrupts can start happening after the atomic store
    319300                processor   * proc = __cfaabi_tls.this_processor;
    320                 /* paranoid */ verify( !poll || proc );
     301                /* paranoid */ verify( proc );
    321302
    322303                with( __cfaabi_tls.preemption_state ){
     
    340321                                // Signal the compiler that a fence is needed but only for signal handlers
    341322                                __atomic_signal_fence(__ATOMIC_RELEASE);
    342                                 if( poll && proc->pending_preemption ) {
     323                                if( proc->pending_preemption ) {
    343324                                        proc->pending_preemption = false;
    344325                                        force_yield( __POLL_PREEMPTION );
    345326                                }
    346327                        }
     328                }
     329
     330                // For debugging purposes : keep track of the last person to enable the interrupts
     331                __cfaabi_dbg_debug_do( proc->last_enable = caller; )
     332        }
     333
     334        // Disable interrupts by incrementint the counter
     335        // Don't execute any pending __cfactx_switch even if counter reaches 0
     336        void enable_interrupts_noPoll() {
     337                unsigned short prev = __cfaabi_tls.preemption_state.disable_count;
     338                __cfaabi_tls.preemption_state.disable_count -= 1;
     339                // If this triggers someone is enabled already enabled interrupts
     340                /* paranoid */ verifyf( prev != 0u, "Incremented from %u\n", prev );
     341                if( prev == 1 ) {
     342                        #if GCC_VERSION > 50000
     343                                static_assert(__atomic_always_lock_free(sizeof(__cfaabi_tls.preemption_state.enabled), &__cfaabi_tls.preemption_state.enabled), "Must be lock-free");
     344                        #endif
     345                        // Set enabled flag to true
     346                        // should be atomic to avoid preemption in the middle of the operation.
     347                        // use memory order RELAXED since there is no inter-thread on this variable requirements
     348                        __atomic_store_n(&__cfaabi_tls.preemption_state.enabled, true, __ATOMIC_RELAXED);
     349
     350                        // Signal the compiler that a fence is needed but only for signal handlers
     351                        __atomic_signal_fence(__ATOMIC_RELEASE);
    347352                }
    348353        }
     
    580585
    581586        // Setup proper signal handlers
    582         __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO ); // __cfactx_switch handler
    583         __cfaabi_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO ); // debug handler
     587        __cfaabi_sigaction( SIGUSR1, sigHandler_ctxSwitch, SA_SIGINFO | SA_RESTART ); // __cfactx_switch handler
     588        __cfaabi_sigaction( SIGALRM, sigHandler_alarm    , SA_SIGINFO | SA_RESTART ); // debug handler
    584589
    585590        signal_block( SIGALRM );
     
    684689}
    685690
     691#if !defined(__CFA_NO_STATISTICS__)
     692        int __print_alarm_stats = 0;
     693#endif
     694
    686695// Main of the alarm thread
    687696// Waits on SIGALRM and send SIGUSR1 to whom ever needs it
    688697static void * alarm_loop( __attribute__((unused)) void * args ) {
    689698        __processor_id_t id;
    690         register_proc_id(&id);
     699        id.full_proc = false;
     700        id.id = doregister(&id);
    691701        __cfaabi_tls.this_proc_id = &id;
    692702
     703        #if !defined(__CFA_NO_STATISTICS__)
     704                struct __stats_t local_stats;
     705                __cfaabi_tls.this_stats = &local_stats;
     706                __init_stats( &local_stats );
     707        #endif
    693708
    694709        // Block sigalrms to control when they arrive
     
    749764EXIT:
    750765        __cfaabi_dbg_print_safe( "Kernel : Preemption thread stopping\n" );
    751         register_proc_id(&id);
    752 
     766        unregister(&id);
     767
     768        #if !defined(__CFA_NO_STATISTICS__)
     769                if( 0 != __print_alarm_stats ) {
     770                        __print_stats( &local_stats, __print_alarm_stats, "Alarm", "Thread", 0p );
     771                }
     772        #endif
    753773        return 0p;
    754774}
  • libcfa/src/concurrency/ready_queue.cfa

    r5407cdc rfeacef9  
    1717// #define __CFA_DEBUG_PRINT_READY_QUEUE__
    1818
    19 // #define USE_MPSC
    20 
    21 #define USE_RELAXED_FIFO
    22 // #define USE_WORK_STEALING
     19// #define USE_SNZI
    2320
    2421#include "bits/defs.hfa"
     
    3128#include <unistd.h>
    3229
     30#include "snzi.hfa"
    3331#include "ready_subqueue.hfa"
    3432
    3533static const size_t cache_line_size = 64;
    36 
    37 #if !defined(__CFA_NO_STATISTICS__)
    38         #define __STATS(...) __VA_ARGS__
    39 #else
    40         #define __STATS(...)
    41 #endif
    4234
    4335// No overriden function, no environment variable, no define
     
    4739#endif
    4840
    49 #if   defined(USE_RELAXED_FIFO)
    50         #define BIAS 4
    51         #define READYQ_SHARD_FACTOR 4
    52         #define SEQUENTIAL_SHARD 1
    53 #elif defined(USE_WORK_STEALING)
    54         #define READYQ_SHARD_FACTOR 2
    55         #define SEQUENTIAL_SHARD 2
    56 #else
    57         #error no scheduling strategy selected
    58 #endif
    59 
    60 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats));
    61 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats));
    62 static inline struct $thread * search(struct cluster * cltr);
    63 static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred);
    64 
     41#define BIAS 16
    6542
    6643// returns the maximum number of processors the RWLock support
     
    11693//=======================================================================
    11794// Lock-Free registering/unregistering of threads
    118 void register_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     95unsigned doregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {
    11996        __cfadbg_print_safe(ready_queue, "Kernel : Registering proc %p for RW-Lock\n", proc);
    12097
     
    130107                        /*paranoid*/ verify(0 == (__alignof__(data[i]) % cache_line_size));
    131108                        /*paranoid*/ verify((((uintptr_t)&data[i]) % cache_line_size) == 0);
    132                         proc->id = i;
     109                        return i;
    133110                }
    134111        }
     
    157134        /*paranoid*/ verify(__alignof__(data[n]) == (2 * cache_line_size));
    158135        /*paranoid*/ verify((((uintptr_t)&data[n]) % cache_line_size) == 0);
    159         proc->id = n;
    160 }
    161 
    162 void unregister_proc_id( struct __processor_id_t * proc ) with(*__scheduler_lock) {
     136        return n;
     137}
     138
     139void unregister( struct __processor_id_t * proc ) with(*__scheduler_lock) {
    163140        unsigned id = proc->id;
    164141        /*paranoid*/ verify(id < ready);
     
    215192
    216193//=======================================================================
    217 // Cforall Ready Queue used for scheduling
     194// Cforall Reqdy Queue used for scheduling
    218195//=======================================================================
    219196void ?{}(__ready_queue_t & this) with (this) {
    220197        lanes.data  = 0p;
    221         lanes.tscs  = 0p;
    222198        lanes.count = 0;
    223199}
    224200
    225201void ^?{}(__ready_queue_t & this) with (this) {
    226         verify( SEQUENTIAL_SHARD == lanes.count );
     202        verify( 1 == lanes.count );
     203        #ifdef USE_SNZI
     204                verify( !query( snzi ) );
     205        #endif
    227206        free(lanes.data);
    228         free(lanes.tscs);
    229207}
    230208
    231209//-----------------------------------------------------------------------
    232 #if defined(USE_RELAXED_FIFO)
    233         //-----------------------------------------------------------------------
    234         // get index from random number with or without bias towards queues
    235         static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
    236                 unsigned i;
    237                 bool local;
     210__attribute__((hot)) bool query(struct cluster * cltr) {
     211        #ifdef USE_SNZI
     212                return query(cltr->ready_queue.snzi);
     213        #endif
     214        return true;
     215}
     216
     217static inline [unsigned, bool] idx_from_r(unsigned r, unsigned preferred) {
     218        unsigned i;
     219        bool local;
     220        #if defined(BIAS)
    238221                unsigned rlow  = r % BIAS;
    239222                unsigned rhigh = r / BIAS;
     
    241224                        // (BIAS - 1) out of BIAS chances
    242225                        // Use perferred queues
    243                         i = preferred + (rhigh % READYQ_SHARD_FACTOR);
     226                        i = preferred + (rhigh % 4);
    244227                        local = true;
    245228                }
     
    250233                        local = false;
    251234                }
    252                 return [i, local];
    253         }
    254 
    255         __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
    256                 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    257 
    258                 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
    259                 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
    260 
    261                 // write timestamp
    262                 thrd->link.ts = rdtscl();
    263 
    264                 bool local;
    265                 int preferred = external ? -1 : kernelTLS().this_processor->rdq.id;
    266 
    267                 // Try to pick a lane and lock it
    268                 unsigned i;
    269                 do {
    270                         // Pick the index of a lane
    271                         unsigned r = __tls_rand_fwd();
    272                         [i, local] = idx_from_r(r, preferred);
    273 
    274                         i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    275 
    276                         #if !defined(__CFA_NO_STATISTICS__)
    277                                 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED);
    278                                 else if(local) __tls_stats()->ready.push.local.attempt++;
    279                                 else __tls_stats()->ready.push.share.attempt++;
     235        #else
     236                i = r;
     237                local = false;
     238        #endif
     239        return [i, local];
     240}
     241
     242//-----------------------------------------------------------------------
     243__attribute__((hot)) bool push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
     244        __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
     245
     246        // write timestamp
     247        thrd->link.ts = rdtscl();
     248
     249        __attribute__((unused)) bool local;
     250        __attribute__((unused)) int preferred;
     251        #if defined(BIAS)
     252                preferred =
     253                        //*
     254                        kernelTLS().this_processor ? kernelTLS().this_processor->id * 4 : -1;
     255                        /*/
     256                        thrd->link.preferred * 4;
     257                        //*/
     258        #endif
     259
     260        // Try to pick a lane and lock it
     261        unsigned i;
     262        do {
     263                // Pick the index of a lane
     264                // unsigned r = __tls_rand();
     265                unsigned r = __tls_rand_fwd();
     266                [i, local] = idx_from_r(r, preferred);
     267
     268                #if !defined(__CFA_NO_STATISTICS__)
     269                        if(local) {
     270                                __tls_stats()->ready.pick.push.local++;
     271                        }
     272                #endif
     273
     274                i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     275
     276                #if !defined(__CFA_NO_STATISTICS__)
     277                        __tls_stats()->ready.pick.push.attempt++;
     278                #endif
     279
     280                // If we can't lock it retry
     281        } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
     282
     283        bool first = false;
     284
     285        // Actually push it
     286        #ifdef USE_SNZI
     287                bool lane_first =
     288        #endif
     289
     290        push(lanes.data[i], thrd);
     291
     292        #ifdef USE_SNZI
     293                // If this lane used to be empty we need to do more
     294                if(lane_first) {
     295                        // Check if the entire queue used to be empty
     296                        first = !query(snzi);
     297
     298                        // Update the snzi
     299                        arrive( snzi, i );
     300                }
     301        #endif
     302
     303        __tls_rand_advance_bck();
     304
     305        // Unlock and return
     306        __atomic_unlock( &lanes.data[i].lock );
     307
     308        __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
     309
     310        // Update statistics
     311        #if !defined(__CFA_NO_STATISTICS__)
     312                #if defined(BIAS)
     313                        if( local ) __tls_stats()->ready.pick.push.lsuccess++;
     314                #endif
     315                __tls_stats()->ready.pick.push.success++;
     316        #endif
     317
     318        // return whether or not the list was empty before this push
     319        return first;
     320}
     321
     322static struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j);
     323static struct $thread * try_pop(struct cluster * cltr, unsigned i);
     324
     325// Pop from the ready queue from a given cluster
     326__attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) {
     327        /* paranoid */ verify( lanes.count > 0 );
     328        unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     329        int preferred;
     330        #if defined(BIAS)
     331                // Don't bother trying locally too much
     332                int local_tries = 8;
     333                preferred = kernelTLS().this_processor->id * 4;
     334        #endif
     335
     336
     337        // As long as the list is not empty, try finding a lane that isn't empty and pop from it
     338        #ifdef USE_SNZI
     339                while( query(snzi) ) {
     340        #else
     341                for(25) {
     342        #endif
     343                // Pick two lists at random
     344                // unsigned ri = __tls_rand();
     345                // unsigned rj = __tls_rand();
     346                unsigned ri = __tls_rand_bck();
     347                unsigned rj = __tls_rand_bck();
     348
     349                unsigned i, j;
     350                __attribute__((unused)) bool locali, localj;
     351                [i, locali] = idx_from_r(ri, preferred);
     352                [j, localj] = idx_from_r(rj, preferred);
     353
     354                #if !defined(__CFA_NO_STATISTICS__)
     355                        if(locali) {
     356                                __tls_stats()->ready.pick.pop.local++;
     357                        }
     358                        if(localj) {
     359                                __tls_stats()->ready.pick.pop.local++;
     360                        }
     361                #endif
     362
     363                i %= count;
     364                j %= count;
     365
     366                // try popping from the 2 picked lists
     367                struct $thread * thrd = try_pop(cltr, i, j);
     368                if(thrd) {
     369                        #if defined(BIAS) && !defined(__CFA_NO_STATISTICS__)
     370                                if( locali || localj ) __tls_stats()->ready.pick.pop.lsuccess++;
    280371                        #endif
    281 
    282                 #if defined(USE_MPSC)
    283                         // mpsc always succeeds
    284                 } while( false );
    285                 #else
    286                         // If we can't lock it retry
    287                 } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
    288                 #endif
    289 
    290                 // Actually push it
    291                 push(lanes.data[i], thrd);
    292 
    293                 #if !defined(USE_MPSC)
    294                         // Unlock and return
    295                         __atomic_unlock( &lanes.data[i].lock );
    296                 #endif
    297 
    298                 // Mark the current index in the tls rng instance as having an item
    299                 __tls_rand_advance_bck();
    300 
    301                 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
    302 
    303                 // Update statistics
    304                 #if !defined(__CFA_NO_STATISTICS__)
    305                         if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED);
    306                         else if(local) __tls_stats()->ready.push.local.success++;
    307                         else __tls_stats()->ready.push.share.success++;
    308                 #endif
    309         }
    310 
    311         // Pop from the ready queue from a given cluster
    312         __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
    313                 /* paranoid */ verify( lanes.count > 0 );
    314                 /* paranoid */ verify( kernelTLS().this_processor );
    315                 /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
    316 
    317                 unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
    318                 int preferred = kernelTLS().this_processor->rdq.id;
    319 
    320 
    321                 // As long as the list is not empty, try finding a lane that isn't empty and pop from it
    322                 for(25) {
    323                         // Pick two lists at random
    324                         unsigned ri = __tls_rand_bck();
    325                         unsigned rj = __tls_rand_bck();
    326 
    327                         unsigned i, j;
    328                         __attribute__((unused)) bool locali, localj;
    329                         [i, locali] = idx_from_r(ri, preferred);
    330                         [j, localj] = idx_from_r(rj, preferred);
    331 
    332                         i %= count;
    333                         j %= count;
    334 
    335                         // try popping from the 2 picked lists
    336                         struct $thread * thrd = try_pop(cltr, i, j __STATS(, *(locali || localj ? &__tls_stats()->ready.pop.local : &__tls_stats()->ready.pop.help)));
    337                         if(thrd) {
    338                                 return thrd;
    339                         }
    340                 }
    341 
    342                 // All lanes where empty return 0p
    343                 return 0p;
    344         }
    345 
    346         __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) { return pop_fast(cltr); }
    347         __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr) {
    348                 return search(cltr);
    349         }
    350 #endif
    351 #if defined(USE_WORK_STEALING)
    352         __attribute__((hot)) void push(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
    353                 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr);
    354 
    355                 const bool external = (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);
    356                 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count );
    357 
    358                 // write timestamp
    359                 thrd->link.ts = rdtscl();
    360 
    361                 // Try to pick a lane and lock it
    362                 unsigned i;
    363                 do {
    364                         #if !defined(__CFA_NO_STATISTICS__)
    365                                 if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.attempt, 1, __ATOMIC_RELAXED);
    366                                 else __tls_stats()->ready.push.local.attempt++;
    367                         #endif
    368 
    369                         if(unlikely(external)) {
    370                                 i = __tls_rand() % lanes.count;
    371                         }
    372                         else {
    373                                 processor * proc = kernelTLS().this_processor;
    374                                 unsigned r = proc->rdq.its++;
    375                                 i =  proc->rdq.id + (r % READYQ_SHARD_FACTOR);
    376                         }
    377 
    378 
    379                 #if defined(USE_MPSC)
    380                         // mpsc always succeeds
    381                 } while( false );
    382                 #else
    383                         // If we can't lock it retry
    384                 } while( !__atomic_try_acquire( &lanes.data[i].lock ) );
    385                 #endif
    386 
    387                 // Actually push it
    388                 push(lanes.data[i], thrd);
    389 
    390                 #if !defined(USE_MPSC)
    391                         // Unlock and return
    392                         __atomic_unlock( &lanes.data[i].lock );
    393                 #endif
    394 
    395                 #if !defined(__CFA_NO_STATISTICS__)
    396                         if(unlikely(external)) __atomic_fetch_add(&cltr->stats->ready.push.extrn.success, 1, __ATOMIC_RELAXED);
    397                         else __tls_stats()->ready.push.local.success++;
    398                 #endif
    399 
    400                 __cfadbg_print_safe(ready_queue, "Kernel : Pushed %p on cluster %p (idx: %u, mask %llu, first %d)\n", thrd, cltr, i, used.mask[0], lane_first);
    401         }
    402 
    403         // Pop from the ready queue from a given cluster
    404         __attribute__((hot)) $thread * pop_fast(struct cluster * cltr) with (cltr->ready_queue) {
    405                 /* paranoid */ verify( lanes.count > 0 );
    406                 /* paranoid */ verify( kernelTLS().this_processor );
    407                 /* paranoid */ verify( kernelTLS().this_processor->rdq.id < lanes.count );
    408 
    409                 processor * proc = kernelTLS().this_processor;
    410 
    411                 if(proc->rdq.target == -1u) {
    412                         proc->rdq.target = __tls_rand() % lanes.count;
    413                         unsigned it1  = proc->rdq.itr;
    414                         unsigned it2  = proc->rdq.itr + 1;
    415                         unsigned idx1 = proc->rdq.id + (it1 % READYQ_SHARD_FACTOR);
    416                         unsigned idx2 = proc->rdq.id + (it2 % READYQ_SHARD_FACTOR);
    417                         unsigned long long tsc1 = ts(lanes.data[idx1]);
    418                         unsigned long long tsc2 = ts(lanes.data[idx2]);
    419                         proc->rdq.cutoff = min(tsc1, tsc2);
    420                         if(proc->rdq.cutoff == 0) proc->rdq.cutoff = -1ull;
    421                 }
    422                 else {
    423                         unsigned target = proc->rdq.target;
    424                         proc->rdq.target = -1u;
    425                         if(lanes.tscs[target].tv < proc->rdq.cutoff) {
    426                                 $thread * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help));
    427                                 if(t) return t;
    428                         }
    429                 }
    430 
    431                 for(READYQ_SHARD_FACTOR) {
    432                         unsigned i = proc->rdq.id + (--proc->rdq.itr % READYQ_SHARD_FACTOR);
    433                         if($thread * t = try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.local))) return t;
    434                 }
    435                 return 0p;
    436         }
    437 
    438         __attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
    439                 unsigned i = __tls_rand() % lanes.count;
    440                 return try_pop(cltr, i __STATS(, __tls_stats()->ready.pop.steal));
    441         }
    442 
    443         __attribute__((hot)) struct $thread * pop_search(struct cluster * cltr) with (cltr->ready_queue) {
    444                 return search(cltr);
    445         }
    446 #endif
    447 
    448 //=======================================================================
    449 // Various Ready Queue utilities
    450 //=======================================================================
    451 // these function work the same or almost the same
    452 // whether they are using work-stealing or relaxed fifo scheduling
    453 
    454 //-----------------------------------------------------------------------
    455 // try to pop from a lane given by index w
    456 static inline struct $thread * try_pop(struct cluster * cltr, unsigned w __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) {
    457         __STATS( stats.attempt++; )
    458 
    459         // Get relevant elements locally
    460         __intrusive_lane_t & lane = lanes.data[w];
    461 
    462         // If list looks empty retry
    463         if( is_empty(lane) ) {
    464                 __STATS( stats.espec++; )
    465                 return 0p;
    466         }
    467 
    468         // If we can't get the lock retry
    469         if( !__atomic_try_acquire(&lane.lock) ) {
    470                 __STATS( stats.elock++; )
    471                 return 0p;
    472         }
    473 
    474         // If list is empty, unlock and retry
    475         if( is_empty(lane) ) {
    476                 __atomic_unlock(&lane.lock);
    477                 __STATS( stats.eempty++; )
    478                 return 0p;
    479         }
    480 
    481         // Actually pop the list
    482         struct $thread * thrd;
    483         thrd = pop(lane);
    484 
    485         /* paranoid */ verify(thrd);
    486         /* paranoid */ verify(lane.lock);
    487 
    488         // Unlock and return
    489         __atomic_unlock(&lane.lock);
    490 
    491         // Update statistics
    492         __STATS( stats.success++; )
    493 
    494         #if defined(USE_WORK_STEALING)
    495                 lanes.tscs[w].tv = thrd->link.ts;
    496         #endif
    497 
    498         // return the popped thread
    499         return thrd;
    500 }
    501 
    502 //-----------------------------------------------------------------------
    503 // try to pop from any lanes making sure you don't miss any threads push
    504 // before the start of the function
    505 static inline struct $thread * search(struct cluster * cltr) with (cltr->ready_queue) {
     372                        return thrd;
     373                }
     374        }
     375
     376        // All lanes where empty return 0p
     377        return 0p;
     378}
     379
     380__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
    506381        /* paranoid */ verify( lanes.count > 0 );
    507382        unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
     
    509384        for(i; count) {
    510385                unsigned idx = (offset + i) % count;
    511                 struct $thread * thrd = try_pop(cltr, idx __STATS(, __tls_stats()->ready.pop.search));
     386                struct $thread * thrd = try_pop(cltr, idx);
    512387                if(thrd) {
    513388                        return thrd;
     
    519394}
    520395
     396
    521397//-----------------------------------------------------------------------
    522 // Check that all the intrusive queues in the data structure are still consistent
     398// Given 2 indexes, pick the list with the oldest push an try to pop from it
     399static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j) with (cltr->ready_queue) {
     400        #if !defined(__CFA_NO_STATISTICS__)
     401                __tls_stats()->ready.pick.pop.attempt++;
     402        #endif
     403
     404        // Pick the bet list
     405        int w = i;
     406        if( __builtin_expect(!is_empty(lanes.data[j]), true) ) {
     407                w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j;
     408        }
     409
     410        return try_pop(cltr, w);
     411}
     412
     413static inline struct $thread * try_pop(struct cluster * cltr, unsigned w) with (cltr->ready_queue) {
     414        // Get relevant elements locally
     415        __intrusive_lane_t & lane = lanes.data[w];
     416
     417        // If list looks empty retry
     418        if( is_empty(lane) ) return 0p;
     419
     420        // If we can't get the lock retry
     421        if( !__atomic_try_acquire(&lane.lock) ) return 0p;
     422
     423
     424        // If list is empty, unlock and retry
     425        if( is_empty(lane) ) {
     426                __atomic_unlock(&lane.lock);
     427                return 0p;
     428        }
     429
     430        // Actually pop the list
     431        struct $thread * thrd;
     432        thrd = pop(lane);
     433
     434        /* paranoid */ verify(thrd);
     435        /* paranoid */ verify(lane.lock);
     436
     437        #ifdef USE_SNZI
     438                // If this was the last element in the lane
     439                if(emptied) {
     440                        depart( snzi, w );
     441                }
     442        #endif
     443
     444        // Unlock and return
     445        __atomic_unlock(&lane.lock);
     446
     447        // Update statistics
     448        #if !defined(__CFA_NO_STATISTICS__)
     449                __tls_stats()->ready.pick.pop.success++;
     450        #endif
     451
     452        // Update the thread bias
     453        thrd->link.preferred = w / 4;
     454
     455        // return the popped thread
     456        return thrd;
     457}
     458//-----------------------------------------------------------------------
     459
     460bool remove_head(struct cluster * cltr, struct $thread * thrd) with (cltr->ready_queue) {
     461        for(i; lanes.count) {
     462                __intrusive_lane_t & lane = lanes.data[i];
     463
     464                bool removed = false;
     465
     466                __atomic_acquire(&lane.lock);
     467                        if(head(lane)->link.next == thrd) {
     468                                $thread * pthrd;
     469                                pthrd = pop(lane);
     470
     471                                /* paranoid */ verify( pthrd == thrd );
     472
     473                                removed = true;
     474                                #ifdef USE_SNZI
     475                                        if(emptied) {
     476                                                depart( snzi, i );
     477                                        }
     478                                #endif
     479                        }
     480                __atomic_unlock(&lane.lock);
     481
     482                if( removed ) return true;
     483        }
     484        return false;
     485}
     486
     487//-----------------------------------------------------------------------
     488
    523489static void check( __ready_queue_t & q ) with (q) {
    524         #if defined(__CFA_WITH_VERIFY__) && !defined(USE_MPSC)
     490        #if defined(__CFA_WITH_VERIFY__)
    525491                {
    526492                        for( idx ; lanes.count ) {
     
    533499                                assert(tail(sl)->link.prev->link.next == tail(sl) );
    534500
    535                                 if(is_empty(sl)) {
     501                                if(sl.before.link.ts == 0l) {
    536502                                        assert(tail(sl)->link.prev == head(sl));
    537503                                        assert(head(sl)->link.next == tail(sl));
     
    545511}
    546512
    547 //-----------------------------------------------------------------------
    548 // Given 2 indexes, pick the list with the oldest push an try to pop from it
    549 static inline struct $thread * try_pop(struct cluster * cltr, unsigned i, unsigned j __STATS(, __stats_readyQ_pop_t & stats)) with (cltr->ready_queue) {
    550         // Pick the bet list
    551         int w = i;
    552         if( __builtin_expect(!is_empty(lanes.data[j]), true) ) {
    553                 w = (ts(lanes.data[i]) < ts(lanes.data[j])) ? i : j;
    554         }
    555 
    556         return try_pop(cltr, w __STATS(, stats));
    557 }
    558 
    559513// Call this function of the intrusive list was moved using memcpy
    560514// fixes the list so that the pointers back to anchors aren't left dangling
    561515static inline void fix(__intrusive_lane_t & ll) {
    562         #if !defined(USE_MPSC)
    563                 // if the list is not empty then follow he pointer and fix its reverse
    564                 if(!is_empty(ll)) {
    565                         head(ll)->link.next->link.prev = head(ll);
    566                         tail(ll)->link.prev->link.next = tail(ll);
    567                 }
    568                 // Otherwise just reset the list
    569                 else {
    570                         verify(tail(ll)->link.next == 0p);
    571                         tail(ll)->link.prev = head(ll);
    572                         head(ll)->link.next = tail(ll);
    573                         verify(head(ll)->link.prev == 0p);
    574                 }
    575         #endif
    576 }
    577 
    578 static void assign_list(unsigned & value, dlist(processor, processor) & list, unsigned count) {
    579         processor * it = &list`first;
    580         for(unsigned i = 0; i < count; i++) {
    581                 /* paranoid */ verifyf( it, "Unexpected null iterator, at index %u of %u\n", i, count);
    582                 it->rdq.id = value;
    583                 it->rdq.target = -1u;
    584                 value += READYQ_SHARD_FACTOR;
    585                 it = &(*it)`next;
    586         }
    587 }
    588 
    589 static void reassign_cltr_id(struct cluster * cltr) {
    590         unsigned preferred = 0;
    591         assign_list(preferred, cltr->procs.actives, cltr->procs.total - cltr->procs.idle);
    592         assign_list(preferred, cltr->procs.idles  , cltr->procs.idle );
    593 }
    594 
    595 static void fix_times( struct cluster * cltr ) with( cltr->ready_queue ) {
    596         #if defined(USE_WORK_STEALING)
    597                 lanes.tscs = alloc(lanes.count, lanes.tscs`realloc);
    598                 for(i; lanes.count) {
    599                         lanes.tscs[i].tv = ts(lanes.data[i]);
    600                 }
    601         #endif
     516        // if the list is not empty then follow he pointer and fix its reverse
     517        if(!is_empty(ll)) {
     518                head(ll)->link.next->link.prev = head(ll);
     519                tail(ll)->link.prev->link.next = tail(ll);
     520        }
     521        // Otherwise just reset the list
     522        else {
     523                verify(tail(ll)->link.next == 0p);
     524                tail(ll)->link.prev = head(ll);
     525                head(ll)->link.next = tail(ll);
     526                verify(head(ll)->link.prev == 0p);
     527        }
    602528}
    603529
    604530// Grow the ready queue
    605 void ready_queue_grow(struct cluster * cltr) {
    606         size_t ncount;
    607         int target = cltr->procs.total;
    608 
     531void ready_queue_grow  (struct cluster * cltr, int target) {
    609532        /* paranoid */ verify( ready_mutate_islocked() );
    610533        __cfadbg_print_safe(ready_queue, "Kernel : Growing ready queue\n");
     
    615538        // grow the ready queue
    616539        with( cltr->ready_queue ) {
     540                #ifdef USE_SNZI
     541                        ^(snzi){};
     542                #endif
     543
    617544                // Find new count
    618545                // Make sure we always have atleast 1 list
    619                 if(target >= 2) {
    620                         ncount = target * READYQ_SHARD_FACTOR;
    621                 } else {
    622                         ncount = SEQUENTIAL_SHARD;
    623                 }
     546                size_t ncount = target >= 2 ? target * 4: 1;
    624547
    625548                // Allocate new array (uses realloc and memcpies the data)
     
    638561                // Update original
    639562                lanes.count = ncount;
    640         }
    641 
    642         fix_times(cltr);
    643 
    644         reassign_cltr_id(cltr);
     563
     564                #ifdef USE_SNZI
     565                        // Re-create the snzi
     566                        snzi{ log2( lanes.count / 8 ) };
     567                        for( idx; (size_t)lanes.count ) {
     568                                if( !is_empty(lanes.data[idx]) ) {
     569                                        arrive(snzi, idx);
     570                                }
     571                        }
     572                #endif
     573        }
    645574
    646575        // Make sure that everything is consistent
     
    653582
    654583// Shrink the ready queue
    655 void ready_queue_shrink(struct cluster * cltr) {
     584void ready_queue_shrink(struct cluster * cltr, int target) {
    656585        /* paranoid */ verify( ready_mutate_islocked() );
    657586        __cfadbg_print_safe(ready_queue, "Kernel : Shrinking ready queue\n");
     
    660589        /* paranoid */ check( cltr->ready_queue );
    661590
    662         int target = cltr->procs.total;
    663 
    664591        with( cltr->ready_queue ) {
     592                #ifdef USE_SNZI
     593                        ^(snzi){};
     594                #endif
     595
    665596                // Remember old count
    666597                size_t ocount = lanes.count;
     
    668599                // Find new count
    669600                // Make sure we always have atleast 1 list
    670                 lanes.count = target >= 2 ? target * READYQ_SHARD_FACTOR: SEQUENTIAL_SHARD;
     601                lanes.count = target >= 2 ? target * 4: 1;
    671602                /* paranoid */ verify( ocount >= lanes.count );
    672                 /* paranoid */ verify( lanes.count == target * READYQ_SHARD_FACTOR || target < 2 );
     603                /* paranoid */ verify( lanes.count == target * 4 || target < 2 );
    673604
    674605                // for printing count the number of displaced threads
     
    713644                        fix(lanes.data[idx]);
    714645                }
    715         }
    716 
    717         fix_times(cltr);
    718 
    719         reassign_cltr_id(cltr);
     646
     647                #ifdef USE_SNZI
     648                        // Re-create the snzi
     649                        snzi{ log2( lanes.count / 8 ) };
     650                        for( idx; (size_t)lanes.count ) {
     651                                if( !is_empty(lanes.data[idx]) ) {
     652                                        arrive(snzi, idx);
     653                                }
     654                        }
     655                #endif
     656        }
    720657
    721658        // Make sure that everything is consistent
  • libcfa/src/concurrency/ready_subqueue.hfa

    r5407cdc rfeacef9  
    22
    33#define __CFA_NO_SCHED_STATS__
    4 
    5 #include "containers/queueLockFree.hfa"
    64
    75// Intrusives lanes which are used by the relaxed ready queue
    86struct __attribute__((aligned(128))) __intrusive_lane_t {
    97
    10         #if defined(USE_MPSC)
    11                 mpsc_queue($thread) queue;
    12                 __attribute__((aligned(128)))
    13         #else
    14                 // anchor for the head and the tail of the queue
    15                 __attribute__((aligned(128))) struct __sentinel_t {
    16                         // Link lists fields
    17                         // instrusive link field for threads
    18                         // must be exactly as in $thread
    19                         __thread_desc_link link;
    20                 } before, after;
    21         #endif
     8        // anchor for the head and the tail of the queue
     9        __attribute__((aligned(128))) struct __sentinel_t {
     10                // Link lists fields
     11                // instrusive link field for threads
     12                // must be exactly as in $thread
     13                __thread_desc_link link;
     14        } before, after;
    2215
    2316        // spin lock protecting the queue
     
    4235// Get the head pointer (one before the first element) from the anchor
    4336static inline $thread * head(const __intrusive_lane_t & this) {
    44         #if defined(USE_MPSC)
    45                 return this.queue.head;
    46         #else
    47                 $thread * rhead = ($thread *)(
    48                         (uintptr_t)( &this.before ) - offsetof( $thread, link )
    49                 );
    50                 /* paranoid */ verify(rhead);
    51                 return rhead;
    52         #endif
     37        $thread * rhead = ($thread *)(
     38                (uintptr_t)( &this.before ) - offsetof( $thread, link )
     39        );
     40        /* paranoid */ verify(rhead);
     41        return rhead;
    5342}
    5443
    5544// Get the tail pointer (one after the last element) from the anchor
    5645static inline $thread * tail(const __intrusive_lane_t & this) {
    57         #if defined(USE_MPSC)
    58                 return this.queue.tail;
    59         #else
    60                 $thread * rtail = ($thread *)(
    61                         (uintptr_t)( &this.after ) - offsetof( $thread, link )
    62                 );
    63                 /* paranoid */ verify(rtail);
    64                 return rtail;
    65         #endif
     46        $thread * rtail = ($thread *)(
     47                (uintptr_t)( &this.after ) - offsetof( $thread, link )
     48        );
     49        /* paranoid */ verify(rtail);
     50        return rtail;
    6651}
    6752
     
    7055        this.lock = false;
    7156
    72         #if !defined(USE_MPSC)
    73                 this.before.link.prev = 0p;
    74                 this.before.link.next = tail(this);
    75                 this.before.link.ts   = 0;
    76 
    77                 this.after .link.prev = head(this);
    78                 this.after .link.next = 0p;
    79                 this.after .link.ts   = 0;
    80 
    81                 #if !defined(__CFA_NO_SCHED_STATS__)
    82                         this.stat.diff = 0;
    83                         this.stat.push = 0;
    84                         this.stat.pop  = 0;
    85                 #endif
    86 
    87                 // We add a boat-load of assertions here because the anchor code is very fragile
    88                 /* paranoid */ verify(((uintptr_t)( head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.before));
    89                 /* paranoid */ verify(((uintptr_t)( tail(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.after ));
    90                 /* paranoid */ verify(head(this)->link.prev == 0p );
    91                 /* paranoid */ verify(head(this)->link.next == tail(this) );
    92                 /* paranoid */ verify(tail(this)->link.next == 0p );
    93                 /* paranoid */ verify(tail(this)->link.prev == head(this) );
    94                 /* paranoid */ verify(&head(this)->link.prev == &this.before.link.prev );
    95                 /* paranoid */ verify(&head(this)->link.next == &this.before.link.next );
    96                 /* paranoid */ verify(&tail(this)->link.prev == &this.after .link.prev );
    97                 /* paranoid */ verify(&tail(this)->link.next == &this.after .link.next );
    98                 /* paranoid */ verify(__alignof__(__intrusive_lane_t) == 128);
    99                 /* paranoid */ verify(__alignof__(this) == 128);
    100                 /* paranoid */ verifyf(((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128));
    101         #endif
     57        this.before.link.prev = 0p;
     58        this.before.link.next = tail(this);
     59        this.before.link.ts   = 0;
     60
     61        this.after .link.prev = head(this);
     62        this.after .link.next = 0p;
     63        this.after .link.ts   = 0;
     64
     65        #if !defined(__CFA_NO_SCHED_STATS__)
     66                this.stat.diff = 0;
     67                this.stat.push = 0;
     68                this.stat.pop  = 0;
     69        #endif
     70
     71        // We add a boat-load of assertions here because the anchor code is very fragile
     72        /* paranoid */ verify(((uintptr_t)( head(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.before));
     73        /* paranoid */ verify(((uintptr_t)( tail(this) ) + offsetof( $thread, link )) == (uintptr_t)(&this.after ));
     74        /* paranoid */ verify(head(this)->link.prev == 0p );
     75        /* paranoid */ verify(head(this)->link.next == tail(this) );
     76        /* paranoid */ verify(tail(this)->link.next == 0p );
     77        /* paranoid */ verify(tail(this)->link.prev == head(this) );
     78        /* paranoid */ verify(&head(this)->link.prev == &this.before.link.prev );
     79        /* paranoid */ verify(&head(this)->link.next == &this.before.link.next );
     80        /* paranoid */ verify(&tail(this)->link.prev == &this.after .link.prev );
     81        /* paranoid */ verify(&tail(this)->link.next == &this.after .link.next );
     82        /* paranoid */ verify(__alignof__(__intrusive_lane_t) == 128);
     83        /* paranoid */ verify(__alignof__(this) == 128);
     84        /* paranoid */ verifyf(((intptr_t)(&this) % 128) == 0, "Expected address to be aligned %p %% 128 == %zd", &this, ((intptr_t)(&this) % 128));
    10285}
    10386
    10487// Dtor is trivial
    10588void ^?{}( __intrusive_lane_t & this ) {
    106         #if !defined(USE_MPSC)
    107                 // Make sure the list is empty
    108                 /* paranoid */ verify(head(this)->link.prev == 0p );
    109                 /* paranoid */ verify(head(this)->link.next == tail(this) );
    110                 /* paranoid */ verify(tail(this)->link.next == 0p );
    111                 /* paranoid */ verify(tail(this)->link.prev == head(this) );
    112         #endif
     89        // Make sure the list is empty
     90        /* paranoid */ verify(head(this)->link.prev == 0p );
     91        /* paranoid */ verify(head(this)->link.next == tail(this) );
     92        /* paranoid */ verify(tail(this)->link.next == 0p );
     93        /* paranoid */ verify(tail(this)->link.prev == head(this) );
    11394}
    11495
     
    11697// returns true of lane was empty before push, false otherwise
    11798bool push(__intrusive_lane_t & this, $thread * node) {
    118         #if defined(USE_MPSC)
    119                 inline $thread * volatile & ?`next ( $thread * this )  __attribute__((const)) {
    120                         return this->link.next;
     99        #if defined(__CFA_WITH_VERIFY__)
     100                /* paranoid */ verify(this.lock);
     101                /* paranoid */ verify(node->link.ts != 0);
     102                /* paranoid */ verify(node->link.next == 0p);
     103                /* paranoid */ verify(node->link.prev == 0p);
     104                /* paranoid */ verify(tail(this)->link.next == 0p);
     105                /* paranoid */ verify(head(this)->link.prev == 0p);
     106
     107                if(this.before.link.ts == 0l) {
     108                        /* paranoid */ verify(tail(this)->link.prev == head(this));
     109                        /* paranoid */ verify(head(this)->link.next == tail(this));
     110                } else {
     111                        /* paranoid */ verify(tail(this)->link.prev != head(this));
     112                        /* paranoid */ verify(head(this)->link.next != tail(this));
    121113                }
    122                 push(this.queue, node);
    123         #else
    124                 #if defined(__CFA_WITH_VERIFY__)
    125                         /* paranoid */ verify(this.lock);
    126                         /* paranoid */ verify(node->link.ts != 0);
    127                         /* paranoid */ verify(node->link.next == 0p);
    128                         /* paranoid */ verify(node->link.prev == 0p);
    129                         /* paranoid */ verify(tail(this)->link.next == 0p);
    130                         /* paranoid */ verify(head(this)->link.prev == 0p);
    131 
    132                         if(this.before.link.ts == 0l) {
    133                                 /* paranoid */ verify(tail(this)->link.prev == head(this));
    134                                 /* paranoid */ verify(head(this)->link.next == tail(this));
    135                         } else {
    136                                 /* paranoid */ verify(tail(this)->link.prev != head(this));
    137                                 /* paranoid */ verify(head(this)->link.next != tail(this));
    138                         }
    139                 #endif
    140 
    141                 // Get the relevant nodes locally
    142                 $thread * tail = tail(this);
    143                 $thread * prev = tail->link.prev;
    144 
    145                 // Do the push
    146                 node->link.next = tail;
    147                 node->link.prev = prev;
    148                 prev->link.next = node;
    149                 tail->link.prev = node;
    150 
    151                 // Update stats
    152                 #if !defined(__CFA_NO_SCHED_STATS__)
    153                         this.stat.diff++;
    154                         this.stat.push++;
    155                 #endif
    156 
    157                 verify(node->link.next == tail(this));
    158 
    159                 // Check if the queue used to be empty
    160                 if(this.before.link.ts == 0l) {
    161                         this.before.link.ts = node->link.ts;
    162                         /* paranoid */ verify(node->link.prev == head(this));
    163                         return true;
    164                 }
    165                 return false;
    166         #endif
     114        #endif
     115
     116        // Get the relevant nodes locally
     117        $thread * tail = tail(this);
     118        $thread * prev = tail->link.prev;
     119
     120        // Do the push
     121        node->link.next = tail;
     122        node->link.prev = prev;
     123        prev->link.next = node;
     124        tail->link.prev = node;
     125
     126        // Update stats
     127        #if !defined(__CFA_NO_SCHED_STATS__)
     128                this.stat.diff++;
     129                this.stat.push++;
     130        #endif
     131
     132        verify(node->link.next == tail(this));
     133
     134        // Check if the queue used to be empty
     135        if(this.before.link.ts == 0l) {
     136                this.before.link.ts = node->link.ts;
     137                /* paranoid */ verify(node->link.prev == head(this));
     138                return true;
     139        }
     140        return false;
    167141}
    168142
     
    172146$thread * pop(__intrusive_lane_t & this) {
    173147        /* paranoid */ verify(this.lock);
    174         #if defined(USE_MPSC)
    175                 inline $thread * volatile & ?`next ( $thread * this )  __attribute__((const)) {
    176                         return this->link.next;
    177                 }
    178                 return pop(this.queue);
    179         #else
    180                 /* paranoid */ verify(this.before.link.ts != 0ul);
    181 
    182                 // Get anchors locally
    183                 $thread * head = head(this);
    184                 $thread * tail = tail(this);
    185 
    186                 // Get the relevant nodes locally
    187                 $thread * node = head->link.next;
    188                 $thread * next = node->link.next;
    189 
    190                 /* paranoid */ verify(node != tail);
    191                 /* paranoid */ verify(node);
    192 
    193                 // Do the pop
    194                 head->link.next = next;
    195                 next->link.prev = head;
    196                 node->link.next = 0p;
    197                 node->link.prev = 0p;
    198 
    199                 // Update head time stamp
    200                 this.before.link.ts = next->link.ts;
    201 
    202                 // Update stats
    203                 #ifndef __CFA_NO_SCHED_STATS__
    204                         this.stat.diff--;
    205                         this.stat.pop ++;
    206                 #endif
    207 
    208                 // Check if we emptied list and return accordingly
    209                 /* paranoid */ verify(tail(this)->link.next == 0p);
    210                 /* paranoid */ verify(head(this)->link.prev == 0p);
    211                 if(next == tail) {
    212                         /* paranoid */ verify(this.before.link.ts == 0);
    213                         /* paranoid */ verify(tail(this)->link.prev == head(this));
    214                         /* paranoid */ verify(head(this)->link.next == tail(this));
    215                         return node;
    216                 }
    217                 else {
    218                         /* paranoid */ verify(next->link.ts != 0);
    219                         /* paranoid */ verify(tail(this)->link.prev != head(this));
    220                         /* paranoid */ verify(head(this)->link.next != tail(this));
    221                         /* paranoid */ verify(this.before.link.ts != 0);
    222                         return node;
    223                 }
    224         #endif
     148        /* paranoid */ verify(this.before.link.ts != 0ul);
     149
     150        // Get anchors locally
     151        $thread * head = head(this);
     152        $thread * tail = tail(this);
     153
     154        // Get the relevant nodes locally
     155        $thread * node = head->link.next;
     156        $thread * next = node->link.next;
     157
     158        /* paranoid */ verify(node != tail);
     159        /* paranoid */ verify(node);
     160
     161        // Do the pop
     162        head->link.next = next;
     163        next->link.prev = head;
     164        node->link.next = 0p;
     165        node->link.prev = 0p;
     166
     167        // Update head time stamp
     168        this.before.link.ts = next->link.ts;
     169
     170        // Update stats
     171        #ifndef __CFA_NO_SCHED_STATS__
     172                this.stat.diff--;
     173                this.stat.pop ++;
     174        #endif
     175
     176        // Check if we emptied list and return accordingly
     177        /* paranoid */ verify(tail(this)->link.next == 0p);
     178        /* paranoid */ verify(head(this)->link.prev == 0p);
     179        if(next == tail) {
     180                /* paranoid */ verify(this.before.link.ts == 0);
     181                /* paranoid */ verify(tail(this)->link.prev == head(this));
     182                /* paranoid */ verify(head(this)->link.next == tail(this));
     183                return node;
     184        }
     185        else {
     186                /* paranoid */ verify(next->link.ts != 0);
     187                /* paranoid */ verify(tail(this)->link.prev != head(this));
     188                /* paranoid */ verify(head(this)->link.next != tail(this));
     189                /* paranoid */ verify(this.before.link.ts != 0);
     190                return node;
     191        }
    225192}
    226193
    227194// Check whether or not list is empty
    228195static inline bool is_empty(__intrusive_lane_t & this) {
    229         #if defined(USE_MPSC)
    230                 return this.queue.head == 0p;
    231         #else
    232                 // Cannot verify here since it may not be locked
    233                 return this.before.link.ts == 0;
    234         #endif
     196        // Cannot verify here since it may not be locked
     197        return this.before.link.ts == 0;
    235198}
    236199
    237200// Return the timestamp
    238201static inline unsigned long long ts(__intrusive_lane_t & this) {
    239         #if defined(USE_MPSC)
    240                 $thread * tl = this.queue.head;
    241                 if(!tl) return -1ull;
    242                 return tl->link.ts;
    243         #else
    244                 // Cannot verify here since it may not be locked
    245                 return this.before.link.ts;
    246         #endif
    247 }
    248 
    249 // Aligned timestamps which are used by the relaxed ready queue
    250 struct __attribute__((aligned(128))) __timestamp_t {
    251         volatile unsigned long long tv;
    252 };
    253 
    254 void  ?{}(__timestamp_t & this) { this.tv = 0; }
    255 void ^?{}(__timestamp_t & this) {}
     202        // Cannot verify here since it may not be locked
     203        return this.before.link.ts;
     204}
  • libcfa/src/concurrency/stats.cfa

    r5407cdc rfeacef9  
    55#include <inttypes.h>
    66#include "bits/debug.hfa"
    7 #include "bits/locks.hfa"
    87#include "stats.hfa"
    9 #include "strstream.hfa"
    108
    119#if !defined(__CFA_NO_STATISTICS__)
    1210        void __init_stats( struct __stats_t * stats ) {
    13                 stats->ready.push.local.attempt = 0;
    14                 stats->ready.push.local.success = 0;
    15                 stats->ready.push.share.attempt = 0;
    16                 stats->ready.push.share.success = 0;
    17                 stats->ready.push.extrn.attempt = 0;
    18                 stats->ready.push.extrn.success = 0;
    19                 stats->ready.pop.local .attempt = 0;
    20                 stats->ready.pop.local .success = 0;
    21                 stats->ready.pop.local .elock   = 0;
    22                 stats->ready.pop.local .eempty  = 0;
    23                 stats->ready.pop.local .espec   = 0;
    24                 stats->ready.pop.help  .attempt = 0;
    25                 stats->ready.pop.help  .success = 0;
    26                 stats->ready.pop.help  .elock   = 0;
    27                 stats->ready.pop.help  .eempty  = 0;
    28                 stats->ready.pop.help  .espec   = 0;
    29                 stats->ready.pop.steal .attempt = 0;
    30                 stats->ready.pop.steal .success = 0;
    31                 stats->ready.pop.steal .elock   = 0;
    32                 stats->ready.pop.steal .eempty  = 0;
    33                 stats->ready.pop.steal .espec   = 0;
    34                 stats->ready.pop.search.attempt = 0;
    35                 stats->ready.pop.search.success = 0;
    36                 stats->ready.pop.search.elock   = 0;
    37                 stats->ready.pop.search.eempty  = 0;
    38                 stats->ready.pop.search.espec   = 0;
     11                stats->ready.pick.push.attempt  = 0;
     12                stats->ready.pick.push.success  = 0;
     13                stats->ready.pick.push.local    = 0;
     14                stats->ready.pick.push.lsuccess = 0;
     15                stats->ready.pick.pop .probe    = 0;
     16                stats->ready.pick.pop .attempt  = 0;
     17                stats->ready.pick.pop .success  = 0;
     18                stats->ready.pick.pop .local    = 0;
     19                stats->ready.pick.pop .lsuccess = 0;
    3920                stats->ready.threads.migration = 0;
    40                 stats->ready.threads.extunpark = 0;
    41                 stats->ready.threads.threads   = 0;
    4221                stats->ready.sleep.halts   = 0;
    4322                stats->ready.sleep.cancels = 0;
     
    4625
    4726                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    48                         stats->io.alloc.fast        = 0;
    49                         stats->io.alloc.slow        = 0;
    50                         stats->io.alloc.fail        = 0;
    51                         stats->io.alloc.revoke      = 0;
    52                         stats->io.alloc.block       = 0;
    53                         stats->io.submit.fast       = 0;
    54                         stats->io.submit.slow       = 0;
    55                         stats->io.flush.external    = 0;
    56                         stats->io.calls.flush       = 0;
    57                         stats->io.calls.submitted   = 0;
    58                         stats->io.calls.drain       = 0;
    59                         stats->io.calls.completed   = 0;
    60                         stats->io.calls.errors.busy = 0;
    61                         stats->io.poller.sleeps     = 0;
    62                 #endif
    63 
    64                 #if defined(CFA_STATS_ARRAY)
    65                         stats->array.values = alloc(CFA_STATS_ARRAY);
    66                         stats->array.cnt = 0;
     27                        stats->io.submit_q.submit_avg.rdy = 0;
     28                        stats->io.submit_q.submit_avg.csm = 0;
     29                        stats->io.submit_q.submit_avg.cnt = 0;
     30                        stats->io.submit_q.look_avg.val   = 0;
     31                        stats->io.submit_q.look_avg.cnt   = 0;
     32                        stats->io.submit_q.look_avg.block = 0;
     33                        stats->io.submit_q.alloc_avg.val   = 0;
     34                        stats->io.submit_q.alloc_avg.cnt   = 0;
     35                        stats->io.submit_q.alloc_avg.block = 0;
     36                        stats->io.submit_q.helped = 0;
     37                        stats->io.submit_q.leader = 0;
     38                        stats->io.submit_q.busy   = 0;
     39                        stats->io.complete_q.completed_avg.val = 0;
     40                        stats->io.complete_q.completed_avg.cnt = 0;
     41                        stats->io.complete_q.blocks = 0;
    6742                #endif
    6843        }
    6944
    7045        void __tally_stats( struct __stats_t * cltr, struct __stats_t * proc ) {
    71                 __atomic_fetch_add( &cltr->ready.push.local.attempt, proc->ready.push.local.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.local.attempt = 0;
    72                 __atomic_fetch_add( &cltr->ready.push.local.success, proc->ready.push.local.success, __ATOMIC_SEQ_CST ); proc->ready.push.local.success = 0;
    73                 __atomic_fetch_add( &cltr->ready.push.share.attempt, proc->ready.push.share.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.share.attempt = 0;
    74                 __atomic_fetch_add( &cltr->ready.push.share.success, proc->ready.push.share.success, __ATOMIC_SEQ_CST ); proc->ready.push.share.success = 0;
    75                 __atomic_fetch_add( &cltr->ready.push.extrn.attempt, proc->ready.push.extrn.attempt, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.attempt = 0;
    76                 __atomic_fetch_add( &cltr->ready.push.extrn.success, proc->ready.push.extrn.success, __ATOMIC_SEQ_CST ); proc->ready.push.extrn.success = 0;
    77                 __atomic_fetch_add( &cltr->ready.pop.local .attempt, proc->ready.pop.local .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.local .attempt = 0;
    78                 __atomic_fetch_add( &cltr->ready.pop.local .success, proc->ready.pop.local .success, __ATOMIC_SEQ_CST ); proc->ready.pop.local .success = 0;
    79                 __atomic_fetch_add( &cltr->ready.pop.local .elock  , proc->ready.pop.local .elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.local .elock   = 0;
    80                 __atomic_fetch_add( &cltr->ready.pop.local .eempty , proc->ready.pop.local .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.local .eempty  = 0;
    81                 __atomic_fetch_add( &cltr->ready.pop.local .espec  , proc->ready.pop.local .espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.local .espec   = 0;
    82                 __atomic_fetch_add( &cltr->ready.pop.help  .attempt, proc->ready.pop.help  .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.help  .attempt = 0;
    83                 __atomic_fetch_add( &cltr->ready.pop.help  .success, proc->ready.pop.help  .success, __ATOMIC_SEQ_CST ); proc->ready.pop.help  .success = 0;
    84                 __atomic_fetch_add( &cltr->ready.pop.help  .elock  , proc->ready.pop.help  .elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.help  .elock   = 0;
    85                 __atomic_fetch_add( &cltr->ready.pop.help  .eempty , proc->ready.pop.help  .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.help  .eempty  = 0;
    86                 __atomic_fetch_add( &cltr->ready.pop.help  .espec  , proc->ready.pop.help  .espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.help  .espec   = 0;
    87                 __atomic_fetch_add( &cltr->ready.pop.steal .attempt, proc->ready.pop.steal .attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .attempt = 0;
    88                 __atomic_fetch_add( &cltr->ready.pop.steal .success, proc->ready.pop.steal .success, __ATOMIC_SEQ_CST ); proc->ready.pop.steal .success = 0;
    89                 __atomic_fetch_add( &cltr->ready.pop.steal .elock  , proc->ready.pop.steal .elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .elock   = 0;
    90                 __atomic_fetch_add( &cltr->ready.pop.steal .eempty , proc->ready.pop.steal .eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .eempty  = 0;
    91                 __atomic_fetch_add( &cltr->ready.pop.steal .espec  , proc->ready.pop.steal .espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.steal .espec   = 0;
    92                 __atomic_fetch_add( &cltr->ready.pop.search.attempt, proc->ready.pop.search.attempt, __ATOMIC_SEQ_CST ); proc->ready.pop.search.attempt = 0;
    93                 __atomic_fetch_add( &cltr->ready.pop.search.success, proc->ready.pop.search.success, __ATOMIC_SEQ_CST ); proc->ready.pop.search.success = 0;
    94                 __atomic_fetch_add( &cltr->ready.pop.search.elock  , proc->ready.pop.search.elock  , __ATOMIC_SEQ_CST ); proc->ready.pop.search.elock   = 0;
    95                 __atomic_fetch_add( &cltr->ready.pop.search.eempty , proc->ready.pop.search.eempty , __ATOMIC_SEQ_CST ); proc->ready.pop.search.eempty  = 0;
    96                 __atomic_fetch_add( &cltr->ready.pop.search.espec  , proc->ready.pop.search.espec  , __ATOMIC_SEQ_CST ); proc->ready.pop.search.espec   = 0;
     46                __atomic_fetch_add( &cltr->ready.pick.push.attempt , proc->ready.pick.push.attempt , __ATOMIC_SEQ_CST ); proc->ready.pick.push.attempt  = 0;
     47                __atomic_fetch_add( &cltr->ready.pick.push.success , proc->ready.pick.push.success , __ATOMIC_SEQ_CST ); proc->ready.pick.push.success  = 0;
     48                __atomic_fetch_add( &cltr->ready.pick.push.local   , proc->ready.pick.push.local   , __ATOMIC_SEQ_CST ); proc->ready.pick.push.local    = 0;
     49                __atomic_fetch_add( &cltr->ready.pick.push.lsuccess, proc->ready.pick.push.lsuccess, __ATOMIC_SEQ_CST ); proc->ready.pick.push.lsuccess = 0;
     50                __atomic_fetch_add( &cltr->ready.pick.pop .probe   , proc->ready.pick.pop .probe   , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .probe    = 0;
     51                __atomic_fetch_add( &cltr->ready.pick.pop .attempt , proc->ready.pick.pop .attempt , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .attempt  = 0;
     52                __atomic_fetch_add( &cltr->ready.pick.pop .success , proc->ready.pick.pop .success , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .success  = 0;
     53                __atomic_fetch_add( &cltr->ready.pick.pop .local   , proc->ready.pick.pop .local   , __ATOMIC_SEQ_CST ); proc->ready.pick.pop .local    = 0;
     54                __atomic_fetch_add( &cltr->ready.pick.pop .lsuccess, proc->ready.pick.pop .lsuccess, __ATOMIC_SEQ_CST ); proc->ready.pick.pop .lsuccess = 0;
    9755                __atomic_fetch_add( &cltr->ready.threads.migration , proc->ready.threads.migration , __ATOMIC_SEQ_CST ); proc->ready.threads.migration  = 0;
    98                 __atomic_fetch_add( &cltr->ready.threads.extunpark , proc->ready.threads.extunpark , __ATOMIC_SEQ_CST ); proc->ready.threads.extunpark  = 0;
    99                 __atomic_fetch_add( &cltr->ready.threads.threads   , proc->ready.threads.threads   , __ATOMIC_SEQ_CST ); proc->ready.threads.threads    = 0;
    10056                __atomic_fetch_add( &cltr->ready.sleep.halts       , proc->ready.sleep.halts       , __ATOMIC_SEQ_CST ); proc->ready.sleep.halts        = 0;
    10157                __atomic_fetch_add( &cltr->ready.sleep.cancels     , proc->ready.sleep.cancels     , __ATOMIC_SEQ_CST ); proc->ready.sleep.cancels      = 0;
     
    10460
    10561                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    106                         __atomic_fetch_add( &cltr->io.alloc.fast       , proc->io.alloc.fast       , __ATOMIC_SEQ_CST ); proc->io.alloc.fast        = 0;
    107                         __atomic_fetch_add( &cltr->io.alloc.slow       , proc->io.alloc.slow       , __ATOMIC_SEQ_CST ); proc->io.alloc.slow        = 0;
    108                         __atomic_fetch_add( &cltr->io.alloc.fail       , proc->io.alloc.fail       , __ATOMIC_SEQ_CST ); proc->io.alloc.fail        = 0;
    109                         __atomic_fetch_add( &cltr->io.alloc.revoke     , proc->io.alloc.revoke     , __ATOMIC_SEQ_CST ); proc->io.alloc.revoke      = 0;
    110                         __atomic_fetch_add( &cltr->io.alloc.block      , proc->io.alloc.block      , __ATOMIC_SEQ_CST ); proc->io.alloc.block       = 0;
    111                         __atomic_fetch_add( &cltr->io.submit.fast      , proc->io.submit.fast      , __ATOMIC_SEQ_CST ); proc->io.submit.fast       = 0;
    112                         __atomic_fetch_add( &cltr->io.submit.slow      , proc->io.submit.slow      , __ATOMIC_SEQ_CST ); proc->io.submit.slow       = 0;
    113                         __atomic_fetch_add( &cltr->io.flush.external   , proc->io.flush.external   , __ATOMIC_SEQ_CST ); proc->io.flush.external    = 0;
    114                         __atomic_fetch_add( &cltr->io.calls.flush      , proc->io.calls.flush      , __ATOMIC_SEQ_CST ); proc->io.calls.flush       = 0;
    115                         __atomic_fetch_add( &cltr->io.calls.submitted  , proc->io.calls.submitted  , __ATOMIC_SEQ_CST ); proc->io.calls.submitted   = 0;
    116                         __atomic_fetch_add( &cltr->io.calls.drain      , proc->io.calls.drain      , __ATOMIC_SEQ_CST ); proc->io.calls.drain       = 0;
    117                         __atomic_fetch_add( &cltr->io.calls.completed  , proc->io.calls.completed  , __ATOMIC_SEQ_CST ); proc->io.calls.completed   = 0;
    118                         __atomic_fetch_add( &cltr->io.calls.errors.busy, proc->io.calls.errors.busy, __ATOMIC_SEQ_CST ); proc->io.calls.errors.busy = 0;
    119                         __atomic_fetch_add( &cltr->io.poller.sleeps    , proc->io.poller.sleeps    , __ATOMIC_SEQ_CST ); proc->io.poller.sleeps     = 0;
     62                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.rdy     , proc->io.submit_q.submit_avg.rdy     , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.rdy      = 0;
     63                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.csm     , proc->io.submit_q.submit_avg.csm     , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.csm      = 0;
     64                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.avl     , proc->io.submit_q.submit_avg.avl     , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.avl      = 0;
     65                        __atomic_fetch_add( &cltr->io.submit_q.submit_avg.cnt     , proc->io.submit_q.submit_avg.cnt     , __ATOMIC_SEQ_CST ); proc->io.submit_q.submit_avg.cnt      = 0;
     66                        __atomic_fetch_add( &cltr->io.submit_q.look_avg.val       , proc->io.submit_q.look_avg.val       , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.val        = 0;
     67                        __atomic_fetch_add( &cltr->io.submit_q.look_avg.cnt       , proc->io.submit_q.look_avg.cnt       , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.cnt        = 0;
     68                        __atomic_fetch_add( &cltr->io.submit_q.look_avg.block     , proc->io.submit_q.look_avg.block     , __ATOMIC_SEQ_CST ); proc->io.submit_q.look_avg.block      = 0;
     69                        __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.val      , proc->io.submit_q.alloc_avg.val      , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.val       = 0;
     70                        __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.cnt      , proc->io.submit_q.alloc_avg.cnt      , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.cnt       = 0;
     71                        __atomic_fetch_add( &cltr->io.submit_q.alloc_avg.block    , proc->io.submit_q.alloc_avg.block    , __ATOMIC_SEQ_CST ); proc->io.submit_q.alloc_avg.block     = 0;
     72                        __atomic_fetch_add( &cltr->io.submit_q.helped             , proc->io.submit_q.helped             , __ATOMIC_SEQ_CST ); proc->io.submit_q.helped              = 0;
     73                        __atomic_fetch_add( &cltr->io.submit_q.leader             , proc->io.submit_q.leader             , __ATOMIC_SEQ_CST ); proc->io.submit_q.leader              = 0;
     74                        __atomic_fetch_add( &cltr->io.submit_q.busy               , proc->io.submit_q.busy               , __ATOMIC_SEQ_CST ); proc->io.submit_q.busy                = 0;
     75                        __atomic_fetch_add( &cltr->io.complete_q.completed_avg.val, proc->io.complete_q.completed_avg.val, __ATOMIC_SEQ_CST ); proc->io.complete_q.completed_avg.val = 0;
     76                        __atomic_fetch_add( &cltr->io.complete_q.completed_avg.cnt, proc->io.complete_q.completed_avg.cnt, __ATOMIC_SEQ_CST ); proc->io.complete_q.completed_avg.cnt = 0;
     77                        __atomic_fetch_add( &cltr->io.complete_q.blocks           , proc->io.complete_q.blocks           , __ATOMIC_SEQ_CST ); proc->io.complete_q.blocks            = 0;
    12078                #endif
    12179        }
    12280
    123         #define eng3(X) (ws(3, 3, unit(eng( X ))))
    124 
    12581        void __print_stats( struct __stats_t * stats, int flags, const char * type, const char * name, void * id ) with( *stats ) {
    12682
    127                 char buf[1024];
    128                 ostrstream sstr = { buf, 1024 };
     83                if( flags & CFA_STATS_READY_Q ) {
     84                        double push_sur = (100.0 * ((double)ready.pick.push.success) / ready.pick.push.attempt);
     85                        double pop_sur  = (100.0 * ((double)ready.pick.pop .success) / ready.pick.pop .attempt);
    12986
    130                 if( flags & CFA_STATS_READY_Q ) {
     87                        double push_len = ((double)ready.pick.push.attempt) / ready.pick.push.success;
     88                        double pop_len  = ((double)ready.pick.pop .attempt) / ready.pick.pop .success;
    13189
    132                         sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - Ready Q Stats -----";
     90                        double lpush_sur = (100.0 * ((double)ready.pick.push.lsuccess) / ready.pick.push.local);
     91                        double lpop_sur  = (100.0 * ((double)ready.pick.pop .lsuccess) / ready.pick.pop .local);
    13392
    134                         uint64_t totalR = ready.pop.local.success + ready.pop.help.success + ready.pop.steal.success + ready.pop.search.success;
    135                         uint64_t totalS = ready.push.local.success + ready.push.share.success + ready.push.extrn.success;
    136                         sstr | "- totals   : " | eng3(totalR) | "run," | eng3(totalS) | "schd (" | eng3(ready.push.extrn.success) | "ext," | eng3(ready.threads.migration) | "mig," | eng3(ready.threads.extunpark) | " eupk)";
     93                        double lpush_len = ((double)ready.pick.push.local) / ready.pick.push.lsuccess;
     94                        double lpop_len  = ((double)ready.pick.pop .local) / ready.pick.pop .lsuccess;
    13795
    138                         double push_len = ((double)ready.push.local.attempt + ready.push.share.attempt + ready.push.extrn.attempt) / totalS;
    139                         double sLcl_len = ready.push.local.success ? ((double)ready.push.local.attempt) / ready.push.local.success : 0;
    140                         double sOth_len = ready.push.share.success ? ((double)ready.push.share.attempt) / ready.push.share.success : 0;
    141                         double sExt_len = ready.push.extrn.success ? ((double)ready.push.extrn.attempt) / ready.push.extrn.success : 0;
    142                         sstr | "- push avg : " | ws(3, 3, push_len)
    143                              | "- l: " | eng3(ready.push.local.attempt) | " (" | ws(3, 3, sLcl_len) | ")"
    144                              | ", s: " | eng3(ready.push.share.attempt) | " (" | ws(3, 3, sOth_len) | ")"
    145                              | ", e: " | eng3(ready.push.extrn.attempt) | " (" | ws(3, 3, sExt_len) | ")";
    146 
    147                         double rLcl_pc = (100.0 * (double)ready.pop.local .success) / totalR;
    148                         sstr | "- local    : " | eng3(ready.pop.local .success) | "-"| ws(3, 3, rLcl_pc) | '%'
    149                              | " (" | eng3(ready.pop.local .attempt) | " try," | eng3(ready.pop.local .espec) | " spc," | eng3(ready.pop.local .elock) | " lck," | eng3(ready.pop.local .eempty) | " ept)";
    150                         double rHlp_pc = (100.0 * (double)ready.pop.help  .success) / totalR;
    151                         sstr | "- help     : " | eng3(ready.pop.help  .success) | "-"| ws(3, 3, rHlp_pc) | '%'
    152                              | " (" | eng3(ready.pop.help  .attempt) | " try," | eng3(ready.pop.help  .espec) | " spc," | eng3(ready.pop.help  .elock) | " lck," | eng3(ready.pop.help  .eempty) | " ept)";
    153                         double rStl_pc = (100.0 * (double)ready.pop.steal .success) / totalR;
    154                         sstr | "- steal    : " | eng3(ready.pop.steal .success) | "-"| ws(3, 3, rStl_pc) | '%'
    155                              | " (" | eng3(ready.pop.steal .attempt) | " try," | eng3(ready.pop.steal .espec) | " spc," | eng3(ready.pop.steal .elock) | " lck," | eng3(ready.pop.steal .eempty) | " ept)";
    156                         double rSch_pc = (100.0 * (double)ready.pop.search.success) / totalR;
    157                         sstr | "- search   : " | eng3(ready.pop.search.success) | "-"| ws(3, 3, rSch_pc) | '%'
    158                              | " (" | eng3(ready.pop.search.attempt) | " try," | eng3(ready.pop.search.espec) | " spc," | eng3(ready.pop.search.elock) | " lck," | eng3(ready.pop.search.eempty) | " ept)";
    159 
    160                         sstr | "- Idle Slp : " | eng3(ready.sleep.halts) | "halt," | eng3(ready.sleep.cancels) | "cancel," | eng3(ready.sleep.wakes) | "wake," | eng3(ready.sleep.exits) | "exit";
    161                         sstr | nl;
     96                        __cfaabi_bits_print_safe( STDOUT_FILENO,
     97                                "----- %s \"%s\" (%p) - Ready Q Stats -----\n"
     98                                "- total threads run      : %'15" PRIu64 "\n"
     99                                "- total threads scheduled: %'15" PRIu64 "\n"
     100                                "- push average probe len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n"
     101                                "- pop  average probe len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n"
     102                                "- local push avg prb len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n"
     103                                "- local pop  avg prb len : %'18.2lf, %'18.2lf%% (%'15" PRIu64 " attempts)\n"
     104                                "- thread migrations      : %'15" PRIu64 "\n"
     105                                "- Idle Sleep -\n"
     106                                "-- halts                 : %'15" PRIu64 "\n"
     107                                "-- cancelled halts       : %'15" PRIu64 "\n"
     108                                "-- schedule wake         : %'15" PRIu64 "\n"
     109                                "-- wake on exit          : %'15" PRIu64 "\n"
     110                                "\n"
     111                                , type, name, id
     112                                , ready.pick.pop.success
     113                                , ready.pick.push.success
     114                                , push_len, push_sur, ready.pick.push.attempt
     115                                , pop_len , pop_sur , ready.pick.pop .attempt
     116                                , lpush_len, lpush_sur, ready.pick.push.local
     117                                , lpop_len , lpop_sur , ready.pick.pop .local
     118                                , ready.threads.migration
     119                                , ready.sleep.halts, ready.sleep.cancels, ready.sleep.wakes, ready.sleep.exits
     120                        );
    162121                }
    163122
    164123                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    165124                        if( flags & CFA_STATS_IO ) {
    166                                 sstr | "----- " | type | "\"" | name | "\" (" | "" | id | "" | ") - I/O Stats -----";
     125                                double avgrdy = ((double)io.submit_q.submit_avg.rdy) / io.submit_q.submit_avg.cnt;
     126                                double avgcsm = ((double)io.submit_q.submit_avg.csm) / io.submit_q.submit_avg.cnt;
    167127
    168                                 uint64_t total_allocs = io.alloc.fast + io.alloc.slow;
    169                                 double avgfasta = (100.0 * (double)io.alloc.fast) / total_allocs;
    170                                 sstr | "- total allocations : " | eng3(io.alloc.fast) | "fast," | eng3(io.alloc.slow) | "slow (" | ws(3, 3, avgfasta) | "%)";
    171                                 sstr | "-     failures      : " | eng3(io.alloc.fail) | "oom, " | eng3(io.alloc.revoke) | "rvk, " | eng3(io.alloc.block) | "blk";
     128                                double lavgv = 0;
     129                                double lavgb = 0;
     130                                if(io.submit_q.look_avg.cnt != 0) {
     131                                        lavgv = ((double)io.submit_q.look_avg.val  ) / io.submit_q.look_avg.cnt;
     132                                        lavgb = ((double)io.submit_q.look_avg.block) / io.submit_q.look_avg.cnt;
     133                                }
    172134
    173                                 uint64_t total_submits = io.submit.fast + io.submit.slow;
    174                                 double avgfasts = (100.0 * (double)io.submit.fast) / total_submits;
    175                                 sstr | "- total submits     : " | eng3(io.submit.fast) | "fast," | eng3(io.submit.slow) | "slow (" | ws(3, 3, avgfasts) | "%)";
    176                                 sstr | "- flush external    : " | eng3(io.flush.external);
     135                                double aavgv = 0;
     136                                double aavgb = 0;
     137                                if(io.submit_q.alloc_avg.cnt != 0) {
     138                                        aavgv = ((double)io.submit_q.alloc_avg.val  ) / io.submit_q.alloc_avg.cnt;
     139                                        aavgb = ((double)io.submit_q.alloc_avg.block) / io.submit_q.alloc_avg.cnt;
     140                                }
    177141
    178                                 sstr | "- io_uring_enter    : " | eng3(io.calls.flush) | " (" | eng3(io.calls.drain) | ", " | eng3(io.calls.errors.busy) | " EBUSY)";
    179 
    180                                 double avgsubs = ((double)io.calls.submitted) / io.calls.flush;
    181                                 double avgcomp = ((double)io.calls.completed) / io.calls.drain;
    182                                 sstr | "-     submits       : " | eng3(io.calls.submitted) | "(" | ws(3, 3, avgsubs) | "/flush)";
    183                                 sstr | "-     completes     : " | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)";
    184 
    185                                 sstr | "- poller sleeping   : " | eng3(io.poller.sleeps);
    186                                 sstr | nl;
     142                                __cfaabi_bits_print_safe( STDOUT_FILENO,
     143                                        "----- %s \"%s\" (%p) - I/O Stats -----\n"
     144                                        "- total submit calls     : %'15" PRIu64 "\n"
     145                                        "- avg ready entries      : %'18.2lf\n"
     146                                        "- avg submitted entries  : %'18.2lf\n"
     147                                        "- total helped entries   : %'15" PRIu64 "\n"
     148                                        "- total leader entries   : %'15" PRIu64 "\n"
     149                                        "- total busy submit      : %'15" PRIu64 "\n"
     150                                        "- total ready search     : %'15" PRIu64 "\n"
     151                                        "- avg ready search len   : %'18.2lf\n"
     152                                        "- avg ready search block : %'18.2lf\n"
     153                                        "- total alloc search     : %'15" PRIu64 "\n"
     154                                        "- avg alloc search len   : %'18.2lf\n"
     155                                        "- avg alloc search block : %'18.2lf\n"
     156                                        "- total wait calls       : %'15" PRIu64 "\n"
     157                                        "- avg completion/wait    : %'18.2lf\n"
     158                                        "- total completion blocks: %'15" PRIu64 "\n"
     159                                        "\n"
     160                                        , type,  name, id
     161                                        , io.submit_q.submit_avg.cnt
     162                                        , avgrdy, avgcsm
     163                                        , io.submit_q.helped, io.submit_q.leader, io.submit_q.busy
     164                                        , io.submit_q.look_avg.cnt
     165                                        , lavgv, lavgb
     166                                        , io.submit_q.alloc_avg.cnt
     167                                        , aavgv, aavgb
     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
     171                                );
    187172                        }
    188173                #endif
    189 
    190                 if(flags) write( sstr, stdout );
    191174        }
    192 
    193         #if defined(CFA_STATS_ARRAY)
    194                 extern "C" {
    195                         #include <stdio.h>
    196                         #include <errno.h>
    197                         #include <sys/stat.h>
    198                         #include <fcntl.h>
    199                 }
    200 
    201                 void __flush_stat( struct __stats_t * this, const char * name, void * handle) {
    202                         int ret = mkdir(".cfadata", 0755);
    203                         if(ret < 0 && errno != EEXIST) abort("Failed to create directory .cfadata: %d\n", errno);
    204 
    205                         char filename[100];
    206                         snprintf(filename, 100, ".cfadata/%s%p.data", name, handle);
    207 
    208                         int fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0644);
    209                         if(fd < 0) abort("Failed to create file %s: %d\n", filename, errno);
    210 
    211                         for(i; this->array.cnt) {
    212                                 char line[100];
    213                                 size_t n = snprintf(line, 100, "%llu, %lld\n", this->array.values[i].ts, this->array.values[i].value);
    214                                 write(fd, line, n);
    215                         }
    216 
    217                         this->array.cnt = 0;
    218                         close(fd);
    219                 }
    220 
    221                 static __spinlock_t stats_lock;
    222 
    223                 void __push_stat( struct __stats_t * this, int64_t value, bool external, const char * name, void * handle ) {
    224                         if(external) lock(stats_lock __cfaabi_dbg_ctx2);
    225 
    226                         if( this->array.cnt >= CFA_STATS_ARRAY ) __flush_stat( this, name, handle );
    227 
    228                         size_t idx = this->array.cnt;
    229                         this->array.cnt++;
    230 
    231                         if(external) unlock(stats_lock);
    232 
    233                         this->array.values[idx].ts = rdtscl();
    234                         this->array.values[idx].value = value;
    235                 }
    236         #endif
    237175#endif
  • libcfa/src/concurrency/stats.hfa

    r5407cdc rfeacef9  
    11#pragma once
    2 
    3 // #define CFA_STATS_ARRAY 10000
    42
    53#include <stdint.h>
     
    1614        static inline void __print_stats( struct __stats_t *, int, const char *, const char *, void * ) {}
    1715#else
    18         struct __stats_readyQ_pop_t {
    19                 // number of attemps at poping something
    20                 volatile uint64_t attempt;
    2116
    22                 // number of successes at poping
    23                 volatile uint64_t success;
    24 
    25                 // number of attempts failed due to the lock being held
    26                 volatile uint64_t elock;
    27 
    28                 // number of attempts failed due to the queue being empty (lock held)
    29                 volatile uint64_t eempty;
    30 
    31                 // number of attempts failed due to the queue looking empty (lock not held)
    32                 volatile uint64_t espec;
    33         };
    34 
    35         struct __attribute__((aligned(64))) __stats_readyQ_t {
    36                 // Push statistic
     17        struct __attribute__((aligned(64))) __stats_readQ_t {
    3718                struct {
     19                        // Push statistic
    3820                        struct {
    39                                 // number of attemps at pushing something to preferred queues
     21                                // number of attemps at pushing something
    4022                                volatile uint64_t attempt;
    4123
     24                                // number of successes at pushing
     25                                volatile uint64_t success;
     26
     27                                // number of attemps at pushing something to preferred queues
     28                                volatile uint64_t local;
     29
    4230                                // number of successes at pushing to preferred queues
     31                                volatile uint64_t lsuccess;
     32                        } push;
     33
     34                        // Pop statistic
     35                        struct {
     36                                // number of reads of the mask
     37                                // picking an empty __cfa_readyQ_mask_t counts here
     38                                // but not as an attempt
     39                                volatile uint64_t probe;
     40
     41                                // number of attemps at poping something
     42                                volatile uint64_t attempt;
     43
     44                                // number of successes at poping
    4345                                volatile uint64_t success;
    44                         }
    45                         // Stats for local queue within cluster
    46                         local,
    4746
    48                         // Stats for non-local queues within cluster
    49                         share,
     47                                // number of attemps at poping something to preferred queues
     48                                volatile uint64_t local;
    5049
    51                         // Stats from outside cluster
    52                         extrn;
    53                 } push;
    54 
    55                 // Pop statistic
    56                 struct {
    57                         // pop from local queue
    58                         __stats_readyQ_pop_t local;
    59 
    60                         // pop before looking at local queue
    61                         __stats_readyQ_pop_t help;
    62 
    63                         // pop from some other queue
    64                         __stats_readyQ_pop_t steal;
    65 
    66                         // pop when searching queues sequentially
    67                         __stats_readyQ_pop_t search;
    68                 } pop;
    69 
     50                                // number of successes at poping to preferred queues
     51                                volatile uint64_t lsuccess;
     52                        } pop;
     53                } pick;
    7054                struct {
    7155                        volatile uint64_t migration;
    72                         volatile uint64_t extunpark;
    73                         volatile  int64_t threads; // number of threads in the system, includes only local change
    7456                } threads;
    7557                struct {
     
    8466                struct __attribute__((aligned(64))) __stats_io_t{
    8567                        struct {
    86                                 volatile uint64_t fast;
    87                                 volatile uint64_t slow;
    88                                 volatile uint64_t fail;
    89                                 volatile uint64_t revoke;
    90                                 volatile uint64_t block;
    91                         } alloc;
     68                                struct {
     69                                        volatile uint64_t rdy;
     70                                        volatile uint64_t csm;
     71                                        volatile uint64_t avl;
     72                                        volatile uint64_t cnt;
     73                                } submit_avg;
     74                                struct {
     75                                        volatile uint64_t val;
     76                                        volatile uint64_t cnt;
     77                                        volatile uint64_t block;
     78                                } look_avg;
     79                                struct {
     80                                        volatile uint64_t val;
     81                                        volatile uint64_t cnt;
     82                                        volatile uint64_t block;
     83                                } alloc_avg;
     84                                volatile uint64_t helped;
     85                                volatile uint64_t leader;
     86                                volatile uint64_t busy;
     87                        } submit_q;
    9288                        struct {
    93                                 volatile uint64_t fast;
    94                                 volatile uint64_t slow;
    95                         } submit;
    96                         struct {
    97                                 volatile uint64_t external;
    98                         } flush;
    99                         struct {
    100                                 volatile uint64_t drain;
    101                                 volatile uint64_t completed;
    102                                 volatile uint64_t flush;
    103                                 volatile uint64_t submitted;
    10489                                struct {
    105                                         volatile uint64_t busy;
    106                                 } errors;
    107                         } calls;
    108                         struct {
    109                                 volatile uint64_t sleeps;
    110                         } poller;
    111                 };
    112         #endif
    113 
    114         #if defined(CFA_STATS_ARRAY)
    115                 struct __stats_elem_t {
    116                         long long int ts;
    117                         int64_t value;
     90                                        volatile uint64_t val;
     91                                        volatile uint64_t cnt;
     92                                } completed_avg;
     93                                volatile uint64_t blocks;
     94                        } complete_q;
    11895                };
    11996        #endif
    12097
    12198        struct __attribute__((aligned(128))) __stats_t {
    122                 __stats_readyQ_t ready;
     99                __stats_readQ_t ready;
    123100                #if defined(CFA_HAVE_LINUX_IO_URING_H)
    124101                        __stats_io_t    io;
    125102                #endif
    126 
    127                 #if defined(CFA_STATS_ARRAY)
    128                         struct {
    129                                 __stats_elem_t * values;
    130                                 volatile size_t cnt;
    131                         } array;
    132                 #endif
    133 
    134103        };
    135104
     
    137106        void __tally_stats( struct __stats_t *, struct __stats_t * );
    138107        void __print_stats( struct __stats_t *, int, const char *, const char *, void * );
    139         #if defined(CFA_STATS_ARRAY)
    140                 void __push_stat ( struct __stats_t *, int64_t value, bool external, const char * name, void * handle);
    141                 void __flush_stat( struct __stats_t *, const char *, void * );
    142         #else
    143                 static inline void __push_stat ( struct __stats_t *, int64_t, bool, const char *, void * ) {}
    144                 static inline void __flush_stat( struct __stats_t *, const char *, void * ) {}
    145         #endif
    146108#endif
    147109
  • libcfa/src/concurrency/thread.cfa

    r5407cdc rfeacef9  
    3939        link.next = 0p;
    4040        link.prev = 0p;
    41         link.preferred = -1u;
    42         last_proc = 0p;
     41        link.preferred = -1;
    4342        #if defined( __CFA_WITH_VERIFY__ )
    4443                canary = 0x0D15EA5E0D15EA5Ep;
     
    6362}
    6463
     64FORALL_DATA_INSTANCE(ThreadCancelled, (thread_t &), (thread_t))
     65
    6566forall(T &)
    6667void copy(ThreadCancelled(T) * dst, ThreadCancelled(T) * src) {
     
    7273forall(T &)
    7374const char * msg(ThreadCancelled(T) *) {
    74         return "ThreadCancelled(...)";
     75        return "ThreadCancelled";
    7576}
    7677
    7778forall(T &)
    7879static void default_thread_cancel_handler(ThreadCancelled(T) & ) {
    79         // Improve this error message, can I do formatting?
    8080        abort( "Unhandled thread cancellation.\n" );
    8181}
    8282
    83 forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))
    84     | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
     83forall(T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)))
    8584void ?{}( thread_dtor_guard_t & this,
    8685                T & thrd, void(*cancelHandler)(ThreadCancelled(T) &)) {
    87         $monitor * m = get_monitor(thrd);
     86        $monitor * m = get_monitor(thrd);
    8887        $thread * desc = get_thread(thrd);
    8988
     
    104103        }
    105104        desc->state = Cancelled;
    106         void(*defaultResumptionHandler)(ThreadCancelled(T) &) =
     105        void(*defaultResumptionHandler)(ThreadCancelled(T) &) = 
    107106                join ? cancelHandler : default_thread_cancel_handler;
    108107
     108        ThreadCancelled(T) except;
    109109        // TODO: Remove explitate vtable set once trac#186 is fixed.
    110         ThreadCancelled(T) except;
    111         except.virtual_table = &_default_vtable;
     110        except.virtual_table = &get_exception_vtable(&except);
    112111        except.the_thread = &thrd;
    113112        except.the_exception = __cfaehm_cancellation_exception( cancellation );
    114         // Why is this cast required?
    115         throwResume (ThreadCancelled(T) &)except;
     113        throwResume except;
    116114
    117115        except.the_exception->virtual_table->free( except.the_exception );
     
    136134        /* paranoid */ verify( this_thrd->context.SP );
    137135
    138         schedule_thread$( this_thrd );
    139         enable_interrupts();
     136        __schedule_thread( this_thrd );
     137        enable_interrupts( __cfaabi_dbg_ctx );
    140138}
    141139
     
    160158
    161159//-----------------------------------------------------------------------------
    162 forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))
    163     | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
     160forall(T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)))
    164161T & join( T & this ) {
    165162        thread_dtor_guard_t guard = { this, defaultResumptionHandler };
     
    170167        disable_interrupts();
    171168        uint64_t ret = __tls_rand();
    172         enable_interrupts();
     169        enable_interrupts( __cfaabi_dbg_ctx );
    173170        return ret;
    174171}
  • libcfa/src/concurrency/thread.hfa

    r5407cdc rfeacef9  
    3232};
    3333
    34 EHM_FORALL_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
     34FORALL_DATA_EXCEPTION(ThreadCancelled, (thread_t &), (thread_t)) (
    3535        thread_t * the_thread;
    3636        exception_t * the_exception;
     
    4242forall(T &)
    4343const char * msg(ThreadCancelled(T) *);
     44
     45// define that satisfies the trait without using the thread keyword
     46#define DECL_THREAD(X) $thread* get_thread(X& this) __attribute__((const)) { return &this.__thrd; } void main(X& this)
    4447
    4548// Inline getters for threads/coroutines/monitors
     
    7982};
    8083
    81 forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T))
    82     | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
     84forall( T & | is_thread(T) | IS_EXCEPTION(ThreadCancelled, (T)) )
    8385void ?{}( thread_dtor_guard_t & this, T & thrd, void(*)(ThreadCancelled(T) &) );
    8486void ^?{}( thread_dtor_guard_t & this );
     
    126128//----------
    127129// join
    128 forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T))
    129     | { EHM_DEFAULT_VTABLE(ThreadCancelled, (T)); })
     130forall( T & | is_thread(T) | IS_RESUMPTION_EXCEPTION(ThreadCancelled, (T)) )
    130131T & join( T & this );
    131132
  • libcfa/src/containers/list.hfa

    r5407cdc rfeacef9  
    8383                (this.is_terminator){ 1 };
    8484        }
    85         static inline void ?=?( $mgd_link(tE) &this, tE* elem ) {
    86                 this.elem = elem ;
    87                 this.terminator = 0p;
    88                 this.is_terminator = 0;
    89         }
    90         static inline void ?=?( $mgd_link(tE) &this, void * terminator ) {
    91                 this.elem = 0p;
    92                 this.terminator = terminator;
    93                 this.is_terminator = 1;
     85        forall ( tInit | { void ?{}( $mgd_link(tE) &, tInit); } )
     86        static inline void ?=?( $mgd_link(tE) &this, tInit i ) {
     87                ^?{}( this );
     88                ?{}( this, i );
    9489        }
    9590        struct $dlinks {
     
    186181
    187182        static inline void insert_after(Tnode &list_pos, Telem &to_insert) {
    188                 verify (&list_pos != 0p);
    189                 verify (&to_insert != 0p);
     183                assert (&list_pos != 0p);
     184                assert (&to_insert != 0p);
    190185                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
    191                 verify($prev_link(singleton_to_insert).elem == 0p);
    192                 verify($next_link(singleton_to_insert).elem == 0p);
     186                assert($prev_link(singleton_to_insert).elem == 0p);
     187                assert($next_link(singleton_to_insert).elem == 0p);
    193188                $prev_link(singleton_to_insert) = & $tempcv_n2e(list_pos);
    194189                $next_link(singleton_to_insert) = $next_link(list_pos);
     
    209204
    210205        static inline void insert_before(Tnode &list_pos, Telem &to_insert) {
    211                 verify (&list_pos != 0p);
    212                 verify (&to_insert != 0p);
     206                assert (&list_pos != 0p);
     207                assert (&to_insert != 0p);
    213208                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
    214                 verify($prev_link(singleton_to_insert).elem == 0p);
    215                 verify($next_link(singleton_to_insert).elem == 0p);
     209                assert($prev_link(singleton_to_insert).elem == 0p);
     210                assert($next_link(singleton_to_insert).elem == 0p);
    216211                $next_link(singleton_to_insert) = & $tempcv_n2e(list_pos);
    217212                $prev_link(singleton_to_insert) = $prev_link(list_pos);
     
    232227
    233228    static inline void insert_first(dlist(Tnode, Telem) &list, Telem &to_insert) {
    234                 verify (&list != 0p);
    235                 verify (&to_insert != 0p);
     229                assert (&list != 0p);
     230                assert (&to_insert != 0p);
    236231                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
    237                 verify($prev_link(singleton_to_insert).elem == 0p);
    238                 verify($next_link(singleton_to_insert).elem == 0p);
     232                assert($prev_link(singleton_to_insert).elem == 0p);
     233                assert($next_link(singleton_to_insert).elem == 0p);
    239234
    240235                $prev_link(singleton_to_insert) = (void*) &list;
     
    254249
    255250    static inline void insert_last(dlist(Tnode, Telem) &list, Telem &to_insert) {
    256                 verify (&list != 0p);
    257                 verify (&to_insert != 0p);
     251                assert (&list != 0p);
     252                assert (&to_insert != 0p);
    258253                Tnode &singleton_to_insert = $tempcv_e2n(to_insert);
    259                 verify($next_link(singleton_to_insert).elem == 0p);
    260                 verify($prev_link(singleton_to_insert).elem == 0p);
     254                assert($next_link(singleton_to_insert).elem == 0p);
     255                assert($prev_link(singleton_to_insert).elem == 0p);
    261256
    262257                $next_link(singleton_to_insert) = (void*) &list;
     
    276271
    277272    static inline void remove(Tnode &list_pos) {
    278                 verify( &list_pos != 0p );
     273                assert( &list_pos != 0p );
    279274
    280275                $mgd_link(Telem) &incoming_from_prev = *0p;
     
    313308
    314309        static inline bool ?`is_empty(dlist(Tnode, Telem) &list) {
    315                 verify( &list != 0p );
     310                assert( &list != 0p );
    316311                $dlinks(Telem) *listLinks = & list.$links;
    317312                if (listLinks->next.is_terminator) {
    318                         verify(listLinks->prev.is_terminator);
    319                         verify(listLinks->next.terminator);
    320                         verify(listLinks->prev.terminator);
     313                        assert(listLinks->prev.is_terminator);
     314                        assert(listLinks->next.terminator);
     315                        assert(listLinks->prev.terminator);
    321316                        return true;
    322317                } else {
    323                         verify(!listLinks->prev.is_terminator);
    324                         verify(listLinks->next.elem);
    325                         verify(listLinks->prev.elem);
     318                        assert(!listLinks->prev.is_terminator);
     319                        assert(listLinks->next.elem);
     320                        assert(listLinks->prev.elem);
    326321                        return false;
    327322                }
     
    329324
    330325        static inline Telem & pop_first(dlist(Tnode, Telem) &list) {
    331                 verify( &list != 0p );
    332                 verify( !list`is_empty );
     326                assert( &list != 0p );
     327                assert( !list`is_empty );
    333328                $dlinks(Telem) *listLinks = & list.$links;
    334329                Telem & first = *listLinks->next.elem;
     
    339334
    340335        static inline Telem & pop_last(dlist(Tnode, Telem) &list) {
    341                 verify( &list != 0p );
    342                 verify( !list`is_empty );
     336                assert( &list != 0p );
     337                assert( !list`is_empty );
    343338                $dlinks(Telem) *listLinks = & list.$links;
    344339                Telem & last = *listLinks->prev.elem;
  • libcfa/src/exception.c

    r5407cdc rfeacef9  
    1010// Created On       : Mon Jun 26 15:13:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Feb 24 13:40:00 2021
    13 // Update Count     : 36
     12// Last Modified On : Tue Oct 27 16:27:00 2020
     13// Update Count     : 35
    1414//
    1515
     
    2626#include "concurrency/invoke.h"
    2727#include "stdhdr/assert.h"
    28 #include "virtual.h"
    2928
    3029#if defined( __ARM_ARCH )
     
    4746const _Unwind_Exception_Class __cfaehm_exception_class = 0x4c50575500414643;
    4847
    49 // Base Exception type id:
    50 struct __cfa__parent_vtable __cfatid_exception_t = {
    51         NULL,
     48// Base exception vtable is abstract, you should not have base exceptions.
     49struct __cfaehm_base_exception_t_vtable
     50                ___cfaehm_base_exception_t_vtable_instance = {
     51        .parent = NULL,
     52        .size = 0,
     53        .copy = NULL,
     54        .free = NULL,
     55        .msg = NULL
    5256};
    5357
  • libcfa/src/exception.h

    r5407cdc rfeacef9  
    1010// Created On       : Mon Jun 26 15:11:00 2017
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Apr  8 15:20:00 2021
    13 // Update Count     : 12
     12// Last Modified On : Tue Oct 27 14:45:00 2020
     13// Update Count     : 11
    1414//
    1515
     
    2929struct __cfaehm_base_exception_t;
    3030typedef struct __cfaehm_base_exception_t exception_t;
    31 struct __cfa__parent_vtable;
    3231struct __cfaehm_base_exception_t_vtable {
    33         const struct __cfa__parent_vtable * __cfavir_typeid;
     32        const struct __cfaehm_base_exception_t_vtable * parent;
    3433        size_t size;
    3534        void (*copy)(struct __cfaehm_base_exception_t *this,
     
    4140        struct __cfaehm_base_exception_t_vtable const * virtual_table;
    4241};
    43 extern struct __cfa__parent_vtable __cfatid_exception_t;
     42extern struct __cfaehm_base_exception_t_vtable
     43        ___cfaehm_base_exception_t_vtable_instance;
    4444
    4545
     
    104104        /* The first field must be a pointer to a virtual table.
    105105         * That virtual table must be a decendent of the base exception virtual table.
    106          * The virtual table must point at the prober type-id.
    107          * None of these can be enforced in an assertion.
    108106         */
     107        virtualT const & get_exception_vtable(exceptT *);
     108        // Always returns the virtual table for this type (associated types hack).
    109109};
    110110
  • libcfa/src/exception.hfa

    r5407cdc rfeacef9  
    1010// Created On       : Thu Apr  7 10:25:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Apr  8 15:16:00 2021
    13 // Update Count     : 4
     12// Last Modified On : Tue Aug  4 16:22:00 2020
     13// Update Count     : 3
    1414//
    1515
     
    1818// -----------------------------------------------------------------------------------------------
    1919
    20 // EHM_EXCEPTION(exception_name)(fields...);
    21 // Create an exception (a virtual structure that inherits from exception_t)
    22 // with the given name and fields.
    23 #define EHM_EXCEPTION(exception_name) \
    24         _EHM_TYPE_ID_STRUCT(exception_name, ); \
    25         _EHM_TYPE_ID_VALUE(exception_name, ); \
    26         _EHM_VIRTUAL_TABLE_STRUCT(exception_name, , ); \
    27         _EHM_EXCEPTION_STRUCT(exception_name, , )
    28 
    29 // EHM_EXTERN_VTABLE(exception_name, table_name);
    30 // Forward declare a virtual table called table_name for exception_name type.
    31 #define EHM_EXTERN_VTABLE(exception_name, table_name) \
    32         _EHM_EXTERN_VTABLE(exception_name, , table_name)
    33 
    34 // EHM_VIRTUAL_TABLE(exception_name, table_name);
    35 // Define a virtual table called table_name for exception_name type.
    36 #define EHM_VIRTUAL_TABLE(exception_name, table_name) \
    37         _EHM_DEFINE_COPY(exception_name, ) \
    38         _EHM_DEFINE_MSG(exception_name, ) \
    39         _EHM_VIRTUAL_TABLE(exception_name, , table_name)
    40 
    41 // EHM_FORALL_EXCEPTION(exception_name, (assertions), (parameters))(fields...);
    42 // As EHM_EXCEPTION but for polymorphic types instead of monomorphic ones.
    43 // The assertions list should include all polymorphic parameters and
    44 // assertions inside a parentisized list. Parameters should include all the
    45 // polymorphic parameter names inside a parentisized list (same order).
    46 #define EHM_FORALL_EXCEPTION(exception_name, assertions, parameters) \
    47         _EHM_TYPE_ID_STRUCT(exception_name, forall assertions); \
    48         _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall assertions, parameters); \
    49         _EHM_EXCEPTION_STRUCT(exception_name, forall assertions, parameters)
    50 
    51 // EHM_FORALL_EXTERN_VTABLE(exception_name, (arguments), table_name);
    52 // As EHM_EXTERN_VTABLE but for polymorphic types instead of monomorphic ones.
    53 // Arguments should be the parentisized list of polymorphic arguments.
    54 #define EHM_FORALL_EXTERN_VTABLE(exception_name, arguments, table_name) \
    55         _EHM_EXTERN_VTABLE(exception_name, arguments, table_name)
    56 
    57 // EHM_FORALL_VIRTUAL_TABLE(exception_name, (arguments), table_name);
    58 // As EHM_VIRTUAL_TABLE but for polymorphic types instead of monomorphic ones.
    59 // Arguments should be the parentisized list of polymorphic arguments.
    60 #define EHM_FORALL_VIRTUAL_TABLE(exception_name, arguments, table_name) \
    61         _EHM_TYPE_ID_VALUE(exception_name, arguments); \
    62         _EHM_DEFINE_COPY(exception_name, arguments) \
    63         _EHM_DEFINE_MSG(exception_name, arguments) \
    64         _EHM_VIRTUAL_TABLE(exception_name, arguments, table_name)
    65 
    66 // EHM_DEFAULT_VTABLE(exception_name, (arguments))
    67 // Create a declaration for a (possibly polymorphic) default vtable.
    68 #define EHM_DEFAULT_VTABLE(exception_name, arguments) \
    69         _EHM_VTABLE_TYPE(exception_name) arguments & const _default_vtable
     20// TRIVIAL_EXCEPTION_DECLARATION(exception_name);
     21// Declare a trivial exception, one that adds no fields or features.
     22// This will make the exception visible and may go in a .hfa or .cfa file.
     23#define TRIVIAL_EXCEPTION_DECLARATION(...) \
     24        _EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__)
     25
     26// TRIVIAL_EXCEPTION_INSTANCE(exception_name);
     27// Create the trival exception. This must be used exactly once and should be used in a .cfa file,
     28// as it creates the unique instance of the virtual table.
     29#define TRIVIAL_EXCEPTION_INSTANCE(...) _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__)
     30
     31// TRIVIAL_EXCEPTION(exception_name[, parent_name]);
     32// Does both of the above, a short hand if the exception is only used in one .cfa file.
     33// For legacy reasons this is the only one that official supports having a parent other than the
     34// base exception. This feature may be removed or changed.
     35#define TRIVIAL_EXCEPTION(...) \
     36        _EXC_DISPATCH(_TRIVIAL_EXCEPTION_DECLARATION, __VA_ARGS__); \
     37        _EXC_DISPATCH(_TRIVIAL_EXCEPTION_INSTANCE, __VA_ARGS__)
     38
     39// FORALL_TRIVIAL_EXCEPTION(exception_name, (assertions...), (parameters...));
     40// Forward declare a polymorphic but otherwise trivial exception type. You must provide the entire
     41// assertion list (exactly what would go in the forall clause) and parameters list (only the
     42// parameter names from the assertion list, same order and comma seperated). This should be
     43// visible where ever use the exception. This just generates the polymorphic framework, see
     44// POLY_VTABLE_DECLARATION to allow instantiations.
     45#define FORALL_TRIVIAL_EXCEPTION(exception_name, assertions, parameters) \
     46        _FORALL_TRIVIAL_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, )
     47
     48// FORALL_TRIVIAL_INSTANCE(exception_name, (assertions...), (parameters...))
     49// Create the forall trivial exception. The assertion list and parameters must match.
     50// There must be exactly one use of this in a program for each exception type. This just
     51// generates the polymorphic framework, see POLY_VTABLE_INSTANCE to allow instantiations.
     52#define FORALL_TRIVIAL_INSTANCE(exception_name, assertions, parameters) \
     53        _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters)
     54
     55// DATA_EXCEPTION(exception_name)(fields...);
     56// Forward declare an exception that adds fields but no features. The added fields go in the
     57// second argument list. The virtual table instance must be provided later (see VTABLE_INSTANCE).
     58#define DATA_EXCEPTION(...) _EXC_DISPATCH(_DATA_EXCEPTION, __VA_ARGS__)
     59
     60// FORALL_DATA_EXCEPTION(exception_name, (assertions...), (parameters...))(fields...);
     61// Define a polymorphic exception that adds fields but no additional features. The assertion list
     62// and matching parameters must match. Then you can give the list of fields. This should be
     63// visible where ever you use the exception. This just generates the polymorphic framework, see
     64// POLY_VTABLE_DECLARATION to allow instantiations.
     65#define FORALL_DATA_EXCEPTION(exception_name, assertions, parameters) \
     66        _FORALL_DATA_EXCEPTION(exception_name, __cfaehm_base_exception_t, assertions, parameters, )
     67
     68// FORALL_DATA_INSTANCE(exception_name, (assertions...), (parameters...))
     69// Create a polymorphic data exception. The assertion list and parameters must match. This should
     70// appear once in each program. This just generates the polymorphic framework, see
     71// POLY_VTABLE_INSTANCE to allow instantiations.
     72#define FORALL_DATA_INSTANCE(exception_name, assertions, parameters) \
     73        _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters)
     74
     75// VTABLE_DECLARATION(exception_name)([new_features...]);
     76// Declare a virtual table type for an exception with exception_name. You may also add features
     77// (fields on the virtual table) by including them in the second list.
     78#define VTABLE_DECLARATION(...) _EXC_DISPATCH(_VTABLE_DECLARATION, __VA_ARGS__)
     79
     80// VTABLE_INSTANCE(exception_name)(msg [, others...]);
     81// Create the instance of the virtual table. There must be exactly one instance of a virtual table
     82// for each exception type. This fills in most of the fields of the virtual table (uses ?=? and
     83// ^?{}) but you must provide the message function and any other fields added in the declaration.
     84#define VTABLE_INSTANCE(...) _EXC_DISPATCH(_VTABLE_INSTANCE, __VA_ARGS__)
     85
     86// FORALL_VTABLE_DECLARATION(exception_name, (assertions...), (parameters...))([new_features...]);
     87// Declare a polymorphic virtual table type for an exception with exception_name, the given
     88// assertions and parameters. You may also add features (fields on the virtual table). This just
     89// generates the polymorphic framework, see POLY_VTABLE_DECLARATION to allow instantiations.
     90#define FORALL_VTABLE_DECLARATION(exception_name, assertions, parameters) \
     91        _FORALL_VTABLE_DECLARATION(exception_name, __cfaehm_base_exception_t, assertions, parameters, )
     92
     93// POLY_VTABLE_DECLARATION(exception_name, types...);
     94// Declares that an instantiation for this exception exists for the given types. This should be
     95// visible anywhere you use the instantiation of the exception is used.
     96#define POLY_VTABLE_DECLARATION(exception_name, ...) \
     97        VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable(exception_name(__VA_ARGS__) *); \
     98        extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name)
     99
     100// POLY_VTABLE_INSTANCE(exception_name, types...)(msg [, others...]);
     101// Creates an instantiation for the given exception for the given types. This should occur only
     102// once in the entire program. You must fill in all features, message and any others given in the
     103// initial declaration.
     104#define POLY_VTABLE_INSTANCE(exception_name, ...) \
     105        _POLY_VTABLE_INSTANCE(exception_name, __cfaehm_base_exception_t, __VA_ARGS__)
     106
     107// VTABLE_TYPE(exception_name) | VTABLE_NAME(exception_name)
     108// Get the name of the vtable type or the name of the vtable instance for an exception type.
     109#define VTABLE_TYPE(exception_name) struct _GLUE2(exception_name,_vtable)
     110#define VTABLE_NAME(exception_name) _GLUE3(_,exception_name,_vtable_instance)
     111
     112// VTABLE_FIELD(exception_name);
     113// FORALL_VTABLE_FIELD(exception_name, (parameters-or-types));
     114// The declaration of the virtual table field. Should be the first declaration in a virtual type.
     115#define VTABLE_FIELD(exception_name) VTABLE_TYPE(exception_name) const * virtual_table
     116#define FORALL_VTABLE_FIELD(exception_name, parameters) \
     117        VTABLE_TYPE(exception_name) parameters const * virtual_table
     118
     119// VTABLE_INIT(object_reference, exception_name);
     120// Sets a virtual table field on an object to the virtual table instance for the type.
     121#define VTABLE_INIT(this, exception_name) (this).virtual_table = &VTABLE_NAME(exception_name)
     122
     123// VTABLE_ASSERTION(exception_name, (parameters...))
     124// The assertion that there is an instantiation of the vtable for the exception and types.
     125#define VTABLE_ASSERTION(exception_name, parameters) \
     126        { VTABLE_TYPE(exception_name) parameters VTABLE_NAME(exception_name); }
    70127
    71128// IS_EXCEPTION(exception_name [, (...parameters)])
     
    78135#define IS_TERMINATION_EXCEPTION(...) _IS_EXCEPTION(is_termination_exception, __VA_ARGS__, , ~)
    79136
    80 // Macros starting with a leading underscore are internal.
    81 
    82 // Create an exception type definition. must be tailing, can be polymorphic.
    83 #define _EHM_EXCEPTION_STRUCT(exception_name, forall_clause, parameters) \
    84         forall_clause struct exception_name { \
    85                 _EHM_VTABLE_TYPE(exception_name) parameters const * virtual_table; \
    86                 _CLOSE
    87 
    88 // Create a (possibly polymorphic) virtual table forward declaration.
    89 #define _EHM_EXTERN_VTABLE(exception_name, arguments, table_name) \
    90         extern const _EHM_VTABLE_TYPE(exception_name) arguments table_name
    91 
    92 // Create a (possibly polymorphic) virtual table definition.
    93 #define _EHM_VIRTUAL_TABLE(exception_type, arguments, table_name) \
    94         const _EHM_VTABLE_TYPE(exception_type) arguments table_name @= { \
    95                 .__cfavir_typeid : &_EHM_TYPE_ID_NAME(exception_type), \
    96                 .size : sizeof(struct exception_type arguments), \
    97                 .copy : copy, \
    98                 .^?{} : ^?{}, \
    99                 .msg : msg, \
     137// All internal helper macros begin with an underscore.
     138#define _CLOSE(...) __VA_ARGS__ }
     139#define _GLUE2(left, right) left##right
     140#define _GLUE3(left, middle, right) left##middle##right
     141#define _EXC_DISPATCH(to, ...) to(__VA_ARGS__,__cfaehm_base_exception_t,)
     142#define _UNPACK(...) __VA_ARGS__
     143
     144#define _TRIVIAL_EXCEPTION_DECLARATION(exception_name, parent_name, ...) \
     145        _VTABLE_DECLARATION(exception_name, parent_name)(); \
     146        struct exception_name { \
     147                VTABLE_FIELD(exception_name); \
     148        }; \
     149        void ?{}(exception_name & this); \
     150        const char * _GLUE2(exception_name,_msg)(exception_name * this)
     151
     152#define _TRIVIAL_EXCEPTION_INSTANCE(exception_name, parent_name, ...) \
     153        void ?{}(exception_name & this) { \
     154                VTABLE_INIT(this, exception_name); \
     155        } \
     156        const char * _GLUE2(exception_name,_msg)(exception_name * this) { \
     157                return #exception_name; \
     158        } \
     159        _VTABLE_INSTANCE(exception_name, parent_name,)(_GLUE2(exception_name,_msg))
     160
     161#define _FORALL_TRIVIAL_EXCEPTION(exception_name, parent_name, assertions, \
     162                parameters, parent_parameters) \
     163        _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \
     164                parameters, parent_parameters)(); \
     165        forall assertions struct exception_name { \
     166                FORALL_VTABLE_FIELD(exception_name, parameters); \
     167        }; \
     168        _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters)
     169
     170#define _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) \
     171        forall(_UNPACK assertions | \
     172                is_exception(exception_name parameters, VTABLE_TYPE(exception_name) parameters)) \
     173        void ?{}(exception_name parameters & this)
     174
     175#define _FORALL_CTOR0_INSTANCE(exception_name, assertions, parameters) \
     176        _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters) { \
     177                (this).virtual_table = &get_exception_vtable(&this); \
    100178        }
    101179
    102 // Create a (possibly polymorphic) copy function from an assignment operator.
    103 #define _EHM_DEFINE_FORALL_COPY(exception_name, forall_clause, parameters) \
    104         forall_clause void copy(exception_name parameters * this, \
    105                         exception_name parameters * that) { \
    106                 *this = *that; \
    107         }
    108 
    109 #define _EHM_DEFINE_COPY(exception_name, arguments) \
    110         void copy(exception_name arguments * this, exception_name arguments * that) { \
    111                 *this = *that; \
    112         }
    113 
    114 // Create a (possibly polymorphic) msg function
    115 #define _EHM_DEFINE_FORALL_MSG(exception_name, forall_clause, parameters) \
    116         forall_clause const char * msg(exception_name parameters * this) { \
    117                 return #exception_name #parameters; \
    118         }
    119 
    120 #define _EHM_DEFINE_MSG(exception_name, arguments) \
    121         const char * msg(exception_name arguments * this) { \
    122                 return #exception_name #arguments; \
    123         }
    124 
    125 // Produces the C compatable name of the virtual table type for a virtual type.
    126 #define _EHM_VTABLE_TYPE(type_name) struct _GLUE2(type_name,_vtable)
    127 
    128 // Create the vtable type for exception name.
    129 #define _EHM_VIRTUAL_TABLE_STRUCT(exception_name, forall_clause, parameters) \
    130         forall_clause struct exception_name; \
    131         forall_clause _EHM_VTABLE_TYPE(exception_name) { \
    132                 _EHM_TYPE_ID_TYPE(exception_name) parameters const * __cfavir_typeid; \
     180#define _DATA_EXCEPTION(exception_name, parent_name, ...) \
     181        _VTABLE_DECLARATION(exception_name, parent_name)(); \
     182        struct exception_name { \
     183                VTABLE_FIELD(exception_name); \
     184                _CLOSE
     185
     186#define _FORALL_DATA_EXCEPTION(exception_name, parent_name, \
     187                assertions, parameters, parent_parameters) \
     188        _FORALL_VTABLE_DECLARATION(exception_name, parent_name, \
     189                assertions, parameters, parent_parameters)(); \
     190        _FORALL_CTOR0_DECLARATION(exception_name, assertions, parameters); \
     191        forall assertions struct exception_name { \
     192                FORALL_VTABLE_FIELD(exception_name, parameters); \
     193                _CLOSE
     194
     195#define _VTABLE_DECLARATION(exception_name, parent_name, ...) \
     196        struct exception_name; \
     197        VTABLE_TYPE(exception_name); \
     198        VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *); \
     199        extern VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name); \
     200        VTABLE_TYPE(exception_name) { \
     201                VTABLE_TYPE(parent_name) const * parent; \
     202                size_t size; \
     203                void (*copy)(exception_name * this, exception_name * other); \
     204                void (*^?{})(exception_name & this); \
     205                const char * (*msg)(exception_name * this); \
     206                _CLOSE
     207
     208#define _VTABLE_INSTANCE(exception_name, parent_name, ...) \
     209        VTABLE_TYPE(exception_name) const & get_exception_vtable(exception_name *) { \
     210                return VTABLE_NAME(exception_name); \
     211        } \
     212        void _GLUE2(exception_name,_copy)(exception_name * this, exception_name * other) { \
     213                *this = *other; \
     214        } \
     215        VTABLE_TYPE(exception_name) VTABLE_NAME(exception_name) @= { \
     216                &VTABLE_NAME(parent_name), sizeof(exception_name), \
     217                _GLUE2(exception_name,_copy), ^?{}, \
     218                _CLOSE
     219
     220#define _FORALL_VTABLE_DECLARATION(exception_name, parent_name, assertions, \
     221                parameters, parent_parameters) \
     222        forall assertions struct exception_name; \
     223        forall assertions VTABLE_TYPE(exception_name) { \
     224                VTABLE_TYPE(parent_name) parent_parameters const * parent; \
    133225                size_t size; \
    134226                void (*copy)(exception_name parameters * this, exception_name parameters * other); \
    135227                void (*^?{})(exception_name parameters & this); \
    136228                const char * (*msg)(exception_name parameters * this); \
    137         }
    138 
    139 // Define the function required to satify the trait for exceptions.
    140 #define _EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \
    141         forall_clause inline void mark_exception( \
    142                 exception_name parameters const &, \
    143                 _EHM_VTABLE_TYPE(exception_name) parameters const &) {} \
    144 
    145 #define __EHM_TRAIT_FUNCTION(exception_name, forall_clause, parameters) \
    146         forall_clause inline _EHM_VTABLE_TYPE(exception_name) parameters const & \
    147                         get_exception_vtable(exception_name parameters const & this) { \
    148                 /* This comes before the structure definition, but we know the offset. */ \
    149                 /* return (_EHM_VTABLE_TYPE(exception_name) parameters const &)this; */ \
    150                 assert(false); \
    151         }
    152 
    153 // Generates a new type-id structure. This is used to mangle the name of the
    154 // type-id instance so it also includes polymorphic information. Must be the
    155 // direct decendent of exception_t.
    156 // The second field is used to recover type information about the exception.
    157 #define _EHM_TYPE_ID_STRUCT(exception_name, forall_clause) \
    158         forall_clause _EHM_TYPE_ID_TYPE(exception_name) { \
    159                 __cfa__parent_vtable const * parent; \
    160         }
    161 
    162 // Generate a new type-id value.
    163 #define _EHM_TYPE_ID_VALUE(exception_name, arguments) \
    164         __attribute__(( section(".gnu.linkonce." "__cfatid_" #exception_name) )) \
    165         _EHM_TYPE_ID_TYPE(exception_name) arguments const \
    166                         _EHM_TYPE_ID_NAME(exception_name) = { \
    167                 &__cfatid_exception_t, \
    168         }
    169 
    170 // _EHM_TYPE_ID_STRUCT and _EHM_TYPE_ID_VALUE are the two that would need to
    171 // be updated to extend the hierarchy if we are still using macros when that
    172 // is added.
    173 
    174 // Produce the C compatable name of the type-id type for an exception type.
    175 #define _EHM_TYPE_ID_TYPE(exception_name) \
    176         struct _GLUE2(__cfatid_struct_, exception_name)
    177 
    178 // Produce the name of the instance of the type-id for an exception type.
    179 #define _EHM_TYPE_ID_NAME(exception_name) _GLUE2(__cfatid_,exception_name)
     229                _CLOSE
     230
     231#define _POLY_VTABLE_INSTANCE(exception_name, parent_name, ...) \
     232        extern VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name); \
     233        VTABLE_TYPE(exception_name)(__VA_ARGS__) const & get_exception_vtable( \
     234                        exception_name(__VA_ARGS__) *) { \
     235                return VTABLE_NAME(exception_name); \
     236        } \
     237        void _GLUE2(exception_name,_copy)( \
     238                        exception_name(__VA_ARGS__) * this, exception_name(__VA_ARGS__) * other) { \
     239                *this = *other; \
     240        } \
     241        VTABLE_TYPE(exception_name)(__VA_ARGS__) VTABLE_NAME(exception_name) @= { \
     242                &VTABLE_NAME(parent_name), sizeof(exception_name(__VA_ARGS__)), \
     243                _GLUE2(exception_name,_copy), ^?{}, \
     244                _CLOSE
    180245
    181246#define _IS_EXCEPTION(kind, exception_name, parameters, ...) \
    182         kind(exception_name parameters, _EHM_VTABLE_TYPE(exception_name) parameters)
    183 
    184 // Internal helper macros:
    185 #define _CLOSE(...) __VA_ARGS__ }
    186 #define _GLUE2(left, right) left##right
     247        kind(exception_name parameters, VTABLE_TYPE(exception_name) parameters)
  • libcfa/src/fstream.cfa

    r5407cdc rfeacef9  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 22:08:57 2021
    13 // Update Count     : 442
    14 //
    15 
    16 #include "fstream.hfa"                                                                  // also includes iostream.hfa
     12// Last Modified On : Fri Jun 19 16:24:54 2020
     13// Update Count     : 384
     14//
     15
     16#include "fstream.hfa"
    1717
    1818#include <stdio.h>                                                                              // vfprintf, vfscanf
    1919#include <stdlib.h>                                                                             // exit
    2020#include <stdarg.h>                                                                             // varargs
    21 #include <string.h>                                                                             // strncpy, strerror
     21#include <string.h>                                                                             // strlen
     22#include <float.h>                                                                              // DBL_DIG, LDBL_DIG
     23#include <complex.h>                                                                    // creal, cimag
    2224#include <assert.h>
    2325#include <errno.h>                                                                              // errno
    2426
     27
    2528// *********************************** ofstream ***********************************
    2629
     
    2932
    3033void ?{}( ofstream & os, void * file ) {
    31         os.file$ = file;
    32         os.sepDefault$ = true;
    33         os.sepOnOff$ = false;
    34         os.nlOnOff$ = true;
    35         os.prt$ = false;
    36         os.sawNL$ = false;
    37         os.acquired$ = false;
    38         sepSetCur$( os, sepGet( os ) );
     34        os.$file = file;
     35        os.$sepDefault = true;
     36        os.$sepOnOff = false;
     37        os.$nlOnOff = true;
     38        os.$prt = false;
     39        os.$sawNL = false;
     40        $sepSetCur( os, sepGet( os ) );
    3941        sepSet( os, " " );
    4042        sepSetTuple( os, ", " );
     
    4244
    4345// private
    44 bool sepPrt$( ofstream & os ) { setNL$( os, false ); return os.sepOnOff$; }
    45 void sepReset$( ofstream & os ) { os.sepOnOff$ = os.sepDefault$; }
    46 void sepReset$( ofstream & os, bool reset ) { os.sepDefault$ = reset; os.sepOnOff$ = os.sepDefault$; }
    47 const char * sepGetCur$( ofstream & os ) { return os.sepCur$; }
    48 void sepSetCur$( ofstream & os, const char sepCur[] ) { os.sepCur$ = sepCur; }
    49 bool getNL$( ofstream & os ) { return os.sawNL$; }
    50 void setNL$( ofstream & os, bool state ) { os.sawNL$ = state; }
    51 bool getANL$( ofstream & os ) { return os.nlOnOff$; }
    52 bool getPrt$( ofstream & os ) { return os.prt$; }
    53 void setPrt$( ofstream & os, bool state ) { os.prt$ = state; }
     46bool $sepPrt( ofstream & os ) { $setNL( os, false ); return os.$sepOnOff; }
     47void $sepReset( ofstream & os ) { os.$sepOnOff = os.$sepDefault; }
     48void $sepReset( ofstream & os, bool reset ) { os.$sepDefault = reset; os.$sepOnOff = os.$sepDefault; }
     49const char * $sepGetCur( ofstream & os ) { return os.$sepCur; }
     50void $sepSetCur( ofstream & os, const char sepCur[] ) { os.$sepCur = sepCur; }
     51bool $getNL( ofstream & os ) { return os.$sawNL; }
     52void $setNL( ofstream & os, bool state ) { os.$sawNL = state; }
     53bool $getANL( ofstream & os ) { return os.$nlOnOff; }
     54bool $getPrt( ofstream & os ) { return os.$prt; }
     55void $setPrt( ofstream & os, bool state ) { os.$prt = state; }
    5456
    5557// public
    56 void ?{}( ofstream & os ) { os.file$ = 0p; }
     58void ?{}( ofstream & os ) { os.$file = 0p; }
    5759
    5860void ?{}( ofstream & os, const char name[], const char mode[] ) {
     
    6870} // ^?{}
    6971
    70 void sepOn( ofstream & os ) { os.sepOnOff$ = ! getNL$( os ); }
    71 void sepOff( ofstream & os ) { os.sepOnOff$ = false; }
     72void sepOn( ofstream & os ) { os.$sepOnOff = ! $getNL( os ); }
     73void sepOff( ofstream & os ) { os.$sepOnOff = false; }
    7274
    7375bool sepDisable( ofstream & os ) {
    74         bool temp = os.sepDefault$;
    75         os.sepDefault$ = false;
    76         sepReset$( os );
     76        bool temp = os.$sepDefault;
     77        os.$sepDefault = false;
     78        $sepReset( os );
    7779        return temp;
    7880} // sepDisable
    7981
    8082bool sepEnable( ofstream & os ) {
    81         bool temp = os.sepDefault$;
    82         os.sepDefault$ = true;
    83         if ( os.sepOnOff$ ) sepReset$( os );                            // start of line ?
     83        bool temp = os.$sepDefault;
     84        os.$sepDefault = true;
     85        if ( os.$sepOnOff ) $sepReset( os );                            // start of line ?
    8486        return temp;
    8587} // sepEnable
    8688
    87 void nlOn( ofstream & os ) { os.nlOnOff$ = true; }
    88 void nlOff( ofstream & os ) { os.nlOnOff$ = false; }
    89 
    90 const char * sepGet( ofstream & os ) { return os.separator$; }
     89void nlOn( ofstream & os ) { os.$nlOnOff = true; }
     90void nlOff( ofstream & os ) { os.$nlOnOff = false; }
     91
     92const char * sepGet( ofstream & os ) { return os.$separator; }
    9193void sepSet( ofstream & os, const char s[] ) {
    9294        assert( s );
    93         strncpy( os.separator$, s, ofstream_sepSize - 1 );
    94         os.separator$[ofstream_sepSize - 1] = '\0';
     95        strncpy( os.$separator, s, sepSize - 1 );
     96        os.$separator[sepSize - 1] = '\0';
    9597} // sepSet
    9698
    97 const char * sepGetTuple( ofstream & os ) { return os.tupleSeparator$; }
     99const char * sepGetTuple( ofstream & os ) { return os.$tupleSeparator; }
    98100void sepSetTuple( ofstream & os, const char s[] ) {
    99101        assert( s );
    100         strncpy( os.tupleSeparator$, s, ofstream_sepSize - 1 );
    101         os.tupleSeparator$[ofstream_sepSize - 1] = '\0';
     102        strncpy( os.$tupleSeparator, s, sepSize - 1 );
     103        os.$tupleSeparator[sepSize - 1] = '\0';
    102104} // sepSet
    103105
    104106void ends( ofstream & os ) {
    105         if ( getANL$( os ) ) nl( os );
    106         else setPrt$( os, false );                                                      // turn off
     107        if ( $getANL( os ) ) nl( os );
     108        else $setPrt( os, false );                                                      // turn off
    107109        if ( &os == &exit ) exit( EXIT_FAILURE );
    108110        if ( &os == &abort ) abort();
    109         if ( os.acquired$ ) { os.acquired$ = false; release( os ); }
    110111} // ends
    111112
    112 bool fail( ofstream & os ) {
    113         return os.file$ == 0 || ferror( (FILE *)(os.file$) );
     113int fail( ofstream & os ) {
     114        return os.$file == 0 || ferror( (FILE *)(os.$file) );
    114115} // fail
    115116
    116117int flush( ofstream & os ) {
    117         return fflush( (FILE *)(os.file$) );
     118        return fflush( (FILE *)(os.$file) );
    118119} // flush
    119120
     
    134135
    135136void close( ofstream & os ) {
    136   if ( (FILE *)(os.file$) == 0p ) return;
    137   if ( (FILE *)(os.file$) == (FILE *)stdout || (FILE *)(os.file$) == (FILE *)stderr ) return;
    138 
    139         if ( fclose( (FILE *)(os.file$) ) == EOF ) {
     137  if ( (FILE *)(os.$file) == 0p ) return;
     138  if ( (FILE *)(os.$file) == (FILE *)stdout || (FILE *)(os.$file) == (FILE *)stderr ) return;
     139
     140        if ( fclose( (FILE *)(os.$file) ) == EOF ) {
    140141                abort | IO_MSG "close output" | nl | strerror( errno );
    141142        } // if
    142         os.file$ = 0p;
     143        os.$file = 0p;
    143144} // close
    144145
     
    148149        } // if
    149150
    150         if ( fwrite( data, 1, size, (FILE *)(os.file$) ) != size ) {
     151        if ( fwrite( data, 1, size, (FILE *)(os.$file) ) != size ) {
    151152                abort | IO_MSG "write" | nl | strerror( errno );
    152153        } // if
     
    157158        va_list args;
    158159        va_start( args, format );
    159         int len = vfprintf( (FILE *)(os.file$), format, args );
     160        int len = vfprintf( (FILE *)(os.$file), format, args );
    160161        if ( len == EOF ) {
    161                 if ( ferror( (FILE *)(os.file$) ) ) {
     162                if ( ferror( (FILE *)(os.$file) ) ) {
    162163                        abort | IO_MSG "invalid write";
    163164                } // if
     
    165166        va_end( args );
    166167
    167         setPrt$( os, true );                                                            // called in output cascade
    168         sepReset$( os );                                                                        // reset separator
     168        $setPrt( os, true );                                                            // called in output cascade
     169        $sepReset( os );                                                                        // reset separator
    169170        return len;
    170171} // fmt
    171 
    172 inline void acquire( ofstream & os ) {
    173         lock( os.lock$ );
    174         if ( ! os.acquired$ ) os.acquired$ = true;
    175         else unlock( os.lock$ );
    176 } // acquire
    177 
    178 inline void release( ofstream & os ) {
    179         unlock( os.lock$ );
    180 } // release
    181 
    182 void ?{}( osacquire & acq, ofstream & os ) { &acq.os = &os; lock( os.lock$ ); }
    183 void ^?{}( osacquire & acq ) { release( acq.os ); }
    184172
    185173static ofstream soutFile = { (FILE *)stdout };
     
    188176ofstream & serr = serrFile, & stderr = serrFile;
    189177
    190 static ofstream lsoutFile = { (FILE *)stdout };
    191 ofstream & lsout = lsoutFile;
    192 
    193178static ofstream exitFile = { (FILE *)stdout };
    194179ofstream & exit = exitFile;
     
    196181ofstream & abort = abortFile;
    197182
    198 ofstream & nl( ofstream & os ) {
    199         nl$( os );                                                                                      // call basic_ostream nl
    200         flush( os );
    201         return os;
    202         // (ofstream &)(os | '\n');
    203         // setPrt$( os, false );                                                        // turn off
    204         // setNL$( os, true );
    205         // flush( os );
    206         // return sepOff( os );                                                 // prepare for next line
    207 } // nl
    208183
    209184// *********************************** ifstream ***********************************
     
    212187// private
    213188void ?{}( ifstream & is, void * file ) {
    214         is.file$ = file;
    215         is.nlOnOff$ = false;
    216         is.acquired$ = false;
     189        is.$file = file;
     190        is.$nlOnOff = false;
    217191} // ?{}
    218192
    219193// public
    220 void ?{}( ifstream & is ) { is.file$ = 0p; }
     194void ?{}( ifstream & is ) { is.$file = 0p; }
    221195
    222196void ?{}( ifstream & is, const char name[], const char mode[] ) {
     
    232206} // ^?{}
    233207
    234 void nlOn( ifstream & os ) { os.nlOnOff$ = true; }
    235 void nlOff( ifstream & os ) { os.nlOnOff$ = false; }
    236 bool getANL( ifstream & os ) { return os.nlOnOff$; }
    237 
    238 bool fail( ifstream & is ) {
    239         return is.file$ == 0p || ferror( (FILE *)(is.file$) );
     208void nlOn( ifstream & os ) { os.$nlOnOff = true; }
     209void nlOff( ifstream & os ) { os.$nlOnOff = false; }
     210bool getANL( ifstream & os ) { return os.$nlOnOff; }
     211
     212int fail( ifstream & is ) {
     213        return is.$file == 0p || ferror( (FILE *)(is.$file) );
    240214} // fail
    241215
    242 void ends( ifstream & is ) {
    243         if ( is.acquired$ ) { is.acquired$ = false; release( is ); }
    244 } // ends
    245 
    246216int eof( ifstream & is ) {
    247         return feof( (FILE *)(is.file$) );
     217        return feof( (FILE *)(is.$file) );
    248218} // eof
    249219
     
    256226        } // if
    257227        #endif // __CFA_DEBUG__
    258         is.file$ = file;
     228        is.$file = file;
    259229} // open
    260230
     
    264234
    265235void close( ifstream & is ) {
    266   if ( (FILE *)(is.file$) == 0p ) return;
    267   if ( (FILE *)(is.file$) == (FILE *)stdin ) return;
    268 
    269         if ( fclose( (FILE *)(is.file$) ) == EOF ) {
     236  if ( (FILE *)(is.$file) == 0p ) return;
     237  if ( (FILE *)(is.$file) == (FILE *)stdin ) return;
     238
     239        if ( fclose( (FILE *)(is.$file) ) == EOF ) {
    270240                abort | IO_MSG "close input" | nl | strerror( errno );
    271241        } // if
    272         is.file$ = 0p;
     242        is.$file = 0p;
    273243} // close
    274244
     
    278248        } // if
    279249
    280         if ( fread( data, size, 1, (FILE *)(is.file$) ) == 0 ) {
     250        if ( fread( data, size, 1, (FILE *)(is.$file) ) == 0 ) {
    281251                abort | IO_MSG "read" | nl | strerror( errno );
    282252        } // if
     
    289259        } // if
    290260
    291         if ( ungetc( c, (FILE *)(is.file$) ) == EOF ) {
     261        if ( ungetc( c, (FILE *)(is.$file) ) == EOF ) {
    292262                abort | IO_MSG "ungetc" | nl | strerror( errno );
    293263        } // if
     
    299269
    300270        va_start( args, format );
    301         int len = vfscanf( (FILE *)(is.file$), format, args );
     271        int len = vfscanf( (FILE *)(is.$file), format, args );
    302272        if ( len == EOF ) {
    303                 if ( ferror( (FILE *)(is.file$) ) ) {
     273                if ( ferror( (FILE *)(is.$file) ) ) {
    304274                        abort | IO_MSG "invalid read";
    305275                } // if
     
    309279} // fmt
    310280
    311 inline void acquire( ifstream & is ) {
    312         lock( is.lock$ );
    313         if ( ! is.acquired$ ) is.acquired$ = true;
    314         else unlock( is.lock$ );
    315 } // acquire
    316 
    317 inline void release( ifstream & is ) {
    318         unlock( is.lock$ );
    319 } // release
    320 
    321 void ?{}( isacquire & acq, ifstream & is ) { &acq.is = &is; lock( is.lock$ ); }
    322 void ^?{}( isacquire & acq ) { release( acq.is ); }
    323 
    324281static ifstream sinFile = { (FILE *)stdin };
    325282ifstream & sin = sinFile, & stdin = sinFile;
     
    329286
    330287
    331 EHM_VIRTUAL_TABLE(Open_Failure, Open_Failure_main_table);
    332288void ?{}( Open_Failure & this, ofstream & ostream ) {
    333         this.virtual_table = &Open_Failure_main_table;
     289        VTABLE_INIT(this, Open_Failure);
    334290        this.ostream = &ostream;
    335291        this.tag = 1;
    336292}
    337293void ?{}( Open_Failure & this, ifstream & istream ) {
    338         this.virtual_table = &Open_Failure_main_table;
     294        VTABLE_INIT(this, Open_Failure);
    339295        this.istream = &istream;
    340296        this.tag = 0;
    341297}
     298const char * Open_Failure_msg(Open_Failure * this) {
     299        return "Open_Failure";
     300}
     301VTABLE_INSTANCE(Open_Failure)(Open_Failure_msg);
    342302void throwOpen_Failure( ofstream & ostream ) {
    343303        Open_Failure exc = { ostream };
  • libcfa/src/fstream.hfa

    r5407cdc rfeacef9  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 22:00:30 2021
    13 // Update Count     : 226
     12// Last Modified On : Fri Jun 19 16:29:17 2020
     13// Update Count     : 189
    1414//
    1515
    1616#pragma once
    1717
    18 #include "bits/weakso_locks.hfa"                                                // mutex_lock
     18#include "bits/weakso_locks.hfa"
    1919#include "iostream.hfa"
    2020#include <exception.hfa>
     
    2424
    2525
    26 enum { ofstream_sepSize = 16 };
     26enum { sepSize = 16 };
    2727struct ofstream {
    28         void * file$;
    29         bool sepDefault$;
    30         bool sepOnOff$;
    31         bool nlOnOff$;
    32         bool prt$;                                                                                      // print text
    33         bool sawNL$;
    34         const char * sepCur$;
    35         char separator$[ofstream_sepSize];
    36         char tupleSeparator$[ofstream_sepSize];
    37         multiple_acquisition_lock lock$;
    38         bool acquired$;
     28        void * $file;
     29        bool $sepDefault;
     30        bool $sepOnOff;
     31        bool $nlOnOff;
     32        bool $prt;                                                                                      // print text
     33        bool $sawNL;
     34        const char * $sepCur;
     35        char $separator[sepSize];
     36        char $tupleSeparator[sepSize];
     37//      multiple_acquisition_lock lock;
    3938}; // ofstream
    4039
    41 // Satisfies ostream
    42 
    4340// private
    44 bool sepPrt$( ofstream & );
    45 void sepReset$( ofstream & );
    46 void sepReset$( ofstream &, bool );
    47 const char * sepGetCur$( ofstream & );
    48 void sepSetCur$( ofstream &, const char [] );
    49 bool getNL$( ofstream & );
    50 void setNL$( ofstream &, bool );
    51 bool getANL$( ofstream & );
    52 bool getPrt$( ofstream & );
    53 void setPrt$( ofstream &, bool );
     41bool $sepPrt( ofstream & );
     42void $sepReset( ofstream & );
     43void $sepReset( ofstream &, bool );
     44const char * $sepGetCur( ofstream & );
     45void $sepSetCur( ofstream &, const char [] );
     46bool $getNL( ofstream & );
     47void $setNL( ofstream &, bool );
     48bool $getANL( ofstream & );
     49bool $getPrt( ofstream & );
     50void $setPrt( ofstream &, bool );
    5451
    5552// public
     
    6663void sepSetTuple( ofstream &, const char [] );
    6764
    68 void ends( ofstream & );
    69 int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
    70 
    71 bool fail( ofstream & );
     65void ends( ofstream & os );
     66int fail( ofstream & );
    7267int flush( ofstream & );
    73 void open( ofstream &, const char name[], const char mode[] ); // FIX ME: use default = "w"
     68void open( ofstream &, const char name[], const char mode[] );
    7469void open( ofstream &, const char name[] );
    7570void close( ofstream & );
    7671ofstream & write( ofstream &, const char data[], size_t size );
     72int fmt( ofstream &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
    7773
    78 void acquire( ofstream & );
    79 void release( ofstream & );
    80 
    81 struct osacquire {
    82         ofstream & os;
    83 };
    84 void ?{}( osacquire & acq, ofstream & );
    85 void ^?{}( osacquire & acq );
    86 
    87 void ?{}( ofstream & );
    88 void ?{}( ofstream &, const char name[], const char mode[] ); // FIX ME: use default = "w"
    89 void ?{}( ofstream &, const char name[] );
    90 void ^?{}( ofstream & );
    91 
    92 // private
    93 static inline ofstream & nl$( ofstream & os ) { return nl( os ); } // remember basic_ostream nl
    94 // public
    95 ofstream & nl( ofstream & os );                                                 // override basic_ostream nl
     74void ?{}( ofstream & os );
     75void ?{}( ofstream & os, const char name[], const char mode[] );
     76void ?{}( ofstream & os, const char name[] );
     77void ^?{}( ofstream & os );
    9678
    9779extern ofstream & sout, & stdout, & serr, & stderr;             // aliases
     
    10385
    10486struct ifstream {
    105         void * file$;
    106         bool nlOnOff$;
    107         multiple_acquisition_lock lock$;
    108         bool acquired$;
     87        void * $file;
     88        bool $nlOnOff;
    10989}; // ifstream
    110 
    111 // Satisfies istream
    11290
    11391// public
     
    11593void nlOff( ifstream & );
    11694bool getANL( ifstream & );
    117 void ends( ifstream & );
    118 int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    119 
    120 bool fail( ifstream & is );
     95int fail( ifstream & is );
    12196int eof( ifstream & is );
    122 void open( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r"
     97void open( ifstream & is, const char name[], const char mode[] );
    12398void open( ifstream & is, const char name[] );
    12499void close( ifstream & is );
    125100ifstream & read( ifstream & is, char * data, size_t size );
    126101ifstream & ungetc( ifstream & is, char c );
    127 
    128 void acquire( ifstream & is );
    129 void release( ifstream & is );
    130 
    131 struct isacquire {
    132         ifstream & is;
    133 };
    134 void ?{}( isacquire & acq, ifstream & is );
    135 void ^?{}( isacquire & acq );
     102int fmt( ifstream &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    136103
    137104void ?{}( ifstream & is );
    138 void ?{}( ifstream & is, const char name[], const char mode[] ); // FIX ME: use default = "r"
     105void ?{}( ifstream & is, const char name[], const char mode[] );
    139106void ?{}( ifstream & is, const char name[] );
    140107void ^?{}( ifstream & is );
     
    146113
    147114
    148 EHM_EXCEPTION(Open_Failure)(
     115DATA_EXCEPTION(Open_Failure)(
    149116        union {
    150117                ofstream * ostream;
     
    155122);
    156123
    157 void ?{}( Open_Failure & this, ofstream & );
    158 void ?{}( Open_Failure & this, ifstream & );
     124void ?{}( Open_Failure & this, ofstream & ostream );
     125void ?{}( Open_Failure & this, ifstream & istream );
    159126
    160127// Local Variables: //
  • libcfa/src/gmp.hfa

    r5407cdc rfeacef9  
    1010// Created On       : Tue Apr 19 08:43:43 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 20 20:59:21 2021
    13 // Update Count     : 32
     12// Last Modified On : Sun Feb  9 09:56:54 2020
     13// Update Count     : 31
    1414//
    1515
     
    263263        forall( ostype & | ostream( ostype ) ) {
    264264                ostype & ?|?( ostype & os, Int mp ) {
    265                         if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     265                        if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    266266                        gmp_printf( "%Zd", mp.mpz );
    267267                        sepOn( os );
  • libcfa/src/heap.cfa

    r5407cdc rfeacef9  
    1010// Created On       : Tue Dec 19 21:58:35 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 20 21:20:48 2021
    13 // Update Count     : 1033
     12// Last Modified On : Sun Jan 10 11:20:49 2021
     13// Update Count     : 1031
    1414//
    1515
     
    5252static bool prtFree = false;
    5353
    54 bool prtFree() {
     54inline bool prtFree() {
    5555        return prtFree;
    5656} // prtFree
     
    11281128
    11291129        // Set the alignment for an the allocation and return previous alignment or 0 if no alignment.
    1130         size_t malloc_alignment_set$( void * addr, size_t alignment ) {
     1130        size_t $malloc_alignment_set( void * addr, size_t alignment ) {
    11311131          if ( unlikely( addr == 0p ) ) return libAlign();      // minimum alignment
    11321132                size_t ret;
     
    11391139                } // if
    11401140                return ret;
    1141         } // malloc_alignment_set$
     1141        } // $malloc_alignment_set
    11421142
    11431143
     
    11531153
    11541154        // Set allocation is zero filled and return previous zero filled.
    1155         bool malloc_zero_fill_set$( void * addr ) {
     1155        bool $malloc_zero_fill_set( void * addr ) {
    11561156          if ( unlikely( addr == 0p ) ) return false;           // null allocation is not zero fill
    11571157                HeapManager.Storage.Header * header = headerAddr( addr );
     
    11621162                header->kind.real.blockSize |= 2;                               // mark as zero filled
    11631163                return ret;
    1164         } // malloc_zero_fill_set$
     1164        } // $malloc_zero_fill_set
    11651165
    11661166
     
    11761176
    11771177        // Set allocation size and return previous size.
    1178         size_t malloc_size_set$( void * addr, size_t size ) {
     1178        size_t $malloc_size_set( void * addr, size_t size ) {
    11791179          if ( unlikely( addr == 0p ) ) return 0;                       // null allocation has 0 size
    11801180                HeapManager.Storage.Header * header = headerAddr( addr );
     
    11851185                header->kind.real.size = size;
    11861186                return ret;
    1187         } // malloc_size_set$
     1187        } // $malloc_size_set
    11881188
    11891189
  • libcfa/src/iostream.cfa

    r5407cdc rfeacef9  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 18:01:03 2021
    13 // Update Count     : 1330
     12// Last Modified On : Mon Aug 24 08:31:35 2020
     13// Update Count     : 1130
    1414//
    1515
     
    3636
    3737
    38 forall( ostype & | basic_ostream( ostype ) ) {
     38forall( ostype & | ostream( ostype ) ) {
    3939        ostype & ?|?( ostype & os, bool b ) {
    40                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     40                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    4141                fmt( os, "%s", b ? "true" : "false" );
    4242                return os;
     
    4848        ostype & ?|?( ostype & os, char c ) {
    4949                fmt( os, "%c", c );
    50                 if ( c == '\n' ) setNL$( os, true );
     50                if ( c == '\n' ) $setNL( os, true );
    5151                return sepOff( os );
    5252        } // ?|?
     
    5656
    5757        ostype & ?|?( ostype & os, signed char sc ) {
    58                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     58                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    5959                fmt( os, "%hhd", sc );
    6060                return os;
     
    6565
    6666        ostype & ?|?( ostype & os, unsigned char usc ) {
    67                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     67                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    6868                fmt( os, "%hhu", usc );
    6969                return os;
     
    7474
    7575        ostype & ?|?( ostype & os, short int si ) {
    76                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     76                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    7777                fmt( os, "%hd", si );
    7878                return os;
     
    8383
    8484        ostype & ?|?( ostype & os, unsigned short int usi ) {
    85                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     85                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    8686                fmt( os, "%hu", usi );
    8787                return os;
     
    9292
    9393        ostype & ?|?( ostype & os, int i ) {
    94                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     94                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    9595                fmt( os, "%d", i );
    9696                return os;
     
    101101
    102102        ostype & ?|?( ostype & os, unsigned int ui ) {
    103                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     103                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    104104                fmt( os, "%u", ui );
    105105                return os;
     
    110110
    111111        ostype & ?|?( ostype & os, long int li ) {
    112                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     112                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    113113                fmt( os, "%ld", li );
    114114                return os;
     
    119119
    120120        ostype & ?|?( ostype & os, unsigned long int uli ) {
    121                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     121                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    122122                fmt( os, "%lu", uli );
    123123                return os;
     
    128128
    129129        ostype & ?|?( ostype & os, long long int lli ) {
    130                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     130                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    131131                fmt( os, "%lld", lli );
    132132                return os;
     
    137137
    138138        ostype & ?|?( ostype & os, unsigned long long int ulli ) {
    139                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     139                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    140140                fmt( os, "%llu", ulli );
    141141                return os;
     
    145145        } // ?|?
    146146
    147         #if defined( __SIZEOF_INT128__ )
     147#if defined( __SIZEOF_INT128__ )
    148148        //      UINT64_MAX 18_446_744_073_709_551_615_ULL
    149149        #define P10_UINT64 10_000_000_000_000_000_000_ULL       // 19 zeroes
    150150
    151151        static inline void base10_128( ostype & os, unsigned int128 val ) {
    152                 #if defined(__GNUC__) && __GNUC_PREREQ(7,0)             // gcc version >= 7
     152#if defined(__GNUC__) && __GNUC_PREREQ(7,0)                             // gcc version >= 7
    153153                if ( val > P10_UINT64 ) {
    154                 #else
     154#else
    155155                if ( (uint64_t)(val >> 64) != 0 || (uint64_t)val > P10_UINT64 ) { // patch gcc 5 & 6 -O3 bug
    156                 #endif // __GNUC_PREREQ(7,0)
     156#endif // __GNUC_PREREQ(7,0)
    157157                        base10_128( os, val / P10_UINT64 );                     // recursive
    158158                        fmt( os, "%.19lu", (uint64_t)(val % P10_UINT64) );
     
    171171
    172172        ostype & ?|?( ostype & os, int128 llli ) {
    173                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     173                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    174174                base10_128( os, llli );
    175175                return os;
     
    180180
    181181        ostype & ?|?( ostype & os, unsigned int128 ullli ) {
    182                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     182                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    183183                base10_128( os, ullli );
    184184                return os;
     
    187187                (ostype &)(os | ullli); ends( os );
    188188        } // ?|?
    189         #endif // __SIZEOF_INT128__
     189#endif // __SIZEOF_INT128__
    190190
    191191        #define PrintWithDP( os, format, val, ... ) \
     
    195195                        int len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
    196196                        fmt( os, "%s", buf ); \
    197                         if ( isfinite( val ) ) { /* if number, print decimal point when no fraction or exponent */ \
     197                        if ( isfinite( val ) ) {                                        /* if number, always print decimal point */ \
    198198                                for ( int i = 0;; i += 1 ) { \
    199199                                        if ( i == len ) { fmt( os, "." ); break; } \
    200                                         if ( buf[i] == '.' || buf[i] == 'e' || buf[i] == 'E' ) break; /* decimal point or scientific ? */ \
     200                                        if ( buf[i] == '.' ) break; \
    201201                                } /* for */ \
    202202                        } /* if */ \
     
    204204
    205205        ostype & ?|?( ostype & os, float f ) {
    206                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     206                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    207207                PrintWithDP( os, "%g", f );
    208208                return os;
     
    213213
    214214        ostype & ?|?( ostype & os, double d ) {
    215                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     215                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    216216                PrintWithDP( os, "%.*lg", d, DBL_DIG );
    217217                return os;
     
    222222
    223223        ostype & ?|?( ostype & os, long double ld ) {
    224                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     224                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    225225                PrintWithDP( os, "%.*Lg", ld, LDBL_DIG );
    226226                return os;
     
    231231
    232232        ostype & ?|?( ostype & os, float _Complex fc ) {
    233                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     233                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    234234//              os | crealf( fc ) | nonl;
    235235                PrintWithDP( os, "%g", crealf( fc ) );
     
    243243
    244244        ostype & ?|?( ostype & os, double _Complex dc ) {
    245                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     245                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    246246//              os | creal( dc ) | nonl;
    247247                PrintWithDP( os, "%.*lg", creal( dc ), DBL_DIG );
     
    255255
    256256        ostype & ?|?( ostype & os, long double _Complex ldc ) {
    257                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     257                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    258258//              os | creall( ldc ) || nonl;
    259259                PrintWithDP( os, "%.*Lg", creall( ldc ), LDBL_DIG );
     
    266266        } // ?|?
    267267
    268         ostype & ?|?( ostype & os, const char s[] ) {
     268        ostype & ?|?( ostype & os, const char str[] ) {
    269269                enum { Open = 1, Close, OpenClose };
    270270                static const unsigned char mask[256] @= {
     
    282282                }; // mask
    283283
    284           if ( s[0] == '\0' ) { sepOff( os ); return os; } // null string => no separator
     284          if ( str[0] == '\0' ) { sepOff( os ); return os; } // null string => no separator
    285285
    286286                // first character IS NOT spacing or closing punctuation => add left separator
    287                 unsigned char ch = s[0];                                                // must make unsigned
    288                 if ( sepPrt$( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
    289                         fmt( os, "%s", sepGetCur$( os ) );
     287                unsigned char ch = str[0];                                              // must make unsigned
     288                if ( $sepPrt( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
     289                        fmt( os, "%s", $sepGetCur( os ) );
    290290                } // if
    291291
    292292                // if string starts line, must reset to determine open state because separator is off
    293                 sepReset$( os );                                                                // reset separator
     293                $sepReset( os );                                                                // reset separator
    294294
    295295                // last character IS spacing or opening punctuation => turn off separator for next item
    296                 int len = strlen( s );
    297                 ch = s[len - 1];                                                                // must make unsigned
    298                 fmt( os, "%s", s );                                                             // fmt resets seperator, but reset it again
    299                 if ( sepPrt$( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
     296                size_t len = strlen( str );
     297                ch = str[len - 1];                                                              // must make unsigned
     298                if ( $sepPrt( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
    300299                        sepOn( os );
    301300                } else {
    302301                        sepOff( os );
    303302                } // if
    304                 if ( ch == '\n' ) setNL$( os, true );                   // check *AFTER* sepPrt$ call above as it resets NL flag
    305                 return os;
    306 //              return write( os, s, len );
    307         } // ?|?
    308         void ?|?( ostype & os, const char s[] ) {
    309                 (ostype &)(os | s); ends( os );
    310         } // ?|?
    311 
    312 //      ostype & ?|?( ostype & os, const char16_t * s ) {
    313 //              if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    314 //              fmt( os, "%ls", s );
     303                if ( ch == '\n' ) $setNL( os, true );                   // check *AFTER* $sepPrt call above as it resets NL flag
     304                return write( os, str, len );
     305        } // ?|?
     306
     307        void ?|?( ostype & os, const char str[] ) {
     308                (ostype &)(os | str); ends( os );
     309        } // ?|?
     310
     311//      ostype & ?|?( ostype & os, const char16_t * str ) {
     312//              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     313//              fmt( os, "%ls", str );
    315314//              return os;
    316315//      } // ?|?
    317316
    318317// #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
    319 //      ostype & ?|?( ostype & os, const char32_t * s ) {
    320 //              if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    321 //              fmt( os, "%ls", s );
     318//      ostype & ?|?( ostype & os, const char32_t * str ) {
     319//              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     320//              fmt( os, "%ls", str );
    322321//              return os;
    323322//      } // ?|?
    324323// #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )
    325324
    326 //      ostype & ?|?( ostype & os, const wchar_t * s ) {
    327 //              if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
    328 //              fmt( os, "%ls", s );
     325//      ostype & ?|?( ostype & os, const wchar_t * str ) {
     326//              if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
     327//              fmt( os, "%ls", str );
    329328//              return os;
    330329//      } // ?|?
    331330
    332331        ostype & ?|?( ostype & os, const void * p ) {
    333                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     332                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    334333                fmt( os, "%p", p );
    335334                return os;
     
    341340        // manipulators
    342341        ostype & ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
    343                 return manip( os );
     342                (ostype &)(manip( os ));
     343                return os;
    344344        } // ?|?
    345345        void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
    346                 manip( os );
    347                 if ( getPrt$( os ) ) ends( os );                                // something printed ?
    348                 setPrt$( os, false );                                                   // turn off
     346                (ostype &)(manip( os ));
     347                if ( $getPrt( os ) ) ends( os );                                // something printed ?
     348                $setPrt( os, false );                                                   // turn off
    349349        } // ?|?
    350350
     
    359359        ostype & nl( ostype & os ) {
    360360                (ostype &)(os | '\n');
    361                 setPrt$( os, false );                                                   // turn off
    362                 setNL$( os, true );
     361                $setPrt( os, false );                                                   // turn off
     362                $setNL( os, true );
     363                flush( os );
    363364                return sepOff( os );                                                    // prepare for next line
    364365        } // nl
    365366
    366367        ostype & nonl( ostype & os ) {
    367                 setPrt$( os, false );                                                   // turn off
     368                $setPrt( os, false );                                                   // turn off
    368369                return os;
    369370        } // nonl
     
    398399                return os;
    399400        } // nlOff
    400 } // distribution
    401 
    402 forall( ostype & | ostream( ostype ) ) {
    403         ostype & acquire( ostype & os ) {
    404                 acquire( os );                                                                  // call void returning
    405                 return os;
    406         } // acquire
    407401} // distribution
    408402
     
    411405        ostype & ?|?( ostype & os, T arg, Params rest ) {
    412406                (ostype &)(os | arg);                                                   // print first argument
    413                 sepSetCur$( os, sepGetTuple( os ) );                    // switch to tuple separator
     407                $sepSetCur( os, sepGetTuple( os ) );                    // switch to tuple separator
    414408                (ostype &)(os | rest);                                                  // print remaining arguments
    415                 sepSetCur$( os, sepGet( os ) );                                 // switch to regular separator
     409                $sepSetCur( os, sepGet( os ) );                                 // switch to regular separator
    416410                return os;
    417411        } // ?|?
     
    419413                // (ostype &)(?|?( os, arg, rest )); ends( os );
    420414                (ostype &)(os | arg);                                                   // print first argument
    421                 sepSetCur$( os, sepGetTuple( os ) );                    // switch to tuple separator
     415                $sepSetCur( os, sepGetTuple( os ) );                    // switch to tuple separator
    422416                (ostype &)(os | rest);                                                  // print remaining arguments
    423                 sepSetCur$( os, sepGet( os ) );                                 // switch to regular separator
     417                $sepSetCur( os, sepGet( os ) );                                 // switch to regular separator
    424418                ends( os );
    425419        } // ?|?
     
    448442// Default prefix for non-decimal prints is 0b, 0, 0x.
    449443#define IntegralFMTImpl( T, IFMTNP, IFMTP ) \
    450 forall( ostype & | basic_ostream( ostype ) ) { \
     444forall( ostype & | ostream( ostype ) ) { \
    451445        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    452                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \
     446                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
    453447\
    454448                if ( f.base == 'b' || f.base == 'B' ) {                 /* bespoke binary format */ \
     
    523517                return os; \
    524518        } /* ?|? */ \
    525         void ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    526                 (ostype &)(os | f); ends( os ); \
    527         } /* ?|? */ \
     519        void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
    528520} // distribution
    529521
    530 IntegralFMTImpl( signed char, "     *hh ", "     *.*hh " )
    531 IntegralFMTImpl( unsigned char, "     *hh ", "     *.*hh " )
    532 IntegralFMTImpl( signed short int, "     *h ", "     *.*h " )
    533 IntegralFMTImpl( unsigned short int, "     *h ", "     *.*h " )
    534 IntegralFMTImpl( signed int, "     * ", "     *.* " )
    535 IntegralFMTImpl( unsigned int, "     * ", "     *.* " )
    536 IntegralFMTImpl( signed long int, "     *l ", "     *.*l " )
    537 IntegralFMTImpl( unsigned long int, "     *l ", "     *.*l " )
    538 IntegralFMTImpl( signed long long int, "     *ll ", "     *.*ll " )
    539 IntegralFMTImpl( unsigned long long int, "     *ll ", "     *.*ll " )
    540 
    541 
     522IntegralFMTImpl( signed char, "%    *hh ", "%    *.*hh " )
     523IntegralFMTImpl( unsigned char, "%    *hh ", "%    *.*hh " )
     524IntegralFMTImpl( signed short int, "%    *h ", "%    *.*h " )
     525IntegralFMTImpl( unsigned short int, "%    *h ", "%    *.*h " )
     526IntegralFMTImpl( signed int, "%    * ", "%    *.* " )
     527IntegralFMTImpl( unsigned int, "%    * ", "%    *.* " )
     528IntegralFMTImpl( signed long int, "%    *l ", "%    *.*l " )
     529IntegralFMTImpl( unsigned long int, "%    *l ", "%    *.*l " )
     530IntegralFMTImpl( signed long long int, "%    *ll ", "%    *.*ll " )
     531IntegralFMTImpl( unsigned long long int, "%    *ll ", "%    *.*ll " )
     532
     533#if 0
    542534#if defined( __SIZEOF_INT128__ )
    543535// Default prefix for non-decimal prints is 0b, 0, 0x.
    544 forall( ostype & | basic_ostream( ostype ) )
     536#define IntegralFMTImpl128( T, SIGNED, CODE, IFMTNP, IFMTP ) \
     537forall( ostype & | ostream( ostype ) ) \
     538static void base10_128( ostype & os, _Ostream_Manip(T) f ) { \
     539        if ( f.val > UINT64_MAX ) { \
     540                unsigned long long int lsig = f.val % P10_UINT64; \
     541                f.val /= P10_UINT64; /* msig */ \
     542                base10_128( os, f ); /* recursion */ \
     543                _Ostream_Manip(unsigned long long int) fmt @= { lsig, 0, 19, 'u', { .all : 0 } }; \
     544                fmt.flags.nobsdp = true; \
     545                /* printf( "fmt1 %c %lld %d\n", fmt.base, fmt.val, fmt.all ); */ \
     546                sepOff( os ); \
     547                (ostype &)(os | fmt); \
     548        } else { \
     549                /* printf( "fmt2 %c %lld %d\n", f.base, (unsigned long long int)f.val, f.all ); */ \
     550                _Ostream_Manip(SIGNED long long int) fmt @= { (SIGNED long long int)f.val, f.wd, f.pc, f.base, { .all : f.all } }; \
     551                (ostype &)(os | fmt); \
     552        } /* if */ \
     553} /* base10_128 */ \
     554forall( ostype & | ostream( ostype ) ) { \
     555        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
     556                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     557\
     558                if ( f.base == 'b' | f.base == 'B' | f.base == 'o' | f.base == 'x' | f.base == 'X' ) { \
     559                        unsigned long long int msig = (unsigned long long int)(f.val >> 64); \
     560                        unsigned long long int lsig = (unsigned long long int)(f.val); \
     561                        _Ostream_Manip(SIGNED long long int) fmt @= { msig, f.wd, f.pc, f.base, { .all : f.all } }; \
     562                        _Ostream_Manip(unsigned long long int) fmt2 @= { lsig, 0, 0, f.base, { .all : 0 } }; \
     563                        if ( msig == 0 ) { \
     564                                fmt.val = lsig; \
     565                                (ostype &)(os | fmt); \
     566                        } else { \
     567                                fmt2.flags.pad0 = fmt2.flags.nobsdp = true;     \
     568                                if ( f.base == 'b' | f.base == 'B' ) { \
     569                                        if ( fmt.flags.pc && fmt.pc > 64 ) fmt.pc -= 64; else { fmt.flags.pc = false; fmt.pc = 0; } \
     570                                        if ( fmt.flags.left ) { \
     571                                                fmt.flags.left = false; \
     572                                                fmt.wd = 0; \
     573                                                /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
     574                                                fmt2.flags.left = true; \
     575                                                int msigd = high1( msig ); \
     576                                                fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
     577                                                if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0b base specifier */ \
     578                                                if ( (int)fmt2.wd < 64 ) fmt2.wd = 64; /* cast deals with negative value */ \
     579                                                fmt2.flags.pc = true; fmt2.pc = 64; \
     580                                        } else { \
     581                                                if ( fmt.wd > 64 ) fmt.wd -= 64; \
     582                                                else fmt.wd = 1; \
     583                                                /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
     584                                                fmt2.wd = 64; \
     585                                        } /* if */ \
     586                                        /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
     587                                        (ostype &)(os | fmt | "" | fmt2); \
     588                                } else if ( f.base == 'o' ) { \
     589                                        if ( fmt.flags.pc && fmt.pc > 22 ) fmt.pc -= 22; else { fmt.flags.pc = false; fmt.pc = 0; } \
     590                                        fmt.val = (unsigned long long int)fmt.val >> 2; \
     591                                        fmt2.val = ((msig & 0x3) << 1) + ((lsig & 0x8000000000000000U) != 0); \
     592                                        if ( fmt.flags.left ) { \
     593                                                fmt.flags.left = false; \
     594                                                fmt.wd = 0; \
     595                                                /* printf( "L %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
     596                                                (ostype &)(os | fmt | "" | fmt2); \
     597                                                sepOff( os ); \
     598                                                fmt2.flags.left = true; \
     599                                                int msigd = ceiling_div( high1( fmt.val ), 3 ); \
     600                                                fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
     601                                                if ( ! fmt.flags.nobsdp ) fmt2.wd -= 1; /* compensate for 0 base specifier */ \
     602                                                if ( (int)fmt2.wd < 21 ) fmt2.wd = 21; /* cast deals with negative value */ \
     603                                                fmt2.flags.pc = true; fmt2.pc = 21; \
     604                                        } else { \
     605                                                if ( fmt.wd > 22 ) fmt.wd -= 22; \
     606                                                else fmt.wd = 1; \
     607                                                /* printf( "R %llo %llo %llo %d %d '%c' %x %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all, fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
     608                                                (ostype &)(os | fmt | "" | fmt2); \
     609                                                sepOff( os ); \
     610                                                fmt2.wd = 21; \
     611                                        } /* if */ \
     612                                        fmt2.val = lsig & 0x7fffffffffffffffU; \
     613                                        /* printf( "\nC %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
     614                                        (ostype &)(os | fmt2); \
     615                                } else { /* f.base == 'x'  | f.base == 'X' */ \
     616                                        if ( fmt.flags.pc && fmt.pc > 16 ) fmt.pc -= 16; else { fmt.flags.pc = false; fmt.pc = 0; } \
     617                                        if ( fmt.flags.left ) { \
     618                                                fmt.flags.left = false; \
     619                                                fmt.wd = 0; \
     620                                                /* printf( "L %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
     621                                                fmt2.flags.left = true; \
     622                                                int msigd = high1( msig ); \
     623                                                fmt2.wd = f.wd - (fmt.pc > msigd ? fmt.pc : msigd); \
     624                                                if ( ! fmt.flags.nobsdp ) fmt2.wd -= 2; /* compensate for 0x base specifier */ \
     625                                                if ( (int)fmt2.wd < 16 ) fmt2.wd = 16; /* cast deals with negative value */ \
     626                                                fmt2.flags.pc = true; fmt2.pc = 16; \
     627                                        } else { \
     628                                                if ( fmt.wd > 16 ) fmt.wd -= 16; \
     629                                                else fmt.wd = 1; \
     630                                                /* printf( "R %llo %llo %llo %d %d '%c' %x\n", msig, lsig, fmt.val, fmt.wd, fmt.pc, fmt.base, fmt.all ); */ \
     631                                                fmt2.wd = 16; \
     632                                        } /* if */ \
     633                                        /* printf( "C %llo %d %d '%c' %x\n", fmt2.val, fmt2.wd, fmt2.pc, fmt2.base, fmt2.all ); */ \
     634                                        (ostype &)(os | fmt | "" | fmt2); \
     635                                } /* if */ \
     636                        } /* if */ \
     637                } else { \
     638                        if ( CODE == 'd' ) { \
     639                                if ( f.val < 0 )  { fmt( os, "-" ); sepOff( os ); f.val = -f.val; f.flags.sign = false; } \
     640                        } /* if */ \
     641                        base10_128( os, f ); \
     642                } /* if */ \
     643                return os; \
     644        } /* ?|? */ \
     645        void ?|?( ostype & os, _Ostream_Manip(T) f ) { (ostype &)(os | f); ends( os ); } \
     646} // distribution
     647
     648IntegralFMTImpl128( int128, signed, 'd', "%    *ll ", "%    *.*ll " )
     649IntegralFMTImpl128( unsigned int128, unsigned, 'u', "%    *ll ", "%    *.*ll " )
     650#endif // __SIZEOF_INT128__
     651#endif // 0
     652
     653#if 1
     654#if defined( __SIZEOF_INT128__ )
     655// Default prefix for non-decimal prints is 0b, 0, 0x.
     656forall( ostype & | ostream( ostype ) )
    545657static inline void base_128( ostype & os, unsigned int128 val, unsigned int128 power, _Ostream_Manip(uint64_t) & f, unsigned int maxdig, unsigned int bits, unsigned int cnt = 0 ) {
    546658        int wd = 1;                                                                                     // f.wd is never 0 because 0 implies left-pad
     
    607719
    608720#define IntegralFMTImpl128( T ) \
    609 forall( ostype & | basic_ostream( ostype ) ) { \
     721forall( ostype & | ostream( ostype ) ) { \
    610722        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    611723                _Ostream_Manip(uint64_t) fmt; \
     
    629741IntegralFMTImpl128( unsigned int128 )
    630742#endif // __SIZEOF_INT128__
     743#endif // 0
    631744
    632745// *********************************** floating point ***********************************
    633746
    634 static const char *suffixes[] = {
    635         "y", "z", "a", "f", "p", "n", "u", "m", "",
    636         "K", "M", "G", "T", "P", "E", "Z", "Y"
    637 };
    638 #define SUFFIXES_START (-24) /* Smallest power for which there is a suffix defined. */
    639 #define SUFFIXES_END (SUFFIXES_START + (int)((sizeof(suffixes) / sizeof(char *) - 1) * 3))
    640 
    641 #define PrintWithDP2( os, format, ... ) \
     747#define PrintWithDP2( os, format, val, ... ) \
    642748        { \
    643                 if ( ! f.flags.eng ) { \
    644                         len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
    645                         if ( isfinite( f.val ) && ( f.pc != 0 || ! f.flags.nobsdp ) ) { /* if number, print decimal point when no fraction or exponent */ \
    646                                 for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */ \
    647                                 if ( i == len ) { \
    648                                         if ( ! f.flags.left ) { \
    649                                                 buf[i] = '.'; buf[i + 1] = '\0'; \
    650                                                 if ( buf[0] == ' ' ) bufbeg = 1; /* decimal point within width */ \
    651                                         } else { \
    652                                                 for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \
    653                                                 buf[i] = '.'; \
    654                                                 if ( i == len ) buf[i + 1] = '\0'; \
    655                                         } /* if */ \
     749                enum { size = 48 }; \
     750                char buf[size]; \
     751                int bufbeg = 0, i, len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
     752                if ( isfinite( val ) && (f.base != 'g' || f.pc != 0) ) { /* if number, print decimal point */ \
     753                        for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E'; i += 1 ); /* decimal point or scientific ? */ \
     754                        if ( i == len && ! f.flags.nobsdp ) { \
     755                                if ( ! f.flags.left ) { \
     756                                        buf[i] = '.'; buf[i + 1] = '\0'; \
     757                                        if ( buf[0] == ' ' ) bufbeg = 1;        /* decimal point within width */ \
     758                                } else { \
     759                                        for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \
     760                                        buf[i] = '.'; \
     761                                        if ( i == len ) buf[i + 1] = '\0'; \
    656762                                } /* if */ \
    657763                        } /* if */ \
    658                 } else { \
    659                         int exp10, len2; \
    660                         eng( f.val, f.pc, exp10 );                                      /* changes arguments */ \
    661                         if ( ! f.flags.left && f.wd > 1 ) { \
    662                                 /* Exponent size (number of digits, 'e', optional minus sign) */ \
    663                                 f.wd -= lrint( floor( log10( abs( exp10 ) ) ) ) + 1 + 1 + (exp10 < 0 ? 1 : 0); \
    664                                 if ( f.wd < 1 ) f.wd = 1; \
    665                         } /* if */ \
    666                         len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
    667                         if ( f.flags.left ) { \
    668                                 for ( len -= 1; len > 0 && buf[len] == ' '; len -= 1 ); \
    669                                 len += 1; \
    670                         } /* if */ \
    671                         if ( ! f.flags.nobsdp || (exp10 < SUFFIXES_START) || (exp10 > SUFFIXES_END) ) { \
    672                                 len2 = snprintf( &buf[len], size - len, "e%d", exp10 ); \
    673                         } else { \
    674                                 len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \
    675                         } /* if */ \
    676                         if ( f.flags.left && len + len2 < f.wd ) buf[len + len2] = ' '; \
    677764                } /* if */ \
    678765                fmt( os, "%s", &buf[bufbeg] ); \
     
    680767
    681768#define FloatingPointFMTImpl( T, DFMTNP, DFMTP ) \
    682 forall( ostype & | basic_ostream( ostype ) ) { \
    683         static void eng( T &value, int & pc, int & exp10 ) { \
    684                 exp10 = lrint( floor( log10( abs( value ) ) ) ); /* round to desired precision */ \
    685                 if ( exp10 < 0 ) exp10 -= 2; \
    686                 exp10 = floor( exp10, 3 ); \
    687                 value *= pow( 10.0, -exp10 ); \
    688                 if ( pc <= 3 ) pc = 3; \
    689         } /* eng */ \
    690 \
     769forall( ostype & | ostream( ostype ) ) { \
    691770        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
    692                 enum { size = 48 }; \
    693                 char buf[size]; \
    694                 int bufbeg = 0, i, len; \
    695 \
    696                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \
    697                 char fmtstr[sizeof(DFMTP) + 8];                                 /* sizeof includes '\0' */ \
     771                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) ); \
     772                char fmtstr[sizeof(DFMTP)];                                             /* sizeof includes '\0' */ \
    698773                if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
    699774                else memcpy( &fmtstr, DFMTP, sizeof(DFMTP) ); \
     
    709784                        fmtstr[sizeof(DFMTNP)-2] = f.base;                      /* sizeof includes '\0' */ \
    710785                        /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star]); */ \
    711                         PrintWithDP2( os, &fmtstr[star], f.wd, f.val ) \
     786                        PrintWithDP2( os, &fmtstr[star], f.val, f.wd ) \
    712787                } else {                                                                                /* precision */ \
    713788                        fmtstr[sizeof(DFMTP)-2] = f.base;                       /* sizeof includes '\0' */ \
    714789                        /* printf( "%g %d %d %s\n", f.val, f.wd, f.pc, &fmtstr[star] ); */ \
    715                         PrintWithDP2( os, &fmtstr[star], f.wd, f.pc, f.val ) \
     790                        PrintWithDP2( os, &fmtstr[star], f.val, f.wd, f.pc ) \
    716791                } /* if */ \
    717792                return os; \
     
    721796} // distribution
    722797
    723 FloatingPointFMTImpl( double, "     * ", "     *.* " )
    724 FloatingPointFMTImpl( long double, "     *L ", "     *.*L " )
     798FloatingPointFMTImpl( double, "%    * ", "%    *.* " )
     799FloatingPointFMTImpl( long double, "%    *L ", "%    *.*L " )
    725800
    726801// *********************************** character ***********************************
    727802
    728 forall( ostype & | basic_ostream( ostype ) ) {
     803forall( ostype & | ostream( ostype ) ) {
    729804        ostype & ?|?( ostype & os, _Ostream_Manip(char) f ) {
    730805                if ( f.base != 'c' ) {                                                  // bespoke binary/octal/hex format
     
    737812                } // if
    738813
    739                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     814                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    740815
    741816                #define CFMTNP "% * "
     
    759834// *********************************** C string ***********************************
    760835
    761 forall( ostype & | basic_ostream( ostype ) ) {
     836forall( ostype & | ostream( ostype ) ) {
    762837        ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f ) {
    763838                if ( ! f.val ) return os;                                               // null pointer ?
     
    775850                } // if
    776851
    777                 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
     852                if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
    778853
    779854                #define SFMTNP "% * "
     
    807882
    808883
    809 forall( istype & | basic_istream( istype ) ) {
     884forall( istype & | istream( istype ) ) {
    810885        istype & ?|?( istype & is, bool & b ) {
    811886                char val[6];
     
    819894                return is;
    820895        } // ?|?
    821         void ?|?( istype & is, bool & b ) {
    822                 (istype &)(is | b); ends( is );
    823         } // ?|?
    824896
    825897        istype & ?|?( istype & is, char & c ) {
     
    833905                return is;
    834906        } // ?|?
    835         void ?|?( istype & is, char & c ) {
    836                 (istype &)(is | c); ends( is );
    837         } // ?|?
    838907
    839908        istype & ?|?( istype & is, signed char & sc ) {
     
    841910                return is;
    842911        } // ?|?
    843         void ?|?( istype & is, signed char & sc ) {
    844                 (istype &)(is | sc); ends( is );
    845         } // ?|?
    846912
    847913        istype & ?|?( istype & is, unsigned char & usc ) {
     
    849915                return is;
    850916        } // ?|?
    851         void ?|?( istype & is, unsigned char & usc ) {
    852                 (istype &)(is | usc); ends( is );
    853         } // ?|?
    854917
    855918        istype & ?|?( istype & is, short int & si ) {
     
    857920                return is;
    858921        } // ?|?
    859         void ?|?( istype & is, short int & si ) {
    860                 (istype &)(is | si); ends( is );
    861         } // ?|?
    862922
    863923        istype & ?|?( istype & is, unsigned short int & usi ) {
     
    865925                return is;
    866926        } // ?|?
    867         void ?|?( istype & is, unsigned short int & usi ) {
    868                 (istype &)(is | usi); ends( is );
    869         } // ?|?
    870927
    871928        istype & ?|?( istype & is, int & i ) {
     
    873930                return is;
    874931        } // ?|?
    875         void ?|?( istype & is, int & i ) {
    876                 (istype &)(is | i); ends( is );
    877         } // ?|?
    878932
    879933        istype & ?|?( istype & is, unsigned int & ui ) {
     
    881935                return is;
    882936        } // ?|?
    883         void ?|?( istype & is, unsigned int & ui ) {
    884                 (istype &)(is | ui); ends( is );
    885         } // ?|?
    886937
    887938        istype & ?|?( istype & is, long int & li ) {
     
    889940                return is;
    890941        } // ?|?
    891         void ?|?( istype & is, long int & li ) {
    892                 (istype &)(is | li); ends( is );
    893         } // ?|?
    894942
    895943        istype & ?|?( istype & is, unsigned long int & ulli ) {
     
    897945                return is;
    898946        } // ?|?
    899         void ?|?( istype & is, unsigned long int & ulli ) {
    900                 (istype &)(is | ulli); ends( is );
    901         } // ?|?
    902947
    903948        istype & ?|?( istype & is, long long int & lli ) {
     
    905950                return is;
    906951        } // ?|?
    907         void ?|?( istype & is, long long int & lli ) {
    908                 (istype &)(is | lli); ends( is );
    909         } // ?|?
    910952
    911953        istype & ?|?( istype & is, unsigned long long int & ulli ) {
     
    913955                return is;
    914956        } // ?|?
    915         void & ?|?( istype & is, unsigned long long int & ulli ) {
    916                 (istype &)(is | ulli); ends( is );
    917         } // ?|?
    918 
    919         #if defined( __SIZEOF_INT128__ )
    920         istype & ?|?( istype & is, int128 & llli ) {
    921                 return (istype &)(is | (unsigned int128 &)llli);
    922         } // ?|?
    923         void ?|?( istype & is, int128 & llli ) {
    924                 (istype &)(is | llli); ends( is );
    925         } // ?|?
    926 
    927         istype & ?|?( istype & is, unsigned int128 & ullli ) {
     957
     958#if defined( __SIZEOF_INT128__ )
     959        istype & ?|?( istype & is, int128 & i128 ) {
     960                return (istype &)(is | (unsigned int128 &)i128);
     961        } // ?|?
     962
     963        istype & ?|?( istype & is, unsigned int128 & ui128 ) {
    928964                char s[40];
    929965                bool sign = false;
     
    932968                // If the input is too large, the value returned is undefined. If there is no input, no value is returned
    933969                if ( fmt( is, "%39[0-9]%*[0-9]", s ) == 1 ) {   // take first 39 characters, ignore remaining
    934                         ullli = 0;
     970                        ui128 = 0;
    935971                        for ( unsigned int i = 0; s[i] != '\0'; i += 1 ) {
    936                                 ullli = ullli * 10 + s[i] - '0';
     972                                ui128 = ui128 * 10 + s[i] - '0';
    937973                        } // for
    938                         if ( sign ) ullli = -ullli;
     974                        if ( sign ) ui128 = -ui128;
    939975                } else if ( sign ) ungetc( is, '-' );                   // return minus when no digits
    940976                return is;
    941977        } // ?|?
    942         void ?|?( istype & is, unsigned int128 & ullli ) {
    943                 (istype &)(is | ullli); ends( is );
    944         } // ?|?
    945         #endif // __SIZEOF_INT128__
     978#endif // __SIZEOF_INT128__
    946979
    947980        istype & ?|?( istype & is, float & f ) {
     
    949982                return is;
    950983        } // ?|?
    951         void ?|?( istype & is, float & f ) {
    952                 (istype &)(is | f); ends( is );
    953         } // ?|?
    954984
    955985        istype & ?|?( istype & is, double & d ) {
     
    957987                return is;
    958988        } // ?|?
    959         void ?|?( istype & is, double & d ) {
    960                 (istype &)(is | d); ends( is );
    961         } // ?|?
    962989
    963990        istype & ?|?( istype & is, long double & ld ) {
     
    965992                return is;
    966993        } // ?|?
    967         void ?|?( istype & is, long double & ld ) {
    968                 (istype &)(is | ld); ends( is );
    969         } // ?|?
     994
    970995
    971996        istype & ?|?( istype & is, float _Complex & fc ) {
     
    9751000                return is;
    9761001        } // ?|?
    977         void ?|?( istype & is, float _Complex & fc ) {
    978                 (istype &)(is | fc); ends( is );
    979         } // ?|?
    9801002
    9811003        istype & ?|?( istype & is, double _Complex & dc ) {
     
    9851007                return is;
    9861008        } // ?|?
    987         void ?|?( istype & is, double _Complex & dc ) {
    988                 (istype &)(is | dc); ends( is );
    989         } // ?|?
    9901009
    9911010        istype & ?|?( istype & is, long double _Complex & ldc ) {
     
    9951014                return is;
    9961015        } // ?|?
    997         void ?|?( istype & is, long double _Complex & ldc ) {
    998                 (istype &)(is | ldc); ends( is );
    999         } // ?|?
    10001016
    10011017        // istype & ?|?( istype & is, const char fmt[] ) {
     
    10041020        // } // ?|?
    10051021
    1006         istype & ?|?( istype & is, char s[] ) {
     1022        istype & ?|?( istype & is, char * s ) {
    10071023                fmt( is, "%s", s );
    10081024                return is;
    1009         } // ?|?
    1010         void ?|?( istype & is, char s[] ) {
    1011                 (istype &)(is | s); ends( is );
    10121025        } // ?|?
    10131026
     
    10161029                return manip( is );
    10171030        } // ?|?
    1018         void ?|?( istype & is, istype & (* manip)( istype & ) ) {
    1019                 manip( is ); ends( is );
    1020         } // ?|?
    10211031
    10221032        istype & nl( istype & is ) {
     
    10361046} // distribution
    10371047
    1038 forall( istype & | istream( istype ) ) {
    1039         istype & acquire( istype & is ) {
    1040                 acquire( is );                                                                  // call void returning
    1041                 return is;
    1042         } // acquire
    1043 } // distribution
    1044 
    10451048// *********************************** manipulators ***********************************
    10461049
    1047 forall( istype & | basic_istream( istype ) ) {
    1048         istype & ?|?( istype & is, _Istream_Cstr f ) {
    1049                 // skip xxx
    1050                 if ( ! f.s ) {
    1051                         // printf( "skip %s %d\n", f.scanset, f.wd );
    1052                         if ( f.wd == -1 ) fmt( is, f.scanset, "" );             // no input arguments
    1053                         else for ( f.wd ) fmt( is, "%*c" );
    1054                         return is;
    1055                 } // if
    1056                 size_t len = 0;
    1057                 if ( f.scanset ) len = strlen( f.scanset );
    1058                 char fmtstr[len + 16];
    1059                 int start = 1;
    1060                 fmtstr[0] = '%';
    1061                 if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; }
    1062                 if ( f.wd != -1 ) { start += sprintf( &fmtstr[start], "%d", f.wd ); }
    1063                 // cstr %s, %*s, %ws, %*ws
    1064                 if ( ! f.scanset ) {
    1065                         fmtstr[start] = 's'; fmtstr[start + 1] = '\0';
    1066                         // printf( "cstr %s\n", fmtstr );
    1067                         fmt( is, fmtstr, f.s );
    1068                         return is;
    1069                 } // if
    1070                 // incl %[xxx],  %*[xxx],  %w[xxx],  %*w[xxx]
    1071                 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx]
    1072                 fmtstr[start] = '['; start += 1;
    1073                 if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; }
    1074                 strcpy( &fmtstr[start], f.scanset );                            // copy includes '\0'
    1075                 len += start;
    1076                 fmtstr[len] = ']'; fmtstr[len + 1] = '\0';
    1077                 // printf( "incl/excl %s\n", fmtstr );
     1050forall( istype & | istream( istype ) )
     1051istype & ?|?( istype & is, _Istream_Cstr f ) {
     1052        // skip xxx
     1053        if ( ! f.s ) {
     1054                // printf( "skip %s %d\n", f.scanset, f.wd );
     1055                if ( f.wd == -1 ) fmt( is, f.scanset, "" );             // no input arguments
     1056                else for ( f.wd ) fmt( is, "%*c" );
     1057                return is;
     1058        } // if
     1059        size_t len = 0;
     1060        if ( f.scanset ) len = strlen( f.scanset );
     1061        char fmtstr[len + 16];
     1062        int start = 1;
     1063        fmtstr[0] = '%';
     1064        if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; }
     1065        if ( f.wd != -1 ) { start += sprintf( &fmtstr[start], "%d", f.wd ); }
     1066        // cstr %s, %*s, %ws, %*ws
     1067        if ( ! f.scanset ) {
     1068                fmtstr[start] = 's'; fmtstr[start + 1] = '\0';
     1069                // printf( "cstr %s\n", fmtstr );
    10781070                fmt( is, fmtstr, f.s );
    10791071                return is;
    1080         } // ?|?
    1081         void ?|?( istype & is, _Istream_Cstr f ) {
    1082                 (istype &)(is | f); ends( is );
    1083         } // ?|?
    1084 
    1085         istype & ?|?( istype & is, _Istream_Char f ) {
    1086                 fmt( is, "%*c" );                                                                       // argument variable unused
    1087                 return is;
    1088         } // ?|?
    1089         void ?|?( istype & is, _Istream_Char f ) {
    1090                 (istype &)(is | f); ends( is );
    1091         } // ?|?
    1092 } // distribution
     1072        } // if
     1073        // incl %[xxx],  %*[xxx],  %w[xxx],  %*w[xxx]
     1074        // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx]
     1075        fmtstr[start] = '['; start += 1;
     1076        if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; }
     1077        strcpy( &fmtstr[start], f.scanset );                            // copy includes '\0'
     1078        len += start;
     1079        fmtstr[len] = ']'; fmtstr[len + 1] = '\0';
     1080        // printf( "incl/excl %s\n", fmtstr );
     1081        fmt( is, fmtstr, f.s );
     1082        return is;
     1083} // ?|?
     1084
     1085forall( istype & | istream( istype ) )
     1086istype & ?|?( istype & is, _Istream_Char f ) {
     1087        fmt( is, "%*c" );                                                                       // argument variable unused
     1088        return is;
     1089} // ?|?
    10931090
    10941091#define InputFMTImpl( T, CODE ) \
    1095 forall( istype & | basic_istream( istype ) ) { \
    1096         istype & ?|?( istype & is, _Istream_Manip(T) f ) { \
    1097                 enum { size = 16 }; \
    1098                 char fmtstr[size]; \
    1099                 if ( f.wd == -1 ) { \
    1100                         snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \
    1101                 } else { \
    1102                         snprintf( fmtstr, size, "%%%s%d%s", f.ignore ? "*" : "", f.wd, CODE ); \
    1103                 } /* if */ \
    1104                 /* printf( "%d %s %p\n", f.wd, fmtstr, &f.val ); */ \
    1105                 fmt( is, fmtstr, &f.val ); \
    1106                 return is; \
    1107         } /* ?|? */ \
    1108         void ?|?( istype & is, _Istream_Manip(T) f ) { \
    1109                 (istype &)(is | f); ends( is ); \
    1110         } /* ?|? */ \
    1111 } // distribution
     1092forall( istype & | istream( istype ) ) \
     1093istype & ?|?( istype & is, _Istream_Manip(T) f ) { \
     1094        enum { size = 16 }; \
     1095        char fmtstr[size]; \
     1096        if ( f.wd == -1 ) { \
     1097                snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \
     1098        } else { \
     1099                snprintf( fmtstr, size, "%%%s%d%s", f.ignore ? "*" : "", f.wd, CODE ); \
     1100        } /* if */ \
     1101        /* printf( "%d %s %p\n", f.wd, fmtstr, &f.val ); */ \
     1102        fmt( is, fmtstr, &f.val ); \
     1103        return is; \
     1104} // ?|?
    11121105
    11131106InputFMTImpl( signed char, "hhi" )
     
    11261119InputFMTImpl( long double, "Lf" )
    11271120
    1128 forall( istype & | basic_istream( istype ) ) {
    1129         istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) {
    1130                 float re, im;
    1131                 _Istream_Manip(float) fmtuc @= { re, fc.wd, fc.ignore };
    1132                 is | fmtuc;
    1133                 &fmtuc.val = &im;
    1134                 is | fmtuc;
    1135                 if ( ! fc.ignore ) fc.val = re + im * _Complex_I; // re/im are uninitialized for ignore
    1136                 return is;
    1137         } // ?|?
    1138         void ?|?( istype & is, _Istream_Manip(float _Complex) fc ) {
    1139                 (istype &)(is | fc); ends( is );
    1140         } // ?|?
    1141 
    1142         istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
    1143                 double re, im;
    1144                 _Istream_Manip(double) fmtuc @= { re, dc.wd, dc.ignore };
    1145                 is | fmtuc;
    1146                 &fmtuc.val = &im;
    1147                 is | fmtuc;
    1148                 if ( ! dc.ignore ) dc.val = re + im * _Complex_I; // re/im are uninitialized for ignore
    1149                 return is;
    1150         } // ?|?
    1151         void ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
    1152                 (istype &)(is | dc); ends( is );
    1153         } // ?|?
    1154 
    1155         istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
    1156                 long double re, im;
    1157                 _Istream_Manip(long double) fmtuc @= { re, ldc.wd, ldc.ignore };
    1158                 is | fmtuc;
    1159                 &fmtuc.val = &im;
    1160                 is | fmtuc;
    1161                 if ( ! ldc.ignore ) ldc.val = re + im * _Complex_I;     // re/im are uninitialized for ignore
    1162                 return is;
    1163         } // ?|?
    1164         void ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
    1165                 (istype &)(is | ldc); ends( is );
    1166         } // ?|?
    1167 } // distribution
     1121forall( istype & | istream( istype ) )
     1122istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) {
     1123        float re, im;
     1124        _Istream_Manip(float) fmtuc @= { re, fc.wd, fc.ignore };
     1125        is | fmtuc;
     1126        &fmtuc.val = &im;
     1127        is | fmtuc;
     1128        if ( ! fc.ignore ) fc.val = re + im * _Complex_I;       // re/im are uninitialized for ignore
     1129        return is;
     1130} // ?|?
     1131
     1132forall( istype & | istream( istype ) )
     1133istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
     1134        double re, im;
     1135        _Istream_Manip(double) fmtuc @= { re, dc.wd, dc.ignore };
     1136        is | fmtuc;
     1137        &fmtuc.val = &im;
     1138        is | fmtuc;
     1139        if ( ! dc.ignore ) dc.val = re + im * _Complex_I;       // re/im are uninitialized for ignore
     1140        return is;
     1141} // ?|?
     1142
     1143forall( istype & | istream( istype ) )
     1144istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
     1145        long double re, im;
     1146        _Istream_Manip(long double) fmtuc @= { re, ldc.wd, ldc.ignore };
     1147        is | fmtuc;
     1148        &fmtuc.val = &im;
     1149        is | fmtuc;
     1150        if ( ! ldc.ignore ) ldc.val = re + im * _Complex_I;     // re/im are uninitialized for ignore
     1151        return is;
     1152} // ?|?
    11681153
    11691154// Local Variables: //
  • libcfa/src/iostream.hfa

    r5407cdc rfeacef9  
    1010// Created On       : Wed May 27 17:56:53 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 27 17:59:21 2021
    13 // Update Count     : 398
     12// Last Modified On : Tue Aug 11 22:16:14 2020
     13// Update Count     : 350
    1414//
    1515
     
    2222
    2323
    24 trait basic_ostream( ostype & ) {
     24trait ostream( ostype & ) {
    2525        // private
    26         bool sepPrt$( ostype & );                                                       // get separator state (on/off)
    27         void sepReset$( ostype & );                                                     // set separator state to default state
    28         void sepReset$( ostype &, bool );                                       // set separator and default state
    29         const char * sepGetCur$( ostype & );                            // get current separator string
    30         void sepSetCur$( ostype &, const char [] );                     // set current separator string
    31         bool getNL$( ostype & );                                                        // check newline
    32         void setNL$( ostype &, bool );                                          // saw newline
    33         bool getANL$( ostype & );                                                       // get auto newline (on/off)
    34         bool getPrt$( ostype & );                                                       // get fmt called in output cascade
    35         void setPrt$( ostype &, bool );                                         // set fmt called in output cascade
     26        bool $sepPrt( ostype & );                                                       // get separator state (on/off)
     27        void $sepReset( ostype & );                                                     // set separator state to default state
     28        void $sepReset( ostype &, bool );                                       // set separator and default state
     29        const char * $sepGetCur( ostype & );                            // get current separator string
     30        void $sepSetCur( ostype &, const char [] );                     // set current separator string
     31        bool $getNL( ostype & );                                                        // check newline
     32        void $setNL( ostype &, bool );                                          // saw newline
     33        bool $getANL( ostype & );                                                       // get auto newline (on/off)
     34        bool $getPrt( ostype & );                                                       // get fmt called in output cascade
     35        void $setPrt( ostype &, bool );                                         // set fmt called in output cascade
    3636        // public
    3737        void sepOn( ostype & );                                                         // turn separator state on
     
    4747        void sepSetTuple( ostype &, const char [] );            // set tuple separator to string (15 character maximum)
    4848
    49         void ends( ostype & );                                                          // end of output statement
     49        void ends( ostype & os );                                                       // end of output statement
     50        int fail( ostype & );
     51        int flush( ostype & );
     52        void open( ostype & os, const char name[], const char mode[] );
     53        void close( ostype & os );
     54        ostype & write( ostype &, const char [], size_t );
    5055        int fmt( ostype &, const char format[], ... ) __attribute__(( format(printf, 2, 3) ));
    51 }; // basic_ostream
    52        
    53 trait ostream( ostype & | basic_ostream( ostype ) ) {
    54         int flush( ostype & );
    55         bool fail( ostype & );                                                          // operation failed?
    56         void open( ostype &, const char name[], const char mode[] );
    57         void close( ostype & );
    58         ostype & write( ostype &, const char [], size_t );
    59         void acquire( ostype & );                                                       // concurrent access
    6056}; // ostream
    6157
     
    7066// implement writable for intrinsic types
    7167
    72 forall( ostype & | basic_ostream( ostype ) ) {
     68forall( ostype & | ostream( ostype ) ) {
    7369        ostype & ?|?( ostype &, bool );
    7470        void ?|?( ostype &, bool );
     
    9793        ostype & ?|?( ostype &, unsigned long long int );
    9894        void ?|?( ostype &, unsigned long long int );
    99         #if defined( __SIZEOF_INT128__ )
     95#if defined( __SIZEOF_INT128__ )
    10096        ostype & ?|?( ostype &, int128 );
    10197        void ?|?( ostype &, int128 );
    10298        ostype & ?|?( ostype &, unsigned int128 );
    10399        void ?|?( ostype &, unsigned int128 );
    104         #endif // __SIZEOF_INT128__
     100#endif // __SIZEOF_INT128__
    105101
    106102        ostype & ?|?( ostype &, float );
     
    121117        void ?|?( ostype &, const char [] );
    122118        // ostype & ?|?( ostype &, const char16_t * );
    123         #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
     119#if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
    124120        // ostype & ?|?( ostype &, const char32_t * );
    125         #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )
     121#endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )
    126122        // ostype & ?|?( ostype &, const wchar_t * );
    127123        ostype & ?|?( ostype &, const void * );
     
    143139} // distribution
    144140
    145 forall( ostype & | ostream( ostype ) ) {
    146         ostype & acquire( ostype & );
    147 } // distribution
    148 
    149141// tuples
    150142forall( ostype &, T, Params... | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) {
     
    164156struct _Ostream_Manip {
    165157        T val;                                                                                          // polymorphic base-type
    166         int wd, pc;                                                                                     // width, precision: signed for computations
     158        unsigned int wd, pc;                                                            // width, precision
    167159        char base;                                                                                      // numeric base / floating-point style
    168160        union {
    169161                unsigned char all;
    170162                struct {
    171                         unsigned char eng:1;                                            // engineering notation
    172163                        unsigned char neg:1;                                            // val is negative
    173164                        unsigned char pc:1;                                                     // precision specified
     
    192183        _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'x', { .all : 0 } }; } \
    193184        _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, CODE, { .all : 0 } }; } \
    194         _Ostream_Manip(T) wd( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \
     185        _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, CODE, { .flags.pc : true } }; } \
    195186        _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
    196         _Ostream_Manip(T) & wd( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
     187        _Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
    197188        _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
    198189        _Ostream_Manip(T) & upcase( _Ostream_Manip(T) & fmt ) { if ( fmt.base == 'x' || fmt.base == 'b' ) fmt.base -= 32; /* upper case */ return fmt; } \
     
    202193        _Ostream_Manip(T) & sign( _Ostream_Manip(T) & fmt ) { fmt.flags.sign = true; return fmt; } \
    203194} /* distribution */ \
    204 forall( ostype & | basic_ostream( ostype ) ) { \
     195forall( ostype & | ostream( ostype ) ) { \
    205196        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
    206197        void ?|?( ostype & os, _Ostream_Manip(T) f ); \
     
    229220        _Ostream_Manip(T) hex( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'a', { .all : 0 } }; } \
    230221        _Ostream_Manip(T) sci( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'e', { .all : 0 } }; } \
    231         _Ostream_Manip(T) eng( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.eng : true } }; } \
    232         _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'g', { .all : 0 } }; } \
    233         _Ostream_Manip(T) wd( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
    234         _Ostream_Manip(T) ws( unsigned int w, unsigned int pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
    235         _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; return fmt; } \
    236         _Ostream_Manip(T) & wd( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { if ( fmt.flags.eng ) fmt.base = 'f'; fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
    237         _Ostream_Manip(T) & ws( unsigned int w, unsigned int pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
     222        _Ostream_Manip(T) wd( unsigned int w, T val ) { return (_Ostream_Manip(T))@{ val, w, 0, 'f', { .all : 0 } }; } \
     223        _Ostream_Manip(T) wd( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'f', { .flags.pc : true } }; } \
     224        _Ostream_Manip(T) ws( unsigned int w, unsigned char pc, T val ) { return (_Ostream_Manip(T))@{ val, w, pc, 'g', { .flags.pc : true } }; } \
     225        _Ostream_Manip(T) & wd( unsigned int w, _Ostream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
     226        _Ostream_Manip(T) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(T) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; } \
    238227        _Ostream_Manip(T) & left( _Ostream_Manip(T) & fmt ) { fmt.flags.left = true; return fmt; } \
    239228        _Ostream_Manip(T) upcase( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'G', { .all : 0 } }; } \
     
    244233        _Ostream_Manip(T) nodp( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
    245234        _Ostream_Manip(T) & nodp( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
    246         _Ostream_Manip(T) unit( T val ) { return (_Ostream_Manip(T))@{ val, 1, 0, 'g', { .flags.nobsdp : true } }; } \
    247         _Ostream_Manip(T) & unit( _Ostream_Manip(T) & fmt ) { fmt.flags.nobsdp = true; return fmt; } \
    248235} /* distribution */ \
    249 forall( ostype & | basic_ostream( ostype ) ) { \
     236forall( ostype & | ostream( ostype ) ) { \
    250237        ostype & ?|?( ostype & os, _Ostream_Manip(T) f ); \
    251238        void ?|?( ostype & os, _Ostream_Manip(T) f ); \
     
    267254        _Ostream_Manip(char) & nobase( _Ostream_Manip(char) & fmt ) { fmt.flags.nobsdp = true; return fmt; }
    268255} // distribution
    269 forall( ostype & | basic_ostream( ostype ) ) {
     256forall( ostype & | ostream( ostype ) ) {
    270257        ostype & ?|?( ostype & os, _Ostream_Manip(char) f );
    271258        void ?|?( ostype & os, _Ostream_Manip(char) f );
     
    279266        _Ostream_Manip(const char *) hex( const char s[] ) { return (_Ostream_Manip(const char *))@{ s, 1, 0, 'x', { .all : 0 } }; }
    280267        _Ostream_Manip(const char *) wd( unsigned int w, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, 0, 's', { .all : 0 } }; }
    281         _Ostream_Manip(const char *) wd( unsigned int w, unsigned int pc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }
     268        _Ostream_Manip(const char *) wd( unsigned int w, unsigned char pc, const char s[] ) { return (_Ostream_Manip(const char *))@{ s, w, pc, 's', { .flags.pc : true } }; }
    282269        _Ostream_Manip(const char *) & wd( unsigned int w, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; return fmt; }
    283         _Ostream_Manip(const char *) & wd( unsigned int w, unsigned int pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
     270        _Ostream_Manip(const char *) & wd( unsigned int w, unsigned char pc, _Ostream_Manip(const char *) & fmt ) { fmt.wd = w; fmt.pc = pc; fmt.flags.pc = true; return fmt; }
    284271        _Ostream_Manip(const char *) & left( _Ostream_Manip(const char *) & fmt ) { fmt.flags.left = true; return fmt; }
    285272        _Ostream_Manip(const char *) & nobase( _Ostream_Manip(const char *) & fmt ) { fmt.flags.nobsdp = true; return fmt; }
    286273} // distribution
    287 forall( ostype & | basic_ostream( ostype ) ) {
     274forall( ostype & | ostream( ostype ) ) {
    288275        ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f );
    289276        void ?|?( ostype & os, _Ostream_Manip(const char *) f );
     
    294281
    295282
    296 trait basic_istream( istype & ) {
    297         bool getANL( istype & );                                                        // get scan newline (on/off)
     283trait istream( istype & ) {
    298284        void nlOn( istype & );                                                          // read newline
    299285        void nlOff( istype & );                                                         // scan newline
    300 
    301         void ends( istype & os );                                                       // end of output statement
    302         int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    303         istype & ungetc( istype &, char );
     286        bool getANL( istype & );                                                        // get scan newline (on/off)
     287        int fail( istype & );
    304288        int eof( istype & );
    305 }; // basic_istream
    306 
    307 trait istream( istype & | basic_istream( istype ) ) {
    308         bool fail( istype & );
    309289        void open( istype & is, const char name[] );
    310290        void close( istype & is );
    311291        istype & read( istype &, char *, size_t );
    312         void acquire( istype & );                                                       // concurrent access
     292        istype & ungetc( istype &, char );
     293        int fmt( istype &, const char format[], ... ) __attribute__(( format(scanf, 2, 3) ));
    313294}; // istream
    314295
     
    317298}; // readable
    318299
    319 forall( istype & | basic_istream( istype ) ) {
     300forall( istype & | istream( istype ) ) {
    320301        istype & ?|?( istype &, bool & );
    321         void ?|?( istype &, bool & );
    322302
    323303        istype & ?|?( istype &, char & );
    324         void ?|?( istype &, char & );
    325304        istype & ?|?( istype &, signed char & );
    326         void ?|?( istype &, signed char & );
    327305        istype & ?|?( istype &, unsigned char & );
    328         void ?|?( istype &, unsigned char & );
    329306
    330307        istype & ?|?( istype &, short int & );
    331         void ?|?( istype &, short int & );
    332308        istype & ?|?( istype &, unsigned short int & );
    333         void ?|?( istype &, unsigned short int & );
    334309        istype & ?|?( istype &, int & );
    335         void ?|?( istype &, int & );
    336310        istype & ?|?( istype &, unsigned int & );
    337         void ?|?( istype &, unsigned int & );
    338311        istype & ?|?( istype &, long int & );
    339         void ?|?( istype &, long int & );
    340312        istype & ?|?( istype &, unsigned long int & );
    341         void ?|?( istype &, unsigned long int & );
    342313        istype & ?|?( istype &, long long int & );
    343         void ?|?( istype &, long long int & );
    344314        istype & ?|?( istype &, unsigned long long int & );
    345         void ?|?( istype &, unsigned long long int & );
    346         #if defined( __SIZEOF_INT128__ )
     315#if defined( __SIZEOF_INT128__ )
    347316        istype & ?|?( istype &, int128 & );
    348         void ?|?( istype &, int128 & );
    349317        istype & ?|?( istype &, unsigned int128 & );
    350         void ?|?( istype &, unsigned int128 & );
    351         #endif // __SIZEOF_INT128__
     318#endif // __SIZEOF_INT128__
    352319
    353320        istype & ?|?( istype &, float & );
    354         void ?|?( istype &, float & );
    355321        istype & ?|?( istype &, double & );
    356         void ?|?( istype &, double & );
    357322        istype & ?|?( istype &, long double & );
    358         void ?|?( istype &, long double & );
    359323
    360324        istype & ?|?( istype &, float _Complex & );
    361         void ?|?( istype &, float _Complex & );
    362325        istype & ?|?( istype &, double _Complex & );
    363         void ?|?( istype &, double _Complex & );
    364326        istype & ?|?( istype &, long double _Complex & );
    365         void ?|?( istype &, long double _Complex & );
    366327
    367328//      istype & ?|?( istype &, const char [] );
    368         istype & ?|?( istype &, char [] );
    369         void ?|?( istype &, char [] );
     329        istype & ?|?( istype &, char * );
    370330
    371331        // manipulators
    372332        istype & ?|?( istype &, istype & (*)( istype & ) );
    373         void ?|?( istype &, istype & (*)( istype & ) );
    374333        istype & nl( istype & is );
    375334        istype & nlOn( istype & );
    376335        istype & nlOff( istype & );
    377 } // distribution
    378 
    379 forall( istype & | istream( istype ) ) {
    380         istype & acquire( istype & );
    381336} // distribution
    382337
     
    397352
    398353static inline {
     354        _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; }
    399355        _Istream_Cstr skip( const char scanset[] ) { return (_Istream_Cstr){ 0p, scanset, -1, { .all : 0 } }; }
    400         _Istream_Cstr skip( unsigned int n ) { return (_Istream_Cstr){ 0p, 0p, n, { .all : 0 } }; }
    401356        _Istream_Cstr incl( const char scanset[], char * s ) { return (_Istream_Cstr){ s, scanset, -1, { .flags.inex : false } }; }
    402357        _Istream_Cstr & incl( const char scanset[], _Istream_Cstr & fmt ) { fmt.scanset = scanset; fmt.flags.inex = false; return fmt; }
     
    408363        _Istream_Cstr & wdi( unsigned int w, _Istream_Cstr & fmt ) { fmt.wd = w; return fmt; }
    409364} // distribution
    410 forall( istype & | basic_istream( istype ) ) {
    411         istype & ?|?( istype & is, _Istream_Cstr f );
    412         void ?|?( istype & is, _Istream_Cstr f );
    413 }
     365forall( istype & | istream( istype ) ) istype & ?|?( istype & is, _Istream_Cstr f );
    414366
    415367struct _Istream_Char {
     
    421373        _Istream_Char & ignore( _Istream_Char & fmt ) { fmt.ignore = true; return fmt; }
    422374} // distribution
    423 forall( istype & | basic_istream( istype ) ) {
    424         istype & ?|?( istype & is, _Istream_Char f );
    425         void ?|?( istype & is, _Istream_Char f );
    426 }
     375forall( istype & | istream( istype ) ) istype & ?|?( istype & is, _Istream_Char f );
    427376
    428377forall( T & | sized( T ) )
     
    440389        _Istream_Manip(T) & wdi( unsigned int w, _Istream_Manip(T) & fmt ) { fmt.wd = w; return fmt; } \
    441390} /* distribution */ \
    442 forall( istype & | basic_istream( istype ) ) { \
     391forall( istype & | istream( istype ) ) { \
    443392        istype & ?|?( istype & is, _Istream_Manip(T) f ); \
    444         void ?|?( istype & is, _Istream_Manip(T) f ); \
    445393} // ?|?
    446394
  • libcfa/src/math.hfa

    r5407cdc rfeacef9  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // math.hfa --
     7// math --
    88//
    99// Author           : Peter A. Buhr
    1010// Created On       : Mon Apr 18 23:37:04 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Apr 15 11:47:56 2021
    13 // Update Count     : 132
     12// Last Modified On : Mon Aug 24 08:56:20 2020
     13// Update Count     : 126
    1414//
    1515
     
    100100        long double _Complex log( long double _Complex x ) { return clogl( x ); }
    101101
    102         // O(1) polymorphic integer log2, using clz, which returns the number of leading 0-bits, starting at the most
    103         // significant bit (single instruction on x86)
    104         int log2( unsigned int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clz( n ); }
    105         long int log2( unsigned long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzl( n ); }
    106         long long int log2( unsigned long long int n ) { return n == 0 ? -1 : sizeof(n) * __CHAR_BIT__ - 1 - __builtin_clzll( n ); }
    107102        float log2( float x ) { return log2f( x ); }
    108103        // extern "C" { double log2( double ); }
  • libcfa/src/startup.cfa

    r5407cdc rfeacef9  
    3939
    4040    void disable_interrupts() __attribute__(( weak )) {}
    41     void enable_interrupts() __attribute__(( weak )) {}
     41    void enable_interrupts_noPoll() __attribute__(( weak )) {}
    4242} // extern "C"
    4343
  • libcfa/src/stdlib.hfa

    r5407cdc rfeacef9  
    1010// Created On       : Thu Jan 28 17:12:35 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Apr 20 21:20:03 2021
    13 // Update Count     : 575
     12// Last Modified On : Thu Jan 21 22:02:13 2021
     13// Update Count     : 574
    1414//
    1515
     
    4444
    4545// Macro because of returns
    46 #define ARRAY_ALLOC$( allocation, alignment, dim ) \
     46#define $ARRAY_ALLOC( allocation, alignment, dim ) \
    4747        if ( _Alignof(T) <= libAlign() ) return (T *)(void *)allocation( dim, (size_t)sizeof(T) ); /* C allocation */ \
    4848        else return (T *)alignment( _Alignof(T), dim, sizeof(T) )
     
    5757
    5858        T * aalloc( size_t dim ) {
    59                 ARRAY_ALLOC$( aalloc, amemalign, dim );
     59                $ARRAY_ALLOC( aalloc, amemalign, dim );
    6060        } // aalloc
    6161
    6262        T * calloc( size_t dim ) {
    63                 ARRAY_ALLOC$( calloc, cmemalign, dim );
     63                $ARRAY_ALLOC( calloc, cmemalign, dim );
    6464        } // calloc
    6565
     
    119119                S_fill(T) ?`fill( T    a[], size_t nmemb )      { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; }
    120120
    121         3. Replace the alloc_internal$ function which is outside ttype forall-block with following function:
    122                 T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) {
     121        3. Replace the $alloc_internal function which is outside ttype forall-block with following function:
     122                T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) {
    123123                        T * ptr = NULL;
    124124                        size_t size = sizeof(T);
     
    145145
    146146                        return ptr;
    147                 } // alloc_internal$
     147                } // $alloc_internal
    148148*/
    149149
     
    175175        S_realloc(T)    ?`realloc ( T * a )                             { return (S_realloc(T)){a}; }
    176176
    177         T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {
     177        T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill ) {
    178178                T * ptr = NULL;
    179179                size_t size = sizeof(T);
     
    206206
    207207                return ptr;
    208         } // alloc_internal$
    209 
    210         forall( TT... | { T * alloc_internal$( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {
    211 
    212                 T * alloc_internal$( void *       , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) {
    213                 return alloc_internal$( Resize, (T*)0p, Align, Dim, Fill, rest);
    214                 }
    215 
    216                 T * alloc_internal$( void * Resize, T *        , size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest) {
    217                 return alloc_internal$( (void*)0p, Realloc, Align, Dim, Fill, rest);
    218                 }
    219 
    220                 T * alloc_internal$( void * Resize, T * Realloc, size_t      , size_t Dim, S_fill(T) Fill, T_align Align, TT rest) {
    221                 return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest);
    222                 }
    223 
    224                 T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T)     , S_fill(T) Fill, TT rest) {
    225                 return alloc_internal$( Resize, Realloc, Align, Dim, Fill, rest);
     208        } // $alloc_internal
     209
     210        forall( TT... | { T * $alloc_internal( void *, T *, size_t, size_t, S_fill(T), TT ); } ) {
     211
     212                T * $alloc_internal( void *       , T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill, T_resize Resize, TT rest) {
     213                return $alloc_internal( Resize, (T*)0p, Align, Dim, Fill, rest);
     214                }
     215
     216                T * $alloc_internal( void * Resize, T *        , size_t Align, size_t Dim, S_fill(T) Fill, S_realloc(T) Realloc, TT rest) {
     217                return $alloc_internal( (void*)0p, Realloc, Align, Dim, Fill, rest);
     218                }
     219
     220                T * $alloc_internal( void * Resize, T * Realloc, size_t      , size_t Dim, S_fill(T) Fill, T_align Align, TT rest) {
     221                return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest);
     222                }
     223
     224                T * $alloc_internal( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T)     , S_fill(T) Fill, TT rest) {
     225                return $alloc_internal( Resize, Realloc, Align, Dim, Fill, rest);
    226226                }
    227227
    228228            T * alloc( TT all ) {
    229                 return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all);
     229                return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (size_t)1, (S_fill(T)){'0'}, all);
    230230            }
    231231
    232232            T * alloc( size_t dim, TT all ) {
    233                 return alloc_internal$( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all);
     233                return $alloc_internal( (void*)0p, (T*)0p, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), dim, (S_fill(T)){'0'}, all);
    234234            }
    235235
  • libcfa/src/time.hfa

    r5407cdc rfeacef9  
    1010// Created On       : Wed Mar 14 23:18:57 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 21 06:32:31 2021
    13 // Update Count     : 667
     12// Last Modified On : Wed Jun 17 16:13:00 2020
     13// Update Count     : 663
    1414//
    1515
     
    2828
    2929static inline {
    30         void ?{}( Duration & dur, timeval t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
    31         void ?{}( Duration & dur, timespec t ) with( dur ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
    32 
    3330        Duration ?=?( Duration & dur, __attribute__((unused)) zero_t ) { return dur{ 0 }; }
    34         Duration ?=?( Duration & dur, timeval t ) with( dur ) {
    35                 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL);
    36                 return dur;
    37         } // ?=?
    38         Duration ?=?( Duration & dur, timespec t ) with( dur ) {
    39                 tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
    40                 return dur;
    41         } // ?=?
    4231
    4332        Duration +?( Duration rhs ) with( rhs ) { return (Duration)@{ +tn }; }
     
    6049        Duration ?%?( Duration lhs, Duration rhs ) { return (Duration)@{ lhs.tn % rhs.tn }; }
    6150        Duration ?%=?( Duration & lhs, Duration rhs ) { lhs = lhs % rhs; return lhs; }
     51
     52        bool ?==?( Duration lhs, Duration rhs ) { return lhs.tn == rhs.tn; }
     53        bool ?!=?( Duration lhs, Duration rhs ) { return lhs.tn != rhs.tn; }
     54        bool ?<? ( Duration lhs, Duration rhs ) { return lhs.tn <  rhs.tn; }
     55        bool ?<=?( Duration lhs, Duration rhs ) { return lhs.tn <= rhs.tn; }
     56        bool ?>? ( Duration lhs, Duration rhs ) { return lhs.tn >  rhs.tn; }
     57        bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tn >= rhs.tn; }
    6258
    6359        bool ?==?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn == 0; }
     
    6763        bool ?>? ( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >  0; }
    6864        bool ?>=?( Duration lhs, __attribute__((unused)) zero_t ) { return lhs.tn >= 0; }
    69 
    70         bool ?==?( Duration lhs, Duration rhs ) { return lhs.tn == rhs.tn; }
    71         bool ?!=?( Duration lhs, Duration rhs ) { return lhs.tn != rhs.tn; }
    72         bool ?<? ( Duration lhs, Duration rhs ) { return lhs.tn <  rhs.tn; }
    73         bool ?<=?( Duration lhs, Duration rhs ) { return lhs.tn <= rhs.tn; }
    74         bool ?>? ( Duration lhs, Duration rhs ) { return lhs.tn >  rhs.tn; }
    75         bool ?>=?( Duration lhs, Duration rhs ) { return lhs.tn >= rhs.tn; }
    7665
    7766        Duration abs( Duration rhs ) { return rhs.tn >= 0 ? rhs : -rhs; }
     
    163152void ?{}( Time & time, int year, int month = 1, int day = 1, int hour = 0, int min = 0, int sec = 0, int64_t nsec = 0 );
    164153static inline {
     154        Time ?=?( Time & time, __attribute__((unused)) zero_t ) { return time{ 0 }; }
     155
    165156        void ?{}( Time & time, timeval t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * 1000; }
    166         void ?{}( Time & time, timespec t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
    167 
    168         Time ?=?( Time & time, __attribute__((unused)) zero_t ) { return time{ 0 }; }
    169157        Time ?=?( Time & time, timeval t ) with( time ) {
    170158                tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_usec * (TIMEGRAN / 1_000_000LL);
    171159                return time;
    172160        } // ?=?
     161
     162        void ?{}( Time & time, timespec t ) with( time ) { tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec; }
    173163        Time ?=?( Time & time, timespec t ) with( time ) {
    174164                tn = (int64_t)t.tv_sec * TIMEGRAN + t.tv_nsec;
  • libcfa/src/virtual.c

    r5407cdc rfeacef9  
    1515
    1616#include "virtual.h"
    17 #include "assert.h"
    1817
    1918int __cfa__is_parent( struct __cfa__parent_vtable const * parent,
    2019        struct __cfa__parent_vtable const * child ) {
    21         assert( child );
    2220        do {
    2321                if ( parent == child )
     
    3028void * __cfa__virtual_cast( struct __cfa__parent_vtable const * parent,
    3129        struct __cfa__parent_vtable const * const * child ) {
    32         assert( child );
    3330        return (__cfa__is_parent(parent, *child)) ? (void *)child : (void *)0;
    3431}
  • src/AST/Convert.cpp

    r5407cdc rfeacef9  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 09 15::37::05 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:43:51 2021
    13 // Update Count     : 36
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Nov 12 10:07:00 2020
     13// Update Count     : 34
    1414//
    1515
     
    327327        const ast::AsmDecl * visit( const ast::AsmDecl * node ) override final {
    328328                auto decl = new AsmDecl( get<AsmStmt>().accept1( node->stmt ) );
    329                 declPostamble( decl, node );
    330                 return nullptr;
    331         }
    332 
    333         const ast::DirectiveDecl * visit( const ast::DirectiveDecl * node ) override final {
    334                 auto decl = new DirectiveDecl( get<DirectiveStmt>().accept1( node->stmt ) );
    335329                declPostamble( decl, node );
    336330                return nullptr;
     
    17751769        }
    17761770
    1777         virtual void visit( const DirectiveDecl * old ) override final {
    1778                 auto decl = new ast::DirectiveDecl{
    1779                         old->location,
    1780                         GET_ACCEPT_1(stmt, DirectiveStmt)
    1781                 };
    1782                 decl->extension  = old->extension;
    1783                 decl->uniqueId   = old->uniqueId;
    1784                 decl->storage    = { old->storageClasses.val };
    1785 
    1786                 this->node = decl;
    1787         }
    1788 
    17891771        virtual void visit( const StaticAssertDecl * old ) override final {
    17901772                auto decl = new ast::StaticAssertDecl{
  • src/AST/Decl.hpp

    r5407cdc rfeacef9  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:25:05 2021
    13 // Update Count     : 32
     12// Last Modified On : Mon Jan 11 20:48:38 2021
     13// Update Count     : 30
    1414//
    1515
     
    365365};
    366366
    367 /// C-preprocessor directive `#...`
    368 class DirectiveDecl : public Decl {
    369 public:
    370         ptr<DirectiveStmt> stmt;
    371 
    372         DirectiveDecl( const CodeLocation & loc, DirectiveStmt * stmt )
    373         : Decl( loc, "", {}, {} ), stmt(stmt) {}
    374 
    375         const DirectiveDecl * accept( Visitor & v ) const override { return v.visit( this ); }
    376 private:
    377         DirectiveDecl * clone() const override { return new DirectiveDecl( *this ); }
    378         MUTATE_FRIEND
    379 };
    380 
    381367class StaticAssertDecl : public Decl {
    382368public:
  • src/AST/Expr.cpp

    r5407cdc rfeacef9  
    260260}
    261261
    262 ConstantExpr * ConstantExpr::from_string( const CodeLocation & loc, const std::string & str ) {
    263         const Type * charType = new BasicType( BasicType::Char );
    264         // Adjust the length of the string for the terminator.
    265         const Expr * strSize = from_ulong( loc, str.size() + 1 );
    266         const Type * strType = new ArrayType( charType, strSize, FixedLen, StaticDim );
    267         const std::string strValue = "\"" + str + "\"";
    268         return new ConstantExpr( loc, strType, strValue, std::nullopt );
    269 }
    270 
    271262ConstantExpr * ConstantExpr::null( const CodeLocation & loc, const Type * ptrType ) {
    272263        return new ConstantExpr{
  • src/AST/Expr.hpp

    r5407cdc rfeacef9  
    438438        long long int intValue() const;
    439439
    440         /// Generates a boolean constant of the given bool.
     440        /// generates a boolean constant of the given bool
    441441        static ConstantExpr * from_bool( const CodeLocation & loc, bool b );
    442         /// Generates an integer constant of the given int.
     442        /// generates an integer constant of the given int
    443443        static ConstantExpr * from_int( const CodeLocation & loc, int i );
    444         /// Generates an integer constant of the given unsigned long int.
     444        /// generates an integer constant of the given unsigned long int
    445445        static ConstantExpr * from_ulong( const CodeLocation & loc, unsigned long i );
    446         /// Generates a string constant from the given string (char type, unquoted string).
    447         static ConstantExpr * from_string( const CodeLocation & loc, const std::string & string );
    448         /// Generates a null pointer value for the given type. void * if omitted.
     446        /// generates a null pointer value for the given type. void * if omitted.
    449447        static ConstantExpr * null( const CodeLocation & loc, const Type * ptrType = nullptr );
    450448
  • src/AST/Fwd.hpp

    r5407cdc rfeacef9  
    99// Author           : Andrew Beach
    1010// Created On       : Wed May  8 16:05:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:37:39 2021
    13 // Update Count     : 4
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Jul 23 14:15:00 2020
     13// Update Count     : 2
    1414//
    1515
     
    3535class TypedefDecl;
    3636class AsmDecl;
    37 class DirectiveDecl;
    3837class StaticAssertDecl;
    3938
  • src/AST/Node.cpp

    r5407cdc rfeacef9  
    99// Author           : Thierry Delisle
    1010// Created On       : Thu May 16 14:16:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:25:06 2021
    13 // Update Count     : 2
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Jun  5 10:21:00 2020
     13// Update Count     : 1
    1414//
    1515
     
    130130template class ast::ptr_base< ast::AsmDecl, ast::Node::ref_type::weak >;
    131131template class ast::ptr_base< ast::AsmDecl, ast::Node::ref_type::strong >;
    132 template class ast::ptr_base< ast::DirectiveDecl, ast::Node::ref_type::weak >;
    133 template class ast::ptr_base< ast::DirectiveDecl, ast::Node::ref_type::strong >;
    134132template class ast::ptr_base< ast::StaticAssertDecl, ast::Node::ref_type::weak >;
    135133template class ast::ptr_base< ast::StaticAssertDecl, ast::Node::ref_type::strong >;
  • src/AST/Pass.hpp

    r5407cdc rfeacef9  
    139139        const ast::Decl *             visit( const ast::TypedefDecl          * ) override final;
    140140        const ast::AsmDecl *          visit( const ast::AsmDecl              * ) override final;
    141         const ast::DirectiveDecl *    visit( const ast::DirectiveDecl        * ) override final;
    142141        const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) override final;
    143142        const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) override final;
  • src/AST/Pass.impl.hpp

    r5407cdc rfeacef9  
    646646
    647647//--------------------------------------------------------------------------
    648 // DirectiveDecl
    649 template< typename core_t >
    650 const ast::DirectiveDecl * ast::Pass< core_t >::visit( const ast::DirectiveDecl * node ) {
    651         VISIT_START( node );
    652 
    653         VISIT(
    654                 maybe_accept( node, &DirectiveDecl::stmt );
    655         )
    656 
    657         VISIT_END( DirectiveDecl, node );
    658 }
    659 
    660 //--------------------------------------------------------------------------
    661648// StaticAssertDecl
    662649template< typename core_t >
  • src/AST/Print.cpp

    r5407cdc rfeacef9  
    387387
    388388        virtual const ast::AsmDecl * visit( const ast::AsmDecl * node ) override final {
    389                 safe_print( node->stmt );
    390                 return node;
    391         }
    392 
    393         virtual const ast::DirectiveDecl * visit( const ast::DirectiveDecl * node ) override final {
    394389                safe_print( node->stmt );
    395390                return node;
  • src/AST/Type.cpp

    r5407cdc rfeacef9  
    105105}
    106106
    107 // --- BaseInstType
    108 
    109107std::vector<readonly<Decl>> BaseInstType::lookup( const std::string& name ) const {
    110108        assertf( aggr(), "Must have aggregate to perform lookup" );
     
    121119template<typename decl_t>
    122120SueInstType<decl_t>::SueInstType(
    123         const base_type * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
    124 : BaseInstType( b->name, q, std::move(as) ), base( b ) {}
     121        const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
     122: BaseInstType( b->name, q, move(as) ), base( b ) {}
    125123
    126124template<typename decl_t>
     
    144142        const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
    145143: BaseInstType( b->name, q, move(as) ), base( b ) {}
    146 
    147 // --- TypeInstType
    148144
    149145void TypeInstType::set_base( const TypeDecl * b ) {
  • src/AST/Visitor.hpp

    r5407cdc rfeacef9  
    99// Author           : Andrew Beach
    1010// Created On       : Thr May 9 15:28:00 2019
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:25:07 2021
    13 // Update Count     : 1
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr May 9 15:33:00 2019
     13// Update Count     : 0
    1414//
    1515
     
    3131    virtual const ast::Decl *             visit( const ast::TypedefDecl          * ) = 0;
    3232    virtual const ast::AsmDecl *          visit( const ast::AsmDecl              * ) = 0;
    33     virtual const ast::DirectiveDecl *    visit( const ast::DirectiveDecl        * ) = 0;
    3433    virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) = 0;
    3534    virtual const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) = 0;
  • src/CodeGen/CodeGenerator.cc

    r5407cdc rfeacef9  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 19:00:42 2021
    13 // Update Count     : 536
     12// Last Modified On : Sun Feb 16 08:32:48 2020
     13// Update Count     : 532
    1414//
    1515#include "CodeGenerator.h"
     
    935935                if ( asmStmt->get_instruction() ) asmStmt->get_instruction()->accept( *visitor );
    936936                output << " )";
    937         }
    938 
    939         void CodeGenerator::postvisit( DirectiveDecl * directiveDecl ) {
    940                 output << endl << directiveDecl->get_stmt()->directive; // endl prevents spaces before directive
    941937        }
    942938
  • src/CodeGen/CodeGenerator.h

    r5407cdc rfeacef9  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:35:38 2021
    13 // Update Count     : 63
     12// Last Modified On : Sun Feb 16 03:58:31 2020
     13// Update Count     : 62
    1414//
    1515
     
    105105                void postvisit( DirectiveStmt * );
    106106                void postvisit( AsmDecl * );                                    // special: statement in declaration context
    107                 void postvisit( DirectiveDecl * );                              // special: statement in declaration context
    108107                void postvisit( IfStmt * );
    109108                void postvisit( SwitchStmt * );
  • src/Common/CodeLocationTools.cpp

    r5407cdc rfeacef9  
    99// Author           : Andrew Beach
    1010// Created On       : Fri Dec  4 15:42:00 2020
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:35:37 2021
    13 // Update Count     : 2
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Wed Dec  9  9:42:00 2020
     13// Update Count     : 1
    1414//
    1515
     
    102102    macro(TypedefDecl, Decl) \
    103103    macro(AsmDecl, AsmDecl) \
    104     macro(DirectiveDecl, DirectiveDecl) \
    105104    macro(StaticAssertDecl, StaticAssertDecl) \
    106105    macro(CompoundStmt, CompoundStmt) \
  • src/Common/PassVisitor.h

    r5407cdc rfeacef9  
    7777        virtual void visit( AsmDecl * asmDecl ) override final;
    7878        virtual void visit( const AsmDecl * asmDecl ) override final;
    79         virtual void visit( DirectiveDecl * directiveDecl ) override final;
    80         virtual void visit( const DirectiveDecl * directiveDecl ) override final;
    8179        virtual void visit( StaticAssertDecl * assertDecl ) override final;
    8280        virtual void visit( const StaticAssertDecl * assertDecl ) override final;
     
    263261        virtual Declaration * mutate( TypedefDecl * typeDecl ) override final;
    264262        virtual AsmDecl * mutate( AsmDecl * asmDecl ) override final;
    265         virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) override final;
    266263        virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) override final;
    267264
  • src/Common/PassVisitor.impl.h

    r5407cdc rfeacef9  
    973973
    974974//--------------------------------------------------------------------------
    975 // DirectiveDecl
    976 template< typename pass_type >
    977 void PassVisitor< pass_type >::visit( DirectiveDecl * node ) {
    978         VISIT_START( node );
    979 
    980         maybeAccept_impl( node->stmt, *this );
    981 
    982         VISIT_END( node );
    983 }
    984 
    985 template< typename pass_type >
    986 void PassVisitor< pass_type >::visit( const DirectiveDecl * node ) {
    987         VISIT_START( node );
    988 
    989         maybeAccept_impl( node->stmt, *this );
    990 
    991         VISIT_END( node );
    992 }
    993 
    994 template< typename pass_type >
    995 DirectiveDecl * PassVisitor< pass_type >::mutate( DirectiveDecl * node ) {
    996         MUTATE_START( node );
    997 
    998         maybeMutate_impl( node->stmt, *this );
    999 
    1000         MUTATE_END( DirectiveDecl, node );
    1001 }
    1002 
    1003 //--------------------------------------------------------------------------
    1004975// StaticAssertDecl
    1005976template< typename pass_type >
  • src/Concurrency/Keywords.cc

    r5407cdc rfeacef9  
    4242
    4343namespace Concurrency {
    44         inline static std::string getTypeIdName( std::string const & exception_name ) {
    45                 return exception_name.empty() ? std::string() : Virtual::typeIdType( exception_name );
    46         }
    4744        inline static std::string getVTableName( std::string const & exception_name ) {
    48                 return exception_name.empty() ? std::string() : Virtual::vtableTypeName( exception_name );
     45                return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name);
    4946        }
    5047
     
    7875                  type_name( type_name ), field_name( field_name ), getter_name( getter_name ),
    7976                  context_error( context_error ), exception_name( exception_name ),
    80                   typeid_name( getTypeIdName( exception_name ) ),
    8177                  vtable_name( getVTableName( exception_name ) ),
    8278                  needs_main( needs_main ), cast_target( cast_target ) {}
     
    8884
    8985                void handle( StructDecl * );
    90                 void addTypeId( StructDecl * );
    9186                void addVtableForward( StructDecl * );
    9287                FunctionDecl * forwardDeclare( StructDecl * );
     
    10499                const std::string context_error;
    105100                const std::string exception_name;
    106                 const std::string typeid_name;
    107101                const std::string vtable_name;
    108102                bool needs_main;
     
    112106                FunctionDecl * dtor_decl = nullptr;
    113107                StructDecl * except_decl = nullptr;
    114                 StructDecl * typeid_decl = nullptr;
    115108                StructDecl * vtable_decl = nullptr;
    116109        };
     
    400393                        except_decl = decl;
    401394                }
    402                 else if ( !typeid_decl && typeid_name == decl->name && decl->body ) {
    403                         typeid_decl = decl;
    404                 }
    405395                else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
    406396                        vtable_decl = decl;
     
    414404                if ( type_decl && isDestructorFor( decl, type_decl ) )
    415405                        dtor_decl = decl;
    416                 else if ( vtable_name.empty() || !decl->has_body() )
     406                else if ( vtable_name.empty() )
     407                        ;
     408                else if( !decl->has_body() )
    417409                        ;
    418410                else if ( auto param = isMainFor( decl, cast_target ) ) {
     
    426418                        std::list< Expression * > poly_args = { new TypeExpr( struct_type->clone() ) };
    427419                        ObjectDecl * vtable_object = Virtual::makeVtableInstance(
    428                                 "_default_vtable_object_declaration",
    429420                                vtable_decl->makeInst( poly_args ), struct_type, nullptr );
    430421                        declsToAddAfter.push_back( vtable_object );
    431                         declsToAddAfter.push_back(
    432                                 new ObjectDecl(
    433                                         Virtual::concurrentDefaultVTableName(),
    434                                         Type::Const,
    435                                         LinkageSpec::Cforall,
    436                                         /* bitfieldWidth */ nullptr,
    437                                         new ReferenceType( Type::Const, vtable_object->type->clone() ),
    438                                         new SingleInit( new VariableExpr( vtable_object ) )
    439                                 )
    440                         );
    441422                        declsToAddAfter.push_back( Virtual::makeGetExceptionFunction(
    442423                                vtable_object, except_decl->makeInst( std::move( poly_args ) )
     
    467448                if( !dtor_decl ) SemanticError( decl, context_error );
    468449
    469                 if ( !exception_name.empty() ) {
    470                         if( !typeid_decl ) SemanticError( decl, context_error );
    471                         if( !vtable_decl ) SemanticError( decl, context_error );
    472 
    473                         addTypeId( decl );
    474                         addVtableForward( decl );
    475                 }
     450                addVtableForward( decl );
    476451                FunctionDecl * func = forwardDeclare( decl );
    477452                ObjectDecl * field = addField( decl );
     
    479454        }
    480455
    481         void ConcurrentSueKeyword::addTypeId( StructDecl * decl ) {
    482                 assert( typeid_decl );
    483                 StructInstType typeid_type( Type::Const, typeid_decl );
    484                 typeid_type.parameters.push_back( new TypeExpr(
    485                         new StructInstType( noQualifiers, decl )
     456        void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
     457                if ( vtable_decl ) {
     458                        std::list< Expression * > poly_args = {
     459                                new TypeExpr( new StructInstType( noQualifiers, decl ) ),
     460                        };
     461                        declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
     462                                vtable_decl->makeInst( poly_args ),
     463                                except_decl->makeInst( poly_args )
    486464                        ) );
    487                 declsToAddBefore.push_back( Virtual::makeTypeIdInstance( &typeid_type ) );
    488         }
    489 
    490         void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
    491                 assert( vtable_decl );
    492                 std::list< Expression * > poly_args = {
    493                         new TypeExpr( new StructInstType( noQualifiers, decl ) ),
    494                 };
    495                 declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
    496                         vtable_decl->makeInst( poly_args ),
    497                         except_decl->makeInst( poly_args )
    498                 ) );
    499                 ObjectDecl * vtable_object = Virtual::makeVtableForward(
    500                         "_default_vtable_object_declaration",
    501                         vtable_decl->makeInst( move( poly_args ) ) );
    502                 declsToAddBefore.push_back( vtable_object );
    503                 declsToAddBefore.push_back(
    504                         new ObjectDecl(
    505                                 Virtual::concurrentDefaultVTableName(),
    506                                 Type::Const,
    507                                 LinkageSpec::Cforall,
    508                                 /* bitfieldWidth */ nullptr,
    509                                 new ReferenceType( Type::Const, vtable_object->type->clone() ),
    510                                 /* init */ nullptr
    511                         )
    512                 );
     465                        declsToAddBefore.push_back( Virtual::makeVtableForward(
     466                                vtable_decl->makeInst( move( poly_args ) ) ) );
     467                // Its only an error if we want a vtable and don't have one.
     468                } else if ( ! vtable_name.empty() ) {
     469                        SemanticError( decl, context_error );
     470                }
    513471        }
    514472
  • src/Parser/DeclarationNode.cc

    r5407cdc rfeacef9  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Mar 23 08:44:08 2021
    13 // Update Count     : 1149
     12// Last Modified On : Mon Jan 11 20:58:07 2021
     13// Update Count     : 1137
    1414//
    1515
     
    167167}
    168168
     169DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {
     170        DeclarationNode * newnode = new DeclarationNode;
     171        newnode->name = name;
     172        newnode->type = new TypeData( TypeData::Function );
     173        newnode->type->function.params = param;
     174        newnode->type->function.body = body;
     175
     176        if ( ret ) {
     177                newnode->type->base = ret->type;
     178                ret->type = nullptr;
     179                delete ret;
     180        } // if
     181
     182        return newnode;
     183} // DeclarationNode::newFunction
     184
     185
    169186DeclarationNode * DeclarationNode::newStorageClass( Type::StorageClasses sc ) {
    170187        DeclarationNode * newnode = new DeclarationNode;
     
    220237        return newnode;
    221238} // DeclarationNode::newForall
     239
     240DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) {
     241        DeclarationNode * newnode = new DeclarationNode;
     242        newnode->type = new TypeData( TypeData::SymbolicInst );
     243        newnode->type->symbolic.name = name;
     244        newnode->type->symbolic.isTypedef = true;
     245        newnode->type->symbolic.params = nullptr;
     246        return newnode;
     247} // DeclarationNode::newFromTypedef
    222248
    223249DeclarationNode * DeclarationNode::newFromGlobalScope() {
     
    263289} // DeclarationNode::newEnum
    264290
     291DeclarationNode * DeclarationNode::newEnumConstant( const string * name, ExpressionNode * constant ) {
     292        DeclarationNode * newnode = new DeclarationNode;
     293        newnode->name = name;
     294        newnode->enumeratorValue.reset( constant );
     295        return newnode;
     296} // DeclarationNode::newEnumConstant
     297
    265298DeclarationNode * DeclarationNode::newName( const string * name ) {
    266299        DeclarationNode * newnode = new DeclarationNode;
    267         assert( ! newnode->name );
    268300        newnode->name = name;
    269301        return newnode;
    270302} // DeclarationNode::newName
    271 
    272 DeclarationNode * DeclarationNode::newEnumConstant( const string * name, ExpressionNode * constant ) {
    273         DeclarationNode * newnode = newName( name );
    274         newnode->enumeratorValue.reset( constant );
    275         return newnode;
    276 } // DeclarationNode::newEnumConstant
    277 
    278 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) {
    279         DeclarationNode * newnode = new DeclarationNode;
    280         newnode->type = new TypeData( TypeData::SymbolicInst );
    281         newnode->type->symbolic.name = name;
    282         newnode->type->symbolic.isTypedef = true;
    283         newnode->type->symbolic.params = nullptr;
    284         return newnode;
    285 } // DeclarationNode::newFromTypedef
    286303
    287304DeclarationNode * DeclarationNode::newFromTypeGen( const string * name, ExpressionNode * params ) {
     
    295312
    296313DeclarationNode * DeclarationNode::newTypeParam( TypeDecl::Kind tc, const string * name ) {
    297         DeclarationNode * newnode = newName( name );
     314        DeclarationNode * newnode = new DeclarationNode;
    298315        newnode->type = nullptr;
     316        assert( ! newnode->name );
     317//      newnode->variable.name = name;
     318        newnode->name = name;
    299319        newnode->variable.tyClass = tc;
    300320        newnode->variable.assertions = nullptr;
     
    323343
    324344DeclarationNode * DeclarationNode::newTypeDecl( const string * name, DeclarationNode * typeParams ) {
    325         DeclarationNode * newnode = newName( name );
     345        DeclarationNode * newnode = new DeclarationNode;
     346        newnode->name = name;
    326347        newnode->type = new TypeData( TypeData::Symbolic );
    327348        newnode->type->symbolic.isTypedef = false;
     
    396417} // DeclarationNode::newBuiltinType
    397418
    398 DeclarationNode * DeclarationNode::newFunction( const string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ) {
    399         DeclarationNode * newnode = newName( name );
    400         newnode->type = new TypeData( TypeData::Function );
    401         newnode->type->function.params = param;
    402         newnode->type->function.body = body;
    403 
    404         if ( ret ) {
    405                 newnode->type->base = ret->type;
    406                 ret->type = nullptr;
    407                 delete ret;
    408         } // if
    409 
    410         return newnode;
    411 } // DeclarationNode::newFunction
    412 
    413419DeclarationNode * DeclarationNode::newAttribute( const string * name, ExpressionNode * expr ) {
    414420        DeclarationNode * newnode = new DeclarationNode;
     
    418424        newnode->attributes.push_back( new Attribute( *name, exprs ) );
    419425        delete name;
    420         return newnode;
    421 }
    422 
    423 DeclarationNode * DeclarationNode::newDirectiveStmt( StatementNode * stmt ) {
    424         DeclarationNode * newnode = new DeclarationNode;
    425         newnode->directiveStmt = stmt;
    426426        return newnode;
    427427}
     
    879879}
    880880
    881 DeclarationNode * DeclarationNode::cloneType( string * name ) {
    882         DeclarationNode * newnode = newName( name );
     881DeclarationNode * DeclarationNode::cloneType( string * newName ) {
     882        DeclarationNode * newnode = new DeclarationNode;
    883883        newnode->type = maybeClone( type );
    884884        newnode->copySpecifiers( this );
     885        assert( newName );
     886        newnode->name = newName;
    885887        return newnode;
    886888}
     
    10701072                return new AsmDecl( strict_dynamic_cast<AsmStmt *>( asmStmt->build() ) );
    10711073        } // if
    1072         if ( directiveStmt ) {
    1073                 return new DirectiveDecl( strict_dynamic_cast<DirectiveStmt *>( directiveStmt->build() ) );
    1074         } // if
    10751074
    10761075        if ( variable.tyClass != TypeDecl::NUMBER_OF_KINDS ) {
  • src/Parser/ParseNode.h

    r5407cdc rfeacef9  
    1010// Created On       : Sat May 16 13:28:16 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 15:19:04 2021
    13 // Update Count     : 897
     12// Last Modified On : Sun Jan  3 18:23:01 2021
     13// Update Count     : 896
    1414//
    1515
     
    249249        static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false );
    250250        static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes
    251         static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement
    252251        static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement
    253252        static DeclarationNode * newStaticAssert( ExpressionNode * condition, Expression * message );
     
    346345        std::string error;
    347346        StatementNode * asmStmt = nullptr;
    348         StatementNode * directiveStmt = nullptr;
    349347
    350348        static UniqueName anonymous;
  • src/Parser/TypeData.h

    r5407cdc rfeacef9  
    77// TypeData.h --
    88//
    9 // Author           : Peter A. Buhr
     9// Author           : Rodolfo G. Esteves
    1010// Created On       : Sat May 16 15:18:36 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Mar 27 09:05:35 2021
    13 // Update Count     : 200
     12// Last Modified On : Fri Dec 13 23:42:35 2019
     13// Update Count     : 199
    1414//
    1515
    1616#pragma once
    1717
    18 #include <iosfwd>                                                                               // for ostream
    19 #include <list>                                                                                 // for list
    20 #include <string>                                                                               // for string
     18#include <iosfwd>                // for ostream
     19#include <list>                  // for list
     20#include <string>                // for string
    2121
    22 #include "ParseNode.h"                                                                  // for DeclarationNode, DeclarationNode::Ag...
    23 #include "SynTree/LinkageSpec.h"                                                // for Spec
    24 #include "SynTree/Type.h"                                                               // for Type, ReferenceToType (ptr only)
    25 #include "SynTree/SynTree.h"                                                    // for Visitor Nodes
     22#include "ParseNode.h"           // for DeclarationNode, DeclarationNode::Ag...
     23#include "SynTree/LinkageSpec.h" // for Spec
     24#include "SynTree/Type.h"        // for Type, ReferenceToType (ptr only)
     25#include "SynTree/SynTree.h"     // for Visitor Nodes
    2626
    2727struct TypeData {
     
    3333                const std::string * name = nullptr;
    3434                DeclarationNode * params = nullptr;
    35                 ExpressionNode * actuals = nullptr;                             // holds actual parameters later applied to AggInst
     35                ExpressionNode * actuals = nullptr;                                             // holds actual parameters later applied to AggInst
    3636                DeclarationNode * fields = nullptr;
    3737                bool body;
     
    6262
    6363        struct Function_t {
    64                 mutable DeclarationNode * params = nullptr;             // mutables modified in buildKRFunction
    65                 mutable DeclarationNode * idList = nullptr;             // old-style
     64                mutable DeclarationNode * params = nullptr;                             // mutables modified in buildKRFunction
     65                mutable DeclarationNode * idList = nullptr;                             // old-style
    6666                mutable DeclarationNode * oldDeclList = nullptr;
    6767                StatementNode * body = nullptr;
    68                 ExpressionNode * withExprs = nullptr;                   // expressions from function's with_clause
     68                ExpressionNode * withExprs = nullptr;                                           // expressions from function's with_clause
    6969        };
    7070
  • src/Parser/TypedefTable.cc

    r5407cdc rfeacef9  
    1010// Created On       : Sat May 16 15:20:13 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 15 20:56:47 2021
    13 // Update Count     : 260
     12// Last Modified On : Sat Feb 15 08:06:36 2020
     13// Update Count     : 259
    1414//
    1515
     
    8989        debugPrint( cerr << "Adding enclosing at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl );
    9090        auto ret = kindTable.insertAt( scope, identifier, kind );
    91         if ( ! ret.second ) ret.first->second = kind;           // exists => update
     91        if ( ! ret.second ) ret.first->second = kind;   // exists => update
    9292} // TypedefTable::addToEnclosingScope
    9393
  • src/Parser/lex.ll

    r5407cdc rfeacef9  
    1010 * Created On       : Sat Sep 22 08:58:10 2001
    1111 * Last Modified By : Peter A. Buhr
    12  * Last Modified On : Thu Apr  1 13:22:31 2021
    13  * Update Count     : 754
     12 * Last Modified On : Tue Oct  6 18:15:41 2020
     13 * Update Count     : 743
    1414 */
    1515
     
    221221break                   { KEYWORD_RETURN(BREAK); }
    222222case                    { KEYWORD_RETURN(CASE); }
    223 catch                   { QKEYWORD_RETURN(CATCH); }                             // CFA
    224 catchResume             { QKEYWORD_RETURN(CATCHRESUME); }               // CFA
     223catch                   { KEYWORD_RETURN(CATCH); }                              // CFA
     224catchResume             { KEYWORD_RETURN(CATCHRESUME); }                // CFA
    225225char                    { KEYWORD_RETURN(CHAR); }
    226226choose                  { KEYWORD_RETURN(CHOOSE); }                             // CFA
     
    247247fallthrough             { KEYWORD_RETURN(FALLTHROUGH); }                // CFA
    248248fallthru                { KEYWORD_RETURN(FALLTHRU); }                   // CFA
    249 finally                 { QKEYWORD_RETURN(FINALLY); }                   // CFA
    250 fixup                   { QKEYWORD_RETURN(FIXUP); }                             // CFA
     249finally                 { KEYWORD_RETURN(FINALLY); }                    // CFA
    251250float                   { KEYWORD_RETURN(FLOAT); }
    252251__float80               { KEYWORD_RETURN(uuFLOAT80); }                  // GCC
     
    288287or                              { QKEYWORD_RETURN(WOR); }                               // CFA
    289288otype                   { KEYWORD_RETURN(OTYPE); }                              // CFA
    290 recover                 { QKEYWORD_RETURN(RECOVER); }                   // CFA
    291289register                { KEYWORD_RETURN(REGISTER); }
    292 report                  { KEYWORD_RETURN(THROWRESUME); }                // CFA
    293290restrict                { KEYWORD_RETURN(RESTRICT); }                   // C99
    294291__restrict              { KEYWORD_RETURN(RESTRICT); }                   // GCC
     
    318315__typeof                { KEYWORD_RETURN(TYPEOF); }                             // GCC
    319316__typeof__              { KEYWORD_RETURN(TYPEOF); }                             // GCC
    320 typeid                  { KEYWORD_RETURN(TYPEID); }                             // GCC
    321317union                   { KEYWORD_RETURN(UNION); }
    322318__uint128_t             { KEYWORD_RETURN(UINT128); }                    // GCC
     
    328324__volatile              { KEYWORD_RETURN(VOLATILE); }                   // GCC
    329325__volatile__    { KEYWORD_RETURN(VOLATILE); }                   // GCC
    330 vtable                  { KEYWORD_RETURN(VTABLE); }                             // CFA
    331 waitfor                 { KEYWORD_RETURN(WAITFOR); }                    // CFA
    332 when                    { KEYWORD_RETURN(WHEN); }                               // CFA
     326waitfor                 { KEYWORD_RETURN(WAITFOR); }
     327when                    { KEYWORD_RETURN(WHEN); }
    333328while                   { KEYWORD_RETURN(WHILE); }
    334329with                    { KEYWORD_RETURN(WITH); }                               // CFA
  • src/Parser/parser.yy

    r5407cdc rfeacef9  
    1010// Created On       : Sat Sep  1 20:22:55 2001
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 26 18:41:54 2021
    13 // Update Count     : 4990
     12// Last Modified On : Wed Feb  3 18:30:12 2021
     13// Update Count     : 4700
    1414//
    1515
     
    3232//
    3333// 1. designation with and without '=' (use ':' instead)
    34 
     34// 2. attributes not allowed in parenthesis of declarator
    3535//
    3636// All of the syntactic extensions for GCC C are marked with the comment "GCC". The second extensions are for Cforall
     
    211211} // forCtrl
    212212
    213 bool forall = false;                                                                    // aggregate have one or more forall qualifiers ?
     213bool forall = false, yyy = false;                                               // aggregate have one or more forall qualifiers ?
    214214
    215215// https://www.gnu.org/software/bison/manual/bison.html#Location-Type
     
    264264%token RESTRICT                                                                                 // C99
    265265%token ATOMIC                                                                                   // C11
    266 %token FORALL MUTEX VIRTUAL VTABLE COERCE                               // CFA
     266%token FORALL MUTEX VIRTUAL COERCE                                              // CFA
    267267%token VOID CHAR SHORT INT LONG FLOAT DOUBLE SIGNED UNSIGNED
    268268%token BOOL COMPLEX IMAGINARY                                                   // C99
     
    270270%token uFLOAT16 uFLOAT32 uFLOAT32X uFLOAT64 uFLOAT64X uFLOAT128 // GCC
    271271%token ZERO_T ONE_T                                                                             // CFA
    272 %token SIZEOF TYPEOF VALIST AUTO_TYPE                                   // GCC
    273 %token OFFSETOF BASETYPEOF TYPEID                                               // CFA
     272%token VALIST                                                                                   // GCC
     273%token AUTO_TYPE                                                                                // GCC
     274%token TYPEOF BASETYPEOF LABEL                                                  // GCC
    274275%token ENUM STRUCT UNION
    275276%token EXCEPTION                                                                                // CFA
    276277%token GENERATOR COROUTINE MONITOR THREAD                               // CFA
    277278%token OTYPE FTYPE DTYPE TTYPE TRAIT                                    // CFA
     279%token SIZEOF OFFSETOF
    278280// %token RESUME                                                                                        // CFA
    279 %token LABEL                                                                                    // GCC
    280281%token SUSPEND                                                                                  // CFA
    281282%token ATTRIBUTE EXTENSION                                                              // GCC
    282283%token IF ELSE SWITCH CASE DEFAULT DO WHILE FOR BREAK CONTINUE GOTO RETURN
    283 %token CHOOSE FALLTHRU FALLTHROUGH WITH WHEN WAITFOR    // CFA
    284 %token DISABLE ENABLE TRY THROW THROWRESUME AT                  // CFA
     284%token CHOOSE DISABLE ENABLE FALLTHRU FALLTHROUGH TRY CATCH CATCHRESUME FINALLY THROW THROWRESUME AT WITH WHEN WAITFOR // CFA
    285285%token ASM                                                                                              // C99, extension ISO/IEC 9899:1999 Section J.5.10(1)
    286286%token ALIGNAS ALIGNOF GENERIC STATICASSERT                             // C11
    287287
    288288// names and constants: lexer differentiates between identifier and typedef names
    289 %token<tok> IDENTIFIER          QUOTED_IDENTIFIER       TYPEDEFname             TYPEGENname
    290 %token<tok> TIMEOUT                     WOR                                     CATCH                   RECOVER                 CATCHRESUME             FIXUP           FINALLY         // CFA
    291 %token<tok> INTEGERconstant     CHARACTERconstant       STRINGliteral
     289%token<tok> IDENTIFIER                  QUOTED_IDENTIFIER               TYPEDEFname                             TYPEGENname
     290%token<tok> TIMEOUT                             WOR
     291%token<tok> INTEGERconstant             CHARACTERconstant               STRINGliteral
    292292%token<tok> DIRECTIVE
    293293// Floating point constant is broken into three kinds of tokens because of the ambiguity with tuple indexing and
     
    321321%type<en> constant
    322322%type<en> tuple                                                 tuple_expression_list
    323 %type<op> ptrref_operator                               unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
     323%type<op> ptrref_operator                               unary_operator                          assignment_operator
    324324%type<en> primary_expression                    postfix_expression                      unary_expression
    325325%type<en> cast_expression_list                  cast_expression                         exponential_expression          multiplicative_expression       additive_expression
     
    373373
    374374%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
    375 %type<decl> vtable vtable_opt default_opt
    376375
    377376%type<decl> trait_declaration trait_declaration_list trait_declaring_list trait_specifier
     
    429428
    430429%type<decl> type_declaration_specifier type_type_specifier type_name typegen_name
    431 %type<decl> typedef_name typedef_declaration typedef_expression
     430%type<decl> typedef typedef_declaration typedef_expression
    432431
    433432%type<decl> variable_type_redeclarator type_ptr type_array type_function
     
    441440
    442441%type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
    443 %type<decl> type_specifier type_specifier_nobody
     442%type<decl> type_specifier type_specifier_nobody enum_specifier_nobody
    444443
    445444%type<decl> variable_declarator variable_ptr variable_array variable_function
    446445%type<decl> variable_abstract_declarator variable_abstract_ptr variable_abstract_array variable_abstract_function
    447446
    448 %type<decl> attribute_list_opt attribute_list attribute attribute_name_list attribute_name
     447%type<decl> attribute_list_opt attribute_list attribute_opt attribute attribute_name_list attribute_name
    449448
    450449// initializers
     
    463462// Order of these lines matters (low-to-high precedence). THEN is left associative over WOR/TIMEOUT/ELSE, WOR is left
    464463// associative over TIMEOUT/ELSE, and TIMEOUT is left associative over ELSE.
    465 %precedence THEN                // rule precedence for IF/WAITFOR statement
    466 %precedence WOR                 // token precedence for start of WOR in WAITFOR statement
    467 %precedence TIMEOUT             // token precedence for start of TIMEOUT in WAITFOR statement
    468 %precedence CATCH               // token precedence for start of TIMEOUT in WAITFOR statement
    469 %precedence RECOVER             // token precedence for start of TIMEOUT in WAITFOR statement
    470 %precedence CATCHRESUME // token precedence for start of TIMEOUT in WAITFOR statement
    471 %precedence FIXUP               // token precedence for start of TIMEOUT in WAITFOR statement
    472 %precedence FINALLY             // token precedence for start of TIMEOUT in WAITFOR statement
    473 %precedence ELSE                // token precedence for start of else clause in IF/WAITFOR statement
    474 
     464%precedence THEN        // rule precedence for IF/WAITFOR statement
     465%precedence WOR         // token precedence for start of WOR in WAITFOR statement
     466%precedence TIMEOUT     // token precedence for start of TIMEOUT in WAITFOR statement
     467%precedence ELSE        // token precedence for start of else clause in IF/WAITFOR statement
    475468
    476469// Handle shift/reduce conflict for generic type by shifting the '(' token. For example, this string is ambiguous:
     
    551544        TIMEOUT
    552545        | WOR
    553         | CATCH
    554         | RECOVER
    555         | CATCHRESUME
    556         | FIXUP
    557         | FINALLY
    558546        ;
    559547
     
    786774        | OFFSETOF '(' type_no_function ',' identifier ')'
    787775                { $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) ); }
    788         | TYPEID '(' type_no_function ')'
    789                 {
    790                         SemanticError( yylloc, "typeid name is currently unimplemented." ); $$ = nullptr;
    791                         // $$ = new ExpressionNode( build_offsetOf( $3, build_varref( $5 ) ) );
    792                 }
    793776        ;
    794777
     
    812795                { $$ = new ExpressionNode( build_cast( $2, $4 ) ); }
    813796        | '(' aggregate_control '&' ')' cast_expression         // CFA
    814                 { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
    815         | '(' aggregate_control '*' ')' cast_expression         // CFA
    816797                { $$ = new ExpressionNode( build_keyword_cast( $2, $5 ) ); }
    817798        | '(' VIRTUAL ')' cast_expression                                       // CFA
     
    958939
    959940assignment_operator:
    960         simple_assignment_operator
    961         | compound_assignment_operator
    962         ;
    963 
    964 simple_assignment_operator:
    965941        '='                                                                                     { $$ = OperKinds::Assign; }
    966         | ATassign                                                                      { $$ = OperKinds::AtAssn; } // CFA
    967         ;
    968 
    969 compound_assignment_operator:
    970         EXPassign                                                                       { $$ = OperKinds::ExpAssn; }
     942        | ATassign                                                                      { $$ = OperKinds::AtAssn; }
     943        | EXPassign                                                                     { $$ = OperKinds::ExpAssn; }
    971944        | MULTassign                                                            { $$ = OperKinds::MulAssn; }
    972945        | DIVassign                                                                     { $$ = OperKinds::DivAssn; }
     
    10461019                { $$ = new StatementNode( build_compound( (StatementNode *)0 ) ); }
    10471020        | '{' push
    1048           local_label_declaration_opt                                           // GCC, local labels appear at start of block
     1021          local_label_declaration_opt                                           // GCC, local labels
    10491022          statement_decl_list                                                           // C99, intermix declarations and statements
    10501023          pop '}'
     
    12441217        | comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA
    12451218                { $$ = forCtrl( $3, $1, $3->clone(), $4, $5, $7 ); }
    1246 
    1247         | comma_expression ';' TYPEDEFname                                      // CFA, array type
    1248                 {
    1249                         SemanticError( yylloc, "Array interator is currently unimplemented." ); $$ = nullptr;
    1250                         $$ = forCtrl( new ExpressionNode( build_varref( $3 ) ), $1, nullptr, OperKinds::Range, nullptr, nullptr );
    1251                 }
    12521219
    12531220                // There is a S/R conflicit if ~ and -~ are factored out.
     
    13991366
    14001367exception_statement:
    1401         TRY compound_statement handler_clause                                   %prec THEN
     1368        TRY compound_statement handler_clause
    14021369                { $$ = new StatementNode( build_try( $2, $3, 0 ) ); }
    14031370        | TRY compound_statement finally_clause
     
    14221389handler_key:
    14231390        CATCH                                                                           { $$ = CatchStmt::Terminate; }
    1424         | RECOVER                                                                       { $$ = CatchStmt::Terminate; }
    14251391        | CATCHRESUME                                                           { $$ = CatchStmt::Resume; }
    1426         | FIXUP                                                                         { $$ = CatchStmt::Resume; }
    14271392        ;
    14281393
     
    17761741        ;
    17771742
     1743enum_specifier_nobody:                                                                  // type specifier - {...}
     1744                // Preclude SUE declarations in restricted scopes (see type_specifier_nobody)
     1745        basic_type_specifier
     1746        | sue_type_specifier_nobody
     1747        ;
     1748
    17781749type_qualifier_list_opt:                                                                // GCC, used in asm_statement
    17791750        // empty
     
    17951766type_qualifier:
    17961767        type_qualifier_name
    1797         | attribute                                                                                     // trick handles most atrribute locations
     1768        | attribute
    17981769        ;
    17991770
     
    19031874        | AUTO_TYPE
    19041875                { $$ = DeclarationNode::newBuiltinType( DeclarationNode::AutoType ); }
    1905         | vtable
    1906         ;
    1907 
    1908 vtable_opt:
    1909         // empty
    1910                 { $$ = nullptr; }
    1911         | vtable;
    1912         ;
    1913 
    1914 vtable:
    1915         VTABLE '(' type_list ')' default_opt
    1916                 { SemanticError( yylloc, "vtable is currently unimplemented." ); $$ = nullptr; }
    1917         ;
    1918 
    1919 default_opt:
    1920         // empty
    1921                 { $$ = nullptr; }
    1922         | DEFAULT
    1923                 { SemanticError( yylloc, "vtable default is currently unimplemented." ); $$ = nullptr; }
    19241876        ;
    19251877
     
    20732025          '{' field_declaration_list_opt '}' type_parameters_opt
    20742026                { $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); }
    2075         | aggregate_key attribute_list_opt TYPEDEFname          // unqualified type name
    2076                 {
    2077                         typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
     2027        | aggregate_key attribute_list_opt type_name
     2028                {
     2029                        // for type_name can be a qualified type name S.T, in which case only the last name in the chain needs a typedef (other names in the chain should already have one)
     2030                        typedefTable.makeTypedef( *$3->type->leafName(), forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
    20782031                        forall = false;                                                         // reset
    20792032                }
    20802033          '{' field_declaration_list_opt '}' type_parameters_opt
    2081                 {
    2082                         DeclarationNode::newFromTypedef( $3 );
    2083                         $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
    2084                 }
    2085         | aggregate_key attribute_list_opt TYPEGENname          // unqualified type name
    2086                 {
    2087                         typedefTable.makeTypedef( *$3, forall || typedefTable.getEnclForall() ? TYPEGENname : TYPEDEFname ); // create typedef
    2088                         forall = false;                                                         // reset
    2089                 }
    2090           '{' field_declaration_list_opt '}' type_parameters_opt
    2091                 {
    2092                         DeclarationNode::newFromTypeGen( $3, nullptr );
    2093                         $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 );
    2094                 }
     2034                { $$ = DeclarationNode::newAggregate( $1, $3->type->symbolic.name, $8, $6, true )->addQualifiers( $2 ); }
    20952035        | aggregate_type_nobody
    20962036        ;
     
    21292069
    21302070aggregate_data:
    2131         STRUCT vtable_opt
    2132                 { $$ = AggregateDecl::Struct; }
     2071        STRUCT
     2072                { yyy = true; $$ = AggregateDecl::Struct; }
    21332073        | UNION
    2134                 { $$ = AggregateDecl::Union; }
     2074                { yyy = true; $$ = AggregateDecl::Union; }
    21352075        | EXCEPTION                                                                                     // CFA
    2136                 { $$ = AggregateDecl::Exception; }
    2137           //            { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     2076                // { yyy = true; $$ = AggregateDecl::Exception; }
     2077                { SemanticError( yylloc, "exception aggregate is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    21382078        ;
    21392079
    21402080aggregate_control:                                                                              // CFA
    21412081        MONITOR
    2142                 { $$ = AggregateDecl::Monitor; }
     2082                { yyy = true; $$ = AggregateDecl::Monitor; }
    21432083        | MUTEX STRUCT
    2144                 { $$ = AggregateDecl::Monitor; }
     2084                { yyy = true; $$ = AggregateDecl::Monitor; }
    21452085        | GENERATOR
    2146                 { $$ = AggregateDecl::Generator; }
     2086                { yyy = true; $$ = AggregateDecl::Generator; }
    21472087        | MUTEX GENERATOR
    21482088                { SemanticError( yylloc, "monitor generator is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    21492089        | COROUTINE
    2150                 { $$ = AggregateDecl::Coroutine; }
     2090                { yyy = true; $$ = AggregateDecl::Coroutine; }
    21512091        | MUTEX COROUTINE
    21522092                { SemanticError( yylloc, "monitor coroutine is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
    21532093        | THREAD
    2154                 { $$ = AggregateDecl::Thread; }
     2094                { yyy = true; $$ = AggregateDecl::Thread; }
    21552095        | MUTEX THREAD
    21562096                { SemanticError( yylloc, "monitor thread is currently unimplemented." ); $$ = AggregateDecl::NoAggregate; }
     
    22482188        ;
    22492189
     2190// Cannot use attribute_list_opt because of ambiguity with enum_specifier_nobody, which already parses attribute.
     2191// Hence, only a single attribute is allowed after the "ENUM".
    22502192enum_type:                                                                                              // enum
    2251         ENUM attribute_list_opt '{' enumerator_list comma_opt '}'
     2193        ENUM attribute_opt '{' enumerator_list comma_opt '}'
    22522194                { $$ = DeclarationNode::newEnum( nullptr, $4, true )->addQualifiers( $2 ); }
    2253         | ENUM attribute_list_opt identifier
     2195        | ENUM attribute_opt identifier
    22542196                { typedefTable.makeTypedef( *$3 ); }
    22552197          '{' enumerator_list comma_opt '}'
    22562198                { $$ = DeclarationNode::newEnum( $3, $6, true )->addQualifiers( $2 ); }
    2257         | ENUM attribute_list_opt typedef_name                          // unqualified type name
     2199        | ENUM attribute_opt typedef                                            // enum cannot be generic
    22582200          '{' enumerator_list comma_opt '}'
    22592201                { $$ = DeclarationNode::newEnum( $3->name, $5, true )->addQualifiers( $2 ); }
    2260         | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
    2261                 {
    2262                         if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    2263                         SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr;
    2264                 }
    2265         | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt
    2266                 {
    2267                         if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    2268                         typedefTable.makeTypedef( *$6 );
    2269                 }
    2270           '{' enumerator_list comma_opt '}'
    2271                 {
    2272                         SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr;
    2273                 }
    2274         | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}'
    2275                 {
    2276                         if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
    2277                         typedefTable.makeTypedef( *$6->name );
    2278                         SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr;
    2279                 }
     2202        | ENUM enum_specifier_nobody '{' enumerator_list comma_opt '}'
     2203                // { $$ = DeclarationNode::newEnum( nullptr, $4, true ); }
     2204                { SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; }
     2205        | ENUM enum_specifier_nobody declarator '{' enumerator_list comma_opt '}'
     2206                // {
     2207                //      typedefTable.makeTypedef( *$3->name );
     2208                //      $$ = DeclarationNode::newEnum( nullptr, $5, true );
     2209                // }
     2210                { SemanticError( yylloc, "Typed enumeration is currently unimplemented." ); $$ = nullptr; }
    22802211        | enum_type_nobody
    22812212        ;
    22822213
    22832214enum_type_nobody:                                                                               // enum - {...}
    2284         ENUM attribute_list_opt identifier
    2285                 { typedefTable.makeTypedef( *$3 ); $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 ); }
    2286         | ENUM attribute_list_opt type_name                                     // qualified type name
    2287                 { typedefTable.makeTypedef( *$3->type->symbolic.name ); $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 ); }
     2215        ENUM attribute_opt identifier
     2216                {
     2217                        typedefTable.makeTypedef( *$3 );
     2218                        $$ = DeclarationNode::newEnum( $3, 0, false )->addQualifiers( $2 );
     2219                }
     2220        | ENUM attribute_opt type_name                                          // enum cannot be generic
     2221                {
     2222                        typedefTable.makeTypedef( *$3->type->symbolic.name );
     2223                        $$ = DeclarationNode::newEnum( $3->type->symbolic.name, 0, false )->addQualifiers( $2 );
     2224                }
    22882225        ;
    22892226
     
    22912228        identifier_or_type_name enumerator_value_opt
    22922229                { $$ = DeclarationNode::newEnumConstant( $1, $2 ); }
    2293         | INLINE type_name
    2294                 { $$ = DeclarationNode::newEnumConstant( new string("inline"), nullptr ); }
    22952230        | enumerator_list ',' identifier_or_type_name enumerator_value_opt
    22962231                { $$ = $1->appendList( DeclarationNode::newEnumConstant( $3, $4 ) ); }
    2297         | enumerator_list ',' INLINE type_name enumerator_value_opt
    2298                 { $$ = $1->appendList( DeclarationNode::newEnumConstant( new string("inline"), nullptr ) ); }
    22992232        ;
    23002233
     
    23042237        // | '=' constant_expression
    23052238        //      { $$ = $2; }
    2306         | simple_assignment_operator initializer
     2239        | '=' initializer
    23072240                { $$ = $2->get_expression(); }                                  // FIX ME: enum only deals with constant_expression
    23082241        ;
     
    24322365        // empty
    24332366                { $$ = nullptr; }
    2434         | simple_assignment_operator initializer        { $$ = $1 == OperKinds::Assign ? $2 : $2->set_maybeConstructed( false ); }
    2435         | '=' VOID                                                                      { $$ = new InitializerNode( true ); }
     2367        | '=' initializer
     2368                { $$ = $2; }
     2369        | '=' VOID
     2370                { $$ = new InitializerNode( true ); }
     2371        | ATassign initializer
     2372                { $$ = $2->set_maybeConstructed( false ); }
    24362373        ;
    24372374
     
    26892626
    26902627external_definition:
    2691         DIRECTIVE
    2692                 { $$ = DeclarationNode::newDirectiveStmt( new StatementNode( build_directive( $1 ) ) ); }
    2693         | declaration
     2628        declaration
    26942629        | external_function_definition
    26952630        | EXTENSION external_definition                                         // GCC, multiple __extension__ allowed, meaning unknown
     
    26992634                }
    27002635        | ASM '(' string_literal ')' ';'                                        // GCC, global assembler statement
    2701                 { $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) ); }
     2636                {
     2637                        $$ = DeclarationNode::newAsmStmt( new StatementNode( build_asm( false, $3, 0 ) ) );
     2638                }
    27022639        | EXTERN STRINGliteral                                                          // C++-style linkage specifier
    27032640                {
     
    28452782        ;
    28462783
     2784attribute_opt:
     2785        // empty
     2786                { $$ = nullptr; }
     2787        | attribute
     2788        ;
     2789
    28472790attribute:                                                                                              // GCC
    28482791        ATTRIBUTE '(' '(' attribute_name_list ')' ')'
     
    29062849// declaring an array of functions versus a pointer to an array of functions.
    29072850
    2908 paren_identifier:
    2909         identifier
    2910                 { $$ = DeclarationNode::newName( $1 ); }
    2911         | '(' paren_identifier ')'                                                      // redundant parenthesis
    2912                 { $$ = $2; }
    2913         ;
    2914 
    29152851variable_declarator:
    29162852        paren_identifier attribute_list_opt
     
    29232859        ;
    29242860
     2861paren_identifier:
     2862        identifier
     2863                { $$ = DeclarationNode::newName( $1 ); }
     2864        | '(' paren_identifier ')'                                                      // redundant parenthesis
     2865                { $$ = $2; }
     2866        ;
     2867
    29252868variable_ptr:
    29262869        ptrref_operator variable_declarator
     
    29282871        | ptrref_operator type_qualifier_list variable_declarator
    29292872                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    2930         | '(' variable_ptr ')' attribute_list_opt                       // redundant parenthesis
    2931                 { $$ = $2->addQualifiers( $4 ); }
    2932         | '(' attribute_list variable_ptr ')' attribute_list_opt // redundant parenthesis
    2933                 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
     2873        | '(' variable_ptr ')' attribute_list_opt
     2874                { $$ = $2->addQualifiers( $4 ); }                               // redundant parenthesis
    29342875        ;
    29352876
     
    29392880        | '(' variable_ptr ')' array_dimension
    29402881                { $$ = $2->addArray( $4 ); }
    2941         | '(' attribute_list variable_ptr ')' array_dimension
    2942                 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    2943         | '(' variable_array ')' multi_array_dimension          // redundant parenthesis
     2882        | '(' variable_array ')' multi_array_dimension          // redundant parenthesis
    29442883                { $$ = $2->addArray( $4 ); }
    2945         | '(' attribute_list variable_array ')' multi_array_dimension // redundant parenthesis
    2946                 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    29472884        | '(' variable_array ')'                                                        // redundant parenthesis
    29482885                { $$ = $2; }
    2949         | '(' attribute_list variable_array ')'                         // redundant parenthesis
    2950                 { $$ = $3->addQualifiers( $2 ); }
    29512886        ;
    29522887
     
    29542889        '(' variable_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    29552890                { $$ = $2->addParamList( $6 ); }
    2956         | '(' attribute_list variable_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    2957                 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    29582891        | '(' variable_function ')'                                                     // redundant parenthesis
    29592892                { $$ = $2; }
    2960         | '(' attribute_list variable_function ')'                      // redundant parenthesis
    2961                 { $$ = $3->addQualifiers( $2 ); }
    29622893        ;
    29632894
     
    29792910        | '(' function_ptr ')' '(' push parameter_type_list_opt pop ')'
    29802911                { $$ = $2->addParamList( $6 ); }
    2981         | '(' attribute_list function_ptr ')' '(' push parameter_type_list_opt pop ')'
    2982                 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    29832912        | '(' function_no_ptr ')'                                                       // redundant parenthesis
    29842913                { $$ = $2; }
    2985         | '(' attribute_list function_no_ptr ')'                        // redundant parenthesis
    2986                 { $$ = $3->addQualifiers( $2 ); }
    29872914        ;
    29882915
     
    29922919        | ptrref_operator type_qualifier_list function_declarator
    29932920                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    2994         | '(' function_ptr ')' attribute_list_opt
    2995                 { $$ = $2->addQualifiers( $4 ); }
    2996         | '(' attribute_list function_ptr ')' attribute_list_opt
    2997                 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
     2921        | '(' function_ptr ')'
     2922                { $$ = $2; }
    29982923        ;
    29992924
     
    30012926        '(' function_ptr ')' array_dimension
    30022927                { $$ = $2->addArray( $4 ); }
    3003         | '(' attribute_list function_ptr ')' array_dimension
    3004                 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    30052928        | '(' function_array ')' multi_array_dimension          // redundant parenthesis
    30062929                { $$ = $2->addArray( $4 ); }
    3007         | '(' attribute_list function_array ')' multi_array_dimension // redundant parenthesis
    3008                 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    30092930        | '(' function_array ')'                                                        // redundant parenthesis
    30102931                { $$ = $2; }
    3011         | '(' attribute_list function_array ')'                         // redundant parenthesis
    3012                 { $$ = $3->addQualifiers( $2 ); }
    30132932        ;
    30142933
     
    30312950        | '(' KR_function_ptr ')' '(' push parameter_type_list_opt pop ')'
    30322951                { $$ = $2->addParamList( $6 ); }
    3033         | '(' attribute_list KR_function_ptr ')' '(' push parameter_type_list_opt pop ')'
    3034                 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    30352952        | '(' KR_function_no_ptr ')'                                            // redundant parenthesis
    30362953                { $$ = $2; }
    3037         | '(' attribute_list KR_function_no_ptr ')'                     // redundant parenthesis
    3038                 { $$ = $3->addQualifiers( $2 ); }
    30392954        ;
    30402955
     
    30462961        | '(' KR_function_ptr ')'
    30472962                { $$ = $2; }
    3048         | '(' attribute_list KR_function_ptr ')'
    3049                 { $$ = $3->addQualifiers( $2 ); }
    30502963        ;
    30512964
     
    30532966        '(' KR_function_ptr ')' array_dimension
    30542967                { $$ = $2->addArray( $4 ); }
    3055         | '(' attribute_list KR_function_ptr ')' array_dimension
    3056                 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    30572968        | '(' KR_function_array ')' multi_array_dimension       // redundant parenthesis
    30582969                { $$ = $2->addArray( $4 ); }
    3059         | '(' attribute_list KR_function_array ')' multi_array_dimension // redundant parenthesis
    3060                 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    30612970        | '(' KR_function_array ')'                                                     // redundant parenthesis
    30622971                { $$ = $2; }
    3063         | '(' attribute_list KR_function_array ')'                      // redundant parenthesis
    3064                 { $$ = $3->addQualifiers( $2 ); }
    30652972        ;
    30662973
     
    30742981// The pattern precludes declaring an array of functions versus a pointer to an array of functions, and returning arrays
    30752982// and functions versus pointers to arrays and functions.
    3076 
    3077 paren_type:
    3078         typedef_name
    3079                 {
    3080                         // hide type name in enclosing scope by variable name
    3081                         typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "ID" );
    3082                 }
    3083         | '(' paren_type ')'
    3084                 { $$ = $2; }
    3085         ;
    30862983
    30872984variable_type_redeclarator:
     
    30952992        ;
    30962993
     2994paren_type:
     2995        typedef
     2996                // hide type name in enclosing scope by variable name
     2997                {
     2998                        // if ( ! typedefTable.existsCurr( *$1->name ) ) {
     2999                                typedefTable.addToEnclosingScope( *$1->name, IDENTIFIER, "ID" );
     3000                        // } else {
     3001                        //      SemanticError( yylloc, string("'") + *$1->name + "' redeclared as different kind of symbol." ); $$ = nullptr;
     3002                        // } // if
     3003                }
     3004        | '(' paren_type ')'
     3005                { $$ = $2; }
     3006        ;
     3007
    30973008type_ptr:
    30983009        ptrref_operator variable_type_redeclarator
     
    31003011        | ptrref_operator type_qualifier_list variable_type_redeclarator
    31013012                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3102         | '(' type_ptr ')' attribute_list_opt                           // redundant parenthesis
    3103                 { $$ = $2->addQualifiers( $4 ); }
    3104         | '(' attribute_list type_ptr ')' attribute_list_opt // redundant parenthesis
    3105                 { $$ = $3->addQualifiers( $2 )->addQualifiers( $5 ); }
     3013        | '(' type_ptr ')' attribute_list_opt
     3014                { $$ = $2->addQualifiers( $4 ); }                               // redundant parenthesis
    31063015        ;
    31073016
     
    31113020        | '(' type_ptr ')' array_dimension
    31123021                { $$ = $2->addArray( $4 ); }
    3113         | '(' attribute_list type_ptr ')' array_dimension
    3114                 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    31153022        | '(' type_array ')' multi_array_dimension                      // redundant parenthesis
    31163023                { $$ = $2->addArray( $4 ); }
    3117         | '(' attribute_list type_array ')' multi_array_dimension // redundant parenthesis
    3118                 { $$ = $3->addQualifiers( $2 )->addArray( $5 ); }
    31193024        | '(' type_array ')'                                                            // redundant parenthesis
    31203025                { $$ = $2; }
    3121         | '(' attribute_list type_array ')'                                     // redundant parenthesis
    3122                 { $$ = $3->addQualifiers( $2 ); }
    31233026        ;
    31243027
     
    31283031        | '(' type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    31293032                { $$ = $2->addParamList( $6 ); }
    3130         | '(' attribute_list type_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
    3131                 { $$ = $3->addQualifiers( $2 )->addParamList( $7 ); }
    31323033        | '(' type_function ')'                                                         // redundant parenthesis
    31333034                { $$ = $2; }
    3134         | '(' attribute_list type_function ')'                          // redundant parenthesis
    3135                 { $$ = $3->addQualifiers( $2 ); }
    31363035        ;
    31373036
     
    31583057        | ptrref_operator type_qualifier_list identifier_parameter_declarator
    31593058                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3160         | '(' identifier_parameter_ptr ')' attribute_list_opt // redundant parenthesis
     3059        | '(' identifier_parameter_ptr ')' attribute_list_opt
    31613060                { $$ = $2->addQualifiers( $4 ); }
    31623061        ;
     
    31923091
    31933092type_parameter_redeclarator:
    3194         typedef_name attribute_list_opt
     3093        typedef attribute_list_opt
    31953094                { $$ = $1->addQualifiers( $2 ); }
    3196         | '&' MUTEX typedef_name attribute_list_opt
     3095        | '&' MUTEX typedef attribute_list_opt
    31973096                { $$ = $3->addPointer( DeclarationNode::newPointer( DeclarationNode::newTypeQualifier( Type::Mutex ), OperKinds::AddressOf ) )->addQualifiers( $4 ); }
    31983097        | type_parameter_ptr
     
    32033102        ;
    32043103
    3205 typedef_name:
     3104typedef:
    32063105        TYPEDEFname
    32073106                { $$ = DeclarationNode::newName( $1 ); }
     
    32153114        | ptrref_operator type_qualifier_list type_parameter_redeclarator
    32163115                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3217         | '(' type_parameter_ptr ')' attribute_list_opt         // redundant parenthesis
     3116        | '(' type_parameter_ptr ')' attribute_list_opt
    32183117                { $$ = $2->addQualifiers( $4 ); }
    32193118        ;
    32203119
    32213120type_parameter_array:
    3222         typedef_name array_parameter_dimension
     3121        typedef array_parameter_dimension
    32233122                { $$ = $1->addArray( $2 ); }
    32243123        | '(' type_parameter_ptr ')' array_parameter_dimension
     
    32273126
    32283127type_parameter_function:
    3229         typedef_name '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     3128        typedef '(' push parameter_type_list_opt pop ')'        // empty parameter list OBSOLESCENT (see 3)
    32303129                { $$ = $1->addParamList( $4 ); }
    32313130        | '(' type_parameter_ptr ')' '(' push parameter_type_list_opt pop ')' // empty parameter list OBSOLESCENT (see 3)
     
    33563255        | ptrref_operator type_qualifier_list abstract_parameter_declarator
    33573256                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3358         | '(' abstract_parameter_ptr ')' attribute_list_opt     // redundant parenthesis
     3257        | '(' abstract_parameter_ptr ')' attribute_list_opt
    33593258                { $$ = $2->addQualifiers( $4 ); }
    33603259        ;
     
    34353334        | ptrref_operator type_qualifier_list variable_abstract_declarator
    34363335                { $$ = $3->addPointer( DeclarationNode::newPointer( $2, $1 ) ); }
    3437         | '(' variable_abstract_ptr ')' attribute_list_opt      // redundant parenthesis
     3336        | '(' variable_abstract_ptr ')' attribute_list_opt
    34383337                { $$ = $2->addQualifiers( $4 ); }
    34393338        ;
  • src/ResolvExpr/CurrentObject.cc

    r5407cdc rfeacef9  
    925925                if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) {
    926926                        if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) {
    927                                 assert( sit->base );
    928927                                return new StructIterator{ loc, sit };
    929928                        } else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) {
    930                                 assert( uit->base );
    931929                                return new UnionIterator{ loc, uit };
    932930                        } else {
  • src/SynTree/Constant.cc

    r5407cdc rfeacef9  
    4242}
    4343
    44 Constant Constant::from_string( const std::string & str ) {
    45         Type * charType = new BasicType( noQualifiers, BasicType::Char );
    46         // Adjust the length of the string for the terminator.
    47         Expression * strSize = new ConstantExpr( Constant::from_ulong( str.size() + 1 ) );
    48         Type * strType = new ArrayType( noQualifiers, charType, strSize, false, false );
    49         const std::string strValue = "\"" + str + "\"";
    50         return Constant( strType, strValue, std::nullopt );
    51 }
    52 
    5344Constant Constant::null( Type * ptrtype ) {
    5445        if ( nullptr == ptrtype ) {
  • src/SynTree/Constant.h

    r5407cdc rfeacef9  
    4747        /// generates an integer constant of the given unsigned long int
    4848        static Constant from_ulong( unsigned long i );
    49         /// generates a string constant from the given string (char type, unquoted string)
    50         static Constant from_string( const std::string & string );
    5149
    5250        /// generates a null pointer value for the given type. void * if omitted.
  • src/SynTree/Declaration.cc

    r5407cdc rfeacef9  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:35:39 2021
    13 // Update Count     : 37
     12// Last Modified On : Wed Dec 11 16:39:56 2019
     13// Update Count     : 36
    1414//
    1515
     
    6666
    6767
    68 DirectiveDecl::DirectiveDecl( DirectiveStmt *stmt ) : Declaration( "", Type::StorageClasses(), LinkageSpec::C ), stmt( stmt ) {
    69 }
    70 
    71 DirectiveDecl::DirectiveDecl( const DirectiveDecl &other ) : Declaration( other ), stmt( maybeClone( other.stmt ) ) {
    72 }
    73 
    74 DirectiveDecl::~DirectiveDecl() {
    75         delete stmt;
    76 }
    77 
    78 void DirectiveDecl::print( std::ostream &os, Indenter indent ) const {
    79         stmt->print( os, indent );
    80 }
    81 
    82 void DirectiveDecl::printShort( std::ostream &os, Indenter indent ) const {
    83         stmt->print( os, indent );
    84 }
    85 
    86 
    8768StaticAssertDecl::StaticAssertDecl( Expression * condition, ConstantExpr * message ) : Declaration( "", Type::StorageClasses(), LinkageSpec::C ), condition( condition ), message( message )  {
    8869}
  • src/SynTree/Declaration.h

    r5407cdc rfeacef9  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:35:36 2021
    13 // Update Count     : 159
     12// Last Modified On : Mon Jan 11 20:48:39 2021
     13// Update Count     : 158
    1414//
    1515
     
    400400};
    401401
    402 class DirectiveDecl : public Declaration {
    403   public:
    404         DirectiveStmt * stmt;
    405 
    406         DirectiveDecl( DirectiveStmt * stmt );
    407         DirectiveDecl( const DirectiveDecl & other );
    408         virtual ~DirectiveDecl();
    409 
    410         DirectiveStmt * get_stmt() { return stmt; }
    411         void set_stmt( DirectiveStmt * newValue ) { stmt = newValue; }
    412 
    413         virtual DirectiveDecl * clone() const override { return new DirectiveDecl( *this ); }
    414         virtual void accept( Visitor & v ) override { v.visit( this ); }
    415         virtual void accept( Visitor & v ) const override { v.visit( this ); }
    416         virtual DirectiveDecl * acceptMutator( Mutator & m )  override { return m.mutate( this ); }
    417         virtual void print( std::ostream & os, Indenter indent = {} ) const override;
    418         virtual void printShort( std::ostream & os, Indenter indent = {} ) const override;
    419 };
    420 
    421402class StaticAssertDecl : public Declaration {
    422403public:
  • src/SynTree/Mutator.h

    r5407cdc rfeacef9  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:35:36 2021
    13 // Update Count     : 18
     12// Last Modified On : Thu Jul 25 22:37:46 2019
     13// Update Count     : 17
    1414//
    1515#pragma once
     
    3434        virtual Declaration * mutate( TypedefDecl * typeDecl ) = 0;
    3535        virtual AsmDecl * mutate( AsmDecl * asmDecl ) = 0;
    36         virtual DirectiveDecl * mutate( DirectiveDecl * directiveDecl ) = 0;
    3736        virtual StaticAssertDecl * mutate( StaticAssertDecl * assertDecl ) = 0;
    3837
  • src/SynTree/SynTree.h

    r5407cdc rfeacef9  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:56:44 2021
    13 // Update Count     : 13
     12// Last Modified On : Thu Jul 25 22:37:45 2019
     13// Update Count     : 12
    1414//
    1515
     
    3636class TypedefDecl;
    3737class AsmDecl;
    38 class DirectiveDecl;
    3938class StaticAssertDecl;
    4039
  • src/SynTree/Visitor.h

    r5407cdc rfeacef9  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Mar 12 18:35:35 2021
    13 // Update Count     : 15
     12// Last Modified On : Thu Jul 25 22:21:49 2019
     13// Update Count     : 14
    1414//
    1515
     
    4545        virtual void visit( AsmDecl * node ) { visit( const_cast<const AsmDecl *>(node) ); }
    4646        virtual void visit( const AsmDecl * asmDecl ) = 0;
    47         virtual void visit( DirectiveDecl * node ) { visit( const_cast<const DirectiveDecl *>(node) ); }
    48         virtual void visit( const DirectiveDecl * directiveDecl ) = 0;
    4947        virtual void visit( StaticAssertDecl * node ) { visit( const_cast<const StaticAssertDecl *>(node) ); }
    5048        virtual void visit( const StaticAssertDecl * assertDecl ) = 0;
  • src/Virtual/ExpandCasts.cc

    r5407cdc rfeacef9  
    3232namespace Virtual {
    3333
    34 static bool is_prefix( const std::string & prefix, const std::string& entire ) {
    35         size_t const p_size = prefix.size();
    36         return (p_size < entire.size() && prefix == entire.substr(0, p_size));
    37 }
    38 
    39 static bool is_type_id_object( const ObjectDecl * objectDecl ) {
    40         const std::string & objectName = objectDecl->name;
    41         return is_prefix( "__cfatid_", objectName );
    42 }
    43 
    4434        // Indented until the new ast code gets added.
    4535
     
    7666        };
    7767
     68        /* Currently virtual depends on the rather brittle name matching between
     69         * a (strict/explicate) virtual type, its vtable type and the vtable
     70         * instance.
     71         * A stronger implementation, would probably keep track of those triads
     72         * and use that information to create better error messages.
     73         */
     74
     75        namespace {
     76
     77        std::string get_vtable_name( std::string const & name ) {
     78                return name + "_vtable";
     79        }
     80
     81        std::string get_vtable_inst_name( std::string const & name ) {
     82                return std::string("_") + get_vtable_name( name ) + "_instance";
     83        }
     84
     85        std::string get_vtable_name_root( std::string const & name ) {
     86                return name.substr(0, name.size() - 7 );
     87        }
     88
     89        std::string get_vtable_inst_name_root( std::string const & name ) {
     90                return get_vtable_name_root( name.substr(1, name.size() - 10 ) );
     91        }
     92
     93        bool is_vtable_inst_name( std::string const & name ) {
     94                return 17 < name.size() &&
     95                        name == get_vtable_inst_name( get_vtable_inst_name_root( name ) );
     96        }
     97
     98        } // namespace
     99
    78100        class VirtualCastCore {
    79                 CastExpr * cast_to_type_id( Expression * expr, int level_of_indirection ) {
     101                Type * pointer_to_pvt(int level_of_indirection) {
    80102                        Type * type = new StructInstType(
    81103                                Type::Qualifiers( Type::Const ), pvt_decl );
     
    83105                                type = new PointerType( noQualifiers, type );
    84106                        }
    85                         return new CastExpr( expr, type );
     107                        return type;
    86108                }
    87109
     
    119141
    120142        void VirtualCastCore::premutate( ObjectDecl * objectDecl ) {
    121                 if ( is_type_id_object( objectDecl ) ) {
    122                         // Multiple definitions should be fine because of linkonce.
    123                         indexer.insert( objectDecl );
     143                if ( is_vtable_inst_name( objectDecl->get_name() ) ) {
     144                        if ( ObjectDecl * existing = indexer.insert( objectDecl ) ) {
     145                                std::string msg = "Repeated instance of virtual table, original found at: ";
     146                                msg += existing->location.filename;
     147                                msg += ":" + toString( existing->location.first_line );
     148                                SemanticError( objectDecl->location, msg );
     149                        }
    124150                }
    125151        }
     
    144170        }
    145171
    146         /// Get the base type from a pointer or reference.
    147         const Type * getBaseType( const Type * type ) {
    148                 if ( auto target = dynamic_cast<const PointerType *>( type ) ) {
    149                         return target->base;
    150                 } else if ( auto target = dynamic_cast<const ReferenceType *>( type ) ) {
    151                         return target->base;
     172        /// Get the virtual table type used in a virtual cast.
     173        Type * getVirtualTableType( const VirtualCastExpr * castExpr ) {
     174                const Type * objectType;
     175                if ( auto target = dynamic_cast<const PointerType *>( castExpr->result ) ) {
     176                        objectType = target->base;
     177                } else if ( auto target = dynamic_cast<const ReferenceType *>( castExpr->result ) ) {
     178                        objectType = target->base;
    152179                } else {
    153                         return nullptr;
    154                 }
    155         }
    156 
    157         /* Attempt to follow the "head" field of the structure to get the...
    158          * Returns nullptr on error, otherwise owner must free returned node.
    159          */
    160         StructInstType * followHeadPointerType(
    161                         const StructInstType * oldType,
    162                         const std::string& fieldName,
    163                         const CodeLocation& errorLocation ) {
    164 
    165                 // First section of the function is all about trying to fill this variable in.
    166                 StructInstType * newType = nullptr;
    167                 {
    168                         const StructDecl * oldDecl = oldType->baseStruct;
    169                         assert( oldDecl );
    170 
    171                         // Helper function for throwing semantic errors.
    172                         auto throwError = [&fieldName, &errorLocation, &oldDecl](const std::string& message) {
    173                                 const std::string& context = "While following head pointer of " +
    174                                         oldDecl->name + " named '" + fieldName + "': ";
    175                                 SemanticError( errorLocation, context + message );
    176                         };
    177 
    178                         if ( oldDecl->members.empty() ) {
    179                                 throwError( "Type has no fields." );
    180                         }
    181                         const Declaration * memberDecl = oldDecl->members.front();
     180                        castError( castExpr, "Virtual cast type must be a pointer or reference type." );
     181                }
     182                assert( objectType );
     183
     184                const StructInstType * structType = dynamic_cast<const StructInstType *>( objectType );
     185                if ( nullptr == structType ) {
     186                        castError( castExpr, "Virtual cast type must refer to a structure type." );
     187                }
     188                const StructDecl * structDecl = structType->baseStruct;
     189                assert( structDecl );
     190
     191                const ObjectDecl * fieldDecl = nullptr;
     192                if ( 0 < structDecl->members.size() ) {
     193                        const Declaration * memberDecl = structDecl->members.front();
    182194                        assert( memberDecl );
    183                         const ObjectDecl * fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
    184                         assert( fieldDecl );
    185                         if ( fieldName != fieldDecl->name ) {
    186                                 throwError( "Head field did not have expected name." );
    187                         }
    188 
    189                         const Type * fieldType = fieldDecl->type;
    190                         if ( nullptr == fieldType ) {
    191                                 throwError( "Could not get head field." );
    192                         }
    193                         const PointerType * ptrType = dynamic_cast<const PointerType *>( fieldType );
    194                         if ( nullptr == ptrType ) {
    195                                 throwError( "First field is not a pointer type." );
    196                         }
    197                         assert( ptrType->base );
    198                         newType = dynamic_cast<StructInstType *>( ptrType->base );
    199                         if ( nullptr == newType ) {
    200                                 throwError( "First field does not point to a structure type." );
    201                         }
    202                 }
    203 
    204                 // Now we can look into copying it.
    205                 newType = newType->clone();
    206                 if ( ! oldType->parameters.empty() ) {
    207                         deleteAll( newType->parameters );
    208                         newType->parameters.clear();
    209                         cloneAll( oldType->parameters, newType->parameters );
    210                 }
    211                 return newType;
    212         }
    213 
    214         /// Get the type-id type from a virtual type.
    215         StructInstType * getTypeIdType( const Type * type, const CodeLocation& errorLocation ) {
    216                 const StructInstType * typeInst = dynamic_cast<const StructInstType *>( type );
    217                 if ( nullptr == typeInst ) {
    218                         return nullptr;
    219                 }
    220                 StructInstType * tableInst =
    221                         followHeadPointerType( typeInst, "virtual_table", errorLocation );
    222                 if ( nullptr == tableInst ) {
    223                         return nullptr;
    224                 }
    225                 StructInstType * typeIdInst =
    226                         followHeadPointerType( tableInst, "__cfavir_typeid", errorLocation );
    227                 delete tableInst;
    228                 return typeIdInst;
     195                        fieldDecl = dynamic_cast<const ObjectDecl *>( memberDecl );
     196                        if ( fieldDecl && fieldDecl->name != "virtual_table" ) {
     197                                fieldDecl = nullptr;
     198                        }
     199                }
     200                if ( nullptr == fieldDecl ) {
     201                        castError( castExpr, "Virtual cast type must have a leading virtual_table field." );
     202                }
     203                const PointerType * fieldType = dynamic_cast<const PointerType *>( fieldDecl->type );
     204                if ( nullptr == fieldType ) {
     205                        castError( castExpr, "Virtual cast type virtual_table field is not a pointer." );
     206                }
     207                assert( fieldType->base );
     208                auto virtualStructType = dynamic_cast<const StructInstType *>( fieldType->base );
     209                assert( virtualStructType );
     210
     211                // Here is the type, but if it is polymorphic it will have lost information.
     212                // (Always a clone so that it may always be deleted.)
     213                StructInstType * virtualType = virtualStructType->clone();
     214                if ( ! structType->parameters.empty() ) {
     215                        deleteAll( virtualType->parameters );
     216                        virtualType->parameters.clear();
     217                        cloneAll( structType->parameters, virtualType->parameters );
     218                }
     219                return virtualType;
    229220        }
    230221
     
    237228                assert( pvt_decl );
    238229
    239                 const Type * base_type = getBaseType( castExpr->result );
    240                 if ( nullptr == base_type ) {
    241                         castError( castExpr, "Virtual cast target must be a pointer or reference type." );
    242                 }
    243                 const Type * type_id_type = getTypeIdType( base_type, castLocation( castExpr ) );
    244                 if ( nullptr == type_id_type ) {
    245                         castError( castExpr, "Ill formed virtual cast target type." );
    246                 }
    247                 ObjectDecl * type_id = indexer.lookup( type_id_type );
    248                 delete type_id_type;
    249                 if ( nullptr == type_id ) {
    250                         castError( castExpr, "Virtual cast does not target a virtual type." );
     230                const Type * vtable_type = getVirtualTableType( castExpr );
     231                ObjectDecl * table = indexer.lookup( vtable_type );
     232                if ( nullptr == table ) {
     233                        SemanticError( castLocation( castExpr ),
     234                                "Could not find virtual table instance." );
    251235                }
    252236
    253237                Expression * result = new CastExpr(
    254238                        new ApplicationExpr( VariableExpr::functionPointer( vcast_decl ), {
    255                                 cast_to_type_id( new AddressExpr( new VariableExpr( type_id ) ), 1 ),
    256                                 cast_to_type_id( castExpr->get_arg(), 2 ),
     239                                        new CastExpr(
     240                                                new AddressExpr( new VariableExpr( table ) ),
     241                                                pointer_to_pvt(1)
     242                                        ),
     243                                        new CastExpr(
     244                                                castExpr->get_arg(),
     245                                                pointer_to_pvt(2)
     246                                        )
    257247                        } ),
    258248                        castExpr->get_result()->clone()
     
    262252                castExpr->set_result( nullptr );
    263253                delete castExpr;
     254                delete vtable_type;
    264255                return result;
    265256        }
  • src/Virtual/Tables.cc

    r5407cdc rfeacef9  
    1010// Created On       : Mon Aug 31 11:11:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr 21 15:36:00 2021
    13 // Update Count     : 2
     12// Last Modified On : Tue Sep  3 14:56:00 2020
     13// Update Count     : 0
    1414//
    1515
     
    2222namespace Virtual {
    2323
    24 std::string typeIdType( std::string const & type_name ) {
    25         return "__cfatid_struct_" + type_name;
    26 }
    27 
    28 std::string typeIdName( std::string const & type_name ) {
    29         return "__cfatid_" + type_name;
    30 }
    31 
    32 static std::string typeIdTypeToInstance( std::string const & type_name ) {
    33         return typeIdName(type_name.substr(16));
    34 }
    35 
    3624std::string vtableTypeName( std::string const & name ) {
    3725        return name + "_vtable";
    38 }
    39 
    40 std::string baseTypeName( std::string const & vtable_type_name ) {
    41         return vtable_type_name.substr(0, vtable_type_name.size() - 7);
    4226}
    4327
     
    5034}
    5135
    52 std::string concurrentDefaultVTableName() {
    53         return "_default_vtable";
    54 }
    55 
    5636bool isVTableInstanceName( std::string const & name ) {
    5737        // There are some delicate length calculations here.
     
    6141
    6242static ObjectDecl * makeVtableDeclaration(
    63                 std::string const & name,
    6443                StructInstType * type, Initializer * init ) {
     44        std::string const & name = instanceName( type->name );
    6545        Type::StorageClasses storage = noStorageClasses;
    6646        if ( nullptr == init ) {
     
    7757}
    7858
    79 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {
     59ObjectDecl * makeVtableForward( StructInstType * type ) {
    8060        assert( type );
    81         return makeVtableDeclaration( name, type, nullptr );
     61        return makeVtableDeclaration( type, nullptr );
    8262}
    8363
    8464ObjectDecl * makeVtableInstance(
    85                 std::string const & name, StructInstType * vtableType,
    86                 Type * objectType, Initializer * init ) {
     65                StructInstType * vtableType, Type * objectType, Initializer * init ) {
    8766        assert( vtableType );
    8867        assert( objectType );
     
    10281                                inits.push_back(
    10382                                                new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );
    104                         } else if ( std::string( "__cfavir_typeid" ) == field->name ) {
    105                                 std::string const & baseType = baseTypeName( vtableType->name );
    106                                 std::string const & typeId = typeIdName( baseType );
    107                                 inits.push_back( new SingleInit( new AddressExpr( new NameExpr( typeId ) ) ) );
    10883                        } else if ( std::string( "size" ) == field->name ) {
    10984                                inits.push_back( new SingleInit( new SizeofExpr( objectType->clone() ) ) );
     
    12095                assert(false);
    12196        }
    122         return makeVtableDeclaration( name, vtableType, init );
     97        return makeVtableDeclaration( vtableType, init );
    12398}
    12499
     
    172147}
    173148
    174 Attribute * linkonce( const std::string & subsection ) {
    175         const std::string section = ".gnu.linkonce." + subsection;
    176         return new Attribute( "section", {
    177                 new ConstantExpr( Constant::from_string( section ) ),
    178         } );
    179149}
    180 
    181 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
    182         assert( typeIdType );
    183         StructInstType * type = typeIdType->clone();
    184         type->tq.is_const = true;
    185         std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );
    186         return new ObjectDecl(
    187                 typeid_name,
    188                 noStorageClasses,
    189                 LinkageSpec::Cforall,
    190                 /* bitfieldWidth */ nullptr,
    191                 type,
    192                 new ListInit( { new SingleInit(
    193                         new AddressExpr( new NameExpr( "__cfatid_exception_t" ) )
    194                         ) } ),
    195                 { linkonce( typeid_name ) },
    196                 noFuncSpecifiers
    197         );
    198 }
    199 
    200 }
  • src/Virtual/Tables.h

    r5407cdc rfeacef9  
    1010// Created On       : Mon Aug 31 11:07:00 2020
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr 21 10:30:00 2021
    13 // Update Count     : 2
     12// Last Modified On : Tue Sep  1 14:29:00 2020
     13// Update Count     : 0
    1414//
    1515
     
    2222namespace Virtual {
    2323
    24 std::string typeIdType( std::string const & type_name );
    25 std::string typeIdName( std::string const & type_name );
    2624std::string vtableTypeName( std::string const & type_name );
    2725std::string instanceName( std::string const & vtable_name );
    2826std::string vtableInstanceName( std::string const & type_name );
    29 std::string concurrentDefaultVTableName();
    3027bool isVTableInstanceName( std::string const & name );
    3128
    32 ObjectDecl * makeVtableForward(
    33         std::string const & name, StructInstType * vtableType );
     29ObjectDecl * makeVtableForward( StructInstType * vtableType );
    3430/* Create a forward declaration of a vtable of the given type.
    3531 * vtableType node is consumed.
    3632 */
    3733
    38 ObjectDecl * makeVtableInstance(
    39         std::string const & name,
    40         StructInstType * vtableType, Type * objectType,
     34ObjectDecl * makeVtableInstance( StructInstType * vtableType, Type * objectType,
    4135        Initializer * init = nullptr );
    4236/* Create an initialized definition of a vtable.
     
    5650 */
    5751
    58 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
    59 /* Build an instance of the type-id from the type of the type-id.
    60  * TODO: Should take the parent type. Currently locked to the exception_t.
    61  */
    62 
    6352}
  • src/main.cc

    r5407cdc rfeacef9  
    1010// Created On       : Fri May 15 23:12:02 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Mar  6 15:49:00 2021
    13 // Update Count     : 656
     12// Last Modified On : Mon Feb  8 21:10:16 2021
     13// Update Count     : 642
    1414//
    1515
     
    101101static string PreludeDirector = "";
    102102
    103 static void parse_cmdline( int argc, char * argv[] );
     103static void parse_cmdline( int argc, char *argv[] );
    104104static void parse( FILE * input, LinkageSpec::Spec linkage, bool shouldExit = false );
    105105static void dump( list< Declaration * > & translationUnit, ostream & out = cout );
    106 static void dump( ast::TranslationUnit && transUnit, ostream & out = cout );
    107106
    108107static void backtrace( int start ) {                                    // skip first N stack frames
     
    159158#define SIGPARMS int sig __attribute__(( unused )), siginfo_t * sfp __attribute__(( unused )), ucontext_t * cxt __attribute__(( unused ))
    160159
    161 static void Signal( int sig, void (* handler)(SIGPARMS), int flags ) {
     160static void Signal( int sig, void (*handler)(SIGPARMS), int flags ) {
    162161        struct sigaction act;
    163162
     
    166165
    167166        if ( sigaction( sig, &act, nullptr ) == -1 ) {
    168             cerr << "*cfa-cpp compilation error* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl;
     167            cerr << "*CFA runtime error* problem installing signal handler, error(" << errno << ") " << strerror( errno ) << endl;
    169168            _exit( EXIT_FAILURE );
    170169        } // if
     
    350349                        PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    351350                        if ( exprp ) {
    352                                 dump( move( transUnit ) );
     351                                translationUnit = convert( move( transUnit ) );
     352                                dump( translationUnit );
    353353                                return EXIT_SUCCESS;
    354354                        } // if
     
    421421                        delete output;
    422422                } // if
    423         } catch ( SemanticErrorException & e ) {
     423        } catch ( SemanticErrorException &e ) {
    424424                if ( errorp ) {
    425425                        cerr << "---AST at error:---" << endl;
     
    432432                } // if
    433433                return EXIT_FAILURE;
    434         } catch ( UnimplementedError & e ) {
     434        } catch ( UnimplementedError &e ) {
    435435                cout << "Sorry, " << e.get_what() << " is not currently implemented" << endl;
    436436                if ( output != &cout ) {
     
    438438                } // if
    439439                return EXIT_FAILURE;
    440         } catch ( CompilerError & e ) {
     440        } catch ( CompilerError &e ) {
    441441                cerr << "Compiler Error: " << e.get_what() << endl;
    442442                cerr << "(please report bugs to [REDACTED])" << endl;
     
    445445                } // if
    446446                return EXIT_FAILURE;
    447         } catch ( std::bad_alloc & ) {
    448                 cerr << "*cfa-cpp compilation error* std::bad_alloc" << endl;
    449                 backtrace( 1 );
    450                 abort();
    451447        } catch ( ... ) {
    452448                exception_ptr eptr = current_exception();
     
    455451                                rethrow_exception(eptr);
    456452                        } else {
    457                                 cerr << "*cfa-cpp compilation error* exception uncaught and unknown" << endl;
    458                         } // if
    459                 } catch( const exception & e ) {
    460                         cerr << "*cfa-cpp compilation error* uncaught exception \"" << e.what() << "\"\n";
     453                                cerr << "Exception Uncaught and Unknown" << endl;
     454                        } // if
     455                } catch(const exception& e) {
     456                        cerr << "Uncaught Exception \"" << e.what() << "\"\n";
    461457                } // try
    462458                return EXIT_FAILURE;
     
    548544enum { printoptsSize = sizeof( printopts ) / sizeof( printopts[0] ) };
    549545
    550 static void usage( char * argv[] ) {
     546static void usage( char *argv[] ) {
    551547    cout << "Usage: " << argv[0] << " [options] [input-file (default stdin)] [output-file (default stdout)], where options are:" << endl;
    552548        int i = 0, j = 1;                                                                       // j skips starting colon
     
    736732} // dump
    737733
    738 static void dump( ast::TranslationUnit && transUnit, ostream & out ) {
    739         std::list< Declaration * > translationUnit = convert( move( transUnit ) );
    740         dump( translationUnit, out );
    741 }
    742 
    743734// Local Variables: //
    744735// tab-width: 4 //
  • tests/.expect/KRfunctions.nast.arm64.txt

    r5407cdc rfeacef9  
    104104    signed int _X1bi_2;
    105105    {
    106         signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1);
    107         ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     106        signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1);
     107        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
    108108    }
    109109
  • tests/.expect/KRfunctions.nast.x64.txt

    r5407cdc rfeacef9  
    104104    signed int _X1bi_2;
    105105    {
    106         signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1);
    107         ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     106        signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1);
     107        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
    108108    }
    109109
  • tests/.expect/KRfunctions.nast.x86.txt

    r5407cdc rfeacef9  
    104104    signed int _X1bi_2;
    105105    {
    106         signed int *(*_tmp_cp_ret6)(signed int __param_0, signed int __param_1);
    107         ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     106        signed int *(*_tmp_cp_ret4)(signed int __param_0, signed int __param_1);
     107        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
    108108    }
    109109
  • tests/.expect/KRfunctions.oast.x64.txt

    r5407cdc rfeacef9  
    104104    signed int _X1bi_2;
    105105    {
    106         signed int *(*_tmp_cp_ret6)(signed int _X1xi_1, signed int _X1yi_1);
    107         ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret6=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret6)));
     106        signed int *(*_tmp_cp_ret4)(signed int _X1xi_1, signed int _X1yi_1);
     107        ((void)(_X1xFPi_ii__2=(((void)(_tmp_cp_ret4=_X3f10FFPi_ii__iPiPid__1(3, (&_X1ai_2), (&_X1bi_2), 3.5))) , _tmp_cp_ret4)));
    108108    }
    109109
  • tests/.expect/attributes.nast.arm64.txt

    r5407cdc rfeacef9  
    66
    77}
    8 struct __anonymous0 {
     8struct __attribute__ ((unused)) __anonymous0 {
    99};
    1010static inline void _X12_constructorFv_S12__anonymous0_autogen___1(struct __anonymous0 *_X4_dstS12__anonymous0_1);
     
    2626    return _X4_retS12__anonymous0_1;
    2727}
    28 __attribute__ ((unused)) struct __anonymous0 _X5DummyS12__anonymous0_1;
    2928struct __attribute__ ((unused)) Agn1;
    3029struct __attribute__ ((unused)) Agn2 {
     
    104103    __attribute__ ((used,unused,unused)) signed int _X2f7i_1;
    105104    __attribute__ ((used,used,unused)) signed int _X2f8i_1;
    106     __attribute__ ((unused)) signed int *_X2f9Pi_1;
    107     __attribute__ ((unused,used)) signed int *_X3f10Pi_1;
    108     __attribute__ ((unused,unused)) signed int *_X3f11Pi_1;
    109     __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1;
    110     __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1;
    111     __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1;
     105    __attribute__ ((unused,unused)) signed int *_X2f9Pi_1;
    112106};
    113107static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1);
     
    123117static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1);
    124118static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1);
    125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1);
    126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1);
    127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1);
    128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1);
    129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1);
    130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1);
     119static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1);
    131120static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    132121    {
     
    166155    }
    167156
    168     {
    169         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    170     }
    171 
    172     {
    173         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    174     }
    175 
    176     {
    177         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    178     }
    179 
    180     {
    181         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    182     }
    183 
    184     {
    185         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    186     }
    187 
    188157}
    189158static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){
     
    224193    }
    225194
    226     {
    227         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);
    228     }
    229 
    230     {
    231         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);
    232     }
    233 
    234     {
    235         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);
    236     }
    237 
    238     {
    239         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);
    240     }
    241 
    242     {
    243         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);
    244     }
    245 
    246195}
    247196static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    248     {
    249         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);
    250     }
    251 
    252     {
    253         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);
    254     }
    255 
    256     {
    257         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);
    258     }
    259 
    260     {
    261         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);
    262     }
    263 
    264     {
    265         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);
    266     }
    267 
    268197    {
    269198        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */);
     
    342271
    343272    {
    344         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));
    345     }
    346 
    347     {
    348         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));
    349     }
    350 
    351     {
    352         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));
    353     }
    354 
    355     {
    356         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));
    357     }
    358 
    359     {
    360         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));
    361     }
    362 
    363     {
    364273        ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1)));
    365274    }
     
    404313    }
    405314
    406     {
    407         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    408     }
    409 
    410     {
    411         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    412     }
    413 
    414     {
    415         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    416     }
    417 
    418     {
    419         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    420     }
    421 
    422     {
    423         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    424     }
    425 
    426315}
    427316static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){
     
    462351    }
    463352
    464     {
    465         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    466     }
    467 
    468     {
    469         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    470     }
    471 
    472     {
    473         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    474     }
    475 
    476     {
    477         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    478     }
    479 
    480     {
    481         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    482     }
    483 
    484353}
    485354static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){
     
    520389    }
    521390
    522     {
    523         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    524     }
    525 
    526     {
    527         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    528     }
    529 
    530     {
    531         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    532     }
    533 
    534     {
    535         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    536     }
    537 
    538     {
    539         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    540     }
    541 
    542391}
    543392static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){
     
    578427    }
    579428
    580     {
    581         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    582     }
    583 
    584     {
    585         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    586     }
    587 
    588     {
    589         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    590     }
    591 
    592     {
    593         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    594     }
    595 
    596     {
    597         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    598     }
    599 
    600429}
    601430static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){
     
    636465    }
    637466
    638     {
    639         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    640     }
    641 
    642     {
    643         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    644     }
    645 
    646     {
    647         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    648     }
    649 
    650     {
    651         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    652     }
    653 
    654     {
    655         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    656     }
    657 
    658467}
    659468static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){
     
    694503    }
    695504
    696     {
    697         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    698     }
    699 
    700     {
    701         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    702     }
    703 
    704     {
    705         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    706     }
    707 
    708     {
    709         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    710     }
    711 
    712     {
    713         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    714     }
    715 
    716505}
    717506static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){
     
    752541    }
    753542
    754     {
    755         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    756     }
    757 
    758     {
    759         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    760     }
    761 
    762     {
    763         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    764     }
    765 
    766     {
    767         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    768     }
    769 
    770     {
    771         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    772     }
    773 
    774543}
    775544static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){
     
    810579    }
    811580
    812     {
    813         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    814     }
    815 
    816     {
    817         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    818     }
    819 
    820     {
    821         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    822     }
    823 
    824     {
    825         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    826     }
    827 
    828     {
    829         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    830     }
    831 
    832 }
    833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){
     581}
     582static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){
    834583    {
    835584        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     
    866615    {
    867616        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    868     }
    869 
    870     {
    871         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    872     }
    873 
    874     {
    875         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    876     }
    877 
    878     {
    879         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    880     }
    881 
    882     {
    883         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    884     }
    885 
    886     {
    887         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    888     }
    889 
    890 }
    891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){
    892     {
    893         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    894     }
    895 
    896     {
    897         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    898     }
    899 
    900     {
    901         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    902     }
    903 
    904     {
    905         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    906     }
    907 
    908     {
    909         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    910     }
    911 
    912     {
    913         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    914     }
    915 
    916     {
    917         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    918     }
    919 
    920     {
    921         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    922     }
    923 
    924     {
    925         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    926     }
    927 
    928     {
    929         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    930     }
    931 
    932     {
    933         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    934     }
    935 
    936     {
    937         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    938     }
    939 
    940     {
    941         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    942     }
    943 
    944     {
    945         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    946     }
    947 
    948 }
    949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){
    950     {
    951         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    952     }
    953 
    954     {
    955         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    956     }
    957 
    958     {
    959         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    960     }
    961 
    962     {
    963         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    964     }
    965 
    966     {
    967         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    968     }
    969 
    970     {
    971         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    972     }
    973 
    974     {
    975         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    976     }
    977 
    978     {
    979         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    980     }
    981 
    982     {
    983         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    984     }
    985 
    986     {
    987         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    988     }
    989 
    990     {
    991         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    992     }
    993 
    994     {
    995         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    996     }
    997 
    998     {
    999         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    1000     }
    1001 
    1002     {
    1003         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1004     }
    1005 
    1006 }
    1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){
    1008     {
    1009         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1010     }
    1011 
    1012     {
    1013         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1014     }
    1015 
    1016     {
    1017         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1018     }
    1019 
    1020     {
    1021         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1022     }
    1023 
    1024     {
    1025         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1026     }
    1027 
    1028     {
    1029         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1030     }
    1031 
    1032     {
    1033         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1034     }
    1035 
    1036     {
    1037         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1038     }
    1039 
    1040     {
    1041         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1042     }
    1043 
    1044     {
    1045         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1046     }
    1047 
    1048     {
    1049         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1050     }
    1051 
    1052     {
    1053         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1054     }
    1055 
    1056     {
    1057         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    1058     }
    1059 
    1060     {
    1061         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1062     }
    1063 
    1064 }
    1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){
    1066     {
    1067         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1068     }
    1069 
    1070     {
    1071         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1072     }
    1073 
    1074     {
    1075         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1076     }
    1077 
    1078     {
    1079         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1080     }
    1081 
    1082     {
    1083         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1084     }
    1085 
    1086     {
    1087         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1088     }
    1089 
    1090     {
    1091         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1092     }
    1093 
    1094     {
    1095         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1096     }
    1097 
    1098     {
    1099         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1100     }
    1101 
    1102     {
    1103         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1104     }
    1105 
    1106     {
    1107         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1108     }
    1109 
    1110     {
    1111         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1112     }
    1113 
    1114     {
    1115         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
    1116     }
    1117 
    1118     {
    1119         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1120     }
    1121 
    1122 }
    1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){
    1124     {
    1125         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1126     }
    1127 
    1128     {
    1129         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1130     }
    1131 
    1132     {
    1133         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1134     }
    1135 
    1136     {
    1137         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1138     }
    1139 
    1140     {
    1141         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1142     }
    1143 
    1144     {
    1145         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1146     }
    1147 
    1148     {
    1149         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1150     }
    1151 
    1152     {
    1153         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1154     }
    1155 
    1156     {
    1157         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1158     }
    1159 
    1160     {
    1161         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1162     }
    1163 
    1164     {
    1165         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1166     }
    1167 
    1168     {
    1169         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1170     }
    1171 
    1172     {
    1173         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
    1174     }
    1175 
    1176     {
    1177         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);
    1178617    }
    1179618
     
    1188627__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    1189628__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
    1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();
    1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();
    1192629__attribute__ ((unused,used)) signed int _X2f1Fi___1();
    1193630__attribute__ ((unused)) signed int _X2f1Fi___1(){
     
    1199636}
    1200637__attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[];
    1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[];
    1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{
    1203     __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[];
    1204 }
    1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{
    1206     __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[];
    1207 }
    1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0);
    1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){
    1210     __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0);
    1211 }
    1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){
    1213     __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0);
    1214 }
    1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){
    1216     __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0);
     638__attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{
     639    __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[];
     640}
     641__attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0);
     642__attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){
     643    __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0);
    1217644}
    1218645signed int _X3vtrFi___1(){
     
    1222649    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)];
    1223650    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)];
    1224     __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)];
    1225     __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2();
     651    __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
    1226652    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
    1227653}
     
    1245671signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    1246672signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int __param_0[((unsigned long int )5)]));
     673signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned long int )5)]));
    1248674signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    1249675signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object3)(signed int (*__param_0)(signed int __param_0)));
     676signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int (*__param_0)(signed int __param_0)));
    1251677signed int _X2adFi___1(){
    1252678    __attribute__ ((unused)) signed int _X10_retval_adi_1;
     
    1350776
    1351777}
    1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5);
    1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7);
    1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9);
    1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)());
    1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));
    1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());
    1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
     778signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4);
     779signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6);
     780signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8);
     781signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)());
     782signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0));
     783signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)());
     784signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0));
    1359785struct Vad {
    1360786    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.nast.x64.txt

    r5407cdc rfeacef9  
    104104    __attribute__ ((used,unused,unused)) signed int _X2f7i_1;
    105105    __attribute__ ((used,used,unused)) signed int _X2f8i_1;
    106     __attribute__ ((unused)) signed int *_X2f9Pi_1;
    107     __attribute__ ((unused,used)) signed int *_X3f10Pi_1;
    108     __attribute__ ((unused,unused)) signed int *_X3f11Pi_1;
    109     __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1;
    110     __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1;
    111     __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1;
     106    __attribute__ ((unused,unused)) signed int *_X2f9Pi_1;
    112107};
    113108static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1);
     
    123118static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1);
    124119static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1);
    125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1);
    126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1);
    127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1);
    128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1);
    129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1);
    130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1);
     120static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1);
    131121static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    132122    {
     
    166156    }
    167157
    168     {
    169         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    170     }
    171 
    172     {
    173         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    174     }
    175 
    176     {
    177         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    178     }
    179 
    180     {
    181         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    182     }
    183 
    184     {
    185         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    186     }
    187 
    188158}
    189159static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){
     
    224194    }
    225195
    226     {
    227         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);
    228     }
    229 
    230     {
    231         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);
    232     }
    233 
    234     {
    235         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);
    236     }
    237 
    238     {
    239         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);
    240     }
    241 
    242     {
    243         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);
    244     }
    245 
    246196}
    247197static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    248     {
    249         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);
    250     }
    251 
    252     {
    253         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);
    254     }
    255 
    256     {
    257         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);
    258     }
    259 
    260     {
    261         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);
    262     }
    263 
    264     {
    265         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);
    266     }
    267 
    268198    {
    269199        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */);
     
    342272
    343273    {
    344         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));
    345     }
    346 
    347     {
    348         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));
    349     }
    350 
    351     {
    352         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));
    353     }
    354 
    355     {
    356         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));
    357     }
    358 
    359     {
    360         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));
    361     }
    362 
    363     {
    364274        ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1)));
    365275    }
     
    404314    }
    405315
    406     {
    407         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    408     }
    409 
    410     {
    411         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    412     }
    413 
    414     {
    415         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    416     }
    417 
    418     {
    419         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    420     }
    421 
    422     {
    423         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    424     }
    425 
    426316}
    427317static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){
     
    462352    }
    463353
    464     {
    465         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    466     }
    467 
    468     {
    469         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    470     }
    471 
    472     {
    473         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    474     }
    475 
    476     {
    477         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    478     }
    479 
    480     {
    481         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    482     }
    483 
    484354}
    485355static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){
     
    520390    }
    521391
    522     {
    523         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    524     }
    525 
    526     {
    527         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    528     }
    529 
    530     {
    531         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    532     }
    533 
    534     {
    535         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    536     }
    537 
    538     {
    539         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    540     }
    541 
    542392}
    543393static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){
     
    578428    }
    579429
    580     {
    581         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    582     }
    583 
    584     {
    585         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    586     }
    587 
    588     {
    589         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    590     }
    591 
    592     {
    593         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    594     }
    595 
    596     {
    597         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    598     }
    599 
    600430}
    601431static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){
     
    636466    }
    637467
    638     {
    639         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    640     }
    641 
    642     {
    643         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    644     }
    645 
    646     {
    647         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    648     }
    649 
    650     {
    651         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    652     }
    653 
    654     {
    655         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    656     }
    657 
    658468}
    659469static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){
     
    694504    }
    695505
    696     {
    697         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    698     }
    699 
    700     {
    701         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    702     }
    703 
    704     {
    705         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    706     }
    707 
    708     {
    709         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    710     }
    711 
    712     {
    713         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    714     }
    715 
    716506}
    717507static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){
     
    752542    }
    753543
    754     {
    755         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    756     }
    757 
    758     {
    759         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    760     }
    761 
    762     {
    763         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    764     }
    765 
    766     {
    767         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    768     }
    769 
    770     {
    771         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    772     }
    773 
    774544}
    775545static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){
     
    810580    }
    811581
    812     {
    813         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    814     }
    815 
    816     {
    817         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    818     }
    819 
    820     {
    821         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    822     }
    823 
    824     {
    825         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    826     }
    827 
    828     {
    829         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    830     }
    831 
    832 }
    833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){
     582}
     583static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){
    834584    {
    835585        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     
    866616    {
    867617        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    868     }
    869 
    870     {
    871         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    872     }
    873 
    874     {
    875         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    876     }
    877 
    878     {
    879         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    880     }
    881 
    882     {
    883         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    884     }
    885 
    886     {
    887         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    888     }
    889 
    890 }
    891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){
    892     {
    893         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    894     }
    895 
    896     {
    897         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    898     }
    899 
    900     {
    901         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    902     }
    903 
    904     {
    905         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    906     }
    907 
    908     {
    909         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    910     }
    911 
    912     {
    913         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    914     }
    915 
    916     {
    917         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    918     }
    919 
    920     {
    921         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    922     }
    923 
    924     {
    925         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    926     }
    927 
    928     {
    929         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    930     }
    931 
    932     {
    933         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    934     }
    935 
    936     {
    937         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    938     }
    939 
    940     {
    941         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    942     }
    943 
    944     {
    945         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    946     }
    947 
    948 }
    949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){
    950     {
    951         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    952     }
    953 
    954     {
    955         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    956     }
    957 
    958     {
    959         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    960     }
    961 
    962     {
    963         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    964     }
    965 
    966     {
    967         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    968     }
    969 
    970     {
    971         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    972     }
    973 
    974     {
    975         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    976     }
    977 
    978     {
    979         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    980     }
    981 
    982     {
    983         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    984     }
    985 
    986     {
    987         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    988     }
    989 
    990     {
    991         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    992     }
    993 
    994     {
    995         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    996     }
    997 
    998     {
    999         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    1000     }
    1001 
    1002     {
    1003         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1004     }
    1005 
    1006 }
    1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){
    1008     {
    1009         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1010     }
    1011 
    1012     {
    1013         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1014     }
    1015 
    1016     {
    1017         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1018     }
    1019 
    1020     {
    1021         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1022     }
    1023 
    1024     {
    1025         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1026     }
    1027 
    1028     {
    1029         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1030     }
    1031 
    1032     {
    1033         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1034     }
    1035 
    1036     {
    1037         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1038     }
    1039 
    1040     {
    1041         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1042     }
    1043 
    1044     {
    1045         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1046     }
    1047 
    1048     {
    1049         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1050     }
    1051 
    1052     {
    1053         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1054     }
    1055 
    1056     {
    1057         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    1058     }
    1059 
    1060     {
    1061         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1062     }
    1063 
    1064 }
    1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){
    1066     {
    1067         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1068     }
    1069 
    1070     {
    1071         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1072     }
    1073 
    1074     {
    1075         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1076     }
    1077 
    1078     {
    1079         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1080     }
    1081 
    1082     {
    1083         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1084     }
    1085 
    1086     {
    1087         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1088     }
    1089 
    1090     {
    1091         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1092     }
    1093 
    1094     {
    1095         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1096     }
    1097 
    1098     {
    1099         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1100     }
    1101 
    1102     {
    1103         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1104     }
    1105 
    1106     {
    1107         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1108     }
    1109 
    1110     {
    1111         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1112     }
    1113 
    1114     {
    1115         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
    1116     }
    1117 
    1118     {
    1119         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1120     }
    1121 
    1122 }
    1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){
    1124     {
    1125         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1126     }
    1127 
    1128     {
    1129         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1130     }
    1131 
    1132     {
    1133         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1134     }
    1135 
    1136     {
    1137         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1138     }
    1139 
    1140     {
    1141         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1142     }
    1143 
    1144     {
    1145         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1146     }
    1147 
    1148     {
    1149         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1150     }
    1151 
    1152     {
    1153         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1154     }
    1155 
    1156     {
    1157         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1158     }
    1159 
    1160     {
    1161         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1162     }
    1163 
    1164     {
    1165         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1166     }
    1167 
    1168     {
    1169         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1170     }
    1171 
    1172     {
    1173         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
    1174     }
    1175 
    1176     {
    1177         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);
    1178618    }
    1179619
     
    1188628__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    1189629__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
    1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();
    1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();
    1192630__attribute__ ((unused,used)) signed int _X2f1Fi___1();
    1193631__attribute__ ((unused)) signed int _X2f1Fi___1(){
     
    1199637}
    1200638__attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[];
    1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[];
    1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{
    1203     __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[];
    1204 }
    1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{
    1206     __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[];
    1207 }
    1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0);
    1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){
    1210     __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0);
    1211 }
    1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){
    1213     __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0);
    1214 }
    1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){
    1216     __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0);
     639__attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{
     640    __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[];
     641}
     642__attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0);
     643__attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){
     644    __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0);
    1217645}
    1218646signed int _X3vtrFi___1(){
     
    1222650    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)];
    1223651    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)];
    1224     __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)];
    1225     __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2();
     652    __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
    1226653    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
    1227654}
     
    1245672signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    1246673signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int __param_0[((unsigned long int )5)]));
     674signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned long int )5)]));
    1248675signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    1249676signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object3)(signed int (*__param_0)(signed int __param_0)));
     677signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int (*__param_0)(signed int __param_0)));
    1251678signed int _X2adFi___1(){
    1252679    __attribute__ ((unused)) signed int _X10_retval_adi_1;
     
    1350777
    1351778}
    1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5);
    1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7);
    1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9);
    1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)());
    1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));
    1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());
    1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
     779signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4);
     780signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6);
     781signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8);
     782signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)());
     783signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0));
     784signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)());
     785signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0));
    1359786struct Vad {
    1360787    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.nast.x86.txt

    r5407cdc rfeacef9  
    104104    __attribute__ ((used,unused,unused)) signed int _X2f7i_1;
    105105    __attribute__ ((used,used,unused)) signed int _X2f8i_1;
    106     __attribute__ ((unused)) signed int *_X2f9Pi_1;
    107     __attribute__ ((unused,used)) signed int *_X3f10Pi_1;
    108     __attribute__ ((unused,unused)) signed int *_X3f11Pi_1;
    109     __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1;
    110     __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1;
    111     __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1;
     106    __attribute__ ((unused,unused)) signed int *_X2f9Pi_1;
    112107};
    113108static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1);
     
    123118static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1);
    124119static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1);
    125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1);
    126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1);
    127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1);
    128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1);
    129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1);
    130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1);
     120static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1);
    131121static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    132122    {
     
    166156    }
    167157
    168     {
    169         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    170     }
    171 
    172     {
    173         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    174     }
    175 
    176     {
    177         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    178     }
    179 
    180     {
    181         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    182     }
    183 
    184     {
    185         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    186     }
    187 
    188158}
    189159static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){
     
    224194    }
    225195
    226     {
    227         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);
    228     }
    229 
    230     {
    231         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);
    232     }
    233 
    234     {
    235         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);
    236     }
    237 
    238     {
    239         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);
    240     }
    241 
    242     {
    243         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);
    244     }
    245 
    246196}
    247197static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    248     {
    249         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);
    250     }
    251 
    252     {
    253         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);
    254     }
    255 
    256     {
    257         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);
    258     }
    259 
    260     {
    261         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);
    262     }
    263 
    264     {
    265         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);
    266     }
    267 
    268198    {
    269199        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */);
     
    342272
    343273    {
    344         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));
    345     }
    346 
    347     {
    348         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));
    349     }
    350 
    351     {
    352         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));
    353     }
    354 
    355     {
    356         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));
    357     }
    358 
    359     {
    360         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));
    361     }
    362 
    363     {
    364274        ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1)));
    365275    }
     
    404314    }
    405315
    406     {
    407         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    408     }
    409 
    410     {
    411         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    412     }
    413 
    414     {
    415         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    416     }
    417 
    418     {
    419         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    420     }
    421 
    422     {
    423         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    424     }
    425 
    426316}
    427317static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){
     
    462352    }
    463353
    464     {
    465         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    466     }
    467 
    468     {
    469         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    470     }
    471 
    472     {
    473         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    474     }
    475 
    476     {
    477         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    478     }
    479 
    480     {
    481         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    482     }
    483 
    484354}
    485355static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){
     
    520390    }
    521391
    522     {
    523         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    524     }
    525 
    526     {
    527         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    528     }
    529 
    530     {
    531         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    532     }
    533 
    534     {
    535         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    536     }
    537 
    538     {
    539         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    540     }
    541 
    542392}
    543393static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){
     
    578428    }
    579429
    580     {
    581         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    582     }
    583 
    584     {
    585         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    586     }
    587 
    588     {
    589         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    590     }
    591 
    592     {
    593         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    594     }
    595 
    596     {
    597         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    598     }
    599 
    600430}
    601431static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){
     
    636466    }
    637467
    638     {
    639         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    640     }
    641 
    642     {
    643         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    644     }
    645 
    646     {
    647         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    648     }
    649 
    650     {
    651         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    652     }
    653 
    654     {
    655         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    656     }
    657 
    658468}
    659469static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){
     
    694504    }
    695505
    696     {
    697         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    698     }
    699 
    700     {
    701         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    702     }
    703 
    704     {
    705         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    706     }
    707 
    708     {
    709         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    710     }
    711 
    712     {
    713         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    714     }
    715 
    716506}
    717507static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){
     
    752542    }
    753543
    754     {
    755         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    756     }
    757 
    758     {
    759         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    760     }
    761 
    762     {
    763         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    764     }
    765 
    766     {
    767         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    768     }
    769 
    770     {
    771         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    772     }
    773 
    774544}
    775545static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){
     
    810580    }
    811581
    812     {
    813         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    814     }
    815 
    816     {
    817         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    818     }
    819 
    820     {
    821         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    822     }
    823 
    824     {
    825         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    826     }
    827 
    828     {
    829         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    830     }
    831 
    832 }
    833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){
     582}
     583static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){
    834584    {
    835585        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     
    866616    {
    867617        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    868     }
    869 
    870     {
    871         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    872     }
    873 
    874     {
    875         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    876     }
    877 
    878     {
    879         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    880     }
    881 
    882     {
    883         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    884     }
    885 
    886     {
    887         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    888     }
    889 
    890 }
    891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){
    892     {
    893         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    894     }
    895 
    896     {
    897         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    898     }
    899 
    900     {
    901         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    902     }
    903 
    904     {
    905         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    906     }
    907 
    908     {
    909         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    910     }
    911 
    912     {
    913         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    914     }
    915 
    916     {
    917         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    918     }
    919 
    920     {
    921         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    922     }
    923 
    924     {
    925         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    926     }
    927 
    928     {
    929         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    930     }
    931 
    932     {
    933         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    934     }
    935 
    936     {
    937         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    938     }
    939 
    940     {
    941         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    942     }
    943 
    944     {
    945         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    946     }
    947 
    948 }
    949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){
    950     {
    951         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    952     }
    953 
    954     {
    955         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    956     }
    957 
    958     {
    959         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    960     }
    961 
    962     {
    963         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    964     }
    965 
    966     {
    967         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    968     }
    969 
    970     {
    971         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    972     }
    973 
    974     {
    975         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    976     }
    977 
    978     {
    979         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    980     }
    981 
    982     {
    983         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    984     }
    985 
    986     {
    987         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    988     }
    989 
    990     {
    991         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    992     }
    993 
    994     {
    995         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    996     }
    997 
    998     {
    999         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    1000     }
    1001 
    1002     {
    1003         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1004     }
    1005 
    1006 }
    1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){
    1008     {
    1009         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1010     }
    1011 
    1012     {
    1013         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1014     }
    1015 
    1016     {
    1017         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1018     }
    1019 
    1020     {
    1021         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1022     }
    1023 
    1024     {
    1025         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1026     }
    1027 
    1028     {
    1029         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1030     }
    1031 
    1032     {
    1033         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1034     }
    1035 
    1036     {
    1037         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1038     }
    1039 
    1040     {
    1041         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1042     }
    1043 
    1044     {
    1045         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1046     }
    1047 
    1048     {
    1049         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1050     }
    1051 
    1052     {
    1053         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1054     }
    1055 
    1056     {
    1057         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    1058     }
    1059 
    1060     {
    1061         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1062     }
    1063 
    1064 }
    1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){
    1066     {
    1067         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1068     }
    1069 
    1070     {
    1071         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1072     }
    1073 
    1074     {
    1075         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1076     }
    1077 
    1078     {
    1079         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1080     }
    1081 
    1082     {
    1083         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1084     }
    1085 
    1086     {
    1087         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1088     }
    1089 
    1090     {
    1091         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1092     }
    1093 
    1094     {
    1095         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1096     }
    1097 
    1098     {
    1099         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1100     }
    1101 
    1102     {
    1103         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1104     }
    1105 
    1106     {
    1107         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1108     }
    1109 
    1110     {
    1111         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1112     }
    1113 
    1114     {
    1115         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
    1116     }
    1117 
    1118     {
    1119         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1120     }
    1121 
    1122 }
    1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){
    1124     {
    1125         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1126     }
    1127 
    1128     {
    1129         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1130     }
    1131 
    1132     {
    1133         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1134     }
    1135 
    1136     {
    1137         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1138     }
    1139 
    1140     {
    1141         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1142     }
    1143 
    1144     {
    1145         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1146     }
    1147 
    1148     {
    1149         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1150     }
    1151 
    1152     {
    1153         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1154     }
    1155 
    1156     {
    1157         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1158     }
    1159 
    1160     {
    1161         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1162     }
    1163 
    1164     {
    1165         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1166     }
    1167 
    1168     {
    1169         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1170     }
    1171 
    1172     {
    1173         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
    1174     }
    1175 
    1176     {
    1177         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);
    1178618    }
    1179619
     
    1188628__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    1189629__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
    1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();
    1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();
    1192630__attribute__ ((unused,used)) signed int _X2f1Fi___1();
    1193631__attribute__ ((unused)) signed int _X2f1Fi___1(){
     
    1199637}
    1200638__attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[];
    1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[];
    1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{
    1203     __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[];
    1204 }
    1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{
    1206     __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[];
    1207 }
    1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __param_0);
    1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(signed int __param_0){
    1210     __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __param_0);
    1211 }
    1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(signed int __param_0){
    1213     __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __param_0);
    1214 }
    1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(signed int __param_0){
    1216     __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __param_0);
     639__attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{
     640    __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[];
     641}
     642__attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0);
     643__attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(signed int __param_0){
     644    __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __param_0);
    1217645}
    1218646signed int _X3vtrFi___1(){
     
    1222650    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned int )5)];
    1223651    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned int )5)];
    1224     __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned int )5)];
    1225     __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2();
     652    __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
    1226653    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
    1227654}
     
    1245672signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    1246673signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int __param_0[((unsigned int )5)]));
     674signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object1)(signed int __param_0[((unsigned int )5)]));
    1248675signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    1249676signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object3)(signed int (*__param_0)(signed int __param_0)));
     677signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object2)(signed int (*__param_0)(signed int __param_0)));
    1251678signed int _X2adFi___1(){
    1252679    __attribute__ ((unused)) signed int _X10_retval_adi_1;
     
    1350777
    1351778}
    1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object4, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object5);
    1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object7);
    1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object8, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object9);
    1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)());
    1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(signed int __param_0));
    1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)());
    1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(signed int __param_0));
     779signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object3, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object4);
     780signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object5, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object6);
     781signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object7, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object8);
     782signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object9)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object10)());
     783signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object11)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object12)(signed int __param_0));
     784signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object13)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object14)());
     785signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(signed int __param_0), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)(signed int __param_0));
    1359786struct Vad {
    1360787    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.oast.x64.txt

    r5407cdc rfeacef9  
    104104    __attribute__ ((used,unused,unused)) signed int _X2f7i_1;
    105105    __attribute__ ((used,used,unused)) signed int _X2f8i_1;
    106     __attribute__ ((unused)) signed int *_X2f9Pi_1;
    107     __attribute__ ((unused,used)) signed int *_X3f10Pi_1;
    108     __attribute__ ((unused,unused)) signed int *_X3f11Pi_1;
    109     __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1;
    110     __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1;
    111     __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1;
     106    __attribute__ ((unused,unused)) signed int *_X2f9Pi_1;
    112107};
    113108static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1);
     
    123118static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1);
    124119static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1);
    125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1);
    126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1);
    127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1);
    128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1);
    129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1);
    130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1);
     120static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1);
    131121static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    132122    {
     
    166156    }
    167157
    168     {
    169         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    170     }
    171 
    172     {
    173         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    174     }
    175 
    176     {
    177         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    178     }
    179 
    180     {
    181         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    182     }
    183 
    184     {
    185         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    186     }
    187 
    188158}
    189159static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){
     
    224194    }
    225195
    226     {
    227         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);
    228     }
    229 
    230     {
    231         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);
    232     }
    233 
    234     {
    235         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);
    236     }
    237 
    238     {
    239         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);
    240     }
    241 
    242     {
    243         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);
    244     }
    245 
    246196}
    247197static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    248     {
    249         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);
    250     }
    251 
    252     {
    253         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);
    254     }
    255 
    256     {
    257         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);
    258     }
    259 
    260     {
    261         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);
    262     }
    263 
    264     {
    265         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);
    266     }
    267 
    268198    {
    269199        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */);
     
    342272
    343273    {
    344         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));
    345     }
    346 
    347     {
    348         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));
    349     }
    350 
    351     {
    352         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));
    353     }
    354 
    355     {
    356         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));
    357     }
    358 
    359     {
    360         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));
    361     }
    362 
    363     {
    364274        ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1)));
    365275    }
     
    404314    }
    405315
    406     {
    407         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    408     }
    409 
    410     {
    411         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    412     }
    413 
    414     {
    415         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    416     }
    417 
    418     {
    419         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    420     }
    421 
    422     {
    423         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    424     }
    425 
    426316}
    427317static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){
     
    462352    }
    463353
    464     {
    465         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    466     }
    467 
    468     {
    469         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    470     }
    471 
    472     {
    473         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    474     }
    475 
    476     {
    477         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    478     }
    479 
    480     {
    481         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    482     }
    483 
    484354}
    485355static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){
     
    520390    }
    521391
    522     {
    523         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    524     }
    525 
    526     {
    527         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    528     }
    529 
    530     {
    531         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    532     }
    533 
    534     {
    535         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    536     }
    537 
    538     {
    539         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    540     }
    541 
    542392}
    543393static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){
     
    578428    }
    579429
    580     {
    581         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    582     }
    583 
    584     {
    585         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    586     }
    587 
    588     {
    589         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    590     }
    591 
    592     {
    593         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    594     }
    595 
    596     {
    597         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    598     }
    599 
    600430}
    601431static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){
     
    636466    }
    637467
    638     {
    639         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    640     }
    641 
    642     {
    643         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    644     }
    645 
    646     {
    647         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    648     }
    649 
    650     {
    651         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    652     }
    653 
    654     {
    655         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    656     }
    657 
    658468}
    659469static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){
     
    694504    }
    695505
    696     {
    697         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    698     }
    699 
    700     {
    701         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    702     }
    703 
    704     {
    705         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    706     }
    707 
    708     {
    709         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    710     }
    711 
    712     {
    713         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    714     }
    715 
    716506}
    717507static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){
     
    752542    }
    753543
    754     {
    755         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    756     }
    757 
    758     {
    759         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    760     }
    761 
    762     {
    763         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    764     }
    765 
    766     {
    767         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    768     }
    769 
    770     {
    771         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    772     }
    773 
    774544}
    775545static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){
     
    810580    }
    811581
    812     {
    813         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    814     }
    815 
    816     {
    817         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    818     }
    819 
    820     {
    821         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    822     }
    823 
    824     {
    825         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    826     }
    827 
    828     {
    829         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    830     }
    831 
    832 }
    833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){
     582}
     583static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){
    834584    {
    835585        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     
    866616    {
    867617        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    868     }
    869 
    870     {
    871         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    872     }
    873 
    874     {
    875         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    876     }
    877 
    878     {
    879         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    880     }
    881 
    882     {
    883         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    884     }
    885 
    886     {
    887         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    888     }
    889 
    890 }
    891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){
    892     {
    893         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    894     }
    895 
    896     {
    897         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    898     }
    899 
    900     {
    901         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    902     }
    903 
    904     {
    905         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    906     }
    907 
    908     {
    909         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    910     }
    911 
    912     {
    913         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    914     }
    915 
    916     {
    917         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    918     }
    919 
    920     {
    921         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    922     }
    923 
    924     {
    925         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    926     }
    927 
    928     {
    929         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    930     }
    931 
    932     {
    933         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    934     }
    935 
    936     {
    937         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    938     }
    939 
    940     {
    941         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    942     }
    943 
    944     {
    945         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    946     }
    947 
    948 }
    949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){
    950     {
    951         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    952     }
    953 
    954     {
    955         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    956     }
    957 
    958     {
    959         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    960     }
    961 
    962     {
    963         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    964     }
    965 
    966     {
    967         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    968     }
    969 
    970     {
    971         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    972     }
    973 
    974     {
    975         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    976     }
    977 
    978     {
    979         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    980     }
    981 
    982     {
    983         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    984     }
    985 
    986     {
    987         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    988     }
    989 
    990     {
    991         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    992     }
    993 
    994     {
    995         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    996     }
    997 
    998     {
    999         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    1000     }
    1001 
    1002     {
    1003         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1004     }
    1005 
    1006 }
    1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){
    1008     {
    1009         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1010     }
    1011 
    1012     {
    1013         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1014     }
    1015 
    1016     {
    1017         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1018     }
    1019 
    1020     {
    1021         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1022     }
    1023 
    1024     {
    1025         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1026     }
    1027 
    1028     {
    1029         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1030     }
    1031 
    1032     {
    1033         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1034     }
    1035 
    1036     {
    1037         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1038     }
    1039 
    1040     {
    1041         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1042     }
    1043 
    1044     {
    1045         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1046     }
    1047 
    1048     {
    1049         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1050     }
    1051 
    1052     {
    1053         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1054     }
    1055 
    1056     {
    1057         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    1058     }
    1059 
    1060     {
    1061         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1062     }
    1063 
    1064 }
    1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){
    1066     {
    1067         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1068     }
    1069 
    1070     {
    1071         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1072     }
    1073 
    1074     {
    1075         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1076     }
    1077 
    1078     {
    1079         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1080     }
    1081 
    1082     {
    1083         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1084     }
    1085 
    1086     {
    1087         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1088     }
    1089 
    1090     {
    1091         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1092     }
    1093 
    1094     {
    1095         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1096     }
    1097 
    1098     {
    1099         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1100     }
    1101 
    1102     {
    1103         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1104     }
    1105 
    1106     {
    1107         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1108     }
    1109 
    1110     {
    1111         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1112     }
    1113 
    1114     {
    1115         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
    1116     }
    1117 
    1118     {
    1119         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1120     }
    1121 
    1122 }
    1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){
    1124     {
    1125         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1126     }
    1127 
    1128     {
    1129         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1130     }
    1131 
    1132     {
    1133         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1134     }
    1135 
    1136     {
    1137         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1138     }
    1139 
    1140     {
    1141         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1142     }
    1143 
    1144     {
    1145         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1146     }
    1147 
    1148     {
    1149         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1150     }
    1151 
    1152     {
    1153         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1154     }
    1155 
    1156     {
    1157         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1158     }
    1159 
    1160     {
    1161         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1162     }
    1163 
    1164     {
    1165         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1166     }
    1167 
    1168     {
    1169         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1170     }
    1171 
    1172     {
    1173         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
    1174     }
    1175 
    1176     {
    1177         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);
    1178618    }
    1179619
     
    1188628__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    1189629__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
    1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();
    1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();
    1192630__attribute__ ((unused,used)) signed int _X2f1Fi___1();
    1193631__attribute__ ((unused)) signed int _X2f1Fi___1(){
     
    1199637}
    1200638__attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[];
    1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[];
    1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{
    1203     __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[];
    1204 }
    1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{
    1206     __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[];
    1207 }
    1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __anonymous_object2);
    1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object3){
    1210     __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __anonymous_object4);
    1211 }
    1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object5){
    1213     __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __anonymous_object6);
    1214 }
    1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object7){
    1216     __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __anonymous_object8);
     639__attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{
     640    __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[];
     641}
     642__attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1);
     643__attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){
     644    __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3);
    1217645}
    1218646signed int _X3vtrFi___1(){
     
    1222650    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned long int )5)];
    1223651    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned long int )5)];
    1224     __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned long int )5)];
    1225     __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2();
     652    __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
    1226653    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
    1227654}
     
    1245672signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    1246673signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object9)(__attribute__ ((unused,unused)) signed int __anonymous_object10[((unsigned long int )5)]));
     674signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object4)(__attribute__ ((unused,unused)) signed int __anonymous_object5[((unsigned long int )5)]));
    1248675signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    1249676signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object11)(__attribute__ ((unused)) signed int (*__anonymous_object12)(__attribute__ ((unused,unused)) signed int __anonymous_object13)));
     677signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object6)(__attribute__ ((unused)) signed int (*__anonymous_object7)(__attribute__ ((unused,unused)) signed int __anonymous_object8)));
    1251678signed int _X2adFi___1(){
    1252679    __attribute__ ((unused)) signed int _X10_retval_adi_1;
     
    1350777
    1351778}
    1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object14, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object15);
    1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object16, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object17);
    1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object18, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object19);
    1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object20)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)());
    1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)(__attribute__ ((unused)) signed int __anonymous_object23), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object24)(__attribute__ ((unused)) signed int __anonymous_object25));
    1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object26)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object27)());
    1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object28)(__attribute__ ((unused)) signed int __anonymous_object29), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object30)(__attribute__ ((unused)) signed int __anonymous_object31));
     779signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object9, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object10);
     780signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object11, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object12);
     781signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object13, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object14);
     782signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)());
     783signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __anonymous_object18), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object19)(__attribute__ ((unused)) signed int __anonymous_object20));
     784signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)());
     785signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object23)(__attribute__ ((unused)) signed int __anonymous_object24), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object25)(__attribute__ ((unused)) signed int __anonymous_object26));
    1359786struct Vad {
    1360787    __attribute__ ((unused)) signed int :4;
  • tests/.expect/attributes.oast.x86.txt

    r5407cdc rfeacef9  
    104104    __attribute__ ((used,unused,unused)) signed int _X2f7i_1;
    105105    __attribute__ ((used,used,unused)) signed int _X2f8i_1;
    106     __attribute__ ((unused)) signed int *_X2f9Pi_1;
    107     __attribute__ ((unused,used)) signed int *_X3f10Pi_1;
    108     __attribute__ ((unused,unused)) signed int *_X3f11Pi_1;
    109     __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1;
    110     __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1;
    111     __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1;
     106    __attribute__ ((unused,unused)) signed int *_X2f9Pi_1;
    112107};
    113108static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1);
     
    123118static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1);
    124119static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1);
    125 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1);
    126 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1);
    127 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1);
    128 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1);
    129 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1);
    130 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1);
     120static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1);
    131121static inline void _X12_constructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    132122    {
     
    166156    }
    167157
    168     {
    169         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    170     }
    171 
    172     {
    173         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    174     }
    175 
    176     {
    177         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    178     }
    179 
    180     {
    181         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    182     }
    183 
    184     {
    185         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    186     }
    187 
    188158}
    189159static inline void _X12_constructorFv_S3FdlS3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1, struct Fdl _X4_srcS3Fdl_1){
     
    224194    }
    225195
    226     {
    227         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1) /* ?{} */);
    228     }
    229 
    230     {
    231         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1) /* ?{} */);
    232     }
    233 
    234     {
    235         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1) /* ?{} */);
    236     }
    237 
    238     {
    239         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1) /* ?{} */);
    240     }
    241 
    242     {
    243         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1) /* ?{} */);
    244     }
    245 
    246196}
    247197static inline void _X11_destructorFv_S3Fdl_autogen___1(struct Fdl *_X4_dstS3Fdl_1){
    248     {
    249         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ^?{} */);
    250     }
    251 
    252     {
    253         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ^?{} */);
    254     }
    255 
    256     {
    257         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ^?{} */);
    258     }
    259 
    260     {
    261         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ^?{} */);
    262     }
    263 
    264     {
    265         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ^?{} */);
    266     }
    267 
    268198    {
    269199        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1) /* ^?{} */);
     
    342272
    343273    {
    344         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X4_srcS3Fdl_1._X3f10Pi_1));
    345     }
    346 
    347     {
    348         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X4_srcS3Fdl_1._X3f11Pi_1));
    349     }
    350 
    351     {
    352         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X4_srcS3Fdl_1._X3f12Pi_1));
    353     }
    354 
    355     {
    356         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X4_srcS3Fdl_1._X3f13Pi_1));
    357     }
    358 
    359     {
    360         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X4_srcS3Fdl_1._X3f14Pi_1));
    361     }
    362 
    363     {
    364274        ((void)_X12_constructorFv_S3FdlS3Fdl_autogen___1((&_X4_retS3Fdl_1), (*_X4_dstS3Fdl_1)));
    365275    }
     
    404314    }
    405315
    406     {
    407         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    408     }
    409 
    410     {
    411         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    412     }
    413 
    414     {
    415         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    416     }
    417 
    418     {
    419         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    420     }
    421 
    422     {
    423         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    424     }
    425 
    426316}
    427317static inline void _X12_constructorFv_S3Fdlii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1){
     
    462352    }
    463353
    464     {
    465         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    466     }
    467 
    468     {
    469         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    470     }
    471 
    472     {
    473         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    474     }
    475 
    476     {
    477         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    478     }
    479 
    480     {
    481         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    482     }
    483 
    484354}
    485355static inline void _X12_constructorFv_S3Fdliii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1){
     
    520390    }
    521391
    522     {
    523         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    524     }
    525 
    526     {
    527         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    528     }
    529 
    530     {
    531         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    532     }
    533 
    534     {
    535         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    536     }
    537 
    538     {
    539         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    540     }
    541 
    542392}
    543393static inline void _X12_constructorFv_S3Fdliiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1){
     
    578428    }
    579429
    580     {
    581         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    582     }
    583 
    584     {
    585         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    586     }
    587 
    588     {
    589         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    590     }
    591 
    592     {
    593         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    594     }
    595 
    596     {
    597         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    598     }
    599 
    600430}
    601431static inline void _X12_constructorFv_S3Fdliiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1){
     
    636466    }
    637467
    638     {
    639         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    640     }
    641 
    642     {
    643         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    644     }
    645 
    646     {
    647         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    648     }
    649 
    650     {
    651         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    652     }
    653 
    654     {
    655         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    656     }
    657 
    658468}
    659469static inline void _X12_constructorFv_S3Fdliiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1){
     
    694504    }
    695505
    696     {
    697         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    698     }
    699 
    700     {
    701         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    702     }
    703 
    704     {
    705         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    706     }
    707 
    708     {
    709         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    710     }
    711 
    712     {
    713         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    714     }
    715 
    716506}
    717507static inline void _X12_constructorFv_S3Fdliiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1){
     
    752542    }
    753543
    754     {
    755         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    756     }
    757 
    758     {
    759         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    760     }
    761 
    762     {
    763         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    764     }
    765 
    766     {
    767         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    768     }
    769 
    770     {
    771         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    772     }
    773 
    774544}
    775545static inline void _X12_constructorFv_S3Fdliiiiiiii_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1){
     
    810580    }
    811581
    812     {
    813         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    814     }
    815 
    816     {
    817         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    818     }
    819 
    820     {
    821         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    822     }
    823 
    824     {
    825         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    826     }
    827 
    828     {
    829         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    830     }
    831 
    832 }
    833 static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1){
     582}
     583static inline void _X12_constructorFv_S3FdliiiiiiiiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused,unused)) signed int *_X2f9Pi_1){
    834584    {
    835585        ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
     
    866616    {
    867617        ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    868     }
    869 
    870     {
    871         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1) /* ?{} */);
    872     }
    873 
    874     {
    875         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    876     }
    877 
    878     {
    879         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    880     }
    881 
    882     {
    883         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    884     }
    885 
    886     {
    887         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    888     }
    889 
    890 }
    891 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1){
    892     {
    893         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    894     }
    895 
    896     {
    897         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    898     }
    899 
    900     {
    901         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    902     }
    903 
    904     {
    905         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    906     }
    907 
    908     {
    909         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    910     }
    911 
    912     {
    913         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    914     }
    915 
    916     {
    917         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    918     }
    919 
    920     {
    921         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    922     }
    923 
    924     {
    925         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    926     }
    927 
    928     {
    929         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    930     }
    931 
    932     {
    933         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1) /* ?{} */);
    934     }
    935 
    936     {
    937         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    938     }
    939 
    940     {
    941         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    942     }
    943 
    944     {
    945         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    946     }
    947 
    948 }
    949 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1){
    950     {
    951         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    952     }
    953 
    954     {
    955         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    956     }
    957 
    958     {
    959         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    960     }
    961 
    962     {
    963         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    964     }
    965 
    966     {
    967         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    968     }
    969 
    970     {
    971         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    972     }
    973 
    974     {
    975         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    976     }
    977 
    978     {
    979         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    980     }
    981 
    982     {
    983         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    984     }
    985 
    986     {
    987         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    988     }
    989 
    990     {
    991         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    992     }
    993 
    994     {
    995         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1) /* ?{} */);
    996     }
    997 
    998     {
    999         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    1000     }
    1001 
    1002     {
    1003         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1004     }
    1005 
    1006 }
    1007 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1){
    1008     {
    1009         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1010     }
    1011 
    1012     {
    1013         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1014     }
    1015 
    1016     {
    1017         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1018     }
    1019 
    1020     {
    1021         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1022     }
    1023 
    1024     {
    1025         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1026     }
    1027 
    1028     {
    1029         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1030     }
    1031 
    1032     {
    1033         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1034     }
    1035 
    1036     {
    1037         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1038     }
    1039 
    1040     {
    1041         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1042     }
    1043 
    1044     {
    1045         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1046     }
    1047 
    1048     {
    1049         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1050     }
    1051 
    1052     {
    1053         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1054     }
    1055 
    1056     {
    1057         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1) /* ?{} */);
    1058     }
    1059 
    1060     {
    1061         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1062     }
    1063 
    1064 }
    1065 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1){
    1066     {
    1067         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1068     }
    1069 
    1070     {
    1071         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1072     }
    1073 
    1074     {
    1075         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1076     }
    1077 
    1078     {
    1079         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1080     }
    1081 
    1082     {
    1083         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1084     }
    1085 
    1086     {
    1087         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1088     }
    1089 
    1090     {
    1091         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1092     }
    1093 
    1094     {
    1095         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1096     }
    1097 
    1098     {
    1099         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1100     }
    1101 
    1102     {
    1103         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1104     }
    1105 
    1106     {
    1107         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1108     }
    1109 
    1110     {
    1111         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1112     }
    1113 
    1114     {
    1115         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
    1116     }
    1117 
    1118     {
    1119         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1) /* ?{} */);
    1120     }
    1121 
    1122 }
    1123 static inline void _X12_constructorFv_S3FdliiiiiiiiPiPiPiPiPiPi_autogen___1(struct Fdl *_X4_dstS3Fdl_1, __attribute__ ((unused)) signed int _X2f1i_1, __attribute__ ((unused)) signed int _X2f2i_1, __attribute__ ((unused,unused)) signed int _X2f3i_1, __attribute__ ((unused)) signed int _X2f4i_1, __attribute__ ((unused,unused)) signed int _X2f5i_1, signed int _X2f6i_1, __attribute__ ((unused,unused)) signed int _X2f7i_1, __attribute__ ((unused)) signed int _X2f8i_1, __attribute__ ((unused)) signed int *_X2f9Pi_1, __attribute__ ((unused)) signed int *_X3f10Pi_1, __attribute__ ((unused,unused)) signed int *_X3f11Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f12Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f13Pi_1, __attribute__ ((unused,unused,unused)) signed int *_X3f14Pi_1){
    1124     {
    1125         ((void)((*_X4_dstS3Fdl_1)._X2f1i_1=_X2f1i_1) /* ?{} */);
    1126     }
    1127 
    1128     {
    1129         ((void)((*_X4_dstS3Fdl_1)._X2f2i_1=_X2f2i_1) /* ?{} */);
    1130     }
    1131 
    1132     {
    1133         ((void)((*_X4_dstS3Fdl_1)._X2f3i_1=_X2f3i_1) /* ?{} */);
    1134     }
    1135 
    1136     {
    1137         ((void)((*_X4_dstS3Fdl_1)._X2f4i_1=_X2f4i_1) /* ?{} */);
    1138     }
    1139 
    1140     {
    1141         ((void)((*_X4_dstS3Fdl_1)._X2f5i_1=_X2f5i_1) /* ?{} */);
    1142     }
    1143 
    1144     {
    1145         ((void)((*_X4_dstS3Fdl_1)._X2f6i_1=_X2f6i_1) /* ?{} */);
    1146     }
    1147 
    1148     {
    1149         ((void)((*_X4_dstS3Fdl_1)._X2f7i_1=_X2f7i_1) /* ?{} */);
    1150     }
    1151 
    1152     {
    1153         ((void)((*_X4_dstS3Fdl_1)._X2f8i_1=_X2f8i_1) /* ?{} */);
    1154     }
    1155 
    1156     {
    1157         ((void)((*_X4_dstS3Fdl_1)._X2f9Pi_1=_X2f9Pi_1) /* ?{} */);
    1158     }
    1159 
    1160     {
    1161         ((void)((*_X4_dstS3Fdl_1)._X3f10Pi_1=_X3f10Pi_1) /* ?{} */);
    1162     }
    1163 
    1164     {
    1165         ((void)((*_X4_dstS3Fdl_1)._X3f11Pi_1=_X3f11Pi_1) /* ?{} */);
    1166     }
    1167 
    1168     {
    1169         ((void)((*_X4_dstS3Fdl_1)._X3f12Pi_1=_X3f12Pi_1) /* ?{} */);
    1170     }
    1171 
    1172     {
    1173         ((void)((*_X4_dstS3Fdl_1)._X3f13Pi_1=_X3f13Pi_1) /* ?{} */);
    1174     }
    1175 
    1176     {
    1177         ((void)((*_X4_dstS3Fdl_1)._X3f14Pi_1=_X3f14Pi_1) /* ?{} */);
    1178618    }
    1179619
     
    1188628__attribute__ ((used,used,used,used)) const signed int (*_X3vd7Fi___1)();
    1189629__attribute__ ((used,used,unused,used,used)) const signed int (*_X3vd8Fi___1)();
    1190 __attribute__ ((used,used,used,used)) const signed int (*_X3vd9Fi___1)();
    1191 __attribute__ ((used,used,unused,used,used)) const signed int (*_X4vd10Fi___1)();
    1192630__attribute__ ((unused,used)) signed int _X2f1Fi___1();
    1193631__attribute__ ((unused)) signed int _X2f1Fi___1(){
     
    1199637}
    1200638__attribute__ ((unused,used,unused)) signed int (*_X2f3FPA0i_i__1(signed int __anonymous_object0))[];
    1201 __attribute__ ((unused,used,unused,unused)) signed int (*_X2f4FPA0i_i__1(signed int __anonymous_object1))[];
    1202 __attribute__ ((unused,unused)) signed int (*_X2f5FPA0i_i__1(signed int _X1pi_1))[]{
    1203     __attribute__ ((unused)) signed int (*_X10_retval_f5PA0i_1)[];
    1204 }
    1205 __attribute__ ((unused,unused)) signed int (*_X2f6FPA0i_i__1(signed int _X1pi_1))[]{
    1206     __attribute__ ((unused)) signed int (*_X10_retval_f6PA0i_1)[];
    1207 }
    1208 __attribute__ ((unused,used,unused)) signed int (*_X2f7FFi_i____1())(signed int __anonymous_object2);
    1209 __attribute__ ((unused,unused)) signed int (*_X2f8FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object3){
    1210     __attribute__ ((unused)) signed int (*_X10_retval_f8Fi_i__1)(signed int __anonymous_object4);
    1211 }
    1212 __attribute__ ((unused,unused)) signed int (*_X2f9FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object5){
    1213     __attribute__ ((unused)) signed int (*_X10_retval_f9Fi_i__1)(signed int __anonymous_object6);
    1214 }
    1215 __attribute__ ((unused,unused)) signed int (*_X3f10FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object7){
    1216     __attribute__ ((unused)) signed int (*_X11_retval_f10Fi_i__1)(signed int __anonymous_object8);
     639__attribute__ ((unused,unused)) signed int (*_X2f3FPA0i_i__1(signed int _X1pi_1))[]{
     640    __attribute__ ((unused)) signed int (*_X10_retval_f3PA0i_1)[];
     641}
     642__attribute__ ((unused,used,unused)) signed int (*_X2f4FFi_i____1())(signed int __anonymous_object1);
     643__attribute__ ((unused,unused)) signed int (*_X2f4FFi_i____1())(__attribute__ ((unused)) signed int __anonymous_object2){
     644    __attribute__ ((unused)) signed int (*_X10_retval_f4Fi_i__1)(signed int __anonymous_object3);
    1217645}
    1218646signed int _X3vtrFi___1(){
     
    1222650    __attribute__ ((unused,unused,unused)) signed int _X2t3A0i_2[((unsigned int )5)];
    1223651    __attribute__ ((unused,unused,unused,unused,unused)) signed int **_X2t4A0PPi_2[((unsigned int )5)];
    1224     __attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X2t5A0PPi_2[((unsigned int )5)];
    1225     __attribute__ ((unused,unused,unused)) signed int _X2t6Fi___2();
     652    __attribute__ ((unused,unused,unused)) signed int _X2t5Fi___2();
    1226653    __attribute__ ((unused,unused,unused,unused)) signed int *_X2t6FPi___2();
    1227654}
     
    1245672signed int _X4tpr2Fi_PPi__1(__attribute__ ((unused,unused,unused,unused,unused,unused)) signed int **_X3FooPPi_1);
    1246673signed int _X4tpr3Fi_Pi__1(__attribute__ ((unused,unused,unused)) signed int *_X3FooPi_1);
    1247 signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object9)(__attribute__ ((unused,unused)) signed int __anonymous_object10[((unsigned int )5)]));
     674signed int _X4tpr4Fi_Fi_Pi___1(__attribute__ ((unused,unused)) signed int (*__anonymous_object4)(__attribute__ ((unused,unused)) signed int __anonymous_object5[((unsigned int )5)]));
    1248675signed int _X4tpr5Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    1249676signed int _X4tpr6Fi_Fi____1(__attribute__ ((unused,unused,unused)) signed int (*_X3FooFi___1)());
    1250 signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object11)(__attribute__ ((unused)) signed int (*__anonymous_object12)(__attribute__ ((unused,unused)) signed int __anonymous_object13)));
     677signed int _X4tpr7Fi_Fi_Fi_i____1(__attribute__ ((unused,unused)) signed int (*__anonymous_object6)(__attribute__ ((unused)) signed int (*__anonymous_object7)(__attribute__ ((unused,unused)) signed int __anonymous_object8)));
    1251678signed int _X2adFi___1(){
    1252679    __attribute__ ((unused)) signed int _X10_retval_adi_1;
     
    1350777
    1351778}
    1352 signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object14, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object15);
    1353 signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object16, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object17);
    1354 signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object18, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object19);
    1355 signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object20)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)());
    1356 signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)(__attribute__ ((unused)) signed int __anonymous_object23), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object24)(__attribute__ ((unused)) signed int __anonymous_object25));
    1357 signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object26)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object27)());
    1358 signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object28)(__attribute__ ((unused)) signed int __anonymous_object29), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object30)(__attribute__ ((unused)) signed int __anonymous_object31));
     779signed int _X4apd1Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object9, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object10);
     780signed int _X4apd2Fi_PPiPPi__1(__attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object11, __attribute__ ((unused,unused,unused,unused)) signed int **__anonymous_object12);
     781signed int _X4apd3Fi_PiPi__1(__attribute__ ((unused,unused,unused)) signed int *__anonymous_object13, __attribute__ ((unused,unused,unused)) signed int *__anonymous_object14);
     782signed int _X4apd4Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object15)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object16)());
     783signed int _X4apd5Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object17)(__attribute__ ((unused)) signed int __anonymous_object18), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object19)(__attribute__ ((unused)) signed int __anonymous_object20));
     784signed int _X4apd6Fi_Fi__Fi____1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object21)(), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object22)());
     785signed int _X4apd7Fi_Fi_i_Fi_i___1(__attribute__ ((unused,unused,unused)) signed int (*__anonymous_object23)(__attribute__ ((unused)) signed int __anonymous_object24), __attribute__ ((unused,unused,unused)) signed int (*__anonymous_object25)(__attribute__ ((unused)) signed int __anonymous_object26));
    1359786struct Vad {
    1360787    __attribute__ ((unused)) signed int :4;
  • tests/.expect/declarationSpecifier.arm64.txt

    r5407cdc rfeacef9  
    11471147
    11481148    {
    1149         signed int _tmp_cp_ret6;
    1150         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     1149        signed int _tmp_cp_ret4;
     1150        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    11511151    }
    11521152
  • tests/.expect/declarationSpecifier.x64.txt

    r5407cdc rfeacef9  
    11471147
    11481148    {
    1149         signed int _tmp_cp_ret6;
    1150         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     1149        signed int _tmp_cp_ret4;
     1150        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    11511151    }
    11521152
  • tests/.expect/declarationSpecifier.x86.txt

    r5407cdc rfeacef9  
    11471147
    11481148    {
    1149         signed int _tmp_cp_ret6;
    1150         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     1149        signed int _tmp_cp_ret4;
     1150        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    11511151    }
    11521152
  • tests/.expect/extension.arm64.txt

    r5407cdc rfeacef9  
    457457
    458458    {
    459         signed int _tmp_cp_ret6;
    460         ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));
     459        signed int _tmp_cp_ret4;
     460        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
    461461    }
    462462
  • tests/.expect/extension.x64.txt

    r5407cdc rfeacef9  
    457457
    458458    {
    459         signed int _tmp_cp_ret6;
    460         ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));
     459        signed int _tmp_cp_ret4;
     460        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
    461461    }
    462462
  • tests/.expect/extension.x86.txt

    r5407cdc rfeacef9  
    457457
    458458    {
    459         signed int _tmp_cp_ret6;
    460         ((void)(((void)(_tmp_cp_ret6=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret6));
     459        signed int _tmp_cp_ret4;
     460        ((void)(((void)(_tmp_cp_ret4=__extension__ _X4fredFi_i__1(3))) , _tmp_cp_ret4));
    461461    }
    462462
  • tests/.expect/gccExtensions.arm64.txt

    r5407cdc rfeacef9  
    339339
    340340    {
    341         signed int _tmp_cp_ret6;
    342         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     341        signed int _tmp_cp_ret4;
     342        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    343343    }
    344344
  • tests/.expect/gccExtensions.x64.txt

    r5407cdc rfeacef9  
    339339
    340340    {
    341         signed int _tmp_cp_ret6;
    342         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     341        signed int _tmp_cp_ret4;
     342        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    343343    }
    344344
  • tests/.expect/gccExtensions.x86.txt

    r5407cdc rfeacef9  
    317317
    318318    {
    319         signed int _tmp_cp_ret6;
    320         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret6=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret6)) /* ?{} */);
     319        signed int _tmp_cp_ret4;
     320        ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
    321321    }
    322322
  • tests/Makefile.am

    r5407cdc rfeacef9  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Tue Mar  2 21:39:01 2021
    14 ## Update Count     : 90
     13## Last Modified On : Fri Oct  9 23:13:07 2020
     14## Update Count     : 86
    1515###############################################################################
    1616
     
    2626archiveerrors=
    2727
    28 DEBUG_FLAGS=-debug -g -O0
     28DEBUG_FLAGS=-debug -O0
    2929
    3030quick_test=avl_test operators numericConstants expression enum array typeof cast raii/dtor-early-exit raii/init_once attributes
     
    4444        -Wall \
    4545        -Wno-unused-function \
    46         -Wno-psabi \
    47         -quiet @CFA_FLAGS@
     46        -quiet @CFA_FLAGS@ \
     47        -DIN_DIR="${abs_srcdir}/.in/"
    4848
    4949AM_CFAFLAGS = -XCFA --deterministic-out
     
    7575        pybin/tools.py \
    7676        long_tests.hfa \
    77         io/.in/io.data \
    78         io/.in/many_read.data \
     77        .in/io.data \
    7978        avltree/avl.h \
    8079        avltree/avl-private.h \
    8180        concurrent/clib.c \
    82         concurrent/clib_tls.c \
    8381        exceptions/with-threads.hfa \
    8482        exceptions/except-io.hfa
     
    144142# don't use distcc to do the linking because distcc doesn't do linking
    145143% : %.cfa $(CFACCBIN)
    146         $(CFACOMPILETEST) -c -o $(abspath ${@}).o -DIN_DIR="$(abspath $(dir ${<}))/.in/"
     144        $(CFACOMPILETEST) -c -o $(abspath ${@}).o
    147145        $(CFACCLINK) ${@}.o -o $(abspath ${@})
    148146        rm $(abspath ${@}).o
     
    172170
    173171SYNTAX_ONLY_CODE = expression typedefRedef variableDeclarator switch numericConstants identFuncDeclarator forall \
    174         init1 limits nested-types stdincludes cast labelledExit array quasiKeyword include/includes builtins/sync warnings/self-assignment
     172        init1 limits nested-types stdincludes cast labelledExit array builtins/sync warnings/self-assignment
    175173$(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN)
    176174        $(CFACOMPILE_SYNTAX)
  • tests/attributes.cfa

    r5407cdc rfeacef9  
    1010// Created On       : Mon Feb  6 16:07:02 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Mar 15 13:53:31 2021
    13 // Update Count     : 38
     12// Last Modified On : Mon Jan 25 21:26:41 2021
     13// Update Count     : 20
    1414//
    1515
     
    4242    __attribute__(( unused )) int f5 __attribute__(( unused ));
    4343    __attribute__(( used )) int f6 __attribute__(( packed )), f7 __attribute__(( unused )) __attribute__(( unused )), __attribute__(( used )) f8 __attribute__(( unused ));
    44     int * f9 __attribute__(( unused ));
    45     __attribute__(( used )) int __attribute__(( unused )) * f10;
    46     int ( ( * f11 __attribute__(( unused )) ) __attribute__(( unused )) );
    47     int ( ( __attribute__(( unused )) * f12  __attribute__(( unused )) ) __attribute__(( unused )) );
    48     int ( ( __attribute__(( unused )) * (f13)  __attribute__(( unused )) ) __attribute__(( unused )) );
    49     int ( ( ( __attribute__(( unused )) * (f14) )  __attribute__(( unused )) ) __attribute__(( unused )) );
     44    int ( ( * (f9) __attribute__(( unused )) ) __attribute__(( unused )) );
    5045};
    5146
     
    6055const __attribute__(( used )) int __attribute__(( used )) vd5[5] __attribute__(( used )), __attribute__(( unused )) ((vd6)[5]) __attribute__(( used ));
    6156const __attribute__(( used )) int __attribute__(( used )) (* __attribute__(( used )) vd7)() __attribute__(( used )), __attribute__(( unused )) ((* __attribute__(( used )) vd8)()) __attribute__(( used ));
    62 const __attribute__(( used )) int __attribute__(( used )) ( __attribute__(( used )) * vd9)() __attribute__(( used )), __attribute__(( unused )) (( __attribute__(( used )) * vd10)()) __attribute__(( used ));
     57
    6358
    6459// function_declarator
     
    6863__attribute__(( unused )) int * __attribute__(( unused )) * const __attribute__(( unused )) f2() {}
    6964__attribute__(( unused )) int (* __attribute__(( unused )) f3(int))[] __attribute__(( used ));
    70 __attribute__(( unused )) int ( __attribute__(( unused )) * __attribute__(( unused )) f4(int))[] __attribute__(( used ));
    71 __attribute__(( unused )) int (* __attribute__(( unused )) f5(int p))[] {}
    72 __attribute__(( unused )) int ( __attribute__(( unused )) * (f6)(int p))[] {}
    73 __attribute__(( unused )) int (* __attribute__(( unused )) f7())(int) __attribute__(( used ));
    74 __attribute__(( unused )) int (* __attribute__(( unused )) f8())(int) {}
    75 __attribute__(( unused )) int ( __attribute__(( unused )) * f9())(int) {}
    76 __attribute__(( unused )) int ( __attribute__(( unused )) * (f10)())(int) {}
     65__attribute__(( unused )) int (* __attribute__(( unused )) f3(int p))[] {}
     66__attribute__(( unused )) int (* __attribute__(( unused )) f4())(int) __attribute__(( used ));
     67__attribute__(( unused )) int (* __attribute__(( unused )) f4())(int) {}
    7768
    7869
     
    8576    __attribute__(( unused )) int __attribute__(( unused )) t3[5] __attribute__(( unused ));
    8677    __attribute__(( unused )) int __attribute__(( unused )) (* (* __attribute__(( unused )) t4[5]) __attribute__(( unused )) ) __attribute__(( unused ));
    87     __attribute__(( unused )) int __attribute__(( unused )) ( __attribute__(( unused )) * ( __attribute__(( unused )) * t5[5]) __attribute__(( unused )) ) __attribute__(( unused ));
    88     __attribute__(( unused )) int __attribute__(( unused )) t6() __attribute__(( unused ));
     78    __attribute__(( unused )) int __attribute__(( unused )) t5() __attribute__(( unused ));
    8979    __attribute__(( unused )) int __attribute__(( unused )) * __attribute__(( unused )) ((t6))() __attribute__(( unused ));
    9080}
  • tests/concurrent/clib.c

    r5407cdc rfeacef9  
     1#include <clib/cfathread.h>
     2
    13#include <stdio.h>
    24#include <stdlib.h>
    3 #include <clib/cfathread.h>
    4 #include <bits/defs.hfa>
    5 
    6 extern "C" {
    7 void _exit(int status);
    8 }
    95
    106thread_local struct drand48_data buffer = { 0 };
     
    1915cfathread_t volatile blocked[blocked_size];
    2016
    21 void * Worker( void * ) {
     17void Worker( cfathread_t this ) {
    2218        for(int i = 0; i < 1000; i++) {
    2319                int idx = myrand() % blocked_size;
     
    2622                        cfathread_unpark( thrd );
    2723                } else {
    28                         cfathread_t thrd = __atomic_exchange_n(&blocked[idx], cfathread_self(), __ATOMIC_SEQ_CST);
     24                        cfathread_t thrd = __atomic_exchange_n(&blocked[idx], this, __ATOMIC_SEQ_CST);
    2925                        cfathread_unpark( thrd );
    3026                        cfathread_park();
     
    3228        }
    3329        printf("Done\n");
    34         return NULL;
    3530}
    3631
    3732volatile bool stop;
    38 void * Unparker( void * ) {
     33void Unparker( cfathread_t this ) {
    3934        while(!stop) {
    4035                int idx = myrand() % blocked_size;
     
    4742        }
    4843        printf("Done Unparker\n");
    49         return NULL;
    5044}
    5145
     
    5751        }
    5852
    59         cfathread_cluster_t cl = cfathread_cluster_self();
    60 
    61         cfathread_cluster_add_worker( cl, NULL, NULL, NULL );
    62         cfathread_cluster_add_worker( cl, NULL, NULL, NULL );
    63         cfathread_cluster_add_worker( cl, NULL, NULL, NULL );
    64 
    65         cfathread_attr_t attr;
    66         cfathread_attr_init(&attr);
    67         cfathread_attr_setcluster(&attr, cl);
    68 
    69         cfathread_t u;
    70         cfathread_create( &u, &attr, Unparker, NULL );
     53        cfathread_setproccnt( 4 );
     54        cfathread_t u = cfathread_create( Unparker );
    7155        {
    7256                cfathread_t t[20];
    7357                for(int i = 0; i < 20; i++) {
    74                         cfathread_create( &t[i], &attr, Worker, NULL );
     58                        t[i] = cfathread_create( Worker );
    7559                }
    7660                for(int i = 0; i < 20; i++) {
    77                         cfathread_join( t[i], NULL );
     61                        cfathread_join( t[i] );
    7862                }
    7963        }
    8064        stop = true;
    81         cfathread_join(u, NULL);
    82         cfathread_attr_destroy(&attr);
    83         fflush(stdout);
    84         _exit(0);
     65        cfathread_join(u);
     66        cfathread_setproccnt( 1 );
    8567}
  • tests/concurrent/coroutineYield.cfa

    r5407cdc rfeacef9  
    3838
    3939
    40 Coroutine c;
    4140int main(int argc, char* argv[]) {
     41        Coroutine c;
    4242        for(int i = 0; TEST(i < N); i++) {
    4343                #if !defined(TEST_FOREVER)
  • tests/concurrent/futures/multi.cfa

    r5407cdc rfeacef9  
    55
    66thread Server {
    7         int pending, done, iteration;
     7        int cnt, iteration;
    88        multi_future(int) * request;
    99};
    1010
    1111void ?{}( Server & this ) {
    12         ((thread&)this){"Server Thread"};
    13         this.pending = 0;
    14         this.done = 0;
     12        this.cnt = 0;
    1513        this.iteration = 0;
    1614        this.request = 0p;
     
    1816
    1917void ^?{}( Server & mutex this ) {
    20         assert(this.pending == 0);
    21         this.request = 0p;
     18        assert(this.cnt == 0);
     19    this.request = 0p;
    2220}
    2321
     
    2624}
    2725
    28 void call( Server & mutex this ) {
    29         this.pending++;
     26void process( Server & mutex this ) {
     27        fulfil( *this.request, this.iteration );
     28        this.iteration++;
    3029}
    3130
    32 void finish( Server & mutex this ) {
    33         this.done++;
     31void call( Server & mutex this ) {
     32        this.cnt++;
    3433}
    3534
     35void finish( Server & mutex this ) { }
     36
    3637void main( Server & this ) {
    37         MAIN_LOOP:
    3838        for() {
    3939                waitfor( ^?{} : this ) {
    4040                        break;
    4141                }
    42                 or waitfor( call: this ) {
    43                         if (this.pending != NFUTURES) { continue MAIN_LOOP; }
    44 
    45                         this.pending = 0;
    46                         fulfil( *this.request, this.iteration );
    47                         this.iteration++;
    48 
    49                         for(NFUTURES) {
    50                                 waitfor( finish: this );
     42                or when( this.cnt < NFUTURES ) waitfor( call: this ) {
     43                        if (this.cnt == NFUTURES) {
     44                                process(this);
    5145                        }
    52 
    53                         reset( *this.request );
    54                         this.done = 0;
     46                }
     47                or waitfor( finish: this ) {
     48                        if (this.cnt == NFUTURES) {
     49                                reset( *this.request );
     50                                this.cnt = 0;
     51                        }
    5552                }
    5653        }
     
    6057Server * the_server;
    6158thread Worker {};
    62 void ?{}(Worker & this) {
    63         ((thread&)this){"Worker Thread"};
    64 }
    65 
    6659multi_future(int) * shared_future;
    6760
  • tests/errors/.expect/completeType.nast.arm64.txt

    r5407cdc rfeacef9  
    1212      Application of
    1313        Variable Expression: *?: forall
    14           instance of type DT (not function type)
     14          DT: data type
    1515          function
    1616        ... with parameters
     
    2121        ... with resolved type:
    2222          pointer to forall
    23             instance of type [unbound] (not function type)
     23            [unbound]:data type
     24            function
     25          ... with parameters
     26            pointer to instance of type [unbound] (not function type)
     27          ... returning
     28            reference to instance of type [unbound] (not function type)
     29
     30        ... to arguments
     31        Variable Expression: x: pointer to instance of struct B with body
     32        ... with resolved type:
     33          pointer to instance of struct B with body
     34
     35      ... with resolved type:
     36        reference to instance of struct B with body
     37    ... to: nothing
     38    ... with resolved type:
     39      void
     40  (types:
     41    void
     42  )
     43  Environment:([unbound]) -> instance of struct B with body (no widening)
     44
     45
     46Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
     47      Application of
     48        Variable Expression: *?: forall
     49          DT: data type
     50          function
     51        ... with parameters
     52          pointer to instance of type DT (not function type)
     53        ... returning
     54          reference to instance of type DT (not function type)
     55
     56        ... with resolved type:
     57          pointer to forall
     58            [unbound]:data type
    2459            function
    2560          ... with parameters
     
    4176    void
    4277  )
    43   Environment:([unbound]DT) -> instance of struct A without body (no widening)
    44 
    45 
    46 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
    47       Application of
    48         Variable Expression: *?: forall
    49           instance of type DT (not function type)
    50           function
    51         ... with parameters
    52           pointer to instance of type DT (not function type)
    53         ... returning
    54           reference to instance of type DT (not function type)
    55 
    56         ... with resolved type:
    57           pointer to forall
    58             instance of type [unbound] (not function type)
    59             function
    60           ... with parameters
    61             pointer to instance of type [unbound] (not function type)
    62           ... returning
    63             reference to instance of type [unbound] (not function type)
    64 
    65         ... to arguments
    66         Variable Expression: x: pointer to instance of struct B with body
    67         ... with resolved type:
    68           pointer to instance of struct B with body
    69 
    70       ... with resolved type:
    71         reference to instance of struct B with body
    72     ... to: nothing
    73     ... with resolved type:
    74       void
    75   (types:
    76     void
    77   )
    78   Environment:([unbound]DT) -> instance of struct B with body (no widening)
     78  Environment:([unbound]) -> instance of struct A without body (no widening)
    7979
    8080
     
    113113Cost ( 0, 1, 0, 0, 1, -5, 0 ): Application of
    114114            Variable Expression: baz: forall
    115               instance of type T (not function type)
    116               with assertions
    117               Variable Expression: ?=?: pointer to function
    118               ... with parameters
    119                 reference to instance of type T (not function type)
    120                 instance of type T (not function type)
    121               ... returning
    122                 instance of type T (not function type)
    123 
    124               ... with resolved type:
    125                 pointer to function
     115              T: sized data type
     116              ... with assertions
     117                ?=?: pointer to function
    126118                ... with parameters
    127119                  reference to instance of type T (not function type)
     
    130122                  instance of type T (not function type)
    131123
    132               Variable Expression: ?{}: pointer to function
    133               ... with parameters
    134                 reference to instance of type T (not function type)
    135               ... returning nothing
    136 
    137               ... with resolved type:
    138                 pointer to function
     124                ?{}: pointer to function
    139125                ... with parameters
    140126                  reference to instance of type T (not function type)
    141127                ... returning nothing
    142128
    143               Variable Expression: ?{}: pointer to function
    144               ... with parameters
    145                 reference to instance of type T (not function type)
    146                 instance of type T (not function type)
    147               ... returning nothing
    148 
    149               ... with resolved type:
    150                 pointer to function
     129                ?{}: pointer to function
    151130                ... with parameters
    152131                  reference to instance of type T (not function type)
     
    154133                ... returning nothing
    155134
    156               Variable Expression: ^?{}: pointer to function
    157               ... with parameters
    158                 reference to instance of type T (not function type)
    159               ... returning nothing
    160 
    161               ... with resolved type:
    162                 pointer to function
     135                ^?{}: pointer to function
    163136                ... with parameters
    164137                  reference to instance of type T (not function type)
    165138                ... returning nothing
     139
    166140
    167141              function
     
    172146            ... with resolved type:
    173147              pointer to forall
    174                 instance of type [unbound] (not function type)
    175                 with assertions
    176                 Variable Expression: ?=?: pointer to function
    177                 ... with parameters
    178                   reference to instance of type T (not function type)
    179                   instance of type T (not function type)
    180                 ... returning
    181                   instance of type T (not function type)
    182 
    183                 ... with resolved type:
    184                   pointer to function
     148                [unbound]:sized data type
     149                ... with assertions
     150                  ?=?: pointer to function
    185151                  ... with parameters
    186152                    reference to instance of type [unbound] (not function type)
     
    189155                    instance of type [unbound] (not function type)
    190156
    191                 Variable Expression: ?{}: pointer to function
    192                 ... with parameters
    193                   reference to instance of type T (not function type)
    194                 ... returning nothing
    195 
    196                 ... with resolved type:
    197                   pointer to function
     157                  ?{}: pointer to function
    198158                  ... with parameters
    199159                    reference to instance of type [unbound] (not function type)
    200160                  ... returning nothing
    201161
    202                 Variable Expression: ?{}: pointer to function
    203                 ... with parameters
    204                   reference to instance of type T (not function type)
    205                   instance of type T (not function type)
    206                 ... returning nothing
    207 
    208                 ... with resolved type:
    209                   pointer to function
     162                  ?{}: pointer to function
    210163                  ... with parameters
    211164                    reference to instance of type [unbound] (not function type)
     
    213166                  ... returning nothing
    214167
    215                 Variable Expression: ^?{}: pointer to function
    216                 ... with parameters
    217                   reference to instance of type T (not function type)
    218                 ... returning nothing
    219 
    220                 ... with resolved type:
    221                   pointer to function
     168                  ^?{}: pointer to function
    222169                  ... with parameters
    223170                    reference to instance of type [unbound] (not function type)
    224171                  ... returning nothing
     172
    225173
    226174                function
     
    240188          void
    241189        )
    242         Environment:([unbound]T) -> instance of type T (not function type) (no widening)
     190        Environment:([unbound]) -> instance of type T (not function type) (no widening)
    243191
    244192      Could not satisfy assertion:
    245 Variable Expression: ?=?: pointer to function
     193?=?: pointer to function
    246194        ... with parameters
    247           reference to instance of type T (not function type)
    248           instance of type T (not function type)
     195          reference to instance of type [unbound] (not function type)
     196          instance of type [unbound] (not function type)
    249197        ... returning
    250           instance of type T (not function type)
     198          instance of type [unbound] (not function type)
    251199
    252         ... with resolved type:
    253           pointer to function
    254           ... with parameters
    255             reference to instance of type [unbound] (not function type)
    256             instance of type [unbound] (not function type)
    257           ... returning
    258             instance of type [unbound] (not function type)
    259 
  • tests/exceptions/.expect/resume-threads.txt

    r5407cdc rfeacef9  
    66
    77catch-all
     8
     9throwing child exception
     10inner parent match
    811
    912caught yin as yin
  • tests/exceptions/.expect/resume.txt

    r5407cdc rfeacef9  
    66
    77catch-all
     8
     9throwing child exception
     10inner parent match
    811
    912caught yin as yin
  • tests/exceptions/.expect/terminate-threads.txt

    r5407cdc rfeacef9  
    55
    66catch-all
     7
     8throwing child exception
     9inner parent match
    710
    811caught yin as yin
  • tests/exceptions/.expect/terminate.txt

    r5407cdc rfeacef9  
    55
    66catch-all
     7
     8throwing child exception
     9inner parent match
    710
    811caught yin as yin
  • tests/exceptions/cancel/coroutine.cfa

    r5407cdc rfeacef9  
    44#include <exception.hfa>
    55
    6 EHM_EXCEPTION(internal_error)();
    7 EHM_VIRTUAL_TABLE(internal_error, internal_vt);
     6TRIVIAL_EXCEPTION(internal_error);
    87
    98coroutine WillCancel {};
     
    1514void main(WillCancel & wc) {
    1615        printf("1");
    17         cancel_stack((internal_error){&internal_vt});
     16        cancel_stack((internal_error){});
    1817        printf("!");
    1918}
  • tests/exceptions/cancel/thread.cfa

    r5407cdc rfeacef9  
    44#include <exception.hfa>
    55
    6 EHM_EXCEPTION(internal_error)();
    7 EHM_VIRTUAL_TABLE(internal_error, internal_vt);
     6TRIVIAL_EXCEPTION(internal_error);
    87
    98thread WillCancel {};
     
    1514void main(WillCancel &) {
    1615        printf("1");
    17         cancel_stack((internal_error){&internal_vt});
     16        cancel_stack((internal_error){});
    1817        printf("!");
    1918}
  • tests/exceptions/conditional.cfa

    r5407cdc rfeacef9  
    66#include <exception.hfa>
    77
    8 EHM_EXCEPTION(num_error)(
    9         int num;
     8VTABLE_DECLARATION(num_error)(
     9        int (*code)(num_error *this);
    1010);
    1111
    12 EHM_VIRTUAL_TABLE(num_error, num_error_vt);
     12struct num_error {
     13        VTABLE_FIELD(num_error);
     14    char * msg;
     15    int num;
     16};
     17
     18const char * num_error_msg(num_error * this) {
     19    if ( ! this->msg ) {
     20        static const char * base = "Num Error with code: X";
     21        this->msg = (char *)malloc(22);
     22        for (int i = 0 ; (this->msg[i] = base[i]) ; ++i);
     23    }
     24    this->msg[21] = '0' + this->num;
     25    return this->msg;
     26}
     27void ?{}(num_error & this, int num) {
     28        VTABLE_INIT(this, num_error);
     29    this.msg = 0;
     30    this.num = num;
     31}
     32void ?{}(num_error & this, num_error & other) {
     33    this.virtual_table = other.virtual_table;
     34    this.msg = 0;
     35    this.num = other.num;
     36}
     37void ^?{}(num_error & this) {
     38    if( this.msg ) free( this.msg );
     39}
     40int num_error_code( num_error * this ) {
     41    return this->num;
     42}
     43
     44VTABLE_INSTANCE(num_error)(
     45        num_error_msg,
     46        num_error_code,
     47);
    1348
    1449void caught_num_error(int expect, num_error * actual) {
     
    1752
    1853int main(int argc, char * argv[]) {
    19         num_error exc = {&num_error_vt, 2};
     54        num_error exc = 2;
    2055
    2156        try {
    2257                throw exc;
    23         } catch (num_error * error ; 3 == error->num ) {
     58        } catch (num_error * error ; 3 == error->virtual_table->code( error )) {
    2459                caught_num_error(3, error);
    25         } catch (num_error * error ; 2 == error->num ) {
     60        } catch (num_error * error ; 2 == error->virtual_table->code( error )) {
    2661                caught_num_error(2, error);
    2762        }
     
    2964        try {
    3065                throwResume exc;
    31         } catchResume (num_error * error ; 3 == error->num ) {
     66        } catchResume (num_error * error ; 3 == error->virtual_table->code( error )) {
    3267                caught_num_error(3, error);
    33         } catchResume (num_error * error ; 2 == error->num ) {
     68        } catchResume (num_error * error ; 2 == error->virtual_table->code( error )) {
    3469                caught_num_error(2, error);
    3570        }
  • tests/exceptions/data-except.cfa

    r5407cdc rfeacef9  
    33#include <exception.hfa>
    44
    5 EHM_EXCEPTION(paired)(
     5DATA_EXCEPTION(paired)(
    66        int first;
    77        int second;
    88);
    99
    10 EHM_VIRTUAL_TABLE(paired, paired_vt);
     10void ?{}(paired & this, int first, int second) {
     11        VTABLE_INIT(this, paired);
     12        this.first = first;
     13        this.second = second;
     14}
    1115
    12 const char * virtual_msg(paired * this) {
    13         return this->virtual_table->msg(this);
     16const char * paired_msg(paired * this) {
     17        return "paired";
     18}
     19
     20VTABLE_INSTANCE(paired)(paired_msg);
     21
     22void throwPaired(int first, int second) {
     23        paired exc = {first, second};
    1424}
    1525
    1626int main(int argc, char * argv[]) {
    17         paired except = {&paired_vt, 3, 13};
     27        paired except = {3, 13};
    1828
    1929        try {
    2030                throw except;
    2131        } catch (paired * exc) {
    22                 printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second);
     32                printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);
    2333                ++exc->first;
    2434        }
    2535
    26         printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second);
     36        printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);
    2737
    2838        try {
    2939                throwResume except;
    3040        } catchResume (paired * exc) {
    31                 printf("%s(%d, %d)\n", virtual_msg(exc), exc->first, exc->second);
     41                printf("%s(%d, %d)\n", paired_msg(exc), exc->first, exc->second);
    3242                ++exc->first;
    3343        }
    3444
    35         printf("%s(%d, %d)\n", virtual_msg(&except), except.first, except.second);
     45        printf("%s(%d, %d)\n", paired_msg(&except), except.first, except.second);
    3646}
  • tests/exceptions/defaults.cfa

    r5407cdc rfeacef9  
    44#include <exception.hfa>
    55
    6 EHM_EXCEPTION(log_message)(
     6DATA_EXCEPTION(log_message)(
    77        char * msg;
    88);
    99
    10 _EHM_DEFINE_COPY(log_message, )
    11 const char * msg(log_message * this) {
     10void ?{}(log_message & this, char * msg) {
     11        VTABLE_INIT(this, log_message);
     12        this.msg = msg;
     13}
     14
     15const char * get_log_message(log_message * this) {
    1216        return this->msg;
    1317}
    14 _EHM_VIRTUAL_TABLE(log_message, , log_vt);
     18
     19VTABLE_INSTANCE(log_message)(get_log_message);
    1520
    1621// Logging messages don't have to be handled.
     
    2328        // We can catch log:
    2429        try {
    25                 throwResume (log_message){&log_vt, "Should be printed.\n"};
     30                throwResume (log_message){"Should be printed.\n"};
    2631        } catchResume (log_message * this) {
    2732                printf("%s", this->virtual_table->msg(this));
    2833        }
    2934        // But we don't have to:
    30         throwResume (log_message){&log_vt, "Should not be printed.\n"};
     35        throwResume (log_message){"Should not be printed.\n"};
    3136}
    3237
    3338// I don't have a good use case for doing the same with termination.
    34 EHM_EXCEPTION(jump)();
     39TRIVIAL_EXCEPTION(jump);
    3540void defaultTerminationHandler(jump &) {
    3641        printf("jump default handler.\n");
    3742}
    3843
    39 EHM_VIRTUAL_TABLE(jump, jump_vt);
    40 
    4144void jump_test(void) {
    4245        try {
    43                 throw (jump){&jump_vt};
     46                throw (jump){};
    4447        } catch (jump * this) {
    4548                printf("jump catch handler.\n");
    4649        }
    47         throw (jump){&jump_vt};
     50        throw (jump){};
    4851}
    4952
    50 EHM_EXCEPTION(first)();
    51 EHM_VIRTUAL_TABLE(first, first_vt);
    52 
    53 EHM_EXCEPTION(unhandled_exception)();
    54 EHM_VIRTUAL_TABLE(unhandled_exception, unhandled_vt);
     53TRIVIAL_EXCEPTION(first);
     54TRIVIAL_EXCEPTION(unhandled_exception);
    5555
    5656void unhandled_test(void) {
    5757        forall(T &, V & | is_exception(T, V))
    5858        void defaultTerminationHandler(T &) {
    59                 throw (unhandled_exception){&unhandled_vt};
     59                throw (unhandled_exception){};
    6060        }
    6161        void defaultTerminationHandler(unhandled_exception &) {
     
    6363        }
    6464        try {
    65                 throw (first){&first_vt};
     65                throw (first){};
    6666        } catch (unhandled_exception * t) {
    6767                printf("Catch unhandled_exception.\n");
     
    6969}
    7070
    71 EHM_EXCEPTION(second)();
    72 EHM_VIRTUAL_TABLE(second, second_vt);
     71TRIVIAL_EXCEPTION(second);
    7372
    7473void cross_test(void) {
    7574        void defaultTerminationHandler(first &) {
    7675                printf("cross terminate default\n");
    77                 throw (second){&second_vt};
     76                throw (second){};
    7877        }
    7978        void defaultResumptionHandler(first &) {
    8079                printf("cross resume default\n");
    81                 throwResume (second){&second_vt};
     80                throwResume (second){};
    8281        }
    8382        try {
    8483                printf("cross terminate throw\n");
    85                 throw (first){&first_vt};
     84                throw (first){};
    8685        } catch (second *) {
    8786                printf("cross terminate catch\n");
     
    8988        try {
    9089                printf("cross resume throw\n");
    91                 throwResume (first){&first_vt};
     90                throwResume (first){};
    9291        } catchResume (second *) {
    9392                printf("cross resume catch\n");
  • tests/exceptions/finally.cfa

    r5407cdc rfeacef9  
    44#include "except-io.hfa"
    55
    6 EHM_EXCEPTION(myth)();
    7 
    8 EHM_VIRTUAL_TABLE(myth, myth_vt);
     6TRIVIAL_EXCEPTION(myth);
    97
    108int main(int argc, char * argv[]) {
    11         myth exc = {&myth_vt};
     9        myth exc;
    1210
    1311        try {
  • tests/exceptions/interact.cfa

    r5407cdc rfeacef9  
    44#include "except-io.hfa"
    55
    6 EHM_EXCEPTION(star)();
    7 EHM_EXCEPTION(moon)();
    8 
    9 EHM_VIRTUAL_TABLE(star, star_vt);
    10 EHM_VIRTUAL_TABLE(moon, moon_vt);
     6TRIVIAL_EXCEPTION(star);
     7TRIVIAL_EXCEPTION(moon);
    118
    129int main(int argc, char * argv[]) {
    1310        // Resume falls back to terminate.
    1411        try {
    15                 throwResume (star){&star_vt};
     12                throwResume (star){};
    1613        } catch (star *) {
    1714                printf("caught as termination\n");
     
    2017        try {
    2118                loud_region a = "try block with resume throw";
    22                 throwResume (star){&star_vt};
     19                throwResume (star){};
    2320        } catch (star *) {
    2421                printf("caught as termination\n");
     
    3229        try {
    3330                try {
    34                         throw (star){&star_vt};
     31                        throw (star){};
    3532                } catchResume (star *) {
    3633                        printf("resume catch on terminate\n");
     
    4643        try {
    4744                try {
    48                         throwResume (star){&star_vt};
     45                        throwResume (star){};
    4946                } catch (star *) {
    5047                        printf("terminate catch on resume\n");
     
    6158                try {
    6259                        try {
    63                                 throw (star){&star_vt};
     60                                throw (star){};
    6461                        } catchResume (star *) {
    6562                                printf("inner resume catch (error)\n");
     
    7875                try {
    7976                        try {
    80                                 throwResume (star){&star_vt};
     77                                throwResume (star){};
    8178                        } catch (star *) {
    8279                                printf("inner termination catch\n");
     
    9794                                try {
    9895                                        printf("throwing resume moon\n");
    99                                         throwResume (moon){&moon_vt};
     96                                        throwResume (moon){};
    10097                                } catch (star *) {
    10198                                        printf("termination catch\n");
    10299                                }
    103100                                printf("throwing resume star\n");
    104                                 throwResume (star){&star_vt};
     101                                throwResume (star){};
    105102                        } catchResume (star *) {
    106103                                printf("resumption star catch\n");
     
    108105                } catchResume (moon *) {
    109106                        printf("resumption moon catch, will terminate\n");
    110                         throw (star){&star_vt};
     107                        throw (star){};
    111108                }
    112109        } catchResume (star *) {
  • tests/exceptions/polymorphic.cfa

    r5407cdc rfeacef9  
    33#include <exception.hfa>
    44
    5 EHM_FORALL_EXCEPTION(proxy, (T&), (T))();
     5FORALL_TRIVIAL_EXCEPTION(proxy, (T), (T));
     6FORALL_TRIVIAL_INSTANCE(proxy, (U), (U))
    67
    7 EHM_FORALL_VIRTUAL_TABLE(proxy, (int), proxy_int);
    8 EHM_FORALL_VIRTUAL_TABLE(proxy, (char), proxy_char);
     8const char * msg(proxy(int) * this) { return "proxy(int)"; }
     9const char * msg(proxy(char) * this) { return "proxy(char)"; }
     10POLY_VTABLE_INSTANCE(proxy, int)(msg);
     11POLY_VTABLE_INSTANCE(proxy, char)(msg);
    912
    1013void proxy_test(void) {
    11         proxy(int) an_int = {&proxy_int};
    12         proxy(char) a_char = {&proxy_char};
    13 
    1414    try {
    15                 throw an_int;
     15                throw (proxy(int)){};
    1616        } catch (proxy(int) *) {
    1717                printf("terminate catch\n");
     
    1919
    2020        try {
    21                 throwResume a_char;
     21                throwResume (proxy(char)){};
    2222        } catchResume (proxy(char) *) {
    2323                printf("resume catch\n");
     
    2525
    2626        try {
    27                 throw a_char;
     27                throw (proxy(char)){};
    2828        } catch (proxy(int) *) {
    2929                printf("caught proxy(int)\n");
     
    3333}
    3434
    35 EHM_FORALL_EXCEPTION(cell, (T), (T))(
     35FORALL_DATA_EXCEPTION(cell, (T), (T))(
    3636        T data;
    3737);
    3838
    39 EHM_FORALL_VIRTUAL_TABLE(cell, (int), int_cell);
    40 EHM_FORALL_VIRTUAL_TABLE(cell, (char), char_cell);
    41 EHM_FORALL_VIRTUAL_TABLE(cell, (bool), bool_cell);
     39FORALL_DATA_INSTANCE(cell, (T), (T))
     40
     41const char * msg(cell(int) * this) { return "cell(int)"; }
     42const char * msg(cell(char) * this) { return "cell(char)"; }
     43const char * msg(cell(bool) * this) { return "cell(bool)"; }
     44POLY_VTABLE_INSTANCE(cell, int)(msg);
     45POLY_VTABLE_INSTANCE(cell, char)(msg);
     46POLY_VTABLE_INSTANCE(cell, bool)(msg);
    4247
    4348void cell_test(void) {
    4449        try {
    45                 cell(int) except = {&int_cell, -7};
     50                cell(int) except;
     51                except.data = -7;
    4652                throw except;
    4753        } catch (cell(int) * error) {
     
    5056
    5157        try {
    52                 cell(bool) ball = {&bool_cell, false};
     58                cell(bool) ball;
     59                ball.data = false;
    5360                throwResume ball;
    5461                printf("%i\n", ball.data);
  • tests/exceptions/resume.cfa

    r5407cdc rfeacef9  
    44#include "except-io.hfa"
    55
    6 EHM_EXCEPTION(yin)();
    7 EHM_EXCEPTION(yang)();
    8 EHM_EXCEPTION(zen)();
    9 
    10 EHM_VIRTUAL_TABLE(yin, yin_vt);
    11 EHM_VIRTUAL_TABLE(yang, yang_vt);
    12 EHM_VIRTUAL_TABLE(zen, zen_vt);
     6TRIVIAL_EXCEPTION(yin);
     7TRIVIAL_EXCEPTION(yang);
     8TRIVIAL_EXCEPTION(zen);
     9TRIVIAL_EXCEPTION(moment_of, zen);
    1310
    1411void in_void(void);
    1512
    1613int main(int argc, char * argv[]) {
    17         yin a_yin = {&yin_vt};
    18         yang a_yang = {&yang_vt};
    19         zen a_zen = {&zen_vt};
    20 
    2114        // The simple throw catchResume test.
    2215        try {
    2316                loud_exit a = "simple try clause";
    2417                printf("simple throw\n");
    25                 throwResume a_zen;
     18                throwResume (zen){};
    2619                printf("end of try clause\n");
    2720        } catchResume (zen * error) {
     
    3326        // Throw catch-all test.
    3427        try {
    35                 throwResume a_zen;
     28                throwResume (zen){};
    3629        } catchResume (exception_t * error) {
    3730                printf("catch-all\n");
     31        }
     32        printf("\n");
     33
     34        // Catch a parent of the given exception.
     35        try {
     36                printf("throwing child exception\n");
     37                throwResume (moment_of){};
     38        } catchResume (zen *) {
     39                printf("inner parent match\n");
     40        } catchResume (moment_of *) {
     41                printf("outer exact match\n");
    3842        }
    3943        printf("\n");
     
    4246        try {
    4347                try {
    44                         throwResume a_yin;
     48                        throwResume (yin){};
    4549                } catchResume (zen *) {
    4650                        printf("caught yin as zen\n");
     
    5862                        loud_exit a = "rethrow inner try";
    5963                        printf("rethrow inner try\n");
    60                         throwResume a_zen;
     64                        throwResume (zen){};
    6165                } catchResume (zen *) {
    6266                        loud_exit a = "rethrowing catch clause";
     
    7377        try {
    7478                try {
    75                         throwResume a_yin;
     79                        throwResume (yin){};
    7680                } catchResume (yin *) {
    7781                        printf("caught yin, will throw yang\n");
    78                         throwResume a_yang;
     82                        throwResume (yang){};
    7983                } catchResume (yang *) {
    8084                        printf("caught exception from same try\n");
     
    8993                try {
    9094                        printf("throwing first exception\n");
    91                         throwResume a_yin;
     95                        throwResume (yin){};
    9296                } catchResume (yin *) {
    9397                        printf("caught first exception\n");
    9498                        try {
    9599                                printf("throwing second exception\n");
    96                                 throwResume a_yang;
     100                                throwResume (yang){};
    97101                        } catchResume (yang *) {
    98102                                printf("caught second exception\n");
     
    110114        try {
    111115                try {
    112                         throwResume a_zen;
    113                         throwResume a_zen;
     116                        throwResume (zen){};
     117                        throwResume (zen){};
    114118                } catchResume (zen *) {
    115119                        printf("inner catch\n");
    116120                }
    117                 throwResume a_zen;
     121                throwResume (zen){};
    118122        } catchResume (zen *) {
    119123                printf("outer catch\n");
     
    126130// Do a throw and rethrow in a void function.
    127131void in_void(void) {
    128     zen a_zen = {&zen_vt};
    129132        try {
    130133                try {
    131134                        printf("throw\n");
    132                         throwResume a_zen;
     135                        throwResume (zen){};
    133136                } catchResume (zen *) {
    134137                        printf("rethrow\n");
  • tests/exceptions/terminate.cfa

    r5407cdc rfeacef9  
    44#include "except-io.hfa"
    55
    6 EHM_EXCEPTION(yin)();
    7 EHM_EXCEPTION(yang)();
    8 EHM_EXCEPTION(zen)();
    9 
    10 EHM_VIRTUAL_TABLE(yin, yin_vt);
    11 EHM_VIRTUAL_TABLE(yang, yang_vt);
    12 EHM_VIRTUAL_TABLE(zen, zen_vt);
     6TRIVIAL_EXCEPTION(yin);
     7TRIVIAL_EXCEPTION(yang);
     8TRIVIAL_EXCEPTION(zen);
     9TRIVIAL_EXCEPTION(moment_of, zen);
    1310
    1411void in_void(void);
    1512
    1613int main(int argc, char * argv[]) {
    17         yin a_yin = {&yin_vt};
    18         yang a_yang = {&yang_vt};
    19         zen a_zen = {&zen_vt};
    20 
    2114        // The simple throw catch test.
    2215        try {
    2316                loud_exit a = "simple try clause";
    2417                printf("simple throw\n");
    25                 throw a_zen;
     18                throw (zen){};
    2619                printf("end of try clause\n");
    2720        } catch (zen * error) {
     
    3326        // Throw catch-all test.
    3427        try {
    35                 throw a_zen;
     28                throw (zen){};
    3629        } catch (exception_t * error) {
    3730                printf("catch-all\n");
     31        }
     32        printf("\n");
     33
     34        // Catch a parent of the given exception.
     35        try {
     36                printf("throwing child exception\n");
     37                throw (moment_of){};
     38        } catch (zen *) {
     39                printf("inner parent match\n");
     40        } catch (moment_of *) {
     41                printf("outer exact match\n");
    3842        }
    3943        printf("\n");
     
    4246        try {
    4347                try {
    44                         throw a_yin;
     48                        throw (yin){};
    4549                } catch (zen *) {
    4650                        printf("caught yin as zen\n");
     
    5862                        loud_exit a = "rethrow inner try";
    5963                        printf("rethrow inner try\n");
    60                         throw a_zen;
     64                        throw (zen){};
    6165                } catch (zen *) {
    6266                        loud_exit a = "rethrowing catch clause";
     
    7377        try {
    7478                try {
    75                         throw a_yin;
     79                        throw (yin){};
    7680                } catch (yin *) {
    7781                        printf("caught yin, will throw yang\n");
    78                         throw a_yang;
     82                        throw (yang){};
    7983                } catch (yang *) {
    8084                        printf("caught exception from same try\n");
     
    8993                try {
    9094                        printf("throwing first exception\n");
    91                         throw a_yin;
     95                        throw (yin){};
    9296                } catch (yin *) {
    9397                        printf("caught first exception\n");
    9498                        try {
    9599                                printf("throwing second exception\n");
    96                                 throw a_yang;
     100                                throw (yang){};
    97101                        } catch (yang *) {
    98102                                printf("caught second exception\n");
     
    110114        try {
    111115                try {
    112                         throw a_zen;
    113                         throw a_zen;
     116                        throw (zen){};
     117                        throw (zen){};
    114118                } catch (zen *) {
    115119                        printf("inner catch\n");
    116120                }
    117                 throw a_zen;
     121                throw (zen){};
    118122        } catch (zen *) {
    119123                printf("outer catch\n");
     
    126130// Do a throw and rethrow in a void function.
    127131void in_void(void) {
    128         zen a_zen = {&zen_vt};
    129132        try {
    130133                try {
    131134                        printf("throw\n");
    132                         throw a_zen;
     135                        throw (zen){};
    133136                } catch (zen *) {
    134137                        printf("rethrow\n");
  • tests/exceptions/trash.cfa

    r5407cdc rfeacef9  
    33#include <exception.hfa>
    44
    5 EHM_EXCEPTION(yin)();
    6 EHM_EXCEPTION(yang)();
    7 
    8 EHM_VIRTUAL_TABLE(yin, yin_vt);
    9 EHM_VIRTUAL_TABLE(yang, yang_vt);
     5TRIVIAL_EXCEPTION(yin);
     6TRIVIAL_EXCEPTION(yang);
    107
    118int main(int argc, char * argv[]) {
    129        try {
    1310                try {
    14                         throw (yin){&yin_vt};
     11                        throw (yin){};
    1512                } finally {
    1613                        try {
    17                                 throw (yang){&yang_vt};
     14                                throw (yang){};
    1815                        } catch (yin *) {
    1916                                printf("inner yin\n");
  • tests/exceptions/type-check.cfa

    r5407cdc rfeacef9  
    33#include <exception.hfa>
    44
    5 EHM_EXCEPTION(truth)();
     5TRIVIAL_EXCEPTION(truth);
    66
    77int main(int argc, char * argv[]) {
  • tests/exceptions/virtual-cast.cfa

    r5407cdc rfeacef9  
    1212#include <assert.h>
    1313
    14 
    15 
    16 // Hand defined alpha virtual type:
    17 struct __cfatid_struct_alpha {
    18         __cfa__parent_vtable const * parent;
    19 };
    20 
    21 __attribute__(( section(".gnu.linkonce.__cfatid_alpha") ))
    22 struct __cfatid_struct_alpha __cfatid_alpha = {
    23         (__cfa__parent_vtable *)0,
    24 };
    25 
    2614struct alpha_vtable {
    27         struct __cfatid_struct_alpha const * const __cfavir_typeid;
     15        alpha_vtable const * const parent;
    2816        char (*code)(void);
    2917};
     
    3927
    4028
    41 // Hand defined beta virtual type:
    42 struct __cfatid_struct_beta {
    43         __cfatid_struct_alpha const * parent;
    44 };
    45 
    46 __attribute__(( section(".gnu.linkonce.__cfatid_beta") ))
    47 struct __cfatid_struct_beta __cfatid_beta = {
    48         &__cfatid_alpha,
    49 };
    50 
    5129struct beta_vtable {
    52         struct __cfatid_struct_beta const * const __cfavir_typeid;
     30        alpha_vtable const * const parent;
    5331        char (*code)(void);
    5432};
     
    6442
    6543
    66 // Hand defined gamma virtual type:
    67 struct __cfatid_struct_gamma {
    68         __cfatid_struct_beta const * parent;
    69 };
    70 
    71 __attribute__(( section(".gnu.linkonce.__cfatid_gamma") ))
    72 struct __cfatid_struct_gamma __cfatid_gamma = {
    73         &__cfatid_beta,
    74 };
    75 
    7644struct gamma_vtable {
    77         struct __cfatid_struct_gamma const * const __cfavir_typeid;
     45        beta_vtable const * const parent;
    7846        char (*code)(void);
    7947};
     
    8957
    9058extern "C" {
    91         alpha_vtable _alpha_vtable_instance = { &__cfatid_alpha, ret_a };
    92         beta_vtable _beta_vtable_instance = { &__cfatid_beta, ret_b };
    93         gamma_vtable _gamma_vtable_instance = { &__cfatid_gamma, ret_g };
     59        alpha_vtable _alpha_vtable_instance = { 0, ret_a };
     60        beta_vtable _beta_vtable_instance = { &_alpha_vtable_instance, ret_b };
     61        gamma_vtable _gamma_vtable_instance = { &_beta_vtable_instance, ret_g };
    9462}
    9563
  • tests/exceptions/virtual-poly.cfa

    r5407cdc rfeacef9  
    88#include <assert.h>
    99
    10 
    11 struct __cfatid_struct_mono_base {
    12     __cfa__parent_vtable const * parent;
    13 };
    14 
    15 __attribute__(( section(".gnu.linkonce.__cfatid_mono_base") ))
    16 struct __cfatid_struct_mono_base __cfatid_mono_base = {
    17     (__cfa__parent_vtable *)0,
    18 };
    19 
    2010struct mono_base_vtable {
    21         __cfatid_struct_mono_base const * const __cfavir_typeid;
     11        mono_base_vtable const * const parent;
    2212};
    2313
     
    2717
    2818forall(T)
    29 struct __cfatid_struct_mono_child {
    30     __cfatid_struct_mono_base const * parent;
    31 };
    32 
    33 forall(T)
    3419struct mono_child_vtable {
    35         __cfatid_struct_mono_child(T) const * const __cfavir_typeid;
     20        mono_base_vtable const * const parent;
    3621};
    3722
     
    4126};
    4227
    43 __cfatid_struct_mono_child(int) __cfatid_mono_child @= {
    44         &__cfatid_mono_base,
    45 };
    46 
     28mono_base_vtable _mono_base_vtable_instance @= { 0 };
    4729mono_child_vtable(int) _mono_child_vtable_instance @= {
    48         &__cfatid_mono_child,
     30        &_mono_base_vtable_instance
    4931};
    5032
     
    5537}
    5638
    57 
    58 forall(U)
    59 struct __cfatid_struct_poly_base {
    60     __cfa__parent_vtable const * parent;
    61 };
    62 
    6339forall(U)
    6440struct poly_base_vtable {
    65         __cfatid_struct_poly_base(U) const * const __cfavir_typeid;
     41        poly_base_vtable(U) const * const parent;
    6642};
    6743
     
    7248
    7349forall(V)
    74 struct __cfatid_struct_poly_child {
    75     __cfatid_struct_poly_base(V) const * parent;
    76 };
    77 
    78 forall(V)
    7950struct poly_child_vtable {
    80         __cfatid_struct_poly_child(V) const * const __cfavir_typeid;
     51        poly_base_vtable(V) const * const parent;
    8152};
    8253
     
    8657};
    8758
    88 __cfatid_struct_poly_base(int) __cfatid_poly_base @= {
    89         (__cfa__parent_vtable *)0,
     59poly_base_vtable(int) _poly_base_vtable_instance @= { 0 };
     60poly_child_vtable(int) _poly_child_vtable_instance @= {
     61        &_poly_base_vtable_instance
    9062};
    91 __cfatid_struct_poly_child(int) __cfatid_poly_child = {
    92     &__cfatid_poly_base,
     63/* Resolver bug keeps me from adding these.
     64poly_base_vtable(char) _poly_base_vtable_instance @= { 0 };
     65poly_child_vtable(char) _poly_child_vtable_instance @= {
     66        &_poly_base_vtable_instance
    9367};
    94 poly_child_vtable(int) _poly_child_vtable_instance @= {
    95         &__cfatid_poly_child,
    96 };
     68*/
    9769
    9870void poly_poly_test() {
     
    10577        mono_poly_test();
    10678        poly_poly_test();
    107         printf( "done\n" );
     79        printf( "done\n" );                             // non-empty .expect file
    10880}
  • tests/linking/exception-nothreads.cfa

    r5407cdc rfeacef9  
    1717#include <exception.hfa>
    1818
    19 EHM_EXCEPTION(ping)();
    20 EHM_VIRTUAL_TABLE(ping, ping_vt);
     19TRIVIAL_EXCEPTION(ping);
    2120
    2221int main(void) {
    2322        try {
    24                 throwResume (ping){&ping_vt};
     23                throwResume (ping){};
    2524        } catchResume (ping *) {
    2625                printf("%s threads\n", threading_enabled() ? "with" : "no");
  • tests/linking/exception-withthreads.cfa

    r5407cdc rfeacef9  
    1818#include "../exceptions/with-threads.hfa"
    1919
    20 EHM_EXCEPTION(ping)();
    21 EHM_VIRTUAL_TABLE(ping, ping_vt);
     20TRIVIAL_EXCEPTION(ping);
    2221
    2322int main(void) {
    2423        try {
    25                 throwResume (ping){&ping_vt};
     24                throwResume (ping){};
    2625        } catchResume (ping *) {
    2726                printf("%s threads\n", threading_enabled() ? "with" : "no");
  • tests/linking/weakso_nothd.cfa

    r5407cdc rfeacef9  
    66//
    77// weakso_nothd.cfa --
    8 // test whether or not using a weakso locks pulls in threads
     8// test whether or not usind a weakso locks pulls in threads
    99//
    1010// Author           : Thierry Delisle
  • tests/meta/.expect/archVast.nast.arm64.txt

    r5407cdc rfeacef9  
    77  char Alternatives are:
    88Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    9       Variable Expression: FA64: double
     9      Variable Expression: FA64: signed int
    1010      ... with resolved type:
    11         double
     11        signed int
    1212    ... to:
    1313      char
     
    3939
    4040Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
    41       Variable Expression: FA64: signed int
     41      Variable Expression: FA64: double
    4242      ... with resolved type:
    43         signed int
     43        double
    4444    ... to:
    4545      char
  • tests/time.cfa

    r5407cdc rfeacef9  
    1010// Created On       : Tue Mar 27 17:24:56 2018
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Apr 16 14:59:53 2021
    13 // Update Count     : 38
     12// Last Modified On : Thu Jun 18 18:14:49 2020
     13// Update Count     : 37
    1414//
    1515
     
    5353        //       | "Newfoundland" | getTime( Newfoundland )
    5454        //       | "local" | getTime()
    55         //       | "local nsec" | timeHiRes()
     55        //       | "local nsec" | getTimeNsec()
    5656        //       | "PST" | PST();                                                               // getTime short form
    5757        // sout | nl;
  • tests/unified_locking/.expect/locks.txt

    r5407cdc rfeacef9  
    1111Start Test 6: owner lock and condition variable 3 wait/notify all
    1212Done Test 6
    13 Start Test 7: fast lock and condition variable single wait/notify
     13Start Test 7: multi acquisiton lock and condition variable multiple acquire and wait/notify
    1414Done Test 7
    15 Start Test 8: fast lock and condition variable 3 wait/notify all
     15Start Test 8: owner lock and condition variable multiple acquire and wait/notify
    1616Done Test 8
    17 Start Test 9: multi acquisiton lock and condition variable multiple acquire and wait/notify
     17Start Test 9: no lock condition variable wait/notify
    1818Done Test 9
    19 Start Test 10: owner lock and condition variable multiple acquire and wait/notify
     19Start Test 10: locked condition variable wait/notify with front()
    2020Done Test 10
    21 Start Test 11: no lock condition variable wait/notify
    22 Done Test 11
    23 Start Test 12: locked condition variable wait/notify with front()
    24 Done Test 12
  • tests/unified_locking/locks.cfa

    r5407cdc rfeacef9  
    1515condition_variable( owner_lock ) c_o;
    1616
    17 fast_lock f;
    18 condition_variable( fast_lock ) c_f;
    19 
    2017thread T_C_M_WS1 {};
    2118
     
    7168                }
    7269                unlock(s);
    73         }
    74 }
    75 
    76 thread T_C_F_WS1 {};
    77 
    78 void main( T_C_F_WS1 & this ) {
    79         for (unsigned int i = 0; i < num_times; i++) {
    80                 lock(f);
    81                 if(empty(c_f) && i != num_times - 1) {
    82                         wait(c_f,f);
    83                 }else{
    84                         notify_one(c_f);
    85                 }
    86                 unlock(f);
    87         }
    88 }
    89 
    90 thread T_C_F_WB1 {};
    91 
    92 void main( T_C_F_WB1 & this ) {
    93         for (unsigned int i = 0; i < num_times; i++) {
    94                 lock(f);
    95                 if(counter(c_f) == 3 || i == num_times - 1) {
    96                         notify_all(c_f);
    97                 }else{
    98                         wait(c_f,f);
    99                 }
    100                 unlock(f);
    10170        }
    10271}
     
    286255        printf("Done Test 6\n");
    287256
    288         printf("Start Test 7: fast lock and condition variable single wait/notify\n");
    289         {
    290                 T_C_F_WS1 t1[2];
     257        printf("Start Test 7: multi acquisiton lock and condition variable multiple acquire and wait/notify\n");
     258        {
     259                T_C_M_WS2 t1[2];
    291260        }
    292261        printf("Done Test 7\n");
    293262
    294         printf("Start Test 8: fast lock and condition variable 3 wait/notify all\n");
    295         {
    296                 T_C_F_WB1 t1[4];
     263        printf("Start Test 8: owner lock and condition variable multiple acquire and wait/notify\n");
     264        {
     265                T_C_O_WS2 t1[2];
    297266        }
    298267        printf("Done Test 8\n");
    299268
    300         printf("Start Test 9: multi acquisiton lock and condition variable multiple acquire and wait/notify\n");
    301         {
    302                 T_C_M_WS2 t1[2];
    303         }
    304         printf("Done Test 9\n");
    305 
    306         printf("Start Test 10: owner lock and condition variable multiple acquire and wait/notify\n");
    307         {
    308                 T_C_O_WS2 t1[2];
    309         }
    310         printf("Done Test 10\n");
    311 
    312         printf("Start Test 11: no lock condition variable wait/notify\n");
     269        printf("Start Test 9: no lock condition variable wait/notify\n");
    313270        {
    314271                T_C_NLW t1;
    315272                T_C_NLS t2;
    316273        }
    317         printf("Done Test 11\n");
    318 
    319         printf("Start Test 12: locked condition variable wait/notify with front()\n");
     274        printf("Done Test 9\n");
     275
     276        printf("Start Test 10: locked condition variable wait/notify with front()\n");
    320277        {
    321278                T_C_S_WNF t1[2];
    322279        }
    323         printf("Done Test 12\n");
     280        printf("Done Test 10\n");
    324281
    325282        // removed to limit test duration. Full test is in long run tests
  • tests/vector_math/.expect/vec4_float.txt

    r5407cdc rfeacef9  
    66zero-assign:<0.,0.,0.,0.>
    77fill-ctor:<1.23,1.23,1.23,1.23>
    8 ?-?:<0.02,0.43,-0.999998,-1e-06>
    9 ?-=?:<0.02,0.43,-0.999998,-1e-06>
    10 -?:<-0.02,-0.43,0.999998,1e-06>
     8?-?:<0.02,0.43,-0.999998,-1e-06.>
     9?-=?:<0.02,0.43,-0.999998,-1e-06.>
     10-?:<-0.02,-0.43,0.999998,1e-06.>
    1111?+?:<2.3,2.45,-9.2,-12.5>
    1212?+=?:<2.3,2.45,-9.2,-12.5>
  • tools/gdb/utils-gdb.py

    r5407cdc rfeacef9  
    2323gdb.execute('handle SIGUSR1 nostop noprint pass')
    2424
    25 CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state yield_state')
     25CfaTypes = collections.namedtuple('CfaTypes', 'cluster_ptr processor_ptr thread_ptr int_ptr thread_state')
    2626
    2727class ThreadInfo:
     
    5252        # GDB types for various structures/types in CFA
    5353        return CfaTypes(cluster_ptr = gdb.lookup_type('struct cluster').pointer(),
    54                 processor_ptr = gdb.lookup_type('struct processor').pointer(),
    55                 thread_ptr = gdb.lookup_type('struct $thread').pointer(),
    56                 int_ptr = gdb.lookup_type('int').pointer(),
    57                 thread_state = gdb.lookup_type('enum __Coroutine_State'),
    58                 yield_state = gdb.lookup_type('enum __Preemption_Reason'))
     54                                  processor_ptr = gdb.lookup_type('struct processor').pointer(),
     55                                         thread_ptr = gdb.lookup_type('struct $thread').pointer(),
     56                                                int_ptr = gdb.lookup_type('int').pointer(),
     57                                   thread_state = gdb.lookup_type('enum __Coroutine_State'))
    5958
    6059def get_addr(addr):
     
    372371        def print_thread(self, thread, tid, marked):
    373372                cfa_t = get_cfa_types()
    374                 ys = str(thread['preempted'].cast(cfa_t.yield_state))
    375                 if ys == '_X15__NO_PREEMPTIONKM19__Preemption_Reason_1':
    376                         state = str(thread['state'].cast(cfa_t.thread_state))
    377                 elif ys == '_X18__ALARM_PREEMPTIONKM19__Preemption_Reason_1':
    378                         state = 'preempted'
    379                 elif ys == '_X19__MANUAL_PREEMPTIONKM19__Preemption_Reason_1':
    380                         state = 'yield'
    381                 elif ys == '_X17__POLL_PREEMPTIONKM19__Preemption_Reason_1':
    382                         state = 'poll'
    383                 else:
    384                         print("error: thread {} in undefined preemption state {}".format(thread, ys))
    385                         state = 'error'
    386                 self.print_formatted(marked, tid, thread['self_cor']['name'].string(), state, str(thread))
     373                self.print_formatted(marked, tid, thread['self_cor']['name'].string(), str(thread['state'].cast(cfa_t.thread_state)), str(thread))
    387374
    388375        def print_threads_by_cluster(self, cluster, print_system = False):
     
    493480                context = thread['context']
    494481
    495 
     482                # lookup for sp,fp and uSwitch
     483                xsp = context['SP'] + 48
     484                xfp = context['FP']
     485
     486                # convert string so we can strip out the address
     487                try:
     488                        xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address + 28)
     489                except:
     490                        print("here")
     491                        return
    496492
    497493                # must be at frame 0 to set pc register
    498494                gdb.execute('select-frame 0')
    499                 if gdb.selected_frame().architecture().name() != 'i386:x86-64':
    500                         print('gdb debugging only supported for i386:x86-64 for now')
    501                         return
    502 
    503                 # gdb seems to handle things much better if we pretend we just entered the context switch
    504                 # pretend the pc is __cfactx_switch and adjust the sp, base pointer doesn't need to change
    505                 # lookup for sp,fp and uSwitch
    506                 xsp = context['SP'] + 40 # 40 = 5 64bit registers : %r15, %r14, %r13, %r12, %rbx WARNING: x64 specific
    507                 xfp = context['FP']
    508 
    509                 # convert string so we can strip out the address
    510                 try:
    511                         xpc = get_addr(gdb.parse_and_eval('__cfactx_switch').address)
    512                 except:
    513                         print("here")
    514                         return
    515495
    516496                # push sp, fp, pc into a global stack
     
    523503
    524504                # update registers for new task
    525                 # print('switching to {} ({}) : [{}, {}, {}]'.format(thread['self_cor']['name'].string(), str(thread), str(xsp), str(xfp), str(xpc)))
    526                 print('switching to thread {} ({})'.format(str(thread), thread['self_cor']['name'].string()))
     505                print('switching to ')
    527506                gdb.execute('set $rsp={}'.format(xsp))
    528507                gdb.execute('set $rbp={}'.format(xfp))
     
    573552
    574553                argv = parse(arg)
     554                print(argv)
    575555                if argv[0].isdigit():
    576556                        cname = " ".join(argv[1:]) if len(argv) > 1 else None
Note: See TracChangeset for help on using the changeset viewer.