Changeset 6e1e2d0


Ignore:
Timestamp:
May 1, 2023, 4:19:09 PM (2 years ago)
Author:
caparsons <caparson@…>
Branches:
ADT, ast-experimental, master
Children:
c083c3d
Parents:
a50fdfb (diff), 985b624 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

resolved merge conflicts

Files:
7 added
1 deleted
86 edited

Legend:

Unmodified
Added
Removed
  • Jenkins/FullBuild

    ra50fdfb r6e1e2d0  
    2020                                        gcc_08_x86_new: { trigger_build( 'gcc-10',  'x86', false ) },
    2121                                        gcc_07_x86_new: { trigger_build( 'gcc-9',   'x86', false ) },
     22                                        gcc_11_x64_new: { trigger_build( 'gcc-11',  'x64', false ) },
    2223                                        gcc_10_x64_new: { trigger_build( 'gcc-10',  'x64', false ) },
    2324                                        gcc_09_x64_new: { trigger_build( 'gcc-9',   'x64', false ) },
    2425                                        gcc_08_x64_new: { trigger_build( 'gcc-8',   'x64', false ) },
    2526                                        gcc_07_x64_new: { trigger_build( 'gcc-7',   'x64', false ) },
    26                                         gcc_06_x64_new: { trigger_build( 'gcc-6',   'x64', false ) },
     27                                        // gcc_06_x64_new: { trigger_build( 'gcc-6',   'x64', false ) },
    2728                                        clang_x64_new:  { trigger_build( 'clang',   'x64', true  ) },
    2829                                )
     
    4142        }
    4243
    43         //If an exception is caught we need to change the status and remember to
    44         //attach the build log to the email
     44        // If an exception is caught we need to change the status and remember to
     45        // attach the build log to the email
    4546        catch (Exception caughtError) {
    4647                echo('error caught')
     
    7374        // Run the build
    7475        // Don't propagate, it doesn't play nice with our email setup
    75         def result = build job: 'Cforall/master',               \
     76        def result = build job: 'Cforall/master',                       \
    7677                parameters: [                                           \
    7778                        [$class: 'StringParameterValue',                \
     
    8384                        [$class: 'BooleanParameterValue',               \
    8485                          name: 'NewAST',                               \
    85                           value: true],                                         \
     86                          value: true],                                 \
    8687                        [$class: 'BooleanParameterValue',               \
    8788                          name: 'RunAllTests',                          \
    88                           value: true],                                         \
     89                          value: true],                                 \
    8990                        [$class: 'BooleanParameterValue',               \
    9091                          name: 'RunBenchmark',                         \
    91                           value: true],                                         \
     92                          value: true],                                 \
    9293                        [$class: 'BooleanParameterValue',               \
    93                           name: 'BuildDocumentation',           \
     94                          name: 'BuildDocumentation',                   \
    9495                          value: doc],                                  \
    9596                        [$class: 'BooleanParameterValue',               \
    9697                          name: 'Publish',                              \
    97                           value: true],                                         \
     98                          value: true],                                 \
    9899                        [$class: 'BooleanParameterValue',               \
    99100                          name: 'Silent',                               \
    100                           value: true],                                         \
    101                 ],                                                              \
     101                          value: true],                                 \
     102                ],                                                      \
    102103                propagate: false
    103104
     
    111112
    112113def trigger_dist(String commitId, String buildNum) {
    113         def result = build job: 'Cforall_Distribute_Ref',       \
     114        def result = build job: 'Cforall_Distribute_Ref',               \
    114115                parameters: [                                           \
    115116                        string(name: 'GitRef', value: commitId),        \
    116                         string(name: 'Build' , value: buildNum) \
    117                 ],                                                              \
     117                        string(name: 'Build' , value: buildNum)         \
     118                ],                                                      \
    118119                propagate: false
    119120
  • Jenkinsfile

    ra50fdfb r6e1e2d0  
    305305                                this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7', '-flto=auto')
    306306                        break
    307                         case 'gcc-6':
    308                                 this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6', '-flto=auto')
    309                         break
    310                         case 'gcc-5':
    311                                 this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5', '-flto=auto')
    312                         break
    313                         case 'gcc-4.9':
    314                                 this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9', '-flto=auto')
    315                         break
     307                        // case 'gcc-6':
     308                        //      this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6', '-flto=auto')
     309                        // break
     310                        // case 'gcc-5':
     311                        //      this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5', '-flto=auto')
     312                        // break
     313                        // case 'gcc-4.9':
     314                        //      this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9', '-flto=auto')
     315                        // break
    316316                        case 'clang':
    317317                                this.Compiler = new CC_Desc('clang', 'clang++-10', 'gcc-10', '-flto=thin -flto-jobs=0')
     
    359359def prepare_build() {
    360360        // prepare the properties
    361         properties ([                                                                                                   \
    362                 buildDiscarder(logRotator(                                                                              \
    363                         artifactDaysToKeepStr: '',                                                                      \
    364                         artifactNumToKeepStr: '',                                                                       \
    365                         daysToKeepStr: '730',                                                                           \
    366                         numToKeepStr: '1000'                                                                            \
    367                 )),                                                                                                             \
    368                 [$class: 'ParametersDefinitionProperty',                                                                \
    369                         parameterDefinitions: [                                                                         \
    370                                 [$class: 'ChoiceParameterDefinition',                                           \
    371                                         description: 'Which compiler to use',                                   \
    372                                         name: 'Compiler',                                                                       \
    373                                         choices: 'gcc-11\ngcc-10\ngcc-9\ngcc-8\ngcc-7\ngcc-6\ngcc-5\ngcc-4.9\nclang',   \
    374                                         defaultValue: 'gcc-8',                                                          \
    375                                 ],                                                                                              \
    376                                 [$class: 'ChoiceParameterDefinition',                                           \
    377                                         description: 'The target architecture',                                 \
    378                                         name: 'Architecture',                                                           \
    379                                         choices: 'x64\nx86',                                                            \
    380                                         defaultValue: 'x64',                                                            \
    381                                 ],                                                                                              \
    382                                 [$class: 'BooleanParameterDefinition',                                                  \
     361        properties ([                                                                           \
     362                buildDiscarder(logRotator(                                                      \
     363                        artifactDaysToKeepStr: '',                                              \
     364                        artifactNumToKeepStr: '',                                               \
     365                        daysToKeepStr: '730',                                                   \
     366                        numToKeepStr: '1000'                                                    \
     367                )),                                                                             \
     368                [$class: 'ParametersDefinitionProperty',                                        \
     369                        parameterDefinitions: [                                                 \
     370                                [$class: 'ChoiceParameterDefinition',                           \
     371                                        description: 'Which compiler to use',                   \
     372                                        name: 'Compiler',                                       \
     373                                        choices: 'gcc-11\ngcc-10\ngcc-9\ngcc-8\ngcc-7\nclang',  \
     374                                        defaultValue: 'gcc-9',                                  \
     375                                ],                                                              \
     376                                [$class: 'ChoiceParameterDefinition',                           \
     377                                        description: 'The target architecture',                 \
     378                                        name: 'Architecture',                                   \
     379                                        choices: 'x64\nx86',                                    \
     380                                        defaultValue: 'x64',                                    \
     381                                ],                                                              \
     382                                [$class: 'BooleanParameterDefinition',                          \
    383383                                        description: 'If false, the test suite is only ran in debug',   \
    384                                         name: 'RunAllTests',                                                            \
    385                                         defaultValue: false,                                                            \
    386                                 ],                                                                                              \
    387                                 [$class: 'BooleanParameterDefinition',                                                  \
    388                                         description: 'If true, jenkins also runs benchmarks',           \
    389                                         name: 'RunBenchmark',                                                           \
    390                                         defaultValue: false,                                                            \
    391                                 ],                                                                                              \
    392                                 [$class: 'BooleanParameterDefinition',                                                  \
    393                                         description: 'If true, jenkins also builds documentation',              \
    394                                         name: 'BuildDocumentation',                                                     \
    395                                         defaultValue: true,                                                             \
    396                                 ],                                                                                              \
    397                                 [$class: 'BooleanParameterDefinition',                                                  \
    398                                         description: 'If true, jenkins also publishes results',                 \
    399                                         name: 'Publish',                                                                        \
    400                                         defaultValue: false,                                                            \
    401                                 ],                                                                                              \
    402                                 [$class: 'BooleanParameterDefinition',                                                  \
    403                                         description: 'If true, jenkins will not send emails',           \
    404                                         name: 'Silent',                                                                         \
    405                                         defaultValue: false,                                                            \
    406                                 ],                                                                                              \
     384                                        name: 'RunAllTests',                                    \
     385                                        defaultValue: false,                                    \
     386                                ],                                                              \
     387                                [$class: 'BooleanParameterDefinition',                          \
     388                                        description: 'If true, jenkins also runs benchmarks',   \
     389                                        name: 'RunBenchmark',                                   \
     390                                        defaultValue: false,                                    \
     391                                ],                                                              \
     392                                [$class: 'BooleanParameterDefinition',                          \
     393                                        description: 'If true, jenkins also builds documentation', \
     394                                        name: 'BuildDocumentation',                             \
     395                                        defaultValue: true,                                     \
     396                                ],                                                              \
     397                                [$class: 'BooleanParameterDefinition',                          \
     398                                        description: 'If true, jenkins also publishes results', \
     399                                        name: 'Publish',                                        \
     400                                        defaultValue: false,                                    \
     401                                ],                                                              \
     402                                [$class: 'BooleanParameterDefinition',                          \
     403                                        description: 'If true, jenkins will not send emails',   \
     404                                        name: 'Silent',                                         \
     405                                        defaultValue: false,                                    \
     406                                ],                                                              \
    407407                        ],
    408408                ]])
     409                                        // choices: 'gcc-11\ngcc-10\ngcc-9\ngcc-8\ngcc-7\ngcc-6\ngcc-5\ngcc-4.9\nclang',
     410                                        // defaultValue: 'gcc-8',
    409411
    410412        // It's unfortunate but it looks like we need to checkout the entire repo just to get
  • doc/bibliography/pl.bib

    ra50fdfb r6e1e2d0  
    74537453}
    74547454
     7455@inproceedings{Kahn74,
     7456    keywords    = {programming language, obect-oriented, polymorphism},
     7457    contributer = {pabuhr@plg},
     7458    title       = {The Semantics of a Simple Language for Parallel Programming},
     7459    author      = {Gilles Kahn},
     7460    booktitle   = {IFIP Congress},
     7461    year        = 1974,
     7462}
     7463
    74557464@article{Baker78,
    74567465    keywords    = {Algol display, FUNARG's, Lisp 1.5, deep binding, environment trees, multiprogramming, shallow binding},
  • doc/theses/colby_parsons_MMAth/.gitignore

    ra50fdfb r6e1e2d0  
    1 build/*.aux
    2 build/*.acn
    3 build/*.acr
    4 build/*.alg
    5 build/*.bbl
    6 build/*.blg
    7 build/*.brf
    8 build/*.dvi
    9 build/*.glg
    10 build/*.glo
    11 build/*.gls
    12 build/*.idx
    13 build/*.ind
    14 build/*.ist
    15 build/*.lof
    16 build/*.log
    17 build/*.lol
    18 build/*.lot
    19 build/*.out
    20 build/*.ps
    21 build/*.pstex
    22 build/*.pstex_t
    23 build/*.tex
    24 build/*.toc
     1# Intermediate Results:
     2build/
     3
     4# Final Files:
    255*.pdf
    26 *.png
    276*.ps
    28 figures/*.tex
    297
    30 examples
     8# The Makefile here is not generated.
     9!Makefile
  • doc/theses/colby_parsons_MMAth/benchmarks/actors/data/nasus_CFA.txt

    ra50fdfb r6e1e2d0  
    115
    221 2 4 8 16 24 32 48
    3 CFA-LV CFA-NS CFA-R
     3Longest-Victim No-Stealing Random
    44executor
    5 CFA-LV:
     5Longest-Victim:
    66proc    time (s)
    771       29.22
     
    454548      1.20
    464648      1.20
    47 CFA-NS:
     47No-Stealing:
    4848proc    time (s)
    49491       28.25
     
    878748      1.18
    888848      1.16
    89 CFA-R:
     89Random:
    9090proc    time (s)
    91911       28.58
     
    131131
    132132matrix
    133 CFA-LV:
     133Longest-Victim:
    134134proc    time (s)
    1351351       105.48
     
    17317348      2.75
    17417448      2.96
    175 CFA-NS:
     175No-Stealing:
    176176proc    time (s)
    1771771       106.01
     
    21521548      2.78
    21621648      2.92
    217 CFA-R:
     217Random:
    218218proc    time (s)
    2192191       105.91
     
    259259
    260260repeat
    261 CFA-LV:
     261Longest-Victim:
    262262proc    time (s)
    2632631       1.17
     
    30130148      13.73
    30230248      14.55
    303 CFA-NS:
     303No-Stealing:
    304304proc    time (s)
    3053051       1.15
     
    34334348      13.03
    34434448      12.83
    345 CFA-R:
     345Random:
    346346proc    time (s)
    3473471       1.15
     
    387387
    388388balance_one
    389 CFA-LV:
     389Longest-Victim:
    390390proc    time (s)
    3913911       20.06
     
    42942948      1.11
    43043048      1.12
    431 CFA-NS:
     431No-Stealing:
    432432proc    time (s)
    4334331       20.13
     
    47147148      19.95
    47247248      20.00
    473 CFA-R:
     473Random:
    474474proc    time (s)
    4754751       19.92
     
    515515
    516516balance_multi
    517 CFA-LV:
     517Longest-Victim:
    518518proc    time (s)
    5195191       8.17
     
    55755748      5.75
    55855848      5.68
    559 CFA-NS:
     559No-Stealing:
    560560proc    time (s)
    5615611       8.10
     
    59959948      9.28
    60060048      9.26
    601 CFA-R:
     601Random:
    602602proc    time (s)
    6036031       8.08
  • doc/theses/colby_parsons_MMAth/benchmarks/actors/data/pyke_CFA.txt

    ra50fdfb r6e1e2d0  
    115
    221 2 4 8 16 24 32 48
    3 CFA-LV CFA-NS CFA-R
     3Longest-Victim No-Stealing Random
    44executor
    5 CFA-LV:
     5Longest-Victim:
    66proc    time (s)
    771       29.04
     
    454548      2.58
    464648      2.55
    47 CFA-NS:
     47No-Stealing:
    4848proc    time (s)
    49491       28.15
     
    878748      2.59
    888848      2.60
    89 CFA-R:
     89Random:
    9090proc    time (s)
    91911       29.06
     
    131131
    132132matrix
    133 CFA-LV:
     133Longest-Victim:
    134134proc    time (s)
    1351351       127.44
     
    17317348      6.83
    17417448      6.81
    175 CFA-NS:
     175No-Stealing:
    176176proc    time (s)
    1771771       127.64
     
    21521548      6.77
    21621648      6.74
    217 CFA-R:
     217Random:
    218218proc    time (s)
    2192191       127.26
     
    259259
    260260repeat
    261 CFA-LV:
     261Longest-Victim:
    262262proc    time (s)
    2632631       1.16
     
    30130148      19.75
    30230248      19.71
    303 CFA-NS:
     303No-Stealing:
    304304proc    time (s)
    3053051       1.18
     
    34334348      13.88
    34434448      13.71
    345 CFA-R:
     345Random:
    346346proc    time (s)
    3473471       1.18
     
    387387
    388388balance_one
    389 CFA-LV:
     389Longest-Victim:
    390390proc    time (s)
    3913911       19.46
     
    42942948      2.12
    43043048      2.17
    431 CFA-NS:
     431No-Stealing:
    432432proc    time (s)
    4334331       21.00
     
    47147148      47.50
    47247248      47.72
    473 CFA-R:
     473Random:
    474474proc    time (s)
    4754751       20.81
     
    515515
    516516balance_multi
    517 CFA-LV:
     517Longest-Victim:
    518518proc    time (s)
    5195191       7.94
     
    55755748      14.38
    55855848      14.50
    559 CFA-NS:
     559No-Stealing:
    560560proc    time (s)
    5615611       8.48
     
    59959948      21.50
    60060048      21.15
    601 CFA-R:
     601Random:
    602602proc    time (s)
    6036031       8.49
  • doc/theses/colby_parsons_MMAth/benchmarks/channels/plotData.py

    ra50fdfb r6e1e2d0  
    7070    if currBench == Bench.Unset:
    7171        if line == "contend:":
    72             name = "Contend"
     72            name = "Channel Contention"
    7373            currBench = Bench.Contend
    7474        elif line == "zero:":
  • doc/theses/colby_parsons_MMAth/code/swap_queues.cfa

    ra50fdfb r6e1e2d0  
    1 // this is a code stub and will not compile
    2 
    3 // tries to atomically swap two queues and returns 0p if the swap failed
    4 // returns ptr to newly owned queue if swap succeeds
    5 static inline work_queue * try_swap_queues( worker & this, unsigned int victim_idx, unsigned int my_idx ) with(this) {
     1// sequential equivalent swap
     2void swap( uint victim_idx, uint my_idx  ) {
     3    // Step 0:
    64    work_queue * my_queue = request_queues[my_idx];
    7     work_queue * other_queue = request_queues[victim_idx];
    8 
    9     // if either queue is 0p then they are in the process of being stolen
    10     if ( other_queue == 0p || my_queue == 0p ) return 0p;
    11 
    12     // try to set our queue ptr to be 0p. If it fails someone moved our queue so return false
    13     if ( !__atomic_compare_exchange_n( &request_queues[my_idx], &my_queue, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) )
    14         return 0p;
    15 
    16     // try to set other queue ptr to be our queue ptr. If it fails someone moved the other queue so fix up then return false
    17     if ( !__atomic_compare_exchange_n( &request_queues[victim_idx], &other_queue, my_queue, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) {
    18         /* paranoid */ verify( request_queues[my_idx] == 0p );
    19         request_queues[my_idx] = my_queue; // reset my queue ptr back to appropriate val
    20         return 0p;
    21     }
    22 
    23     // we have successfully swapped and since our queue is 0p no one will touch it so write back new queue ptr non atomically
    24     request_queues[my_idx] = other_queue; // last write does not need to be atomic
    25     return other_queue;
     5    work_queue * vic_queue = request_queues[victim_idx];
     6    // Step 2:
     7    request_queues[my_idx] = 0p;
     8    // Step 3:
     9    request_queues[victim_idx] = my_queue;
     10    // Step 4:
     11    request_queues[my_idx] = vic_queue;
    2612}
    2713
     
    3521
    3622bool try_swap_queues( worker & this, uint victim_idx, uint my_idx ) with(this) {
     23    // Step 0:
     24    // request_queues is the shared array of all sharded queues
    3725    work_queue * my_queue = request_queues[my_idx];
    3826    work_queue * vic_queue = request_queues[victim_idx];
    3927
     28    // Step 1:
    4029    // If either queue is 0p then they are in the process of being stolen
    4130    // 0p is CForAll's equivalent of C++'s nullptr
    42     if ( vic_queue == 0p || my_queue == 0p ) return false;
     31    if ( vic_queue == 0p ) return false;
    4332
    44     // Try to set our queue ptr to be 0p.
    45     // If this CAS fails someone moved our queue so return false
     33    // Step 2:
     34    // Try to set thief's queue ptr to be 0p.
     35    // If this CAS fails someone stole thief's queue so return false
    4636    if ( !CAS( &request_queues[my_idx], &my_queue, 0p ) )
    4737        return false;
    48 
    49     // Try to set other queue ptr to be our queue ptr.
    50     // If it fails someone moved the other queue, so fix up then return false
     38   
     39    // Step 3:
     40    // Try to set victim queue ptr to be thief's queue ptr.
     41    // If it fails someone stole the other queue, so fix up then return false
    5142    if ( !CAS( &request_queues[victim_idx], &vic_queue, my_queue ) ) {
    5243        request_queues[my_idx] = my_queue; // reset queue ptr back to prev val
     
    5445    }
    5546
     47    // Step 4:
    5648    // Successfully swapped.
    57     // Our queue is 0p so no one will touch it so write back without CAS is safe
     49    // Thief's ptr is 0p so no one will touch it
     50    // Write back without CAS is safe
    5851    request_queues[my_idx] = vic_queue;
    5952    return true;
  • doc/theses/colby_parsons_MMAth/style/style.tex

    ra50fdfb r6e1e2d0  
    33\lstset{language=CFA}                                   % default language
    44
     5\newcommand{\newtermFont}{\emph}
     6\newcommand{\Newterm}[1]{\newtermFont{#1}}
     7
    58\newcommand{\code}[1]{\lstinline[language=CFA]{#1}}
    69\newcommand{\uC}{$\mu$\CC}
     10\newcommand{\PAB}[1]{{\color{red}PAB: #1}}
    711
     12\newsavebox{\myboxA}                                    % used with subfigure
     13\newsavebox{\myboxB}
     14
     15\lstnewenvironment{java}[1][]
     16{\lstset{language=java,moredelim=**[is][\protect\color{red}]{@}{@}}\lstset{#1}}
     17{}
  • doc/theses/colby_parsons_MMAth/text/actors.tex

    ra50fdfb r6e1e2d0  
    9090\begin{cfa}
    9191struct derived_actor {
    92     inline actor;       // Plan-9 C inheritance
     92        inline actor;      // Plan-9 C inheritance
    9393};
    9494void ?{}( derived_actor & this ) { // Default ctor
    95     ((actor &)this){};  // Call to actor ctor
     95        ((actor &)this){};  // Call to actor ctor
    9696}
    9797
    9898struct derived_msg {
    99     inline message;    // Plan-9 C nominal inheritance
    100     char word[12];
     99        inline message; // Plan-9 C nominal inheritance
     100        char word[12];
    101101};
    102102void ?{}( derived_msg & this, char * new_word ) { // Overloaded ctor
    103     ((message &) this){ Nodelete }; // Passing allocation to ctor
    104     strcpy(this.word, new_word);
     103        ((message &) this){ Nodelete }; // Passing allocation to ctor
     104        strcpy(this.word, new_word);
    105105}
    106106
    107107Allocation receive( derived_actor & receiver, derived_msg & msg ) {
    108     printf("The message contained the string: %s\n", msg.word);
    109     return Finished; // Return finished since actor is done
     108        printf("The message contained the string: %s\n", msg.word);
     109        return Finished; // Return finished since actor is done
    110110}
    111111
    112112int main() {
    113     start_actor_system(); // Sets up executor
    114     derived_actor my_actor;       
    115     derived_msg my_msg{ "Hello World" }; // Constructor call
    116     my_actor << my_msg;   // Send message via left shift operator
    117     stop_actor_system(); // Waits until actors are finished
    118     return 0;
     113        start_actor_system(); // Sets up executor
     114        derived_actor my_actor;         
     115        derived_msg my_msg{ "Hello World" }; // Constructor call
     116        my_actor << my_msg;   // Send message via left shift operator
     117        stop_actor_system(); // Waits until actors are finished
     118        return 0;
    119119}
    120120\end{cfa}
     
    229229\section{Envelopes}\label{s:envelope}
    230230In actor systems messages are sent and received by actors.
    231 When a actor receives a message it  executes its behaviour that is associated with that message type.
     231When a actor receives a message it executes its behaviour that is associated with that message type.
    232232However the unit of work that stores the message, the receiving actor's address, and other pertinent information needs to persist between send and the receive.
    233233Furthermore the unit of work needs to be able to be stored in some fashion, usually in a queue, until it is executed by an actor.
     
    301301While other systems are concerned with stealing actors, the \CFA actor system steals queues.
    302302This is a result of \CFA's use of the inverted actor system.
    303  The goal of the \CFA actor work stealing mechanism is to have a zero-victim-cost stealing mechanism.
     303The goal of the \CFA actor work stealing mechanism is to have a zero-victim-cost stealing mechanism.
    304304This does not means that stealing has no cost.
    305305This goal is to ensure that stealing work does not impact the performance of victim workers.
     
    369369
    370370\begin{cfa}
    371 void swap( uint victim_idx, uint my_idx  ) {
    372     // Step 0:
    373     work_queue * my_queue = request_queues[my_idx];
    374     work_queue * vic_queue = request_queues[victim_idx];
    375     // Step 2:
    376     request_queues[my_idx] = 0p;
    377     // Step 3:
    378     request_queues[victim_idx] = my_queue;
    379     // Step 4:
    380     request_queues[my_idx] = vic_queue;
     371void swap( uint victim_idx, uint my_idx ) {
     372        // Step 0:
     373        work_queue * my_queue = request_queues[my_idx];
     374        work_queue * vic_queue = request_queues[victim_idx];
     375        // Step 2:
     376        request_queues[my_idx] = 0p;
     377        // Step 3:
     378        request_queues[victim_idx] = my_queue;
     379        // Step 4:
     380        request_queues[my_idx] = vic_queue;
    381381}
    382382\end{cfa}
     
    389389// This routine is atomic
    390390bool CAS( work_queue ** ptr, work_queue ** old, work_queue * new ) {
    391     if ( *ptr != *old )
    392         return false;
    393     *ptr = new;
    394     return true;
     391        if ( *ptr != *old )
     392                return false;
     393        *ptr = new;
     394        return true;
    395395}
    396396
    397397bool try_swap_queues( worker & this, uint victim_idx, uint my_idx ) with(this) {
    398     // Step 0:
    399     // request_queues is the shared array of all sharded queues
    400     work_queue * my_queue = request_queues[my_idx];
    401     work_queue * vic_queue = request_queues[victim_idx];
    402 
    403     // Step 1:
    404     // If either queue is 0p then they are in the process of being stolen
    405     // 0p is CForAll's equivalent of C++'s nullptr
    406     if ( vic_queue == 0p ) return false;
    407 
    408     // Step 2:
    409     // Try to set thief's queue ptr to be 0p.
    410     // If this CAS fails someone stole thief's queue so return false
    411     if ( !CAS( &request_queues[my_idx], &my_queue, 0p ) )
    412         return false;
    413    
    414     // Step 3:
    415     // Try to set victim queue ptr to be thief's queue ptr.
    416     // If it fails someone stole the other queue, so fix up then return false
    417     if ( !CAS( &request_queues[victim_idx], &vic_queue, my_queue ) ) {
    418         request_queues[my_idx] = my_queue; // reset queue ptr back to prev val
    419         return false;
    420     }
    421 
    422     // Step 4:
    423     // Successfully swapped.
    424     // Thief's ptr is 0p so no one will touch it
    425     // Write back without CAS is safe
    426     request_queues[my_idx] = vic_queue;
    427     return true;
     398        // Step 0:
     399        // request_queues is the shared array of all sharded queues
     400        work_queue * my_queue = request_queues[my_idx];
     401        work_queue * vic_queue = request_queues[victim_idx];
     402
     403        // Step 1:
     404        // If either queue is 0p then they are in the process of being stolen
     405        // 0p is CForAll's equivalent of C++'s nullptr
     406        if ( vic_queue == 0p ) return false;
     407
     408        // Step 2:
     409        // Try to set thief's queue ptr to be 0p.
     410        // If this CAS fails someone stole thief's queue so return false
     411        if ( !CAS( &request_queues[my_idx], &my_queue, 0p ) )
     412                return false;
     413       
     414        // Step 3:
     415        // Try to set victim queue ptr to be thief's queue ptr.
     416        // If it fails someone stole the other queue, so fix up then return false
     417        if ( !CAS( &request_queues[victim_idx], &vic_queue, my_queue ) ) {
     418                request_queues[my_idx] = my_queue; // reset queue ptr back to prev val
     419                return false;
     420        }
     421
     422        // Step 4:
     423        // Successfully swapped.
     424        // Thief's ptr is 0p so no one will touch it
     425        // Write back without CAS is safe
     426        request_queues[my_idx] = vic_queue;
     427        return true;
    428428}
    429429\end{cfa}\label{c:swap}
     
    706706\label{t:StaticActorMessagePerformance}
    707707\begin{tabular}{*{5}{r|}r}
    708     & \multicolumn{1}{c|}{\CFA (100M)} & \multicolumn{1}{c|}{CAF (10M)} & \multicolumn{1}{c|}{Akka (100M)} & \multicolumn{1}{c|}{\uC (100M)} & \multicolumn{1}{c@{}}{ProtoActor (100M)} \\
    709     \hline                                                                                                                                         
    710     AMD         & \input{data/pykeSendStatic} \\
    711     \hline                                                                                                                                         
    712     Intel       & \input{data/nasusSendStatic}
     708        & \multicolumn{1}{c|}{\CFA (100M)} & \multicolumn{1}{c|}{CAF (10M)} & \multicolumn{1}{c|}{Akka (100M)} & \multicolumn{1}{c|}{\uC (100M)} & \multicolumn{1}{c@{}}{ProtoActor (100M)} \\
     709        \hline                                                                                                                                                 
     710        AMD             & \input{data/pykeSendStatic} \\
     711        \hline                                                                                                                                                 
     712        Intel   & \input{data/nasusSendStatic}
    713713\end{tabular}
    714714
     
    719719
    720720\begin{tabular}{*{5}{r|}r}
    721     & \multicolumn{1}{c|}{\CFA (20M)} & \multicolumn{1}{c|}{CAF (2M)} & \multicolumn{1}{c|}{Akka (2M)} & \multicolumn{1}{c|}{\uC (20M)} & \multicolumn{1}{c@{}}{ProtoActor (2M)} \\
    722     \hline                                                                                                                                         
    723     AMD         & \input{data/pykeSendDynamic} \\
    724     \hline                                                                                                                                         
    725     Intel       & \input{data/nasusSendDynamic}
     721        & \multicolumn{1}{c|}{\CFA (20M)} & \multicolumn{1}{c|}{CAF (2M)} & \multicolumn{1}{c|}{Akka (2M)} & \multicolumn{1}{c|}{\uC (20M)} & \multicolumn{1}{c@{}}{ProtoActor (2M)} \\
     722        \hline                                                                                                                                                 
     723        AMD             & \input{data/pykeSendDynamic} \\
     724        \hline                                                                                                                                                 
     725        Intel   & \input{data/nasusSendDynamic}
    726726\end{tabular}
    727727\end{table}
     
    745745In the static send benchmark all systems except CAF have static send costs that are in the same ballpark, only varying by ~70ns.
    746746In the dynamic send benchmark all systems experience slower message sends, as expected due to the extra allocations.
    747 However,  Akka and ProtoActor, slow down by a more significant margin than the \uC and \CFA.
     747However, Akka and ProtoActor, slow down by a more significant margin than the \uC and \CFA.
    748748This is likely a result of Akka and ProtoActor's garbage collection, which can suffer from hits in performance for allocation heavy workloads, whereas \uC and \CFA have explicit allocation/deallocation.
    749749
     
    753753
    754754\begin{figure}
    755     \centering
    756     \begin{subfigure}{0.5\textwidth}
    757         \centering
    758         \scalebox{0.5}{\input{figures/nasusCFABalance-One.pgf}}
    759         \subcaption{AMD \CFA Balance-One Benchmark}
    760         \label{f:BalanceOneAMD}
    761     \end{subfigure}\hfill
    762     \begin{subfigure}{0.5\textwidth}
    763         \centering
    764         \scalebox{0.5}{\input{figures/pykeCFABalance-One.pgf}}
    765         \subcaption{Intel \CFA Balance-One Benchmark}
    766         \label{f:BalanceOneIntel}
    767     \end{subfigure}
    768     \caption{The balance-one benchmark comparing stealing heuristics (lower is better).}
    769 \end{figure}
    770 
    771 \begin{figure}
    772     \centering
    773     \begin{subfigure}{0.5\textwidth}
    774         \centering
    775         \scalebox{0.5}{\input{figures/nasusCFABalance-Multi.pgf}}
    776         \subcaption{AMD \CFA Balance-Multi Benchmark}
    777         \label{f:BalanceMultiAMD}
    778     \end{subfigure}\hfill
    779     \begin{subfigure}{0.5\textwidth}
    780         \centering
    781         \scalebox{0.5}{\input{figures/pykeCFABalance-Multi.pgf}}
    782         \subcaption{Intel \CFA Balance-Multi Benchmark}
    783         \label{f:BalanceMultiIntel}
    784     \end{subfigure}
    785     \caption{The balance-multi benchmark comparing stealing heuristics (lower is better).}
     755        \centering
     756        \subfloat[AMD \CFA Balance-One Benchmark]{
     757                \resizebox{0.5\textwidth}{!}{\input{figures/nasusCFABalance-One.pgf}}
     758                \label{f:BalanceOneAMD}
     759        }
     760        \subfloat[Intel \CFA Balance-One Benchmark]{
     761                \resizebox{0.5\textwidth}{!}{\input{figures/pykeCFABalance-One.pgf}}
     762                \label{f:BalanceOneIntel}
     763        }
     764        \caption{The balance-one benchmark comparing stealing heuristics (lower is better).}
     765\end{figure}
     766
     767\begin{figure}
     768        \centering
     769        \subfloat[AMD \CFA Balance-Multi Benchmark]{
     770                \resizebox{0.5\textwidth}{!}{\input{figures/nasusCFABalance-Multi.pgf}}
     771                \label{f:BalanceMultiAMD}
     772        }
     773        \subfloat[Intel \CFA Balance-Multi Benchmark]{
     774                \resizebox{0.5\textwidth}{!}{\input{figures/pykeCFABalance-Multi.pgf}}
     775                \label{f:BalanceMultiIntel}
     776        }
     777        \caption{The balance-multi benchmark comparing stealing heuristics (lower is better).}
    786778\end{figure}
    787779
     
    817809
    818810\begin{figure}
    819     \centering
    820     \begin{subfigure}{0.5\textwidth}
    821         \centering
    822         \scalebox{0.5}{\input{figures/nasusExecutor.pgf}}
    823         \subcaption{AMD Executor Benchmark}
    824         \label{f:ExecutorAMD}
    825     \end{subfigure}\hfill
    826     \begin{subfigure}{0.5\textwidth}
    827         \centering
    828         \scalebox{0.5}{\input{figures/pykeExecutor.pgf}}
    829         \subcaption{Intel Executor Benchmark}
    830         \label{f:ExecutorIntel}
    831     \end{subfigure}
    832     \caption{The executor benchmark comparing actor systems (lower is better).}
     811        \centering
     812        \subfloat[AMD Executor Benchmark]{
     813                \resizebox{0.5\textwidth}{!}{\input{figures/nasusExecutor.pgf}}
     814                \label{f:ExecutorAMD}
     815        }
     816        \subfloat[Intel Executor Benchmark]{
     817                \resizebox{0.5\textwidth}{!}{\input{figures/pykeExecutor.pgf}}
     818                \label{f:ExecutorIntel}
     819        }
     820        \caption{The executor benchmark comparing actor systems (lower is better).}
    833821\end{figure}
    834822
     
    840828
    841829\begin{figure}
    842     \centering
    843     \begin{subfigure}{0.5\textwidth}
    844         \centering
    845         \scalebox{0.5}{\input{figures/nasusCFAExecutor.pgf}}
    846         \subcaption{AMD \CFA Executor Benchmark}\label{f:cfaExecutorAMD}
    847     \end{subfigure}\hfill
    848     \begin{subfigure}{0.5\textwidth}
    849         \centering
    850         \scalebox{0.5}{\input{figures/pykeCFAExecutor.pgf}}
    851         \subcaption{Intel \CFA Executor Benchmark}\label{f:cfaExecutorIntel}
    852     \end{subfigure}
    853     \caption{Executor benchmark comparing \CFA stealing heuristics (lower is better).}
     830        \centering
     831        \subfloat[AMD \CFA Executor Benchmark]{
     832                \resizebox{0.5\textwidth}{!}{\input{figures/nasusCFAExecutor.pgf}}
     833                \label{f:cfaExecutorAMD}
     834        }
     835        \subfloat[Intel \CFA Executor Benchmark]{
     836                \resizebox{0.5\textwidth}{!}{\input{figures/pykeCFAExecutor.pgf}}
     837                \label{f:cfaExecutorIntel}
     838        }
     839        \caption{Executor benchmark comparing \CFA stealing heuristics (lower is better).}
    854840\end{figure}
    855841
     
    857843
    858844\begin{figure}
    859     \centering
    860     \begin{subfigure}{0.5\textwidth}
    861         \centering
    862         \scalebox{0.5}{\input{figures/nasusRepeat.pgf}}
    863         \subcaption{AMD Repeat Benchmark}\label{f:RepeatAMD}
    864     \end{subfigure}\hfill
    865     \begin{subfigure}{0.5\textwidth}
    866         \centering
    867         \scalebox{0.5}{\input{figures/pykeRepeat.pgf}}
    868         \subcaption{Intel Repeat Benchmark}\label{f:RepeatIntel}
    869     \end{subfigure}
    870     \caption{The repeat benchmark comparing actor systems (lower is better).}
     845        \centering
     846        \subfloat[AMD Repeat Benchmark]{
     847                \resizebox{0.5\textwidth}{!}{\input{figures/nasusRepeat.pgf}}
     848                \label{f:RepeatAMD}
     849        }
     850        \subfloat[Intel Repeat Benchmark]{
     851                \resizebox{0.5\textwidth}{!}{\input{figures/pykeRepeat.pgf}}
     852                \label{f:RepeatIntel}
     853        }
     854        \caption{The repeat benchmark comparing actor systems (lower is better).}
    871855\end{figure}
    872856
     
    881865
    882866\begin{figure}
    883     \centering
    884     \begin{subfigure}{0.5\textwidth}
    885         \centering
    886         \scalebox{0.5}{\input{figures/nasusCFARepeat.pgf}}
    887         \subcaption{AMD \CFA Repeat Benchmark}\label{f:cfaRepeatAMD}
    888     \end{subfigure}\hfill
    889     \begin{subfigure}{0.5\textwidth}
    890         \centering
    891         \scalebox{0.5}{\input{figures/pykeCFARepeat.pgf}}
    892         \subcaption{Intel \CFA Repeat Benchmark}\label{f:cfaRepeatIntel}
    893     \end{subfigure}
    894     \caption{The repeat benchmark comparing \CFA stealing heuristics (lower is better).}
     867        \centering
     868        \subfloat[AMD \CFA Repeat Benchmark]{
     869                \resizebox{0.5\textwidth}{!}{\input{figures/nasusCFARepeat.pgf}}
     870                \label{f:cfaRepeatAMD}
     871        }
     872        \subfloat[Intel \CFA Repeat Benchmark]{
     873                \resizebox{0.5\textwidth}{!}{\input{figures/pykeCFARepeat.pgf}}
     874                \label{f:cfaRepeatIntel}
     875        }
     876        \caption{The repeat benchmark comparing \CFA stealing heuristics (lower is better).}
    895877\end{figure}
    896878
     
    913895
    914896\begin{table}[t]
    915     \centering
    916     \setlength{\extrarowheight}{2pt}
    917     \setlength{\tabcolsep}{5pt}
    918    
    919     \caption{Executor Program Memory High Watermark}
    920     \label{t:ExecutorMemory}
    921     \begin{tabular}{*{5}{r|}r}
    922         & \multicolumn{1}{c|}{\CFA} & \multicolumn{1}{c|}{CAF} & \multicolumn{1}{c|}{Akka} & \multicolumn{1}{c|}{\uC} & \multicolumn{1}{c@{}}{ProtoActor} \\
    923         \hline                                                                                                                                     
    924         AMD             & \input{data/pykeExecutorMem} \\
    925         \hline                                                                                                                                     
    926         Intel   & \input{data/nasusExecutorMem}
    927     \end{tabular}
     897        \centering
     898        \setlength{\extrarowheight}{2pt}
     899        \setlength{\tabcolsep}{5pt}
     900       
     901        \caption{Executor Program Memory High Watermark}
     902        \label{t:ExecutorMemory}
     903        \begin{tabular}{*{5}{r|}r}
     904                & \multicolumn{1}{c|}{\CFA} & \multicolumn{1}{c|}{CAF} & \multicolumn{1}{c|}{Akka} & \multicolumn{1}{c|}{\uC} & \multicolumn{1}{c@{}}{ProtoActor} \\
     905                \hline                                                                                                                                                 
     906                AMD             & \input{data/pykeExecutorMem} \\
     907                \hline                                                                                                                                                 
     908                Intel   & \input{data/nasusExecutorMem}
     909        \end{tabular}
    928910\end{table}
    929911
     
    951933
    952934\begin{figure}
    953     \centering
    954     \begin{subfigure}{0.5\textwidth}
    955         \centering
    956         \scalebox{0.5}{\input{figures/nasusMatrix.pgf}}
    957         \subcaption{AMD Matrix Benchmark}\label{f:MatrixAMD}
    958     \end{subfigure}\hfill
    959     \begin{subfigure}{0.5\textwidth}
    960         \centering
    961         \scalebox{0.5}{\input{figures/pykeMatrix.pgf}}
    962         \subcaption{Intel Matrix Benchmark}\label{f:MatrixIntel}
    963     \end{subfigure}
    964     \caption{The matrix benchmark comparing actor systems (lower is better).}
    965 \end{figure}
    966 
    967 \begin{figure}
    968     \centering
    969     \begin{subfigure}{0.5\textwidth}
    970         \centering
    971         \scalebox{0.5}{\input{figures/nasusCFAMatrix.pgf}}
    972         \subcaption{AMD \CFA Matrix Benchmark}\label{f:cfaMatrixAMD}
    973     \end{subfigure}\hfill
    974     \begin{subfigure}{0.5\textwidth}
    975         \centering
    976         \scalebox{0.5}{\input{figures/pykeCFAMatrix.pgf}}
    977         \subcaption{Intel \CFA Matrix Benchmark}\label{f:cfaMatrixIntel}
    978     \end{subfigure}
    979     \caption{The matrix benchmark comparing \CFA stealing heuristics (lower is better).}
    980 \end{figure}
     935        \centering
     936        \subfloat[AMD Matrix Benchmark]{
     937                \resizebox{0.5\textwidth}{!}{\input{figures/nasusMatrix.pgf}}
     938                \label{f:MatrixAMD}
     939        }
     940        \subfloat[Intel Matrix Benchmark]{
     941                \resizebox{0.5\textwidth}{!}{\input{figures/pykeMatrix.pgf}}
     942                \label{f:MatrixIntel}
     943        }
     944        \caption{The matrix benchmark comparing actor systems (lower is better).}
     945\end{figure}
     946
     947\begin{figure}
     948        \centering
     949        \subfloat[AMD \CFA Matrix Benchmark]{
     950                \resizebox{0.5\textwidth}{!}{\input{figures/nasusCFAMatrix.pgf}}
     951                \label{f:cfaMatrixAMD}
     952        }
     953        \subfloat[Intel \CFA Matrix Benchmark]{
     954                \resizebox{0.5\textwidth}{!}{\input{figures/pykeCFAMatrix.pgf}}
     955                \label{f:cfaMatrixIntel}
     956        }
     957        \caption{The matrix benchmark comparing \CFA stealing heuristics (lower is better).}
     958\end{figure}
     959
     960% Local Variables: %
     961% tab-width: 4 %
     962% End: %
  • doc/theses/colby_parsons_MMAth/text/channels.tex

    ra50fdfb r6e1e2d0  
    55% ======================================================================
    66
    7 Channels were first introduced by Hoare in his paper Communicating Sequentual Processes~\cite{Hoare78}, where he proposes a concurrent language that communicates across processes using input/output channels to send data.
    8 Channels are a concurrent language feature used to perform message passing concurrency, a model of concurrency where threads communicate by sending data as messages, and synchronizing via the message passing mechanism.
    9 This is an alternative to shared memory concurrency, where threads can communicate directly by changing shared memory state.
    10 Most modern concurrent programming languages do not subscribe to just one style of communication between threads, and provide features that support both.
     7Channels are a concurrent-language feature used to perform \Newterm{message-passing concurrency}: a model of concurrency where threads communicate by sending (mostly nonblocking) data as messages and synchronizing by receiving (blocking) sent data.
     8This model is an alternative to shared-memory concurrency, where threads can communicate directly by changing shared state.
     9Most modern concurrent programming languages do not subscribe to just one style of communication among threads and provide features that support multiple approaches.
     10
     11Channels were first introduced by Kahn~\cite{Kahn74} and extended by Hoare~\cite{Hoare78} (CSP).
     12Both papers present a pseudo (unimplemented) concurrent language where processes communicate using input/output channels to send data.
     13Both languages are highly restrictive.
     14Kahn's language restricts a reading process to only wait for data on a single channel at a time and different writing processes cannot send data on the same channel.
     15Hoare's language restricts ...
    1116Channels as a programming language feature has been popularized in recent years due to the language Go, which encourages the use of channels as its fundamental concurrent feature.
     17Go's restrictions are ...
     18\CFA channels do not have these restrictions.
    1219
    1320\section{Producer-Consumer Problem}
    14 Most channels in modern programming languages are built on top of a shared memory buffer. 
    15 While it is possible to create a channel that contains an unbounded buffer, most implementations opt to only support a fixed size channel, where the size is given at the time of channel creation. 
    16 This turns the implementation of a channel into the producer-consumer problem. 
    17 The producer-consumer problem, also known as the bounded buffer problem, was introduced by Dijkstra in his book Cooperating Sequential Processes\cite{Dijkstra65}. 
    18 In the problem threads interact with the buffer in two ways, either consuming values by removing them from the buffer, or producing values and inserting them in the buffer. 
    19 The buffer needs to be protected from concurrent access since each item in the buffer should only be produced and consumed once. 
     21Most channels in modern programming languages are built on top of a shared memory buffer.
     22While it is possible to create a channel that contains an unbounded buffer, most implementations opt to only support a fixed size channel, where the size is given at the time of channel creation.
     23This turns the implementation of a channel into the producer-consumer problem.
     24The producer-consumer problem, also known as the bounded buffer problem, was introduced by Dijkstra in his book Cooperating Sequential Processes\cite{Dijkstra65}.
     25In the problem threads interact with the buffer in two ways, either consuming values by removing them from the buffer, or producing values and inserting them in the buffer.
     26The buffer needs to be protected from concurrent access since each item in the buffer should only be produced and consumed once.
    2027Additionally, a consumer can only remove from a non-empty buffer and a producer can only insert into a non-full buffer.
    2128
    2229\section{First-Come First-Served}
    23 The channel implementations that will be discussed are \gls{fcfs}. 
    24 This term was defined by Lamport~\cite{Lamport74}. 
    25 \gls{fcfs} is defined in relation to a doorway~\cite[p.~330]{Lamport86II}, which is the point at which an ordering among threads can be established. 
    26 Given this doorway, a critical section is said to be \gls{fcfs}, if threads access the shared resource in the order they proceed through the doorway. 
    27 \gls{fcfs} is a fairness property which prevents unequal access to the shared resource and prevents starvation, however it can come at a cost. 
    28 Implementing an algorithm with \gls{fcfs} can lead to double blocking, where entering threads may need to block to allow other threads to proceed first, resulting in blocking both inside and outside the doorway. 
     30The channel implementations that will be discussed are \gls{fcfs}.
     31This term was defined by Lamport~\cite{Lamport74}.
     32\gls{fcfs} is defined in relation to a doorway~\cite[p.~330]{Lamport86II}, which is the point at which an ordering among threads can be established.
     33Given this doorway, a critical section is said to be \gls{fcfs}, if threads access the shared resource in the order they proceed through the doorway.
     34\gls{fcfs} is a fairness property which prevents unequal access to the shared resource and prevents starvation, however it can come at a cost.
     35Implementing an algorithm with \gls{fcfs} can lead to double blocking, where entering threads may need to block to allow other threads to proceed first, resulting in blocking both inside and outside the doorway.
    2936As such algorithms that are not \gls{fcfs} may be more performant but that performance comes with the downside of likely introducing starvation and unfairness.
    3037
    3138\section{Channel Implementation}
    32 The channel implementation in \CFA is a near carbon copy of the Go implementation. 
    33 Experimentation was conducted that varied the producer-consumer problem algorithm and lock type used inside the channel. 
    34 With the exception of non-\gls{fcfs} algorithms, no algorithm or lock usage in the channel implementation was found to be consistently more performant that Go's choice of algorithm and lock implementation. 
     39The channel implementation in \CFA is a near carbon copy of the Go implementation.
     40Experimentation was conducted that varied the producer-consumer problem algorithm and lock type used inside the channel.
     41With the exception of non-\gls{fcfs} algorithms, no algorithm or lock usage in the channel implementation was found to be consistently more performant that Go's choice of algorithm and lock implementation.
    3542As such the research contributions added by \CFA's channel implementation lie in the realm of safety and productivity features.
    3643
    3744\section{Safety and Productivity}
    38 Channels in \CFA come with safety and productivity features to aid users. 
     45Channels in \CFA come with safety and productivity features to aid users.
    3946The features include the following.
    4047
    4148\begin{itemize}
    42 \item Toggle-able statistic collection on channel behvaiour that counts channel operations, and the number of the operations that block.
     49\item Toggle-able statistic collection on channel behaviour that counts channel operations, and the number of the operations that block.
    4350Tracking blocking operations helps users tune their channel size or channel usage when the channel is used for buffering, where the aim is to have as few blocking operations as possible.
    44 \item Deadlock detection on deallocation of the channel. 
     51\item Deadlock detection on deallocation of the channel.
    4552If any threads are blocked inside the channel when it terminates it is detected and informs the user, as this would cause a deadlock.
    46 \item A \code{flush} routine that delivers copies of an element to all waiting consumers, flushing the buffer. 
    47 Programmers can use this to easily to broadcast data to multiple consumers. 
    48 Additionally, the \code{flush} routine is more performant then looping around the \code{insert} operation since it can deliver the elements without having to reaquire mutual exclusion for each element sent.
     53\item A \code{flush} routine that delivers copies of an element to all waiting consumers, flushing the buffer.
     54Programmers can use this to easily to broadcast data to multiple consumers.
     55Additionally, the \code{flush} routine is more performant then looping around the \code{insert} operation since it can deliver the elements without having to reacquire mutual exclusion for each element sent.
    4956\end{itemize}
    5057
    51 The other safety and productivity feature of \CFA channels deals with concurrent termination. 
    52 Terminating concurrent programs is often one of the most difficult parts of writing concurrent code, particularly if graceful termination is needed. 
    53 The difficulty of graceful termination often arises from the usage of synchronization primitives which need to be handled carefully during shutdown. 
    54 It is easy to deadlock during termination if threads are left behind on synchronization primitives. 
    55 Additionally, most synchronization primitives are prone to \gls{toctou} issues where there is race between one thread checking the state of a concurrent object and another thread changing the state. 
    56 \gls{toctou} issues with synchronization primitives often involve a race between one thread checking the primitive for blocked threads and another thread blocking on it. 
    57 Channels are a particularly hard synchronization primitive to terminate since both sending and receiving off a channel can block. 
     58The other safety and productivity feature of \CFA channels deals with concurrent termination.
     59Terminating concurrent programs is often one of the most difficult parts of writing concurrent code, particularly if graceful termination is needed.
     60The difficulty of graceful termination often arises from the usage of synchronization primitives which need to be handled carefully during shutdown.
     61It is easy to deadlock during termination if threads are left behind on synchronization primitives.
     62Additionally, most synchronization primitives are prone to \gls{toctou} issues where there is race between one thread checking the state of a concurrent object and another thread changing the state.
     63\gls{toctou} issues with synchronization primitives often involve a race between one thread checking the primitive for blocked threads and another thread blocking on it.
     64Channels are a particularly hard synchronization primitive to terminate since both sending and receiving off a channel can block.
    5865Thus, improperly handled \gls{toctou} issues with channels often result in deadlocks as threads trying to perform the termination may end up unexpectedly blocking in their attempt to help other threads exit the system.
    5966
    6067% C_TODO: add reference to select chapter, add citation to go channels info
    61 Go channels provide a set of tools to help with concurrent shutdown. 
    62 Channels in Go have a \code{close} operation and a \code{select} statement that both can be used to help threads terminate. 
    63 The \code{select} statement will be discussed in \ref{}, where \CFA's \code{waituntil} statement will be compared with the Go \code{select} statement. 
    64 The \code{close} operation on a channel in Go changes the state of the channel. 
    65 When a channel is closed, sends to the channel will panic and additional calls to \code{close} will panic. 
    66 Receives are handled differently where receivers will never block on a closed channel and will continue to remove elements from the channel. 
    67 Once a channel is empty, receivers can continue to remove elements, but will receive the zero-value version of the element type. 
    68 To aid in avoiding unwanted zero-value elements, Go provides the ability to iterate over a closed channel to remove the remaining elements. 
    69 These design choices for Go channels enforce a specific interaction style with channels during termination, where careful thought is needed to ensure that additional \code{close} calls don't occur and that no sends occur after channels are closed. 
    70 These design choices fit Go's paradigm of error management, where users are expected to explicitly check for errors, rather than letting errors occur and catching them. 
    71 If errors need to occur in Go, return codes are used to pass error information where they are needed. 
     68Go channels provide a set of tools to help with concurrent shutdown.
     69Channels in Go have a \code{close} operation and a \code{select} statement that both can be used to help threads terminate.
     70The \code{select} statement will be discussed in \ref{}, where \CFA's \code{waituntil} statement will be compared with the Go \code{select} statement.
     71The \code{close} operation on a channel in Go changes the state of the channel.
     72When a channel is closed, sends to the channel will panic and additional calls to \code{close} will panic.
     73Receives are handled differently where receivers will never block on a closed channel and will continue to remove elements from the channel.
     74Once a channel is empty, receivers can continue to remove elements, but will receive the zero-value version of the element type.
     75To aid in avoiding unwanted zero-value elements, Go provides the ability to iterate over a closed channel to remove the remaining elements.
     76These design choices for Go channels enforce a specific interaction style with channels during termination, where careful thought is needed to ensure that additional \code{close} calls don't occur and that no sends occur after channels are closed.
     77These design choices fit Go's paradigm of error management, where users are expected to explicitly check for errors, rather than letting errors occur and catching them.
     78If errors need to occur in Go, return codes are used to pass error information where they are needed.
    7279Note that panics in Go can be caught, but it is not considered an idiomatic way to write Go programs.
    7380
    74 While Go's channel closing semantics are powerful enough to perform any concurrent termination needed by a program, their lack of ease of use leaves much to be desired. 
    75 Since both closing and sending panic, once a channel is closed, a user often has to synchronize the senders to a channel before the channel can be closed to avoid panics. 
    76 However, in doing so it renders the \code{close} operation nearly useless, as the only utilities it provides are the ability to ensure that receivers no longer block on the channel, and will receive zero-valued elements. 
    77 This can be useful if the zero-typed element is recognized as a sentinel value, but if another sentinel value is preferred, then \code{close} only provides its non-blocking feature. 
    78 To avoid \gls{toctou} issues during shutdown, a busy wait with a \code{select} statement is often used to add or remove elements from a channel. 
     81While Go's channel closing semantics are powerful enough to perform any concurrent termination needed by a program, their lack of ease of use leaves much to be desired.
     82Since both closing and sending panic, once a channel is closed, a user often has to synchronize the senders to a channel before the channel can be closed to avoid panics.
     83However, in doing so it renders the \code{close} operation nearly useless, as the only utilities it provides are the ability to ensure that receivers no longer block on the channel, and will receive zero-valued elements.
     84This can be useful if the zero-typed element is recognized as a sentinel value, but if another sentinel value is preferred, then \code{close} only provides its non-blocking feature.
     85To avoid \gls{toctou} issues during shutdown, a busy wait with a \code{select} statement is often used to add or remove elements from a channel.
    7986Due to Go's asymmetric approach to channel shutdown, separate synchronization between producers and consumers of a channel has to occur during shutdown.
    8087
     
    8289As such \CFA uses an exception based approach to channel shutdown that is symmetric for both producers and consumers, and supports graceful shutdown.Exceptions in \CFA support both termination and resumption.Termination exceptions operate in the same way as exceptions seen in many popular programming languages such as \CC, Python and Java.
    8390Resumption exceptions are a style of exception that when caught run the corresponding catch block in the same way that termination exceptions do.
    84 The difference between the exception handling mechanisms arises after the exception is handled. 
    85 In termination handling, the control flow continues into the code following the catch after the exception is handled. 
    86 In resumption handling, the control flow returns to the site of the \code{throw}, allowing the control to continue where it left off. 
    87 Note that in resumption, since control can return to the point of error propagation, the stack is not unwound during resumption propagation. 
    88 In \CFA if a resumption is not handled, it is reraised as a termination. 
     91The difference between the exception handling mechanisms arises after the exception is handled.
     92In termination handling, the control flow continues into the code following the catch after the exception is handled.
     93In resumption handling, the control flow returns to the site of the \code{throw}, allowing the control to continue where it left off.
     94Note that in resumption, since control can return to the point of error propagation, the stack is not unwound during resumption propagation.
     95In \CFA if a resumption is not handled, it is reraised as a termination.
    8996This mechanism can be used to create a flexible and robust termination system for channels.
    9097
    91 When a channel in \CFA is closed, all subsequent calls to the channel will throw a resumption exception at the caller. 
    92 If the resumption is handled, then the caller will proceed to attempt to complete their operation. 
    93 If the resumption is not handled it is then rethrown as a termination exception. 
    94 Or, if the resumption is handled, but the subsequent attempt at an operation would block, a termination exception is thrown. 
    95 These termination exceptions allow for non-local transfer that can be used to great effect to eagerly and gracefully shut down a thread. 
    96 When a channel is closed, if there are any blocked producers or consumers inside the channel, they are woken up and also have a resumption thrown at them. 
    97 The resumption exception, \code{channel_closed}, has a couple fields to aid in handling the exception. 
    98 The exception contains a pointer to the channel it was thrown from, and a pointer to an element. 
    99 In exceptions thrown from remove the element pointer will be null. 
    100 In the case of insert the element pointer points to the element that the thread attempted to insert. 
    101 This element pointer allows the handler to know which operation failed and also allows the element to not be lost on a failed insert since it can be moved elsewhere in the handler. 
    102 Furthermore, due to \CFA's powerful exception system, this data can be used to choose handlers based which channel and operation failed. 
    103 Exception handlers in \CFA have an optional predicate after the exception type which can be used to optionally trigger or skip handlers based on the content of an exception. 
    104 It is worth mentioning that the approach of exceptions for termination may incur a larger performance cost during termination that the approach used in Go. 
     98When a channel in \CFA is closed, all subsequent calls to the channel will throw a resumption exception at the caller.
     99If the resumption is handled, then the caller will proceed to attempt to complete their operation.
     100If the resumption is not handled it is then rethrown as a termination exception.
     101Or, if the resumption is handled, but the subsequent attempt at an operation would block, a termination exception is thrown.
     102These termination exceptions allow for non-local transfer that can be used to great effect to eagerly and gracefully shut down a thread.
     103When a channel is closed, if there are any blocked producers or consumers inside the channel, they are woken up and also have a resumption thrown at them.
     104The resumption exception, \code{channel_closed}, has a couple fields to aid in handling the exception.
     105The exception contains a pointer to the channel it was thrown from, and a pointer to an element.
     106In exceptions thrown from remove the element pointer will be null.
     107In the case of insert the element pointer points to the element that the thread attempted to insert.
     108This element pointer allows the handler to know which operation failed and also allows the element to not be lost on a failed insert since it can be moved elsewhere in the handler.
     109Furthermore, due to \CFA's powerful exception system, this data can be used to choose handlers based which channel and operation failed.
     110Exception handlers in \CFA have an optional predicate after the exception type which can be used to optionally trigger or skip handlers based on the content of an exception.
     111It is worth mentioning that the approach of exceptions for termination may incur a larger performance cost during termination that the approach used in Go.
    105112This should not be an issue, since termination is rarely an fast-path of an application and ensuring that termination can be implemented correctly with ease is the aim of the exception approach.
    106113
    107 To highlight the differences between \CFA's and Go's close semantics, an example program is presented. 
    108 The program is a barrier implemented using two channels shown in Listings~\ref{l:cfa_chan_bar} and \ref{l:go_chan_bar}. 
    109 Both of these exaples are implmented using \CFA syntax so that they can be easily compared.
    110 Listing~\ref{l:go_chan_bar} uses go-style channel close semantics and Listing~\ref{l:cfa_chan_bar} uses \CFA close semantics. 
    111 In this problem it is infeasible to use the Go \code{close} call since all tasks are both potentially producers and consumers, causing panics on close to be unavoidable. 
    112 As such in Listing~\ref{l:go_chan_bar} to implement a flush routine for the buffer, a sentinel value of $-1$ has to be used to indicate to threads that they need to leave the barrier. 
    113 This sentinel value has to be checked at two points. 
    114 Furthermore, an additional flag \code{done} is needed to communicate to threads once they have left the barrier that they are done. 
    115 This use of an additional flag or communication method is common in Go channel shutdown code, since to avoid panics on a channel, the shutdown of a channel often has to be communicated with threads before it occurs. 
    116 In the \CFA version~\ref{l:cfa_chan_bar}, the barrier shutdown results in an exception being thrown at threads operating on it, which informs the threads that they must terminate. 
    117 This avoids the need to use a separate communication method other than the barrier, and avoids extra conditional checks on the fast path of the barrier implementation. 
     114To highlight the differences between \CFA's and Go's close semantics, an example program is presented.
     115The program is a barrier implemented using two channels shown in Listings~\ref{l:cfa_chan_bar} and \ref{l:go_chan_bar}.
     116Both of these examples are implemented using \CFA syntax so that they can be easily compared.
     117Listing~\ref{l:go_chan_bar} uses go-style channel close semantics and Listing~\ref{l:cfa_chan_bar} uses \CFA close semantics.
     118In this problem it is infeasible to use the Go \code{close} call since all tasks are both potentially producers and consumers, causing panics on close to be unavoidable.
     119As such in Listing~\ref{l:go_chan_bar} to implement a flush routine for the buffer, a sentinel value of $-1$ has to be used to indicate to threads that they need to leave the barrier.
     120This sentinel value has to be checked at two points.
     121Furthermore, an additional flag \code{done} is needed to communicate to threads once they have left the barrier that they are done.
     122This use of an additional flag or communication method is common in Go channel shutdown code, since to avoid panics on a channel, the shutdown of a channel often has to be communicated with threads before it occurs.
     123In the \CFA version~\ref{l:cfa_chan_bar}, the barrier shutdown results in an exception being thrown at threads operating on it, which informs the threads that they must terminate.
     124This avoids the need to use a separate communication method other than the barrier, and avoids extra conditional checks on the fast path of the barrier implementation.
    118125Also note that in the Go version~\ref{l:go_chan_bar}, the size of the barrier channels has to be larger than in the \CFA version to ensure that the main thread does not block when attempting to clear the barrier.
    119126
    120 \begin{cfa}[tabsize=3,caption={\CFA channel barrier termination},label={l:cfa_chan_bar}]
     127\begin{cfa}[caption={\CFA channel barrier termination},label={l:cfa_chan_bar}]
    121128struct barrier {
    122     channel( int ) barWait;
    123     channel( int ) entryWait;
    124     int size;
     129        channel( int ) barWait;
     130        channel( int ) entryWait;
     131        int size;
    125132}
    126133void ?{}(barrier & this, int size) with(this) {
    127     barWait{size};
    128     entryWait{size};
    129     this.size = size;
    130     for ( j; size )
    131         insert( *entryWait, j );
     134        barWait{size};
     135        entryWait{size};
     136        this.size = size;
     137        for ( j; size )
     138                insert( *entryWait, j );
    132139}
    133140
    134141void flush(barrier & this) with(this) {
    135     close(barWait);
    136     close(entryWait);
     142        close(barWait);
     143        close(entryWait);
    137144}
    138145void wait(barrier & this) with(this) {
    139     int ticket = remove( *entryWait );
    140     if ( ticket == size - 1 ) {
    141         for ( j; size - 1 )
    142             insert( *barWait, j );
    143         return;
    144     }
    145     ticket = remove( *barWait );
    146 
    147     // last one out
    148     if ( size == 1 || ticket == size - 2 ) {
    149         for ( j; size )
    150             insert( *entryWait, j );
    151     }
     146        int ticket = remove( *entryWait );
     147        if ( ticket == size - 1 ) {
     148                for ( j; size - 1 )
     149                        insert( *barWait, j );
     150                return;
     151        }
     152        ticket = remove( *barWait );
     153
     154        // last one out
     155        if ( size == 1 || ticket == size - 2 ) {
     156                for ( j; size )
     157                        insert( *entryWait, j );
     158        }
    152159}
    153160barrier b{Tasks};
     
    155162// thread main
    156163void main(Task & this) {
    157     try {
    158         for ( ;; ) {
    159             wait( b );
    160         }
    161     } catch ( channel_closed * e ) {}
     164        try {
     165                for ( ;; ) {
     166                        wait( b );
     167                }
     168        } catch ( channel_closed * e ) {}
    162169}
    163170
    164171int main() {
    165     {
    166         Task t[Tasks];
    167 
    168         sleep(10`s);
    169         flush( b );
    170     } // wait for tasks to terminate
    171     return 0;
     172        {
     173                Task t[Tasks];
     174
     175                sleep(10`s);
     176                flush( b );
     177        } // wait for tasks to terminate
     178        return 0;
    172179}
    173180\end{cfa}
    174181
    175 \begin{cfa}[tabsize=3,caption={Go channel barrier termination},label={l:go_chan_bar}]
     182\begin{cfa}[caption={Go channel barrier termination},label={l:go_chan_bar}]
    176183
    177184struct barrier {
    178     channel( int ) barWait;
    179     channel( int ) entryWait;
    180     int size;
     185        channel( int ) barWait;
     186        channel( int ) entryWait;
     187        int size;
    181188}
    182189void ?{}(barrier & this, int size) with(this) {
    183     barWait{size + 1};
    184     entryWait{size + 1};
    185     this.size = size;
    186     for ( j; size )
    187         insert( *entryWait, j );
     190        barWait{size + 1};
     191        entryWait{size + 1};
     192        this.size = size;
     193        for ( j; size )
     194                insert( *entryWait, j );
    188195}
    189196
    190197void flush(barrier & this) with(this) {
    191     insert( *entryWait, -1 );
    192     insert( *barWait, -1 );
     198        insert( *entryWait, -1 );
     199        insert( *barWait, -1 );
    193200}
    194201void wait(barrier & this) with(this) {
    195     int ticket = remove( *entryWait );
    196     if ( ticket == -1 ) {
    197         insert( *entryWait, -1 );
    198         return;
    199     }
    200     if ( ticket == size - 1 ) {
    201         for ( j; size - 1 )
    202             insert( *barWait, j );
    203         return;
    204     }
    205     ticket = remove( *barWait );
    206     if ( ticket == -1 ) {
    207         insert( *barWait, -1 );
    208         return;
    209     }
    210 
    211     // last one out
    212     if ( size == 1 || ticket == size - 2 ) {
    213         for ( j; size )
    214             insert( *entryWait, j );
    215     }
     202        int ticket = remove( *entryWait );
     203        if ( ticket == -1 ) {
     204                insert( *entryWait, -1 );
     205                return;
     206        }
     207        if ( ticket == size - 1 ) {
     208                for ( j; size - 1 )
     209                        insert( *barWait, j );
     210                return;
     211        }
     212        ticket = remove( *barWait );
     213        if ( ticket == -1 ) {
     214                insert( *barWait, -1 );
     215                return;
     216        }
     217
     218        // last one out
     219        if ( size == 1 || ticket == size - 2 ) {
     220                for ( j; size )
     221                        insert( *entryWait, j );
     222        }
    216223}
    217224barrier b;
     
    220227// thread main
    221228void main(Task & this) {
    222     for ( ;; ) {
    223         if ( done ) break;
    224         wait( b );
    225     }
     229        for ( ;; ) {
     230                if ( done ) break;
     231                wait( b );
     232        }
    226233}
    227234
    228235int main() {
    229     {
    230         Task t[Tasks];
    231 
    232         sleep(10`s);
    233         done = true;
    234 
    235         flush( b );
    236     } // wait for tasks to terminate
    237     return 0;
     236        {
     237                Task t[Tasks];
     238
     239                sleep(10`s);
     240                done = true;
     241
     242                flush( b );
     243        } // wait for tasks to terminate
     244        return 0;
    238245}
    239246\end{cfa}
    240247
    241 In Listing~\ref{l:cfa_resume} an example of channel closing with resumption is used. 
    242 This program uses resumption in the \code{Consumer} thread main to ensure that all elements in the channel are removed before the consumer thread terminates. 
    243 The producer only has a \code{catch} so the moment it receives an exception it terminates, whereas the consumer will continue to remove from the closed channel via handling resumptions until the buffer is empty, which then throws a termination exception. 
     248In Listing~\ref{l:cfa_resume} an example of channel closing with resumption is used.
     249This program uses resumption in the \code{Consumer} thread main to ensure that all elements in the channel are removed before the consumer thread terminates.
     250The producer only has a \code{catch} so the moment it receives an exception it terminates, whereas the consumer will continue to remove from the closed channel via handling resumptions until the buffer is empty, which then throws a termination exception.
    244251If the same program was implemented in Go it would require explicit synchronization with both producers and consumers by some mechanism outside the channel to ensure that all elements were removed before task termination.
    245252
    246 \begin{cfa}[tabsize=3,caption={\CFA channel resumption usage},label={l:cfa_resume}]
     253\begin{cfa}[caption={\CFA channel resumption usage},label={l:cfa_resume}]
    247254channel( int ) chan{ 128 };
    248255
    249256// Consumer thread main
    250257void main(Consumer & this) {
    251     size_t runs = 0;
    252     try {
    253         for ( ;; ) {
    254             remove( chan );
    255         }
    256     } catchResume ( channel_closed * e ) {}
    257     catch ( channel_closed * e ) {}
     258        size_t runs = 0;
     259        try {
     260                for ( ;; ) {
     261                        remove( chan );
     262                }
     263        } catchResume ( channel_closed * e ) {}
     264        catch ( channel_closed * e ) {}
    258265}
    259266
    260267// Producer thread main
    261268void main(Producer & this) {
    262     int j = 0;
    263     try {
    264         for ( ;;j++ ) {
    265             insert( chan, j );
    266         }
    267     } catch ( channel_closed * e ) {}
     269        int j = 0;
     270        try {
     271                for ( ;;j++ ) {
     272                        insert( chan, j );
     273                }
     274        } catch ( channel_closed * e ) {}
    268275}
    269276
    270277int main( int argc, char * argv[] ) {
    271     {
    272         Consumers c[4];
    273         Producer p[4];
    274 
    275         sleep(10`s);
    276 
    277         for ( i; Channels )
    278             close( channels[i] );
    279     }
    280     return 0;
     278        {
     279                Consumers c[4];
     280                Producer p[4];
     281
     282                sleep(10`s);
     283
     284                for ( i; Channels )
     285                        close( channels[i] );
     286        }
     287        return 0;
    281288}
    282289\end{cfa}
     
    284291\section{Performance}
    285292
    286 Given that the base implementation of the \CFA channels is very similar to the Go implementation, this section aims to show that the performance of the two implementations are comparable. 
    287 One microbenchmark is conducted to compare Go and \CFA. 
    288 The benchmark is a ten second experiment where producers and consumers operate on a channel in parallel and throughput is measured. 
    289 The number of cores is varied to measure how throughtput scales.
    290 The cores are divided equally between producers and consumers, with one producer or consumer owning each core. 
    291 The results of the benchmark are shown in Figure~\ref{f:chanPerf}. 
    292 The performance of Go and \CFA channels on this microbenchmark is comparable. 
     293Given that the base implementation of the \CFA channels is very similar to the Go implementation, this section aims to show that the performance of the two implementations are comparable.
     294One microbenchmark is conducted to compare Go and \CFA.
     295The benchmark is a ten second experiment where producers and consumers operate on a channel in parallel and throughput is measured.
     296The number of cores is varied to measure how throughput scales.
     297The cores are divided equally between producers and consumers, with one producer or consumer owning each core.
     298The results of the benchmark are shown in Figure~\ref{f:chanPerf}.
     299The performance of Go and \CFA channels on this microbenchmark is comparable.
    293300Note, it is expected for the performance to decline as the number of cores increases as the channel operations all occur in a critical section so an increase in cores results in higher contention with no increase in parallelism.
    294301
    295302
    296303\begin{figure}
    297     \centering
    298     \begin{subfigure}{0.5\textwidth}
    299         \centering
    300         \scalebox{0.5}{\input{figures/nasus_Channel_Contention.pgf}}
    301         \subcaption{AMD \CFA Channel Benchmark}\label{f:chanAMD}
    302     \end{subfigure}\hfill
    303     \begin{subfigure}{0.5\textwidth}
    304         \centering
    305         \scalebox{0.5}{\input{figures/pyke_Channel_Contention.pgf}}
    306         \subcaption{Intel \CFA Channel Benchmark}\label{f:chanIntel}
    307     \end{subfigure}
    308     \caption{The channel contention benchmark comparing \CFA and Go channel throughput (higher is better).}
    309     \label{f:chanPerf}
     304        \centering
     305        \subfloat[AMD \CFA Channel Benchmark]{
     306                \resizebox{0.5\textwidth}{!}{\input{figures/nasus_Channel_Contention.pgf}}
     307                \label{f:chanAMD}
     308        }
     309        \subfloat[Intel \CFA Channel Benchmark]{
     310                \resizebox{0.5\textwidth}{!}{\input{figures/pyke_Channel_Contention.pgf}}
     311                \label{f:chanIntel}
     312        }
     313        \caption{The channel contention benchmark comparing \CFA and Go channel throughput (higher is better).}
     314        \label{f:chanPerf}
    310315\end{figure}
     316
     317% Local Variables: %
     318% tab-width: 4 %
     319% End: %
  • doc/theses/colby_parsons_MMAth/text/mutex_stmt.tex

    ra50fdfb r6e1e2d0  
    55% ======================================================================
    66
    7 The mutex statement is a concurrent language feature that aims to support easy lock usage.
    8 The mutex statement is in the form of a clause and following statement, similar to a loop or conditional statement.
    9 In the clause the mutex statement accepts a number of lockable objects, and then locks them for the duration of the following statement.
    10 The locks are acquired in a deadlock free manner and released using \gls{raii}.
    11 The mutex statement provides an avenue for easy lock usage in the common case where locks are used to wrap a critical section.
    12 Additionally, it provides the safety guarantee of deadlock-freedom, both by acquiring the locks in a deadlock-free manner, and by ensuring that the locks release on error, or normal program execution via \gls{raii}.
    13 
    14 \begin{cfa}[tabsize=3,caption={\CFA mutex statement usage},label={l:cfa_mutex_ex}]
     7The mutual exclusion problem was introduced by Dijkstra in 1965~\cite{Dijkstra65,Dijkstra65a}.
     8There are several concurrent processes or threads that communicate by shared variables and from time to time need exclusive access to shared resources.
     9A shared resource and code manipulating it form a pairing called a \Newterm{critical section (CS)}, which is a many-to-one relationship;
     10\eg if multiple files are being written to by multiple threads, only the pairings of simultaneous writes to the same files are CSs.
     11Regions of code where the thread is not interested in the resource are combined into the \Newterm{non-critical section (NCS)}.
     12
     13Exclusive access to a resource is provided by \Newterm{mutual exclusion (MX)}.
     14MX is implemented by some form of \emph{lock}, where the CS is bracketed by lock procedures @acquire@ and @release@.
     15Threads execute a loop of the form:
     16\begin{cfa}
     17loop of $thread$ p:
     18        NCS;
     19        acquire( lock );  CS;  release( lock ); // protected critical section with MX
     20end loop.
     21\end{cfa}
     22MX guarantees there is never more than one thread in the CS.
     23MX must also guarantee eventual progress: when there are competing threads attempting access, eventually some competing thread succeeds, \ie acquires the CS, releases it, and returns to the NCS.
     24% Lamport \cite[p.~329]{Lam86mx} extends this requirement to the exit protocol.
     25A stronger constraint is that every thread that calls @acquire@ eventually succeeds after some reasonable bounded time.
     26
     27\section{Monitor}
     28\CFA provides a high-level locking object, called a \Newterm{monitor}, an elegant, efficient, high-level mechanisms for mutual exclusion and synchronization for shared-memory systems.
     29First proposed by Brinch Hansen~\cite{Hansen73} and later described and extended by C.A.R.~Hoare~\cite{Hoare74}, several concurrent programming languages provide monitors as an explicit language construct: \eg Concurrent Pascal~\cite{ConcurrentPascal}, Mesa~\cite{Mesa}, Turing~\cite{Turing:old}, Modula-3~\cite{Modula-3}, \uC~\cite{Buhr92a} and Java~\cite{Java}.
     30In addition, operating-system kernels and device drivers have a monitor-like structure, although they often use lower-level primitives such as mutex locks or semaphores to manually implement a monitor.
     31
     32Figure~\ref{f:AtomicCounter} shows a \CFA and Java monitor implementing an atomic counter.
     33A \Newterm{monitor} is a programming technique that implicitly binds mutual exclusion to static function scope by call and return.
     34Lock mutual exclusion, defined by acquire/release calls, is independent of lexical context (analogous to block versus heap storage allocation).
     35Restricting acquire and release points in a monitor eases programming, comprehension, and maintenance, at a slight cost in flexibility and efficiency.
     36Ultimately, a monitor is implemented using a combination of basic locks and atomic instructions.
     37
     38\begin{figure}
     39\centering
     40
     41\begin{lrbox}{\myboxA}
     42\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     43@monitor@ Aint {
     44        int cnt;
     45};
     46int ++?( Aint & @mutex@ m ) { return ++m.cnt; }
     47int ?=?( Aint & @mutex@ l, int r ) { l.cnt = r; }
     48int ?=?(int & l, Aint & r) { l = r.cnt; }
     49
     50int i = 0, j = 0;
     51Aint x = { 0 }, y = { 0 };      $\C[1.5in]{// no mutex}$
     52++x;  ++y;                      $\C{// mutex}$
     53x = 2;  y = i;          $\C{// mutex}$
     54i = x;  j = y;          $\C{// no mutex}\CRT$
     55\end{cfa}
     56\end{lrbox}
     57
     58\begin{lrbox}{\myboxB}
     59\begin{java}[aboveskip=0pt,belowskip=0pt]
     60class Aint {
     61        private int cnt;
     62        public Aint( int init ) { cnt = init; }
     63        @synchronized@ public int inc() { return ++cnt; }
     64        @synchronized@ public void set( int r ) {cnt = r;}
     65        public int get() { return cnt; }
     66}
     67int i = 0, j = 0;
     68Aint x = new Aint( 0 ), y = new Aint( 0 );
     69x.inc();  y.inc();
     70x.set( 2 );  y.set( i );
     71i = x.get();  j = y.get();
     72\end{java}
     73\end{lrbox}
     74
     75\subfloat[\CFA]{\label{f:AtomicCounterCFA}\usebox\myboxA}
     76\hspace*{3pt}
     77\vrule
     78\hspace*{3pt}
     79\subfloat[Java]{\label{f:AtomicCounterJava}\usebox\myboxB}
     80\caption{Atomic integer counter}
     81\label{f:AtomicCounter}
     82\end{figure}
     83
     84Like Java, \CFA monitors have \Newterm{multi-acquire} semantics so the thread in the monitor may acquire it multiple times without deadlock, allowing recursion and calling other MX functions.
     85For robustness, \CFA monitors ensure the monitor lock is released regardless of how an acquiring function ends, normal or exceptional, and returning a shared variable is safe via copying before the lock is released.
     86Monitor objects can be passed through multiple helper functions without acquiring mutual exclusion, until a designated function associated with the object is called.
     87\CFA functions are designated MX by one or more pointer/reference parameters having qualifier @mutex@.
     88Java members are designated MX with \lstinline[language=java]{synchronized}, which applies only to the implicit receiver parameter.
     89In the example, the increment and setter operations need mutual exclusion, while the read-only getter operation is not MX because reading an integer is atomic.
     90
     91As stated, the non-object-oriented nature of \CFA monitors allows a function to acquire multiple mutex objects.
     92For example, the bank-transfer problem requires locking two bank accounts to safely debit and credit money between accounts.
     93\begin{cfa}
     94monitor BankAccount {
     95        int balance;
     96};
     97void deposit( BankAccount & mutex b, int deposit ) with( b ) {
     98        balance += deposit;
     99}
     100void transfer( BankAccount & mutex my, BankAccount & mutex your, int me2you ) {
     101        deposit( my, -me2you );         $\C{// debit}$
     102        deposit( your, me2you );        $\C{// credit}$
     103}
     104\end{cfa}
     105The \CFA monitor implementation ensures multi-lock acquisition is done in a deadlock-free manner regardless of the number of MX parameters and monitor arguments.
     106
     107
     108\section{\lstinline{mutex} statement}
     109Restricting implicit lock acquisition to function entry and exit can be awkward for certain problems.
     110To increase locking flexibility, some languages introduce a mutex statement.
     111\VRef[Figure]{f:ReadersWriter} shows the outline of a reader/writer lock written as a \CFA monitor and mutex statements.
     112(The exact lock implement is irrelevant.)
     113The @read@ and @write@ functions are called with a reader/write lock and any arguments to perform reading or writing.
     114The @read@ function is not MX because multiple readers can read simultaneously.
     115MX is acquired within @read@ by calling the (nested) helper functions @StartRead@ and @EndRead@ or executing the mutex statements.
     116Between the calls or statements, reads can execute simultaneous within the body of @read@.
     117The @write@ function does not require refactoring because writing is a CS.
     118The mutex-statement version is better because it has fewer names, less argument/parameter passing, and can possibly hold MX for a shorter duration.
     119
     120\begin{figure}
     121\centering
     122
     123\begin{lrbox}{\myboxA}
     124\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     125monitor RWlock { ... };
     126void read( RWlock & rw, ... ) {
     127        void StartRead( RWlock & @mutex@ rw ) { ... }
     128        void EndRead( RWlock & @mutex@ rw ) { ... }
     129        StartRead( rw );
     130        ... // read without MX
     131        EndRead( rw );
     132}
     133void write( RWlock & @mutex@ rw, ... ) {
     134        ... // write with MX
     135}
     136\end{cfa}
     137\end{lrbox}
     138
     139\begin{lrbox}{\myboxB}
     140\begin{cfa}[aboveskip=0pt,belowskip=0pt]
     141
     142void read( RWlock & rw, ... ) {
     143
     144
     145        @mutex@( rw ) { ... }
     146        ... // read without MX
     147        @mutex@{ rw ) { ... }
     148}
     149void write( RWlock & @mutex@ rw, ... ) {
     150        ... // write with MX
     151}
     152\end{cfa}
     153\end{lrbox}
     154
     155\subfloat[monitor]{\label{f:RWmonitor}\usebox\myboxA}
     156\hspace*{3pt}
     157\vrule
     158\hspace*{3pt}
     159\subfloat[mutex statement]{\label{f:RWmutexstmt}\usebox\myboxB}
     160\caption{Readers writer problem}
     161\label{f:ReadersWriter}
     162\end{figure}
     163
     164This work adds a mutex statement to \CFA, but generalizes it beyond implicit monitor locks.
     165In detail, the mutex statement has a clause and statement block, similar to a conditional or loop statement.
     166The clause accepts any number of lockable objects (like a \CFA MX function prototype), and locks them for the duration of the statement.
     167The locks are acquired in a deadlock free manner and released regardless of how control-flow exits the statement.
     168The mutex statement provides easy lock usage in the common case of lexically wrapping a CS.
     169Examples of \CFA mutex statement are shown in \VRef[Listing]{l:cfa_mutex_ex}.
     170
     171\begin{cfa}[caption={\CFA mutex statement usage},label={l:cfa_mutex_ex}]
    15172owner_lock lock1, lock2, lock3;
    16 int count = 0;
    17 mutex( lock1, lock2, lock3 ) {
    18     // can use block statement
    19     // ...
    20 }
    21 mutex( lock2, lock3 ) count++; // or inline statement
     173@mutex@( lock2, lock3 ) ...;    $\C{// inline statement}$
     174@mutex@( lock1, lock2, lock3 ) { ... }  $\C{// statement block}$
     175void transfer( BankAccount & my, BankAccount & your, int me2you ) {
     176        ... // check values, no MX
     177        @mutex@( my, your ) { // MX is shorter duration that function body
     178                deposit( my, -me2you );  $\C{// debit}$
     179                deposit( your, me2you ); $\C{// credit}$
     180        }
     181}
    22182\end{cfa}
    23183
    24184\section{Other Languages}
    25 There are similar concepts to the mutex statement that exist in other languages.
    26 Java has a feature called a synchronized statement, which looks identical to \CFA's mutex statement, but it has some differences.
    27 The synchronized statement only accepts a single object in its clause.
    28 Any object can be passed to the synchronized statement in Java since all objects in Java are monitors, and the synchronized statement acquires that object's monitor.
    29 In \CC there is a feature in the standard library \code{<mutex>} header called scoped\_lock, which is also similar to the mutex statement.
    30 The scoped\_lock is a class that takes in any number of locks in its constructor, and acquires them in a deadlock-free manner.
    31 It then releases them when the scoped\_lock object is deallocated, thus using \gls{raii}.
    32 An example of \CC scoped\_lock usage is shown in Listing~\ref{l:cc_scoped_lock}.
    33 
    34 \begin{cfa}[tabsize=3,caption={\CC scoped\_lock usage},label={l:cc_scoped_lock}]
    35 std::mutex lock1, lock2, lock3;
    36 {
    37     scoped_lock s( lock1, lock2, lock3 )
    38     // locks are released via raii at end of scope
    39 }
     185There are similar constructs to the mutex statement in other programming languages.
     186Java has a feature called a synchronized statement, which looks like the \CFA's mutex statement, but only accepts a single object in the clause and only handles monitor locks.
     187The \CC standard library has a @scoped_lock@, which is also similar to the mutex statement.
     188The @scoped_lock@ takes any number of locks in its constructor, and acquires them in a deadlock-free manner.
     189It then releases them when the @scoped_lock@ object is deallocated using \gls{raii}.
     190An example of \CC @scoped_lock@ is shown in \VRef[Listing]{l:cc_scoped_lock}.
     191
     192\begin{cfa}[caption={\CC \lstinline{scoped_lock} usage},label={l:cc_scoped_lock}]
     193struct BankAccount {
     194        @recursive_mutex m;@            $\C{// must be recursive}$
     195        int balance = 0;
     196};
     197void deposit( BankAccount & b, int deposit ) {
     198        @scoped_lock lock( b.m );@      $\C{// RAII acquire}$
     199        b.balance += deposit;
     200}                                                               $\C{// RAII release}$
     201void transfer( BankAccount & my, BankAccount & your, int me2you ) {
     202        @scoped_lock lock( my.m, your.m );@     $\C{// RAII acquire}$
     203        deposit( my, -me2you );         $\C{// debit}$
     204        deposit( your, me2you );        $\C{// credit}$
     205}                                                               $\C{// RAII release}$
    40206\end{cfa}
    41207
    42208\section{\CFA implementation}
    43 The \CFA mutex statement takes some ideas from both the Java and \CC features.
    44 The mutex statement can acquire more that one lock in a deadlock-free manner, and releases them via \gls{raii} like \CC, however the syntax is identical to the Java synchronized statement.
    45 This syntactic choice was made so that the body of the mutex statement is its own scope.
    46 Compared to the scoped\_lock, which relies on its enclosing scope, the mutex statement's introduced scope can provide visual clarity as to what code is being protected by the mutex statement, and where the mutual exclusion ends.
    47 \CFA's mutex statement and \CC's scoped\_lock both use parametric polymorphism to allow user defined types to work with the feature.
    48 \CFA's implementation requires types to support the routines \code{lock()} and \code{unlock()}, whereas \CC requires those routines, plus \code{try_lock()}.
    49 The scoped\_lock requires an additional routine since it differs from the mutex statement in how it implements deadlock avoidance.
    50 
    51 The parametric polymorphism allows for locking to be defined for types that may want convenient mutual exclusion.
    52 An example of one such use case in \CFA is \code{sout}.
    53 The output stream in \CFA is called \code{sout}, and functions similarly to \CC's \code{cout}.
    54 \code{sout} has routines that satisfy the mutex statement trait, so the mutex statement can be used to lock the output stream while producing output.
    55 In this case, the mutex statement allows the programmer to acquire mutual exclusion over an object without having to know the internals of the object or what locks need to be acquired.
    56 The ability to do so provides both improves safety and programmer productivity since it abstracts away the concurrent details and provides an interface for optional thread-safety.
    57 This is a commonly used feature when producing output from a concurrent context, since producing output is not thread safe by default.
    58 This use case is shown in Listing~\ref{l:sout}.
    59 
    60 \begin{cfa}[tabsize=3,caption={\CFA sout with mutex statement},label={l:sout}]
    61 mutex( sout )
    62     sout | "This output is protected by mutual exclusion!";
    63 \end{cfa}
    64 
    65 \section{Deadlock Avoidance}
    66 The mutex statement uses the deadlock prevention technique of lock ordering, where the circular-wait condition of a deadlock cannot occur if all locks are acquired in the same order.
    67 The scoped\_lock uses a deadlock avoidance algorithm where all locks after the first are acquired using \code{try_lock} and if any of the attempts to lock fails, all locks so far are released.
    68 This repeats until all locks are acquired successfully.
    69 The deadlock avoidance algorithm used by scoped\_lock is shown in Listing~\ref{l:cc_deadlock_avoid}.
    70 The algorithm presented is taken directly from the source code of the \code{<mutex>} header, with some renaming and comments for clarity.
    71 
    72 \begin{cfa}[caption={\CC scoped\_lock deadlock avoidance algorithm},label={l:cc_deadlock_avoid}]
     209The \CFA mutex statement takes some ideas from both the Java and \CC features.
     210Like Java, \CFA introduces a new statement rather than building from existing language features.
     211(\CFA has sufficient language features to mimic \CC RAII locking.)
     212This syntactic choice makes MX explicit rather than implicit via object declarations.
     213Hence, it is easier for programmers and language tools to identify MX points in a program, \eg scan for all @mutex@ parameters and statements in a body of code.
     214Furthermore, concurrent safety is provided across an entire program for the complex operation of acquiring multiple locks in a deadlock-free manner.
     215Unlike Java, \CFA's mutex statement and \CC's @scoped_lock@ both use parametric polymorphism to allow user defined types to work with this feature.
     216In this case, the polymorphism allows a locking mechanism to acquire MX over an object without having to know the object internals or what kind of lock it is using.
     217\CFA's provides and uses this locking trait:
     218\begin{cfa}
     219forall( L & | sized(L) )
     220trait is_lock {
     221        void lock( L & );
     222        void unlock( L & );
     223};
     224\end{cfa}
     225\CC @scoped_lock@ has this trait implicitly based on functions accessed in a template.
     226@scoped_lock@ also requires @try_lock@ because of its technique for deadlock avoidance \see{\VRef{s:DeadlockAvoidance}}.
     227
     228The following shows how the @mutex@ statement is used with \CFA streams to eliminate unpredictable results when printing in a concurrent program.
     229For example, if two threads execute:
     230\begin{cfa}
     231thread$\(_1\)$ : sout | "abc" | "def";
     232thread$\(_2\)$ : sout | "uvw" | "xyz";
     233\end{cfa}
     234any of the outputs can appear, included a segment fault due to I/O buffer corruption:
     235\begin{cquote}
     236\small\tt
     237\begin{tabular}{@{}l|l|l|l|l@{}}
     238abc def & abc uvw xyz & uvw abc xyz def & abuvwc dexf &  uvw abc def \\
     239uvw xyz & def & & yz & xyz
     240\end{tabular}
     241\end{cquote}
     242The stream type for @sout@ is defined to satisfy the @is_lock@ trait, so the @mutex@ statement can be used to lock an output stream while producing output.
     243From the programmer's perspective, it is sufficient to know an object can be locked and then any necessary MX is easily available via the @mutex@ statement.
     244This ability improves safety and programmer productivity since it abstracts away the concurrent details.
     245Hence, a  programmer can easily protect cascaded I/O expressions:
     246\begin{cfa}
     247thread$\(_1\)$ : mutex( sout )  sout | "abc" | "def";
     248thread$\(_2\)$ : mutex( sout )  sout | "uvw" | "xyz";
     249\end{cfa}
     250constraining the output to two different lines in either order:
     251\begin{cquote}
     252\small\tt
     253\begin{tabular}{@{}l|l@{}}
     254abc def & uvw xyz \\
     255uvw xyz & abc def
     256\end{tabular}
     257\end{cquote}
     258where this level of safe nondeterministic output is acceptable.
     259Alternatively, multiple I/O statements can be protected using the mutex statement block:
     260\begin{cfa}
     261mutex( sout ) { // acquire stream lock for sout for block duration
     262        sout | "abc";
     263        mutex( sout ) sout | "uvw" | "xyz"; // OK because sout lock is recursive
     264        sout | "def";
     265} // implicitly release sout lock
     266\end{cfa}
     267The inner lock acquire is likely to occur through a function call that does a thread-safe print.
     268
     269\section{Deadlock Avoidance}\label{s:DeadlockAvoidance}
     270The mutex statement uses the deadlock avoidance technique of lock ordering, where the circular-wait condition of a deadlock cannot occur if all locks are acquired in the same order.
     271The @scoped_lock@ uses a deadlock avoidance algorithm where all locks after the first are acquired using @try_lock@ and if any of the lock attempts fail, all acquired locks are released.
     272This repeats after selecting a new starting point in a cyclic manner until all locks are acquired successfully.
     273This deadlock avoidance algorithm is shown in Listing~\ref{l:cc_deadlock_avoid}.
     274The algorithm is taken directly from the source code of the @<mutex>@ header, with some renaming and comments for clarity.
     275
     276\begin{cfa}[caption={\CC \lstinline{scoped_lock} deadlock avoidance algorithm},label={l:cc_deadlock_avoid}]
    73277int first = 0;  // first lock to attempt to lock
    74278do {
    75     // locks is the array of locks to acquire
    76     locks[first].lock();    // lock first lock
    77     for (int i = 1; i < Num_Locks; ++i) {   // iterate over rest of locks
    78         const int idx = (first + i) % Num_Locks;
    79         if (!locks[idx].try_lock()) {       // try lock each one
    80             for (int j = i; j != 0; --j)    // release all locks
    81                 locks[(first + j - 1) % Num_Locks].unlock();
    82             first = idx;    // rotate which lock to acquire first
    83             break;
    84         }
    85     }
     279        // locks is the array of locks to acquire
     280        locks[first].lock();                            $\C{// lock first lock}$
     281        for ( int i = 1; i < Num_Locks; i += 1 ) { $\C{// iterate over rest of locks}$
     282                const int idx = (first + i) % Num_Locks;
     283                if ( ! locks[idx].try_lock() ) {   $\C{// try lock each one}$
     284                        for ( int j = i; j != 0; j -= 1 )       $\C{// release all locks}$
     285                                locks[(first + j - 1) % Num_Locks].unlock();
     286                        first = idx;                            $\C{// rotate which lock to acquire first}$
     287                        break;
     288                }
     289        }
    86290// if first lock is still held then all have been acquired
    87 } while (!locks[first].owns_lock());  // is first lock held?
    88 \end{cfa}
    89 
    90 The algorithm in \ref{l:cc_deadlock_avoid} successfully avoids deadlock, however there is a potential livelock scenario.
    91 Given two threads $A$ and $B$, who create a scoped\_lock with two locks $L1$ and $L2$, a livelock can form as follows.
    92 Thread $A$ creates a scoped\_lock with $L1$, $L2$, and $B$ creates a scoped lock with the order $L2$, $L1$.
    93 Both threads acquire the first lock in their order and then fail the try\_lock since the other lock is held.
    94 They then reset their start lock to be their 2nd lock and try again.
    95 This time $A$ has order $L2$, $L1$, and $B$ has order $L1$, $L2$.
    96 This is identical to the starting setup, but with the ordering swapped among threads.
    97 As such, if they each acquire their first lock before the other acquires their second, they can livelock indefinitely.
    98 
    99 The lock ordering algorithm used in the mutex statement in \CFA is both deadlock and livelock free.
    100 It sorts the locks based on memory address and then acquires them.
    101 For locks fewer than 7, it sorts using hard coded sorting methods that perform the minimum number of swaps for a given number of locks.
    102 For 7 or more locks insertion sort is used.
    103 These sorting algorithms were chosen since it is rare to have to hold more than  a handful of locks at a time.
    104 It is worth mentioning that the downside to the sorting approach is that it is not fully compatible with usages of the same locks outside the mutex statement.
    105 If more than one lock is held by a mutex statement, if more than one lock is to be held elsewhere, it must be acquired via the mutex statement, or else the required ordering will not occur.
    106 Comparitively, if the scoped\_lock is used and the same locks are acquired elsewhere, there is no concern of the scoped\_lock deadlocking, due to its avoidance scheme, but it may livelock.
     291} while ( ! locks[first].owns_lock() );  $\C{// is first lock held?}$
     292\end{cfa}
     293
     294While the algorithm in \ref{l:cc_deadlock_avoid} successfully avoids deadlock, there is a livelock scenario.
     295Assume two threads, $A$ and $B$, create a @scoped_lock@ accessing two locks, $L1$ and $L2$.
     296A livelock can form as follows.
     297Thread $A$ creates a @scoped_lock@ with arguments $L1$, $L2$, and $B$ creates a scoped lock with the lock arguments in the opposite order $L2$, $L1$.
     298Both threads acquire the first lock in their order and then fail the @try_lock@ since the other lock is held.
     299Both threads then reset their starting lock to be their second lock and try again.
     300This time $A$ has order $L2$, $L1$, and $B$ has order $L1$, $L2$, which is identical to the starting setup but with the ordering swapped between threads.
     301If the threads perform this action in lock-step, they cycle indefinitely without entering the CS, \ie livelock.
     302Hence, to use @scoped_lock@ safely, a programmer must manually construct and maintain a global ordering of lock arguments passed to @scoped_lock@.
     303
     304The lock ordering algorithm used in \CFA mutex functions and statements is deadlock and livelock free.
     305The algorithm uses the lock memory addresses as keys, sorts the keys, and then acquires the locks in sorted order.
     306For fewer than 7 locks ($2^3-1$), the sort is unrolled performing the minimum number of compare and swaps for the given number of locks;
     307for 7 or more locks, insertion sort is used.
     308Since it is extremely rare to hold more than 6 locks at a time, the algorithm is fast and executes in $O(1)$ time.
     309Furthermore, lock addresses are unique across program execution, even for dynamically allocated locks, so the algorithm is safe across the entire program execution.
     310
     311The downside to the sorting approach is that it is not fully compatible with manual usages of the same locks outside the @mutex@ statement, \ie the lock are acquired without using the @mutex@ statement.
     312The following scenario is a classic deadlock.
     313\begin{cquote}
     314\begin{tabular}{@{}l@{\hspace{30pt}}l@{}}
     315\begin{cfa}
     316lock L1, L2; // assume &L1 < &L2
     317        $\textbf{thread\(_1\)}$
     318acquire( L2 );
     319        acquire( L1 );
     320                CS
     321        release( L1 );
     322release( L2 );
     323\end{cfa}
     324&
     325\begin{cfa}
     326
     327        $\textbf{thread\(_2\)}$
     328mutex( L1, L2 ) {
     329
     330        CS
     331
     332}
     333\end{cfa}
     334\end{tabular}
     335\end{cquote}
     336Comparatively, if the @scoped_lock@ is used and the same locks are acquired elsewhere, there is no concern of the @scoped_lock@ deadlocking, due to its avoidance scheme, but it may livelock.
     337The convenience and safety of the @mutex@ statement, \eg guaranteed lock release with exceptions, should encourage programmers to always use it for locking, mitigating any deadlock scenario.
     338
     339\section{Performance}
     340Given the two multi-acquisition algorithms in \CC and \CFA, each with differing advantages and disadvantages, it interesting to compare their performance.
     341Comparison with Java is not possible, since it only takes a single lock.
     342
     343The comparison starts with a baseline that acquires the locks directly without a mutex statement or @scoped_lock@ in a fixed ordering and then releases them.
     344The baseline helps highlight the cost of the deadlock avoidance/prevention algorithms for each implementation.
     345
     346The benchmark used to evaluate the avoidance algorithms repeatedly acquires a fixed number of locks in a random order and then releases them.
     347The pseudo code for the deadlock avoidance benchmark is shown in \VRef[Listing]{l:deadlock_avoid_pseudo}.
     348To ensure the comparison exercises the implementation of each lock avoidance algorithm, an identical spinlock is implemented in each language using a set of builtin atomics available in both \CC and \CFA.
     349The benchmarks are run for a fixed duration of 10 seconds and then terminate.
     350The total number of times the group of locks is acquired is returned for each thread.
     351Each variation is run 11 times on 2, 4, 8, 16, 24, 32 cores and with 2, 4, and 8 locks being acquired.
     352The median is calculated and is plotted alongside the 95\% confidence intervals for each point.
     353
     354\begin{cfa}[caption={Deadlock avoidance bendchmark pseudo code},label={l:deadlock_avoid_pseudo}]
     355
     356
     357
     358$\PAB{// add pseudo code}$
     359
     360
     361
     362\end{cfa}
     363
     364The performance experiments were run on the following multi-core hardware systems to determine differences across platforms:
     365\begin{list}{\arabic{enumi}.}{\usecounter{enumi}\topsep=5pt\parsep=5pt\itemsep=0pt}
     366% sudo dmidecode -t system
     367\item
     368Supermicro AS--1123US--TR4 AMD EPYC 7662 64--core socket, hyper-threading $\times$ 2 sockets (256 processing units) 2.0 GHz, TSO memory model, running Linux v5.8.0--55--generic, gcc--10 compiler
     369\item
     370Supermicro SYS--6029U--TR4 Intel Xeon Gold 5220R 24--core socket, hyper-threading $\times$ 2 sockets (48 processing units) 2.2GHz, TSO memory model, running Linux v5.8.0--59--generic, gcc--10 compiler
     371\end{list}
     372%The hardware architectures are different in threading (multithreading vs hyper), cache structure (MESI or MESIF), NUMA layout (QPI vs HyperTransport), memory model (TSO vs WO), and energy/thermal mechanisms (turbo-boost).
     373%Software that runs well on one architecture may run poorly or not at all on another.
     374
     375Figure~\ref{f:mutex_bench} shows the results of the benchmark experiments.
     376\PAB{Make the points in the graphs for each line different.
     377Also, make the text in the graphs larger.}
     378The baseline results for both languages are mostly comparable, except for the 8 locks results in \ref{f:mutex_bench8_AMD} and \ref{f:mutex_bench8_Intel}, where the \CFA baseline is slightly slower.
     379The avoidance result for both languages is significantly different, where \CFA's mutex statement achieves throughput that is magnitudes higher than \CC's @scoped_lock@.
     380The slowdown for @scoped_lock@ is likely due to its deadlock-avoidance implementation.
     381Since it uses a retry based mechanism, it can take a long time for threads to progress.
     382Additionally the potential for livelock in the algorithm can result in very little throughput under high contention.
     383For example, on the AMD machine with 32 threads and 8 locks, the benchmarks would occasionally livelock indefinitely, with no threads making any progress for 3 hours before the experiment was terminated manually.
     384It is likely that shorter bouts of livelock occurred in many of the experiments, which would explain large confidence intervals for some of the data points in the \CC data.
     385In Figures~\ref{f:mutex_bench8_AMD} and \ref{f:mutex_bench8_Intel} the mutex statement performs better than the baseline.
     386At 7 locks and above the mutex statement switches from a hard coded sort to insertion sort.
     387It is likely that the improvement in throughput compared to baseline is due to the time spent in the insertion sort, which decreases contention on the locks.
    107388
    108389\begin{figure}
    109     \centering
    110     \begin{subfigure}{0.5\textwidth}
    111         \centering
    112         \scalebox{0.5}{\input{figures/nasus_Aggregate_Lock_2.pgf}}
    113         \subcaption{AMD}
    114     \end{subfigure}\hfill
    115     \begin{subfigure}{0.5\textwidth}
    116         \centering
    117         \scalebox{0.5}{\input{figures/pyke_Aggregate_Lock_2.pgf}}
    118         \subcaption{Intel}
    119     \end{subfigure}
    120 
    121     \begin{subfigure}{0.5\textwidth}
    122         \centering
    123         \scalebox{0.5}{\input{figures/nasus_Aggregate_Lock_4.pgf}}
    124         \subcaption{AMD}
    125     \end{subfigure}\hfill
    126     \begin{subfigure}{0.5\textwidth}
    127         \centering
    128         \scalebox{0.5}{\input{figures/pyke_Aggregate_Lock_4.pgf}}
    129         \subcaption{Intel}
    130     \end{subfigure}
    131 
    132     \begin{subfigure}{0.5\textwidth}
    133         \centering
    134         \scalebox{0.5}{\input{figures/nasus_Aggregate_Lock_8.pgf}}
    135         \subcaption{AMD}\label{f:mutex_bench8_AMD}
    136     \end{subfigure}\hfill
    137     \begin{subfigure}{0.5\textwidth}
    138         \centering
    139         \scalebox{0.5}{\input{figures/pyke_Aggregate_Lock_8.pgf}}
    140         \subcaption{Intel}\label{f:mutex_bench8_Intel}
    141     \end{subfigure}
    142     \caption{The aggregate lock benchmark comparing \CC scoped\_lock and \CFA mutex statement throughput (higher is better).}
    143     \label{f:mutex_bench}
     390        \centering
     391        \subfloat[AMD]{
     392                \resizebox{0.5\textwidth}{!}{\input{figures/nasus_Aggregate_Lock_2.pgf}}
     393        }
     394        \subfloat[Intel]{
     395                \resizebox{0.5\textwidth}{!}{\input{figures/pyke_Aggregate_Lock_2.pgf}}
     396        }
     397
     398        \subfloat[AMD]{
     399                \resizebox{0.5\textwidth}{!}{\input{figures/nasus_Aggregate_Lock_4.pgf}}
     400        }
     401        \subfloat[Intel]{
     402                \resizebox{0.5\textwidth}{!}{\input{figures/pyke_Aggregate_Lock_4.pgf}}
     403        }
     404
     405        \subfloat[AMD]{
     406                \resizebox{0.5\textwidth}{!}{\input{figures/nasus_Aggregate_Lock_8.pgf}}
     407                \label{f:mutex_bench8_AMD}
     408        }
     409        \subfloat[Intel]{
     410                \resizebox{0.5\textwidth}{!}{\input{figures/pyke_Aggregate_Lock_8.pgf}}
     411                \label{f:mutex_bench8_Intel}
     412        }
     413        \caption{The aggregate lock benchmark comparing \CC \lstinline{scoped_lock} and \CFA mutex statement throughput (higher is better).}
     414        \label{f:mutex_bench}
    144415\end{figure}
    145416
    146 \section{Performance}
    147 Performance is compared between \CC's scoped\_lock and \CFA's mutex statement.
    148 Comparison with Java is omitted, since it only takes a single lock.
    149 To ensure that the comparison between \CC and \CFA exercises the implementation of each feature, an identical spinlock is implemented in each language using a set of builtin atomics available in both \CFA and \CC.
    150 Each feature is evaluated on a benchmark which acquires a fixed number of locks in a random order and then releases them.
    151 A baseline is included that acquires the locks directly without a mutex statement or scoped\_lock in a fixed ordering and then releases them.
    152 The baseline helps highlight the cost of the deadlock avoidance/prevention algorithms for each implementation.
    153 The benchmarks are run for a fixed duration of 10 seconds and then terminate and return the total number of times the group of locks were acquired.
    154 Each variation is run 11 times on a variety up to 32 cores and with 2, 4, and 8 locks being acquired.
    155 The median is calculated and is plotted alongside the 95\% confidence intervals for each point.
    156 
    157 Figure~\ref{f:mutex_bench} shows the results of the benchmark.
    158 The baseline runs for both languages are mostly comparable, except for the 8 locks results in \ref{f:mutex_bench8_AMD} and \ref{f:mutex_bench8_Intel}, where the \CFA baseline is slower.
    159 \CFA's mutex statement achieves throughput that is magnitudes higher than \CC's scoped\_lock.
    160 This is likely due to the scoped\_lock deadlock avoidance implementation.
    161 Since it uses a retry based mechanism, it can take a long time for threads to progress.
    162 Additionally the potential for livelock in the algorithm can result in very little throughput under high contention.
    163 It was observed on the AMD machine that with 32 threads and 8 locks the benchmarks would occasionally livelock indefinitely, with no threads making any progress for 3 hours before the experiment was terminated manually.
    164 It is likely that shorter bouts of livelock occured in many of the experiments, which would explain large confidence intervals for some of the data points in the \CC data.
    165 In Figures~\ref{f:mutex_bench8_AMD} and \ref{f:mutex_bench8_Intel} the mutex statement performs better than the baseline.
    166 At 7 locks and above the mutex statement switches from a hard coded sort to insertion sort.
    167 It is likely that the improvement in throughput compared to baseline is due to the time spent in the insertion sort, which decreases contention on the locks.
     417% Local Variables: %
     418% tab-width: 4 %
     419% End: %
  • doc/theses/colby_parsons_MMAth/thesis.tex

    ra50fdfb r6e1e2d0  
    8484\usepackage{tikz} % for diagrams and figures
    8585\def\checkmark{\tikz\fill[scale=0.4](0,.35) -- (.25,0) -- (1,.7) -- (.25,.15) -- cycle;}
    86 \usepackage{subcaption}
    8786\usepackage{fullpage,times,comment}
    8887\usepackage{textcomp}
    8988\usepackage{graphicx}
    9089\usepackage{tabularx}
     90\usepackage[labelformat=simple,aboveskip=0pt,farskip=0pt,font=normalsize]{subfig}
     91\renewcommand\thesubfigure{(\alph{subfigure})}
    9192\input{style}
    9293
  • doc/theses/colby_parsons_MMAth/version.sh

    • Property mode changed from 100755 to 100644
  • doc/theses/mike_brooks_MMath/benchmarks/list/Makefile

    ra50fdfb r6e1e2d0  
    11# For correctness, see test-correctness.sh.
    22# For performance:
    3 #       pushd ~/cfax
    4 #       ~/setcfa build-fast
    5 #       popd
    6 #       make perfprogs CFA=$cfa -j8 MODE=performance
    7 #       make results-latest.csv RUNARGS=5 RUN_NUM_REPS=5
    8 
     3# pushd ~/cfax
     4# . ~/setcfa build-fast
     5# popd
     6# make perfprogs CFA=$cfa -j8 MODE=performance
     7# make results-latest.csv RUN_DURATION_SEC=5 RUN_NUM_REPS=5 RUN_DATA_SIZE_MODE=common5
     8# cp results-latest.csv results-baseline.csv
     9# make results-latest.csv OP_MOVEMENTS=stack OP_POLARITIES=insfirst OP_ACCESSORS=allhead RUN_DURATION_SEC=5 RUN_NUM_REPS=5 RUN_DATA_SIZE_MODE=thorough
     10# cp results-latest.csv results-sizing.csv
    911
    1012CFA = cfa
     
    1214UXX =  ~/u++/u++-7.0.0/bin/u++
    1315
    14 MODE = performance
    15 RUNARGS=
     16MODE=performance
     17EXTRA_COMP_FLAGS=
     18RUN_NUM_REPS=3
     19RUN_DATA_SIZE_MODE=none
     20RUN_DURATION_SEC=5
     21RUN_TASKSET_CPULIST=6
    1622
    1723ifeq "$(MODE)" "performance"
    18 PERFFLAGS_CFA = -nodebug -O3
     24PERFFLAGS_CFA = -DNDEBUG -O3 -nodebug
    1925PERFFLAGS_CC  = -DNDEBUG -O3
    2026else ifeq "$(MODE)" "correctness"
    21 PERFFLAGS_CFA = -debug -O0 -g
    22 PERFFLAGS_CC = -O0 -g
     27PERFFLAGS_CFA = -O0 -g -debug
     28PERFFLAGS_CC  = -O0 -g
    2329else
    2430$(error Bad MODE ($(MODE)); should be performance or correctness)
     
    2632
    2733PERFFLAGS_CXX = $(PERFFLAGS_CC)
    28 PERFFLAGS_UXX = $(PERFFLAGS_CC)
     34PERFFLAGS_UXX = $(PERFFLAGS_CFA)
     35
     36CFLAGS=$(PERFFLAGS_CC) $(EXTRA_COMP_FLAGS)
    2937
    3038SHELL = /usr/bin/bash
     
    101109perfexp--%     driver--%.o     : COMPILER=NO-COMPILER-FOR-$(FX_COARSE)
    102110
     111# Without this %.d rule, ordinary make runs have noise about the recipe for driver--%.o being ill-formed when called on a *.d.
     112# https://stackoverflow.com/questions/3714041/why-does-this-makefile-execute-a-target-on-make-clean
     113# Whatever you -include gets called as a target first.
     114# One such example is driver--upp-upp--stack-insfirst-allhead.d
     115# Without this %.d rule, `make make driver--upp-upp--stack-insfirst-allhead.d` leads to the rule for driver--%.o firing.
     116# Though my dumb human eyes don't see the pattern as matching.
     117%.d:
     118        @touch $@
     119
    103120perfexp--% : driver--%.o observation.o
    104         $(COMPILER) $^ -o $@
     121        $(COMPILER) $(EXTRA_COMP_FLAGS) $^ -o $@
    105122
    106123driver--%.o : driver.c
    107         $(COMPILER) -c $< $(OP_DEFINES) -include op-$(OP).h -include fx-$(FX).h -o $@ -MMD
    108 
    109 
    110 
    111 
    112 RUN_NUM_REPS=3
     124        $(COMPILER) $(EXTRA_COMP_FLAGS) -c $< $(OP_DEFINES) -include op-$(OP).h -include fx-$(FX).h -o $@ -MMD
     125
     126sayhi:
     127        echo $(PERFPROGS)
     128
     129
     130ifeq "$(RUN_DATA_SIZE_MODE)" "common5"
     131RUN_DATA_SIZES=\
     132  7-1000000 \
     133  71-100000 \
     134  809-10000 \
     135  9051-1000 \
     136  72421-100
     137else ifeq "$(RUN_DATA_SIZE_MODE)" "thorough"
     138RUN_DATA_SIZES=\
     139  7-1000000 \
     140  11-100000 \
     141  13-100000 \
     142  19-100000 \
     143  29-100000 \
     144  37-100000 \
     145  53-100000 \
     146  71-100000 \
     147  101-10000 \
     148  149-10000 \
     149  211-10000 \
     150  283-10000 \
     151  401-10000 \
     152  569-10000 \
     153  809-10000 \
     154  1151-1000 \
     155  1601-1000 \
     156  2267-1000 \
     157  3203-1000 \
     158  4547-1000 \
     159  6473-1000 \
     160  9051-1000 \
     161  12809-100 \
     162  18119-100 \
     163  25601-100 \
     164  36209-100 \
     165  51203-100 \
     166  72421-100 \
     167  102407-10 \
     168  144817-10 \
     169  204803-10 \
     170  289637-10 \
     171  409609-10 \
     172  579263-10 \
     173  819229-10 \
     174  1158613-1 \
     175  1638431-1 \
     176  2317057-1 \
     177  3276803-1 \
     178  4634111-1 \
     179  6553621-1 \
     180  9268211-1
     181else ifeq "$(RUN_DATA_SIZE_MODE)" "manual"
     182ifeq "$(RUN_DATA_SIZES)" ""
     183$(error RUN_DATA_SIZE_MODE is manual but RUN_DATA_SIZES not given)
     184endif
     185else ifeq "$(RUN_DATA_SIZE_MODE)" "none"
     186# Assume user manages RUN_ARGS; empty RUN_ARGS just means run with compiled-in defaults
     187RUN_DATA_SIZES=none
     188else
     189$(error Bad RUN_DATA_SIZE_MODE ($(RUN_DATA_SIZE_MODE)); should be common5, thorough or manual)
     190endif
     191
    113192RUN_REP_IDS=$(shell echo {1..$(RUN_NUM_REPS)})              # 1 2 3
    114193RUN_REP_EXTS=$(call cross3,,run,$(RUN_REP_IDS),.1csv)       # run1.1csv run2.1cav run3.1csv
    115194
    116 RESULT1S=$(call cross,.,$(CORES),$(RUN_REP_EXTS))   # lq-tailq--stack-inslast-allhead.run2.1csv
     195RUN_LAUNCHES=$(call cross,--,$(RUN_DATA_SIZES),$(RUN_REP_EXTS))
     196
     197
     198
     199RESULT1S=$(call cross,.,$(CORES),$(RUN_LAUNCHES))   # lq-tailq--stack-inslast-allhead.run2.1csv
     200
    117201
    118202RESULT1S_SHUFD=$(shell shuf -e $(RESULT1S))
    119203
    120204%.1csv : CORE=$(basename $(basename $@))
    121 %.1csv : REP_ID=$(subst .run,,$(suffix $(basename $@)))
     205%.1csv : LAUNCH=$(subst .,,$(suffix $(basename $@)))
     206%.1csv : SIZING=$(call proj,--,$(LAUNCH),1)
     207%.1csv : NUMNODES=$(call proj,-,$(SIZING),1)
     208%.1csv : CHECKDONE=$(call proj,-,$(SIZING),2)
     209%.1csv : REP_ID=$(subst run,,$(call proj,--,$(LAUNCH),2))
     210%.1csv : RUN_ARGS=$(if $(filter none,$(SIZING)),,$(RUN_DURATION_SEC) $(CHECKDONE) $(NUMNODES) -1 $(REP_ID))  # use REP_ID as seed
    122211%.1csv : REP_TIME=$(shell date '+%F %H:%M:%S')
    123212%.1csv : perfprogs FORCE
    124         ./perfexp--$(CORE) $(RUNARGS) | xargs -n 1 printf '%s,%s,%s\n' "$(REP_TIME)" "$(REP_ID)" | tee $@
     213        taskset --cpu-list $(RUN_TASKSET_CPULIST) ./perfexp--$(CORE) $(RUN_ARGS) | xargs -n 1 printf '%s,%s,%s,%s\n' "$(REP_TIME)" "$(REP_ID)" "$(RUN_ARGS)" | tee $@
     214
    125215
    126216BATCHTIME=$(shell date '+%F--%H-%M-%S')
     
    146236.PRECIOUS: result--%.1csv driver--%.o perfexp--% %.o
    147237
    148 
    149238-include *.d
  • doc/theses/mike_brooks_MMath/benchmarks/list/_classic.c

    ra50fdfb r6e1e2d0  
    171171#endif
    172172
    173 
    174 #define Repeat( op ) for ( volatile unsigned int i = 0; i < NoOfNodes; i += 1 ) { op; }
     173volatile unsigned int t = 0;
     174volatile unsigned int i_official = 0;
     175
     176#define Repeat( op ) for ( unsigned int i = 0; (i_official = i, i < NoOfNodes); i += 1 ) { op; }
    175177
    176178int main() {
     
    192194        TAILQ_INIT(&lst);
    193195        start = clock();
    194         for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
     196        for ( t = 0; t < Times; t += 1 ) {
    195197                Repeat( TAILQ_INSERT_TAIL( &lst, &s[i], x ) );
    196198                Repeat( TAILQ_REMOVE( &lst, TAILQ_FIRST( &lst ), x ) );
     
    204206        std::list<S *> lst;
    205207        start = clock();
    206         for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
     208        for ( t = 0; t < Times; t += 1 ) {
    207209                Repeat( lst.push_back( &s[i] ) );
    208210                Repeat( lst.pop_front() );
     
    216218        uSequence<S> lst;
    217219        start = clock();
    218         for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
     220        for ( t = 0; t < Times; t += 1 ) {
    219221                Repeat( lst.addTail( &s[i] ) );
    220222                Repeat( lst.dropHead() );
     
    228230        dlist(S) lst;
    229231        start = clock();
    230         for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
     232        for ( t = 0; t < Times; t += 1 ) {
    231233                Repeat( insert_last( lst, s[i] ) );
    232234                Repeat( remove( lst`first ) );
     
    240242        Sequence(S) lst;
    241243        start = clock();
    242         for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
     244        for ( t = 0; t < Times; t += 1 ) {
    243245                Repeat( addHead( lst, s[i] ) );
    244246                Repeat( dropTail( lst ) );
  • doc/theses/mike_brooks_MMath/benchmarks/list/driver.c

    ra50fdfb r6e1e2d0  
    1717
    1818#if defined(NDEBUG) || (defined(__cforall) && !defined(__CFA_DEBUG__))
    19     enum { DefaultNumNodes = 1000, DefaultExperimentDurSec = 1, DefaultCheckClockFreq = 1000, DefaultExperimentDurOpCount = -1 };
     19    enum { DefaultNumNodes = 1000, DefaultExperimentDurSec = 1, DefaultCheckDonePeriod = 1000, DefaultExperimentDurOpCount = -1, DefaultSeed = 5 };
    2020    #define TRACE(tp)
    2121#else
    22     enum { DefaultNumNodes = 10, DefaultExperimentDurSec = 1, DefaultCheckClockFreq = 2, DefaultExperimentDurOpCount = 20 };
     22    enum { DefaultNumNodes = 10, DefaultExperimentDurSec = 1, DefaultCheckDonePeriod = 2, DefaultExperimentDurOpCount = 20, DefaultSeed = 5 };
    2323    static const char * tp_filter
    2424    // = "";
     
    6363    }
    6464
    65     int bobs_getCurrent() {
     65    void * bobs_getCurrentLoc() {
     66        return BFX_DEREF_POS(B_UserItem, lst, observedItem);
     67    }
     68    int bobs_getCurrentVal() {
    6669        B_UserItem * curUI = BFX_DEREF_POS(B_UserItem, lst, observedItem);
    6770        return curUI->userdata[17];
     
    7275)
    7376
     77unsigned int uDefaultPreemption() {
     78        return 0;
     79}
     80
    7481int main(int argc, const char *argv[]) {
    7582
    76 
    77     const char * usage_args = "[ExperimentDurSec [CheckClockFreq [NumNodes [ExperimentDurOpCount]]]]";
    78     const int static_arg_posns = 4;
     83    const char * usage_args = "[ExperimentDurSec [CheckDonePeriod [NumNodes [ExperimentDurOpCount [Seed]]]]]";
     84    const int static_arg_posns = 5;
    7985
    8086    unsigned int ExperimentDurSec     = DefaultExperimentDurSec;
    81     unsigned int CheckClockFreq       = DefaultCheckClockFreq;
     87    unsigned int CheckDonePeriod      = DefaultCheckDonePeriod;
    8288    unsigned int NumNodes             = DefaultNumNodes;
    8389    size_t       ExperimentDurOpCount = DefaultExperimentDurOpCount;
    84 
    85     switch ((argc < static_arg_posns) ? argc : static_arg_posns) {
    86       case 5: ExperimentDurOpCount = atoi(argv[4]);
    87       case 4: NumNodes = atoi(argv[3]);
    88       case 3: CheckClockFreq = atoi(argv[2]);
    89       case 2: ExperimentDurSec = atoi(argv[1]);
    90     }
    91 
    92     if (ExperimentDurSec == 0 || CheckClockFreq == 0 || NumNodes == 0 || ExperimentDurOpCount == 0 ) {
     90    unsigned int Seed                 = DefaultSeed;
     91
     92    switch (((argc - 1) < static_arg_posns) ? (argc - 1) : static_arg_posns) {
     93      case 5: Seed = atoi(argv[5]);
     94      case 4: ExperimentDurOpCount = atol(argv[4]);
     95      case 3: NumNodes = atoi(argv[3]);
     96      case 2: CheckDonePeriod = atoi(argv[2]);
     97      case 1: ExperimentDurSec = atoi(argv[1]);
     98    }
     99
     100    if (ExperimentDurSec == 0 || CheckDonePeriod == 0 || NumNodes == 0 || ExperimentDurOpCount == 0 || Seed == 0 ) {
    93101        printf("usage: %s %s\n", argv[0], usage_args);
    94102        return -1;
    95103    }
    96104
    97     ui = (B_UserItem*) malloc( NumNodes * sizeof(B_UserItem) );
    98     memset(ui, 0, NumNodes * sizeof(B_UserItem));
    99 
    100     listedItems = (BFX_LISTED_ELEM_T(B_UserItem)*)malloc( NumNodes * sizeof(BFX_LISTED_ELEM_T(B_UserItem)) );
    101     memset(listedItems, 0, NumNodes * sizeof(BFX_LISTED_ELEM_T(B_UserItem)));
    102 
     105  #ifdef DISABLE_CLOCK_RECHECK
     106    if (ExperimentDurSec != -1) {
     107        printf("Error: experiment compiled as fixed-work only.  ExperimentDurSec (currently %d) must be set to -1.\nUsage: %s %s\n", ExperimentDurSec, argv[0], usage_args);
     108        return -1;
     109    }
     110  #endif
     111
     112  #ifdef DISABLE_SHUFFLING_INDIRECTION
     113    #define INSERTPOS(insertNum) insertNum
     114  #else
     115    // To ensure random memory order of nodes being inserted, do so according to a shuffled ordering of them.
     116    unsigned int * insertOrdShuf = (unsigned int *) malloc( (size_t)NumNodes * sizeof(unsigned int) );
     117    if (!insertOrdShuf) {
     118        printf("malloc request for %zd bytes for insertOrdShuf refused\n", (size_t)NumNodes * (size_t)sizeof(unsigned int));
     119        return 1;
     120    }
     121    // Fill with the ordinals (iota)
    103122    for (int i = 0; i < NumNodes; i++) {
    104         B_UserItem * curUI = & ui[i];
     123        insertOrdShuf[i] = i;
     124    }
     125    // Dummy "Seed" of -1 means skip the shuffle: measure overhead of insertOrdShuf indirection
     126    if (Seed != -1) {
     127        // Shuffle
     128        srand(Seed);
     129        for (unsigned int i = 0; i < NumNodes; i++) {
     130            unsigned int nodesRemaining = NumNodes - i;
     131            unsigned int swapWith = i + rand() % nodesRemaining;
     132            unsigned int tempValue = insertOrdShuf[swapWith];
     133            insertOrdShuf[swapWith] = insertOrdShuf[i];
     134            insertOrdShuf[i] = tempValue;
     135        }
     136    }
     137    #define INSERTPOS(insertNum) insertOrdShuf[insertNum]
     138  #endif
     139
     140    ui = (B_UserItem*) malloc( (size_t)NumNodes * (size_t)sizeof(B_UserItem) );
     141    if (!ui) {
     142        printf("malloc request for %zd bytes for ui refused\n", (size_t)NumNodes * (size_t)sizeof(B_UserItem));
     143        return 1;
     144    }
     145    memset(ui, 0, (size_t)NumNodes * (size_t)sizeof(B_UserItem));
     146
     147    listedItems = (BFX_LISTED_ELEM_T(B_UserItem)*)malloc( (size_t)NumNodes * (size_t)sizeof(BFX_LISTED_ELEM_T(B_UserItem)) );
     148    if (!listedItems) {
     149        printf("malloc request for %zd bytes for listedItems refused\n", (size_t)NumNodes * (size_t)sizeof(BFX_LISTED_ELEM_T(B_UserItem)));
     150        return 1;
     151    }
     152    memset(listedItems, 0, (size_t)NumNodes * (size_t)sizeof(BFX_LISTED_ELEM_T(B_UserItem)));
     153
     154    // Fill with demo data
     155    for (unsigned int i = 0; i < NumNodes; i++) {
     156        B_UserItem * curUI = & ui[INSERTPOS(i)];
    105157        curUI->userdata[17] = i;
    106158    }
     
    110162    bobs_init(NumNodes);
    111163
    112     // BOP Convention:
    113     // Action-number arguments are for the BOP cartridge to interpret.
    114     // I.e. the driver assumes no relationship between BOP_INSERT(_,_,xx) and ui[xx].
     164    // BOP_ADDFOO(lst, iters, insNo, item)
     165    // BOP_REMFOO(lst, iters, remNo)
     166    //   lst    lvalue of the list head being added to / removed from
     167    //   iters  array of ADD return values, in logical-insert order; on ADD, is valid at [0..insNo)
     168    //   insNo  counter of the ADD calls (logical insert number)
     169    //   remNo  counter of the REM calls (logical remove number)
     170    //   item   lvalue of the item being added
    115171    // Logical insert number 0 and remove number n-1 are given with a distinguished hook.
    116172    // Logical insert numbers [1,n) and remove numbers [0,n-1) are pumped by the basic SUT hooks.
    117173    // This pattern lets BOP cartridges that measure element-level operations know statically when there is a reference element in the list.
     174    // The driver owns the relationship between a logical insert number and the location of the `item` argument within `ui`.  (Scattered for randomness.)
     175    // The BOP cartridge owns the relationship between logical remove number and any choice of an item in iters.  (Defines stack vs queue.)
    118176
    119177    // Default init/teardown is insert/remove
    120178    // Cartridges whose SUT insert/remove actions work on empty lists need not provide special-case ones.
    121179    #ifndef BOP_INIT
    122     #define BOP_INIT(lst, ui, iters, i) BOP_INSERT(lst, ui, iters, i)
     180    #define BOP_INIT(lst, iters, insNo, item) BOP_INSERT(lst, iters, insNo, item)
    123181    #endif
    124182    #ifndef BOP_TEARDOWN
    125     #define BOP_TEARDOWN(lst, ui, iters, i) BOP_REMOVE(lst, ui, iters, i)
     183    #define BOP_TEARDOWN(lst, iters, remNo) BOP_REMOVE(lst, iters, remNo)
    126184    #endif
    127185
     
    129187    clock_t start = clock();
    130188
    131     while (elapsed_sec <= (double) ExperimentDurSec && bobs_ops_completed < ExperimentDurOpCount) {
    132         for ( int t = 0; t < CheckClockFreq; t += 1 ) {
     189    size_t privateOpsCompleted = 0;
     190
     191    while (elapsed_sec <= (double) ExperimentDurSec && privateOpsCompleted < ExperimentDurOpCount) {
     192        for ( int t = 0; t < CheckDonePeriod; t += 1 ) {
    133193            TRACE('a')
    134194            listedItems[0] =
    135                 BOP_INIT(lst, ui, listedItems, 0);
     195                BOP_INIT(lst, listedItems, 0, ui[INSERTPOS(0)]);
    136196            TRACE('b')
    137197            for ( int privateCurInsert = 1;
     
    141201                TRACE('-')
    142202                listedItems[privateCurInsert] =
    143                     BOP_INSERT( lst, ui, listedItems, privateCurInsert );
     203                    BOP_INSERT( lst, listedItems, privateCurInsert, ui[INSERTPOS(privateCurInsert)] );
    144204                TRACE('+')
    145205            }
     
    150210                ) {
    151211                TRACE('-')
    152                 BOP_REMOVE( lst, ui, listedItems, privateCurRemove-1 );
     212                BOP_REMOVE( lst, listedItems, privateCurRemove-1 );
    153213                TRACE('+')
    154214            }
    155215            TRACE('D')
    156             BOP_TEARDOWN(lst, ui, listedItems, NumNodes-1);
     216            BOP_TEARDOWN(lst, listedItems, NumNodes-1);
    157217            TRACE('d')
     218
     219            privateOpsCompleted += NumNodes;
    158220
    159221            bobs_prog_rollover_flag = 1;
     
    161223            bobs_prog_inserting = 0;
    162224            bobs_prog_removing = 0;           
    163             bobs_ops_completed += NumNodes;
     225            bobs_ops_completed = privateOpsCompleted;
    164226            TRACE('f')
    165227            bobs_prog_rollover_flag = 0;
    166228            TRACE('g')
    167229        }
     230      #ifndef DISABLE_CLOCK_RECHECK
    168231        clock_t end = clock();
    169232        elapsed_sec = ((double)(end - start)) / ((double)CLOCKS_PER_SEC);
    170     }
     233      #endif
     234    }
     235    #ifdef DISABLE_CLOCK_RECHECK
     236    {
     237        clock_t end = clock();
     238        elapsed_sec = ((double)(end - start)) / ((double)CLOCKS_PER_SEC);
     239    }
     240    #endif
    171241
    172242    double mean_op_dur_ns = elapsed_sec / ((double)bobs_ops_completed) * 1000 * 1000 * 1000;
     
    175245    free(ui);
    176246    free(listedItems);
     247    free(insertOrdShuf);
    177248}
  • doc/theses/mike_brooks_MMath/benchmarks/list/observation.c

    ra50fdfb r6e1e2d0  
    2424}
    2525
     26#ifdef BOBS_SHOW_ADDRESSES
     27#define SNAP \
     28    void * userAddr = bobs_getCurrentLoc(); \
     29    int userValue = bobs_getCurrentVal();
     30#define SHOW(pfx, sfx) \
     31    printf(" " pfx "%d@%p" sfx, userValue, userAddr);
     32#else
     33#define SNAP \
     34    int userValue = bobs_getCurrentVal();
     35#define SHOW(pfx, sfx) \
     36    printf(" " pfx "%d" sfx, userValue);
     37#endif
    2638
    2739static void printPreds(unsigned int leash) {
     
    3244        return;
    3345    }
    34     int userValue = bobs_getCurrent();
     46    SNAP
    3547    bobs_movePrev();
    3648    printPreds(leash - 1);
    37     printf(" %d", userValue);
     49    SHOW("", "")
    3850}
    3951static void printSuccs(unsigned int leash) {
     
    4456        return;
    4557    }
    46     int userValue = bobs_getCurrent();
    47     printf(" %d", userValue);
     58    SNAP
     59    SHOW("", "")
    4860    bobs_moveNext();
    4961    printSuccs(leash - 1);
     
    5971
    6072    bobs_seek(here);
    61     int userValue = bobs_getCurrent();
    62     printf(" <%d>", userValue);
     73    SNAP
     74    SHOW("<", ">")
    6375
    6476    bobs_moveNext();
  • doc/theses/mike_brooks_MMath/benchmarks/list/observation.h

    ra50fdfb r6e1e2d0  
    88    extern enum bobs_op_polarity_t { insfirst, inslast } bobs_op_polarity;
    99
    10     void bobs_seek(unsigned int);
    11     void bobs_moveNext();
    12     void bobs_movePrev();
    13     int  bobs_hasCurrent();
    14     int  bobs_getCurrent();
     10    void   bobs_seek(unsigned int);
     11    void   bobs_moveNext();
     12    void   bobs_movePrev();
     13    int    bobs_hasCurrent();
     14    void * bobs_getCurrentLoc();
     15    int    bobs_getCurrentVal();
    1516
    1617    extern volatile size_t       bobs_ops_completed;
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-insfirst-allhead.h

    ra50fdfb r6e1e2d0  
    33// allhead:  inserts and removes happen via the api-provided "last"/"tail"/"back"/"first"/"tail"/"front"
    44
    5 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_FIRST(B_UserItem, lst, ui[i])
    6 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_LAST(B_UserItem, lst)
     5#define BOP_INSERT(lst, iters, insNo, item)  BFX_INSERT_FIRST(B_UserItem, lst, (item))
     6#define BOP_REMOVE(lst, iters, remNo)        BFX_REMOVE_LAST(B_UserItem, lst)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-insfirst-inselem.h

    ra50fdfb r6e1e2d0  
    33// inselem:  inserts happen via an element-level operation and removes happen via the api-provided "last"/"tail"/"back"
    44
    5 #define BOP_INIT(lst, ui, iters, i) BFX_INSERT_FIRST(B_UserItem, lst, ui[i])
     5#define BOP_INIT(lst, iters, insNo, item)    BFX_INSERT_FIRST(B_UserItem, lst, (item))
    66
    7 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_BEFORE(B_UserItem, lst, ui[i], iters[i-1])
    8 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_LAST(B_UserItem, lst)
     7#define BOP_INSERT(lst, iters, insNo, item)  BFX_INSERT_BEFORE(B_UserItem, lst, (item), iters[(insNo)-1])
     8#define BOP_REMOVE(lst, iters, remNo)        BFX_REMOVE_LAST(B_UserItem, lst)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-insfirst-remelem.h

    ra50fdfb r6e1e2d0  
    33// remelem:  removes happen via an element-level operation and inserts happen via the api-provided "first"/"head"/"front"
    44
    5 #define BOP_TEARDOWN(lst, ui, iters, i) BFX_REMOVE_LAST(B_UserItem, lst)
     5#define BOP_TEARDOWN(lst, iters, remNo)      BFX_REMOVE_LAST(B_UserItem, lst)
    66
    7 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_FIRST(B_UserItem, lst, ui[i])
    8 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_HERE(B_UserItem, lst, iters[i])
     7#define BOP_INSERT(lst, iters, insNo, item)  BFX_INSERT_FIRST(B_UserItem, lst, (item))
     8#define BOP_REMOVE(lst, iters, remNo)        BFX_REMOVE_HERE(B_UserItem, lst, iters[(remNo)])
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-inslast-allhead.h

    ra50fdfb r6e1e2d0  
    33// allhead:  inserts and removes happen via the api-provided "last"/"tail"/"back"/"first"/"tail"/"front"
    44
    5 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_LAST(B_UserItem, lst, ui[i])
    6 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_FIRST(B_UserItem, lst)
     5#define BOP_INSERT(lst, iters, insNo, item)  BFX_INSERT_LAST(B_UserItem, lst, (item))
     6#define BOP_REMOVE(lst, iters, remNo)        BFX_REMOVE_FIRST(B_UserItem, lst)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-inslast-inselem.h

    ra50fdfb r6e1e2d0  
    33// inselem:  inserts happen via an element-level operation and removes happen via the api-provided "first"/"tail"/"front"
    44
    5 #define BOP_INIT(lst, ui, iters, i) BFX_INSERT_LAST(B_UserItem, lst, ui[i])
     5#define BOP_INIT(lst, iters, insNo, item)    BFX_INSERT_LAST(B_UserItem, lst, (item))
    66
    7 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_AFTER(B_UserItem, lst, ui[i], iters[i-1])
    8 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_FIRST(B_UserItem, lst)
     7#define BOP_INSERT(lst, iters, insNo, item)  BFX_INSERT_AFTER(B_UserItem, lst, (item), iters[(insNo)-1])
     8#define BOP_REMOVE(lst, iters, remNo)        BFX_REMOVE_FIRST(B_UserItem, lst)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-inslast-remelem.h

    ra50fdfb r6e1e2d0  
    33// remelem:  removes happen via an element-level operation and inserts happen via the api-provided "last"/"tail"/"back"
    44
    5 #define BOP_TEARDOWN(lst, ui, iters, i) BFX_REMOVE_FIRST(B_UserItem, lst)
     5#define BOP_TEARDOWN(lst, iters, remNo)    BFX_REMOVE_FIRST(B_UserItem, lst)
    66
    7 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_LAST(B_UserItem, lst, ui[i])
    8 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_HERE(B_UserItem, lst, iters[i])
     7#define BOP_INSERT(lst, iters, insNo, item) BFX_INSERT_LAST(B_UserItem, lst, (item))
     8#define BOP_REMOVE(lst, iters, remNo)       BFX_REMOVE_HERE(B_UserItem, lst, iters[(remNo)])
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-insfirst-allhead.h

    ra50fdfb r6e1e2d0  
    33// allhead:  inserts and removes happen via the api-provided "first"/"head"/"front"
    44
    5 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_FIRST(B_UserItem, lst, ui[i])
    6 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_FIRST(B_UserItem, lst)
     5#define BOP_INSERT(lst, iters, insNo, item)  BFX_INSERT_FIRST(B_UserItem, lst, (item))
     6#define BOP_REMOVE(lst, iters, remNo)        BFX_REMOVE_FIRST(B_UserItem, lst)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-insfirst-inselem.h

    ra50fdfb r6e1e2d0  
    33// inselem:  inserts happen via an element-level operation and removes happen via the api-provided "first"/"head"/"front"
    44
    5 #define BOP_INIT(lst, ui, iters, i) BFX_INSERT_FIRST(B_UserItem, lst, ui[i])
     5#define BOP_INIT(lst, iters, insNo, item)  BFX_INSERT_FIRST(B_UserItem, lst, (item))
    66
    7 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_BEFORE(B_UserItem, lst, ui[i], iters[i-1])
    8 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_FIRST(B_UserItem, lst)
     7#define BOP_INSERT(lst, iters, insNo, item)  BFX_INSERT_BEFORE(B_UserItem, lst, (item), iters[insNo-1])
     8#define BOP_REMOVE(lst, iters, remNo)        BFX_REMOVE_FIRST(B_UserItem, lst)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-insfirst-remelem.h

    ra50fdfb r6e1e2d0  
    33// remelem:  removes happen via an element-level operation and inserts happen via the api-provided "first"/"head"/"front"
    44
    5 #define BOP_TEARDOWN(lst, ui, iters, i) BFX_REMOVE_FIRST(B_UserItem, lst)
     5#define BOP_TEARDOWN(lst, iters, remNo)      BFX_REMOVE_FIRST(B_UserItem, lst)
    66
    7 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_FIRST(B_UserItem, lst, ui[i])
    8 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_HERE(B_UserItem, lst, iters[NumNodes-(i)-1])
     7#define BOP_INSERT(lst, iters, insNo, item)  BFX_INSERT_FIRST(B_UserItem, lst, (item))
     8#define BOP_REMOVE(lst, iters, remNo)        BFX_REMOVE_HERE(B_UserItem, lst, iters[NumNodes-(remNo)-1])
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-inslast-allhead.h

    ra50fdfb r6e1e2d0  
    33// allhead:  inserts and removes happen via the api-provided "last"/"tail"/"back"
    44
    5 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_LAST(B_UserItem, lst, ui[i])
    6 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_LAST(B_UserItem, lst)
     5#define BOP_INSERT(lst, iters, insNo, item)  BFX_INSERT_LAST(B_UserItem, lst, (item))
     6#define BOP_REMOVE(lst, iters, remNo)        BFX_REMOVE_LAST(B_UserItem, lst)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-inslast-inselem.h

    ra50fdfb r6e1e2d0  
    33// inselem:  inserts happen via an element-level operation and removes happen via the api-provided "last"/"tail"/"back"
    44
    5 #define BOP_INIT(lst, ui, iters, i) BFX_INSERT_LAST(B_UserItem, lst, ui[i])
     5#define BOP_INIT(lst, iters, insNo, item)   BFX_INSERT_LAST(B_UserItem, lst, (item))
    66
    7 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_AFTER(B_UserItem, lst, ui[i], iters[i-1])
    8 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_LAST(B_UserItem, lst)
     7#define BOP_INSERT(lst, iters, insNo, item) BFX_INSERT_AFTER(B_UserItem, lst, (item), iters[(insNo)-1])
     8#define BOP_REMOVE(lst, iters, remNo)      BFX_REMOVE_LAST(B_UserItem, lst)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-inslast-remelem.h

    ra50fdfb r6e1e2d0  
    33// remelem:  removes happen via an element-level operation and inserts happen via the api-provided "last"/"tail"/"back"
    44
    5 #define BOP_TEARDOWN(lst, ui, iters, i) BFX_REMOVE_LAST(B_UserItem, lst)
     5#define BOP_TEARDOWN(lst, iters, remNo)      BFX_REMOVE_LAST(B_UserItem, lst)
    66
    7 #define BOP_INSERT(lst, ui, iters, i) BFX_INSERT_LAST(B_UserItem, lst, ui[i])
    8 #define BOP_REMOVE(lst, ui, iters, i) BFX_REMOVE_HERE(B_UserItem, lst, iters[NumNodes-(i)-1])
     7#define BOP_INSERT(lst, iters, insNo, item)  BFX_INSERT_LAST(B_UserItem, lst, (item))
     8#define BOP_REMOVE(lst, iters, remNo)        BFX_REMOVE_HERE(B_UserItem, lst, iters[NumNodes-(remNo)-1])
  • doc/theses/mike_brooks_MMath/benchmarks/list/results-baseline.csv

    ra50fdfb r6e1e2d0  
    1 2023-04-03 15:39:25,5,./perfexp--lq-tailq--stack-insfirst-inselem,443000000,5.005379,11.298824
    2 2023-04-03 15:39:30,3,./perfexp--lq-tailq--queue-inslast-allhead,570000000,5.007309,8.784753
    3 2023-04-03 15:39:35,3,./perfexp--lq-tailq--stack-inslast-inselem,606000000,5.000877,8.252272
    4 2023-04-03 15:39:40,2,./perfexp--upp-upp--stack-insfirst-remelem,657000000,5.006698,7.620545
    5 2023-04-03 15:39:45,1,./perfexp--lq-tailq--stack-inslast-allhead,617000000,5.002409,8.107632
    6 2023-04-03 15:39:50,2,./perfexp--lq-tailq--stack-inslast-inselem,607000000,5.007467,8.249534
    7 2023-04-03 15:39:55,3,./perfexp--upp-upp--stack-inslast-allhead,572000000,5.002847,8.746236
    8 2023-04-03 15:40:01,5,./perfexp--lq-tailq--queue-insfirst-allhead,536000000,5.000997,9.330218
    9 2023-04-03 15:40:06,5,./perfexp--upp-upp--queue-insfirst-allhead,458000000,5.009543,10.937867
    10 2023-04-03 15:40:11,5,./perfexp--cfa-cfa--queue-inslast-remelem,710000000,5.003976,7.047854
    11 2023-04-03 15:40:16,1,./perfexp--cpp-stlref--stack-inslast-allhead,166000000,5.002189,30.133669
    12 2023-04-03 15:40:21,2,./perfexp--cfa-cfa--stack-inslast-allhead,547000000,5.004804,9.149550
    13 2023-04-03 15:40:26,1,./perfexp--lq-tailq--stack-insfirst-remelem,713000000,5.006425,7.021634
    14 2023-04-03 15:40:31,4,./perfexp--upp-upp--stack-inslast-allhead,567000000,5.003325,8.824206
    15 2023-04-03 15:40:36,2,./perfexp--upp-upp--stack-inslast-inselem,489000000,5.000271,10.225503
    16 2023-04-03 15:40:41,2,./perfexp--cpp-stlref--stack-inslast-remelem,158000000,5.017243,31.754703
    17 2023-04-03 15:40:46,5,./perfexp--upp-upp--stack-inslast-allhead,549000000,5.005594,9.117658
    18 2023-04-03 15:40:51,3,./perfexp--upp-upp--queue-inslast-inselem,487000000,5.003425,10.273973
    19 2023-04-03 15:40:56,4,./perfexp--cfa-cfa--stack-inslast-inselem,538000000,5.004632,9.302290
    20 2023-04-03 15:41:01,3,./perfexp--cfa-cfa--queue-insfirst-remelem,718000000,5.006064,6.972234
    21 2023-04-03 15:41:06,3,./perfexp--cpp-stlref--queue-inslast-inselem,167000000,5.027628,30.105557
    22 2023-04-03 15:41:11,5,./perfexp--cfa-cfa--queue-insfirst-allhead,510000000,5.007280,9.818196
    23 2023-04-03 15:41:16,5,./perfexp--lq-list--stack-insfirst-inselem,462000000,5.010782,10.845848
    24 2023-04-03 15:41:21,5,./perfexp--lq-tailq--queue-inslast-allhead,565000000,5.008089,8.863874
    25 2023-04-03 15:41:26,2,./perfexp--cpp-stlref--queue-insfirst-inselem,167000000,5.002444,29.954754
    26 2023-04-03 15:41:31,3,./perfexp--cpp-stlref--queue-insfirst-allhead,172000000,5.012068,29.139930
    27 2023-04-03 15:41:36,2,./perfexp--upp-upp--queue-insfirst-inselem,465000000,5.003175,10.759516
    28 2023-04-03 15:41:41,4,./perfexp--lq-tailq--queue-inslast-remelem,535000000,5.003059,9.351512
    29 2023-04-03 15:41:46,4,./perfexp--cpp-stlref--queue-inslast-remelem,166000000,5.000510,30.123554
    30 2023-04-03 15:41:51,3,./perfexp--lq-tailq--stack-insfirst-remelem,710000000,5.003302,7.046904
    31 2023-04-03 15:41:56,1,./perfexp--lq-tailq--queue-insfirst-allhead,539000000,5.005817,9.287230
    32 2023-04-03 15:42:01,5,./perfexp--upp-upp--queue-insfirst-remelem,608000000,5.006322,8.234082
    33 2023-04-03 15:42:06,2,./perfexp--cpp-stlref--stack-insfirst-inselem,165000000,5.002635,30.319000
    34 2023-04-03 15:42:11,5,./perfexp--cfa-cfa--queue-insfirst-inselem,510000000,5.009883,9.823300
    35 2023-04-03 15:42:16,1,./perfexp--cfa-cfa--stack-insfirst-allhead,552000000,5.000119,9.058187
    36 2023-04-03 15:42:21,1,./perfexp--lq-list--stack-insfirst-remelem,712000000,5.005641,7.030395
    37 2023-04-03 15:42:26,3,./perfexp--upp-upp--stack-inslast-remelem,685000000,5.000472,7.299959
    38 2023-04-03 15:42:31,1,./perfexp--lq-tailq--stack-insfirst-inselem,444000000,5.008487,11.280376
    39 2023-04-03 15:42:37,2,./perfexp--cpp-stlref--stack-inslast-allhead,161000000,5.025004,31.211205
    40 2023-04-03 15:42:42,3,./perfexp--cfa-cfa--stack-inslast-allhead,545000000,5.002831,9.179506
    41 2023-04-03 15:42:47,1,./perfexp--upp-upp--stack-inslast-allhead,567000000,5.007839,8.832168
    42 2023-04-03 15:42:52,5,./perfexp--cpp-stlref--stack-insfirst-inselem,165000000,5.025721,30.458915
    43 2023-04-03 15:42:57,3,./perfexp--lq-tailq--queue-insfirst-allhead,537000000,5.005007,9.320311
    44 2023-04-03 15:43:02,5,./perfexp--cfa-cfa--stack-insfirst-remelem,759000000,5.000831,6.588710
    45 2023-04-03 15:43:07,4,./perfexp--cpp-stlref--queue-insfirst-remelem,170000000,5.016844,29.510847
    46 2023-04-03 15:43:12,2,./perfexp--upp-upp--queue-insfirst-remelem,664000000,5.002228,7.533476
    47 2023-04-03 15:43:17,4,./perfexp--lq-tailq--queue-insfirst-allhead,537000000,5.005068,9.320425
    48 2023-04-03 15:43:22,3,./perfexp--lq-tailq--stack-insfirst-inselem,444000000,5.009009,11.281552
    49 2023-04-03 15:43:27,5,./perfexp--cfa-cfa--stack-inslast-inselem,538000000,5.000494,9.294599
    50 2023-04-03 15:43:32,3,./perfexp--cpp-stlref--stack-insfirst-inselem,166000000,5.023027,30.259199
    51 2023-04-03 15:43:37,2,./perfexp--cpp-stlref--queue-insfirst-allhead,168000000,5.019833,29.879958
    52 2023-04-03 15:43:42,1,./perfexp--upp-upp--stack-inslast-inselem,491000000,5.000784,10.184896
    53 2023-04-03 15:43:47,3,./perfexp--cpp-stlref--stack-inslast-remelem,159000000,5.025671,31.607994
    54 2023-04-03 15:43:52,1,./perfexp--cfa-cfa--stack-inslast-remelem,768000000,5.003314,6.514732
    55 2023-04-03 15:43:57,5,./perfexp--cfa-cfa--queue-insfirst-remelem,718000000,5.000123,6.963960
    56 2023-04-03 15:44:02,4,./perfexp--cfa-cfa--queue-inslast-remelem,706000000,5.005028,7.089275
    57 2023-04-03 15:44:07,1,./perfexp--lq-tailq--stack-insfirst-allhead,594000000,5.002014,8.420899
    58 2023-04-03 15:44:12,3,./perfexp--lq-tailq--queue-insfirst-inselem,437000000,5.006085,11.455572
    59 2023-04-03 15:44:17,2,./perfexp--lq-tailq--stack-inslast-remelem,826000000,5.000880,6.054334
    60 2023-04-03 15:44:22,3,./perfexp--upp-upp--stack-inslast-inselem,492000000,5.009566,10.182045
    61 2023-04-03 15:44:27,2,./perfexp--upp-upp--stack-inslast-remelem,697000000,5.000839,7.174805
    62 2023-04-03 15:44:32,2,./perfexp--cfa-cfa--stack-insfirst-remelem,756000000,5.000070,6.613849
    63 2023-04-03 15:44:37,5,./perfexp--lq-tailq--stack-insfirst-remelem,717000000,5.007000,6.983264
    64 2023-04-03 15:44:43,4,./perfexp--cfa-cfa--queue-insfirst-inselem,507000000,5.000763,9.863438
    65 2023-04-03 15:44:48,1,./perfexp--cpp-stlref--queue-inslast-inselem,161000000,5.027524,31.226857
    66 2023-04-03 15:44:53,4,./perfexp--cfa-cfa--queue-insfirst-allhead,508000000,5.009748,9.861709
    67 2023-04-03 15:44:58,2,./perfexp--lq-tailq--stack-insfirst-allhead,595000000,5.001977,8.406684
    68 2023-04-03 15:45:03,4,./perfexp--lq-tailq--queue-insfirst-inselem,431000000,5.000710,11.602575
    69 2023-04-03 15:45:08,3,./perfexp--upp-upp--stack-insfirst-allhead,601000000,5.002087,8.322940
    70 2023-04-03 15:45:13,5,./perfexp--lq-tailq--stack-inslast-remelem,828000000,5.002858,6.042099
    71 2023-04-03 15:45:18,4,./perfexp--upp-upp--stack-insfirst-allhead,520000000,5.008182,9.631119
    72 2023-04-03 15:45:23,5,./perfexp--lq-tailq--queue-inslast-remelem,529000000,5.000836,9.453376
    73 2023-04-03 15:45:28,4,./perfexp--cfa-cfa--queue-insfirst-remelem,718000000,5.002385,6.967110
    74 2023-04-03 15:45:33,4,./perfexp--cpp-stlref--stack-inslast-allhead,162000000,5.021934,30.999593
    75 2023-04-03 15:45:38,5,./perfexp--cpp-stlref--stack-inslast-inselem,160000000,5.015857,31.349106
    76 2023-04-03 15:45:43,3,./perfexp--cfa-cfa--stack-inslast-inselem,539000000,5.008154,9.291566
    77 2023-04-03 15:45:48,3,./perfexp--cpp-stlref--stack-inslast-inselem,163000000,5.010634,30.740086
    78 2023-04-03 15:45:53,5,./perfexp--cpp-stlref--stack-insfirst-allhead,166000000,5.018746,30.233410
    79 2023-04-03 15:45:58,1,./perfexp--cfa-cfa--queue-inslast-remelem,710000000,5.006924,7.052006
    80 2023-04-03 15:46:03,1,./perfexp--cpp-stlref--stack-inslast-remelem,156000000,5.000411,32.053917
    81 2023-04-03 15:46:08,2,./perfexp--lq-tailq--stack-inslast-allhead,617000000,5.005184,8.112130
    82 2023-04-03 15:46:13,1,./perfexp--cfa-cfa--queue-insfirst-remelem,719000000,5.003622,6.959140
    83 2023-04-03 15:46:18,4,./perfexp--lq-tailq--queue-inslast-allhead,564000000,5.000835,8.866729
    84 2023-04-03 15:46:23,1,./perfexp--lq-tailq--queue-insfirst-remelem,759000000,5.001690,6.589842
    85 2023-04-03 15:46:28,3,./perfexp--cpp-stlref--queue-insfirst-remelem,169000000,5.025107,29.734361
    86 2023-04-03 15:46:33,1,./perfexp--cpp-stlref--stack-insfirst-allhead,166000000,5.027112,30.283807
    87 2023-04-03 15:46:38,1,./perfexp--cpp-stlref--queue-insfirst-remelem,169000000,5.006199,29.622479
    88 2023-04-03 15:46:44,2,./perfexp--upp-upp--stack-inslast-allhead,566000000,5.000864,8.835449
    89 2023-04-03 15:46:49,2,./perfexp--cfa-cfa--queue-inslast-allhead,517000000,5.009262,9.689095
    90 2023-04-03 15:46:54,2,./perfexp--lq-tailq--stack-insfirst-inselem,445000000,5.000014,11.235987
    91 2023-04-03 15:46:59,3,./perfexp--lq-list--stack-insfirst-remelem,713000000,5.003234,7.017158
    92 2023-04-03 15:47:04,3,./perfexp--lq-tailq--queue-insfirst-remelem,759000000,5.001448,6.589523
    93 2023-04-03 15:47:09,4,./perfexp--cpp-stlref--stack-inslast-inselem,164000000,5.002294,30.501793
    94 2023-04-03 15:47:14,3,./perfexp--cpp-stlref--stack-insfirst-allhead,166000000,5.015560,30.214217
    95 2023-04-03 15:47:19,2,./perfexp--lq-tailq--queue-inslast-remelem,533000000,5.003926,9.388229
    96 2023-04-03 15:47:24,2,./perfexp--cpp-stlref--stack-inslast-inselem,164000000,5.013968,30.572976
    97 2023-04-03 15:47:29,3,./perfexp--lq-tailq--stack-inslast-remelem,833000000,5.003961,6.007156
    98 2023-04-03 15:47:34,2,./perfexp--cfa-cfa--stack-insfirst-allhead,552000000,5.005105,9.067219
    99 2023-04-03 15:47:39,5,./perfexp--upp-upp--queue-inslast-allhead,539000000,5.003768,9.283429
    100 2023-04-03 15:47:44,2,./perfexp--cpp-stlref--queue-inslast-remelem,163000000,5.022589,30.813429
    101 2023-04-03 15:47:49,5,./perfexp--cpp-stlref--queue-inslast-inselem,165000000,5.027219,30.467994
    102 2023-04-03 15:47:54,5,./perfexp--cpp-stlref--queue-inslast-allhead,170000000,5.024832,29.557835
    103 2023-04-03 15:47:59,3,./perfexp--cpp-stlref--queue-inslast-remelem,165000000,5.027366,30.468885
    104 2023-04-03 15:48:04,1,./perfexp--cfa-cfa--stack-inslast-inselem,536000000,5.005369,9.338375
    105 2023-04-03 15:48:09,1,./perfexp--cpp-stlref--queue-inslast-remelem,162000000,5.023907,31.011772
    106 2023-04-03 15:48:14,4,./perfexp--cpp-stlref--stack-insfirst-inselem,165000000,5.002599,30.318782
    107 2023-04-03 15:48:19,4,./perfexp--cfa-cfa--queue-inslast-inselem,519000000,5.007842,9.649021
    108 2023-04-03 15:48:24,4,./perfexp--cpp-stlref--queue-insfirst-inselem,170000000,5.028952,29.582071
    109 2023-04-03 15:48:29,1,./perfexp--lq-tailq--queue-insfirst-inselem,433000000,5.010306,11.571145
    110 2023-04-03 15:48:34,2,./perfexp--cfa-cfa--queue-inslast-remelem,709000000,5.006604,7.061501
    111 2023-04-03 15:48:39,4,./perfexp--upp-upp--stack-inslast-inselem,491000000,5.004649,10.192768
    112 2023-04-03 15:48:44,4,./perfexp--lq-tailq--stack-inslast-inselem,606000000,5.003287,8.256249
    113 2023-04-03 15:48:49,5,./perfexp--lq-tailq--queue-inslast-inselem,557000000,5.007731,8.990540
    114 2023-04-03 15:48:54,4,./perfexp--upp-upp--queue-insfirst-inselem,460000000,5.002636,10.875296
    115 2023-04-03 15:48:59,4,./perfexp--upp-upp--queue-inslast-allhead,537000000,5.005155,9.320587
    116 2023-04-03 15:49:04,2,./perfexp--upp-upp--queue-inslast-allhead,538000000,5.007986,9.308524
    117 2023-04-03 15:49:10,5,./perfexp--upp-upp--stack-insfirst-inselem,526000000,5.007934,9.520787
    118 2023-04-03 15:49:15,5,./perfexp--cpp-stlref--stack-inslast-allhead,165000000,5.014335,30.389909
    119 2023-04-03 15:49:20,5,./perfexp--cpp-stlref--stack-insfirst-remelem,156000000,5.013451,32.137506
    120 2023-04-03 15:49:25,3,./perfexp--cfa-cfa--stack-insfirst-inselem,548000000,5.000615,9.125210
    121 2023-04-03 15:49:30,4,./perfexp--cfa-cfa--stack-inslast-remelem,769000000,5.001464,6.503854
    122 2023-04-03 15:49:35,1,./perfexp--upp-upp--queue-inslast-remelem,603000000,5.003718,8.298040
    123 2023-04-03 15:49:40,2,./perfexp--cpp-stlref--queue-inslast-inselem,164000000,5.012683,30.565140
    124 2023-04-03 15:49:45,5,./perfexp--upp-upp--stack-insfirst-remelem,642000000,5.004144,7.794617
    125 2023-04-03 15:49:50,4,./perfexp--upp-upp--queue-inslast-remelem,606000000,5.001222,8.252842
    126 2023-04-03 15:49:55,2,./perfexp--cpp-stlref--stack-insfirst-remelem,158000000,5.016260,31.748481
    127 2023-04-03 15:50:00,5,./perfexp--cfa-cfa--queue-inslast-allhead,518000000,5.003133,9.658558
    128 2023-04-03 15:50:05,2,./perfexp--upp-upp--queue-inslast-remelem,610000000,5.003194,8.201957
    129 2023-04-03 15:50:10,4,./perfexp--lq-tailq--stack-inslast-remelem,829000000,5.004086,6.036292
    130 2023-04-03 15:50:15,5,./perfexp--lq-tailq--stack-insfirst-allhead,596000000,5.008331,8.403240
    131 2023-04-03 15:50:20,3,./perfexp--cpp-stlref--stack-insfirst-remelem,157000000,5.028128,32.026293
    132 2023-04-03 15:50:25,1,./perfexp--cfa-cfa--stack-inslast-allhead,545000000,5.003736,9.181167
    133 2023-04-03 15:50:30,2,./perfexp--cpp-stlref--stack-insfirst-allhead,166000000,5.011507,30.189801
    134 2023-04-03 15:50:35,2,./perfexp--lq-list--stack-insfirst-inselem,441000000,5.004092,11.347147
    135 2023-04-03 15:50:40,1,./perfexp--lq-tailq--stack-inslast-remelem,831000000,5.002214,6.019511
    136 2023-04-03 15:50:45,2,./perfexp--cfa-cfa--stack-insfirst-inselem,549000000,5.006757,9.119776
    137 2023-04-03 15:50:51,4,./perfexp--upp-upp--stack-inslast-remelem,707000000,5.000598,7.072982
    138 2023-04-03 15:50:56,2,./perfexp--cfa-cfa--queue-inslast-inselem,519000000,5.000666,9.635195
    139 2023-04-03 15:51:01,4,./perfexp--lq-tailq--stack-insfirst-remelem,715000000,5.002704,6.996789
    140 2023-04-03 15:51:06,3,./perfexp--cfa-cfa--stack-inslast-remelem,772000000,5.003203,6.480833
    141 2023-04-03 15:51:11,1,./perfexp--upp-upp--stack-insfirst-inselem,524000000,5.006068,9.553565
    142 2023-04-03 15:51:16,2,./perfexp--upp-upp--queue-insfirst-allhead,510000000,5.009613,9.822771
    143 2023-04-03 15:51:21,3,./perfexp--lq-tailq--queue-inslast-remelem,530000000,5.006810,9.446811
    144 2023-04-03 15:51:26,4,./perfexp--cpp-stlref--stack-insfirst-remelem,159000000,5.007889,31.496157
    145 2023-04-03 15:51:31,4,./perfexp--upp-upp--queue-insfirst-remelem,661000000,5.002903,7.568688
    146 2023-04-03 15:51:36,2,./perfexp--lq-tailq--queue-insfirst-inselem,432000000,5.003819,11.582914
    147 2023-04-03 15:51:41,1,./perfexp--upp-upp--stack-insfirst-remelem,655000000,5.007278,7.644699
    148 2023-04-03 15:51:46,3,./perfexp--lq-tailq--stack-insfirst-allhead,596000000,5.002249,8.393035
    149 2023-04-03 15:51:51,5,./perfexp--upp-upp--stack-inslast-inselem,493000000,5.008268,10.158759
    150 2023-04-03 15:51:56,5,./perfexp--cfa-cfa--queue-inslast-inselem,520000000,5.008160,9.631077
    151 2023-04-03 15:52:01,2,./perfexp--cfa-cfa--queue-insfirst-allhead,509000000,5.001747,9.826615
    152 2023-04-03 15:52:06,2,./perfexp--cfa-cfa--queue-insfirst-remelem,717000000,5.003431,6.978286
    153 2023-04-03 15:52:11,5,./perfexp--cfa-cfa--stack-insfirst-inselem,548000000,5.005236,9.133642
    154 2023-04-03 15:52:16,5,./perfexp--upp-upp--stack-insfirst-allhead,589000000,5.008330,8.503107
    155 2023-04-03 15:52:21,3,./perfexp--upp-upp--queue-inslast-remelem,606000000,5.000791,8.252130
    156 2023-04-03 15:52:26,2,./perfexp--cfa-cfa--queue-insfirst-inselem,509000000,5.005662,9.834306
    157 2023-04-03 15:52:31,2,./perfexp--cpp-stlref--queue-insfirst-remelem,170000000,5.014890,29.499353
    158 2023-04-03 15:52:36,4,./perfexp--upp-upp--stack-insfirst-inselem,526000000,5.008703,9.522249
    159 2023-04-03 15:52:42,3,./perfexp--lq-list--stack-insfirst-inselem,442000000,5.009383,11.333446
    160 2023-04-03 15:52:47,3,./perfexp--cfa-cfa--queue-inslast-inselem,520000000,5.007789,9.630363
    161 2023-04-03 15:52:52,5,./perfexp--cpp-stlref--queue-insfirst-inselem,167000000,5.011863,30.011156
    162 2023-04-03 15:52:57,3,./perfexp--cfa-cfa--stack-insfirst-remelem,761000000,5.004427,6.576120
    163 2023-04-03 15:53:02,1,./perfexp--lq-tailq--queue-inslast-allhead,569000000,5.000007,8.787359
    164 2023-04-03 15:53:07,4,./perfexp--cfa-cfa--stack-insfirst-remelem,755000000,5.006075,6.630563
    165 2023-04-03 15:53:12,1,./perfexp--cfa-cfa--queue-insfirst-allhead,508000000,5.007775,9.857825
    166 2023-04-03 15:53:17,3,./perfexp--upp-upp--queue-insfirst-remelem,662000000,5.003549,7.558231
    167 2023-04-03 15:53:22,1,./perfexp--upp-upp--stack-insfirst-allhead,602000000,5.003572,8.311581
    168 2023-04-03 15:53:27,5,./perfexp--lq-tailq--stack-inslast-allhead,617000000,5.001483,8.106131
    169 2023-04-03 15:53:32,4,./perfexp--lq-list--stack-insfirst-inselem,442000000,5.010176,11.335240
    170 2023-04-03 15:53:37,4,./perfexp--cpp-stlref--stack-insfirst-allhead,166000000,5.013545,30.202078
    171 2023-04-03 15:53:42,5,./perfexp--cfa-cfa--stack-insfirst-allhead,552000000,5.000744,9.059319
    172 2023-04-03 15:53:47,4,./perfexp--lq-tailq--queue-insfirst-remelem,765000000,5.002711,6.539492
    173 2023-04-03 15:53:52,3,./perfexp--cfa-cfa--stack-insfirst-allhead,552000000,5.007654,9.071837
    174 2023-04-03 15:53:57,1,./perfexp--upp-upp--queue-insfirst-remelem,660000000,5.001139,7.577483
    175 2023-04-03 15:54:02,3,./perfexp--cpp-stlref--queue-insfirst-inselem,169000000,5.013091,29.663260
    176 2023-04-03 15:54:07,2,./perfexp--lq-list--stack-insfirst-remelem,713000000,5.006786,7.022140
    177 2023-04-03 15:54:12,1,./perfexp--lq-tailq--stack-inslast-inselem,606000000,5.002385,8.254761
    178 2023-04-03 15:54:17,4,./perfexp--upp-upp--queue-inslast-inselem,487000000,5.003862,10.274871
    179 2023-04-03 15:54:22,1,./perfexp--lq-list--stack-insfirst-allhead,593000000,5.002939,8.436659
    180 2023-04-03 15:54:27,2,./perfexp--lq-tailq--queue-inslast-allhead,565000000,5.004251,8.857081
    181 2023-04-03 15:54:32,5,./perfexp--lq-list--stack-insfirst-allhead,592000000,5.001007,8.447647
    182 2023-04-03 15:54:37,3,./perfexp--upp-upp--queue-inslast-allhead,538000000,5.007986,9.308524
    183 2023-04-03 15:54:42,4,./perfexp--lq-tailq--stack-inslast-allhead,617000000,5.004785,8.111483
    184 2023-04-03 15:54:47,2,./perfexp--lq-tailq--queue-insfirst-allhead,537000000,5.000866,9.312600
    185 2023-04-03 15:54:52,3,./perfexp--lq-tailq--stack-inslast-allhead,593000000,5.001259,8.433826
    186 2023-04-03 15:54:57,5,./perfexp--lq-tailq--stack-inslast-inselem,607000000,5.008090,8.250560
    187 2023-04-03 15:55:02,1,./perfexp--cfa-cfa--queue-inslast-inselem,520000000,5.007405,9.629625
    188 2023-04-03 15:55:07,2,./perfexp--lq-list--stack-insfirst-allhead,590000000,5.000838,8.475997
    189 2023-04-03 15:55:12,3,./perfexp--upp-upp--stack-insfirst-inselem,525000000,5.004319,9.532036
    190 2023-04-03 15:55:17,5,./perfexp--cpp-stlref--queue-insfirst-remelem,170000000,5.018299,29.519406
    191 2023-04-03 15:55:22,3,./perfexp--lq-tailq--queue-inslast-inselem,557000000,5.000287,8.977176
    192 2023-04-03 15:55:28,1,./perfexp--lq-tailq--queue-inslast-inselem,550000000,5.002507,9.095467
    193 2023-04-03 15:55:33,4,./perfexp--lq-tailq--queue-inslast-inselem,557000000,5.002020,8.980287
    194 2023-04-03 15:55:38,1,./perfexp--cfa-cfa--queue-insfirst-inselem,507000000,5.001630,9.865148
    195 2023-04-03 15:55:43,1,./perfexp--cpp-stlref--stack-inslast-inselem,166000000,5.029390,30.297530
    196 2023-04-03 15:55:48,2,./perfexp--upp-upp--queue-inslast-inselem,486000000,5.003020,10.294280
    197 2023-04-03 15:55:53,3,./perfexp--upp-upp--queue-insfirst-inselem,461000000,5.000073,10.846145
    198 2023-04-03 15:55:58,5,./perfexp--cfa-cfa--stack-inslast-allhead,547000000,5.004262,9.148559
    199 2023-04-03 15:56:03,1,./perfexp--lq-tailq--queue-inslast-remelem,546000000,5.005073,9.166800
    200 2023-04-03 15:56:08,3,./perfexp--lq-list--stack-insfirst-allhead,591000000,5.003465,8.466100
    201 2023-04-03 15:56:13,2,./perfexp--lq-tailq--stack-insfirst-remelem,716000000,5.001052,6.984709
    202 2023-04-03 15:56:18,4,./perfexp--cfa-cfa--queue-inslast-allhead,516000000,5.003638,9.696973
    203 2023-04-03 15:56:23,1,./perfexp--cpp-stlref--stack-insfirst-remelem,159000000,5.008347,31.499038
    204 2023-04-03 15:56:28,4,./perfexp--lq-tailq--stack-insfirst-inselem,445000000,5.007219,11.252178
    205 2023-04-03 15:56:33,2,./perfexp--lq-tailq--queue-insfirst-remelem,763000000,5.000451,6.553671
    206 2023-04-03 15:56:38,1,./perfexp--upp-upp--queue-insfirst-inselem,461000000,5.002222,10.850807
    207 2023-04-03 15:56:43,1,./perfexp--cpp-stlref--queue-insfirst-inselem,167000000,5.019099,30.054485
    208 2023-04-03 15:56:48,4,./perfexp--cfa-cfa--stack-insfirst-allhead,553000000,5.005063,9.050747
    209 2023-04-03 15:56:53,2,./perfexp--lq-tailq--queue-inslast-inselem,557000000,5.001068,8.978578
    210 2023-04-03 15:56:58,3,./perfexp--upp-upp--stack-insfirst-remelem,644000000,5.005232,7.772099
    211 2023-04-03 15:57:03,2,./perfexp--cfa-cfa--stack-inslast-inselem,538000000,5.004795,9.302593
    212 2023-04-03 15:57:08,4,./perfexp--cpp-stlref--stack-inslast-remelem,158000000,5.004902,31.676595
    213 2023-04-03 15:57:13,1,./perfexp--upp-upp--queue-inslast-allhead,539000000,5.002228,9.280571
    214 2023-04-03 15:57:18,5,./perfexp--cpp-stlref--stack-inslast-remelem,159000000,5.019823,31.571214
    215 2023-04-03 15:57:23,1,./perfexp--upp-upp--queue-insfirst-allhead,505000000,5.008103,9.917036
    216 2023-04-03 15:57:29,5,./perfexp--lq-tailq--queue-insfirst-inselem,415000000,5.000368,12.049080
    217 2023-04-03 15:57:34,3,./perfexp--cfa-cfa--queue-insfirst-inselem,509000000,5.003350,9.829764
    218 2023-04-03 15:57:39,1,./perfexp--upp-upp--stack-inslast-remelem,687000000,5.005699,7.286316
    219 2023-04-03 15:57:44,2,./perfexp--upp-upp--stack-insfirst-inselem,526000000,5.004338,9.513951
    220 2023-04-03 15:57:49,1,./perfexp--upp-upp--queue-inslast-inselem,489000000,5.001246,10.227497
    221 2023-04-03 15:57:54,3,./perfexp--cfa-cfa--queue-inslast-allhead,516000000,5.004492,9.698628
    222 2023-04-03 15:57:59,5,./perfexp--cfa-cfa--stack-inslast-remelem,772000000,5.002201,6.479535
    223 2023-04-03 15:58:04,5,./perfexp--lq-tailq--queue-insfirst-remelem,762000000,5.002834,6.565399
    224 2023-04-03 15:58:09,1,./perfexp--lq-list--stack-insfirst-inselem,441000000,5.003211,11.345150
    225 2023-04-03 15:58:14,1,./perfexp--cfa-cfa--queue-inslast-allhead,516000000,5.006598,9.702709
    226 2023-04-03 15:58:19,2,./perfexp--upp-upp--stack-insfirst-allhead,602000000,5.000444,8.306385
    227 2023-04-03 15:58:24,3,./perfexp--cfa-cfa--queue-inslast-remelem,702000000,5.005657,7.130566
    228 2023-04-03 15:58:29,4,./perfexp--cpp-stlref--queue-inslast-inselem,166000000,5.026702,30.281337
    229 2023-04-03 15:58:34,4,./perfexp--upp-upp--stack-insfirst-remelem,630000000,5.005706,7.945565
    230 2023-04-03 15:58:39,1,./perfexp--cfa-cfa--stack-insfirst-remelem,759000000,5.004132,6.593059
    231 2023-04-03 15:58:44,5,./perfexp--cpp-stlref--queue-inslast-remelem,167000000,5.024779,30.088497
    232 2023-04-03 15:58:49,5,./perfexp--upp-upp--queue-inslast-inselem,485000000,5.001876,10.313146
    233 2023-04-03 15:58:54,4,./perfexp--lq-tailq--stack-insfirst-allhead,595000000,5.003147,8.408650
    234 2023-04-03 15:58:59,5,./perfexp--upp-upp--stack-inslast-remelem,680000000,5.001317,7.354878
    235 2023-04-03 15:59:04,5,./perfexp--upp-upp--queue-insfirst-inselem,462000000,5.006965,10.837587
    236 2023-04-03 15:59:09,3,./perfexp--cpp-stlref--queue-inslast-allhead,172000000,5.023178,29.204523
    237 2023-04-03 15:59:14,4,./perfexp--cpp-stlref--queue-insfirst-allhead,173000000,5.020339,29.019301
    238 2023-04-03 15:59:19,5,./perfexp--lq-list--stack-insfirst-remelem,712000000,5.002571,7.026083
    239 2023-04-03 15:59:24,4,./perfexp--upp-upp--queue-insfirst-allhead,506000000,5.000700,9.882806
    240 2023-04-03 15:59:29,4,./perfexp--cpp-stlref--queue-inslast-allhead,167000000,5.011863,30.011156
    241 2023-04-03 15:59:34,2,./perfexp--cfa-cfa--stack-inslast-remelem,771000000,5.001426,6.486934
    242 2023-04-03 15:59:39,4,./perfexp--cfa-cfa--stack-insfirst-inselem,550000000,5.005721,9.101311
    243 2023-04-03 15:59:44,1,./perfexp--cfa-cfa--stack-insfirst-inselem,551000000,5.002555,9.079047
    244 2023-04-03 15:59:49,4,./perfexp--cfa-cfa--stack-inslast-allhead,546000000,5.001532,9.160315
    245 2023-04-03 15:59:54,2,./perfexp--cpp-stlref--queue-inslast-allhead,161000000,5.006152,31.094112
    246 2023-04-03 15:59:59,3,./perfexp--cpp-stlref--stack-inslast-allhead,166000000,5.020481,30.243861
    247 2023-04-03 16:00:04,1,./perfexp--cpp-stlref--stack-insfirst-inselem,165000000,5.020233,30.425655
    248 2023-04-03 16:00:09,3,./perfexp--cfa-cfa--queue-insfirst-allhead,509000000,5.003864,9.830774
    249 2023-04-03 16:00:14,4,./perfexp--lq-list--stack-insfirst-allhead,593000000,5.002670,8.436206
    250 2023-04-03 16:00:19,1,./perfexp--cpp-stlref--queue-insfirst-allhead,170000000,5.005779,29.445759
    251 2023-04-03 16:00:25,1,./perfexp--cpp-stlref--queue-inslast-allhead,168000000,5.021567,29.890280
    252 2023-04-03 16:00:30,5,./perfexp--cpp-stlref--queue-insfirst-allhead,170000000,5.030049,29.588524
    253 2023-04-03 16:00:35,5,./perfexp--upp-upp--queue-inslast-remelem,616000000,5.007578,8.129185
    254 2023-04-03 16:00:40,4,./perfexp--lq-list--stack-insfirst-remelem,713000000,5.002819,7.016576
    255 2023-04-03 16:00:45,3,./perfexp--upp-upp--queue-insfirst-allhead,501000000,5.007947,9.995902
     12023-04-06 22:38:43,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-inslast-inselem,159326200,5.104060,32.035284
     22023-04-06 22:38:48,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-remelem,224000000,5.117349,22.845308
     32023-04-06 22:38:54,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-inslast-allhead,224000000,5.062724,22.601446
     42023-04-06 22:38:59,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-allhead,166568300,5.161427,30.986850
     52023-04-06 22:39:04,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-remelem,169890000,5.005365,29.462387
     62023-04-06 22:39:09,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-inslast-inselem,444950000,5.003260,11.244544
     72023-04-06 22:39:14,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-insfirst-inselem,289632000,5.002701,17.272611
     82023-04-06 22:39:19,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-inslast-allhead,343938000,5.050625,14.684696
     92023-04-06 22:39:24,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-inselem,546700000,5.031248,9.202941
     102023-04-06 22:39:29,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-inslast-allhead,177980000,5.214033,29.295612
     112023-04-06 22:39:34,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-inslast-remelem,678825000,5.007971,7.377411
     122023-04-06 22:39:39,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-inslast-remelem,177500000,5.051343,28.458270
     132023-04-06 22:39:44,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-inslast-inselem,617700000,5.012318,8.114486
     142023-04-06 22:39:49,2,5 1000000 7 -1 2  ,./perfexp--lq-list--stack-insfirst-inselem,581000000,5.034526,8.665277
     152023-04-06 22:39:54,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-insfirst-remelem,1309000000,5.007982,3.825807
     162023-04-06 22:39:59,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-inslast-remelem,809400000,5.034582,6.220141
     172023-04-06 22:40:04,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-inslast-allhead,352989000,5.080867,14.393839
     182023-04-06 22:40:10,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-inslast-inselem,159326200,5.152641,32.340199
     192023-04-06 22:40:15,4,5 100 72421 -1 4  ,./perfexp--lq-list--stack-insfirst-remelem,333136600,5.081694,15.254085
     202023-04-06 22:40:20,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-inslast-allhead,672000000,5.041239,7.501844
     212023-04-06 22:40:25,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-remelem,159326200,5.216693,32.742217
     222023-04-06 22:40:30,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-inslast-inselem,908800000,5.036669,5.542109
     232023-04-06 22:40:35,1,5 100 72421 -1 1  ,./perfexp--lq-list--stack-insfirst-inselem,166568300,5.225242,31.369967
     242023-04-06 22:40:41,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-inslast-allhead,137599900,5.143664,37.381306
     252023-04-06 22:40:46,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-inslast-inselem,159326200,5.104856,32.040280
     262023-04-06 22:40:51,5,5 1000000 7 -1 5  ,./perfexp--lq-list--stack-insfirst-allhead,917000000,5.030506,5.485830
     272023-04-06 22:40:56,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-insfirst-remelem,296926100,5.105027,17.192921
     282023-04-06 22:41:01,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-allhead,137599900,5.150764,37.432905
     292023-04-06 22:41:06,1,5 100 72421 -1 1  ,./perfexp--lq-list--stack-insfirst-allhead,166568300,5.054932,30.347503
     302023-04-06 22:41:11,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-insfirst-inselem,130357800,5.100502,39.126941
     312023-04-06 22:41:16,3,5 1000 9051 -1 3  ,./perfexp--lq-list--stack-insfirst-inselem,325836000,5.113777,15.694328
     322023-04-06 22:41:22,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-remelem,169890000,5.046006,29.701607
     332023-04-06 22:41:27,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-insfirst-inselem,477310000,5.055761,10.592196
     342023-04-06 22:41:32,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-remelem,588315000,5.001890,8.502061
     352023-04-06 22:41:37,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-inselem,651000000,5.008924,7.694200
     362023-04-06 22:41:42,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-insfirst-remelem,590570000,5.038027,8.530787
     372023-04-06 22:41:47,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-inslast-remelem,153867000,5.210496,33.863635
     382023-04-06 22:41:52,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-insfirst-remelem,859100000,5.034777,5.860525
     392023-04-06 22:41:57,3,5 10000 809 -1 3  ,./perfexp--lq-list--stack-insfirst-remelem,590570000,5.065984,8.578126
     402023-04-06 22:42:02,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-inslast-inselem,493490000,5.014299,10.160893
     412023-04-06 22:42:07,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-allhead,184600000,5.079109,27.514133
     422023-04-06 22:42:12,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-inselem,231000000,5.041959,21.826662
     432023-04-06 22:42:17,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-inslast-allhead,162918000,5.108416,31.355750
     442023-04-06 22:42:22,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-insfirst-remelem,260715600,5.113112,19.611838
     452023-04-06 22:42:27,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-inslast-inselem,833000000,5.028245,6.036309
     462023-04-06 22:42:33,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-inslast-inselem,352989000,5.105392,14.463318
     472023-04-06 22:42:38,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-inslast-allhead,334887000,5.039581,15.048601
     482023-04-06 22:42:43,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-insfirst-remelem,763000000,5.016755,6.575039
     492023-04-06 22:42:48,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-inslast-allhead,159326200,5.111182,32.079984
     502023-04-06 22:42:53,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-inslast-remelem,979800000,5.002241,5.105369
     512023-04-06 22:42:58,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-inslast-inselem,316785000,5.008967,15.811882
     522023-04-06 22:43:03,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-insfirst-remelem,1316000000,5.025586,3.818834
     532023-04-06 22:43:08,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-inslast-allhead,959000000,5.008021,5.222128
     542023-04-06 22:43:13,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-insfirst-remelem,461601000,5.006449,10.845837
     552023-04-06 22:43:18,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-inslast-inselem,658000000,5.029688,7.643903
     562023-04-06 22:43:23,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-inslast-inselem,658000000,5.022354,7.632757
     572023-04-06 22:43:28,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-inslast-remelem,347620800,5.032410,14.476723
     582023-04-06 22:43:33,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-insfirst-allhead,159326200,5.154973,32.354836
     592023-04-06 22:43:38,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-remelem,169890000,5.130552,30.199258
     602023-04-06 22:43:43,4,5 1000 9051 -1 4  ,./perfexp--lq-list--stack-insfirst-remelem,543060000,5.083894,9.361570
     612023-04-06 22:43:49,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-inslast-remelem,169890000,5.059665,29.782006
     622023-04-06 22:43:54,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-insfirst-allhead,910000000,5.002806,5.497589
     632023-04-06 22:43:59,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-inslast-remelem,575100000,5.010242,8.711949
     642023-04-06 22:44:04,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-insfirst-allhead,728000000,5.022596,6.899170
     652023-04-06 22:44:09,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-inslast-remelem,169890000,5.191497,30.557990
     662023-04-06 22:44:14,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-inslast-allhead,639000000,5.034492,7.878704
     672023-04-06 22:44:19,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-inslast-remelem,311410300,5.098903,16.373585
     682023-04-06 22:44:24,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-insfirst-allhead,325836000,5.135714,15.761653
     692023-04-06 22:44:29,4,5 1000000 7 -1 4  ,./perfexp--lq-list--stack-insfirst-inselem,581000000,5.051661,8.694769
     702023-04-06 22:44:34,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-insfirst-inselem,679000000,5.043664,7.428077
     712023-04-06 22:44:39,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-insfirst-inselem,130357800,5.100746,39.128813
     722023-04-06 22:44:45,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-inselem,137599900,5.151609,37.439046
     732023-04-06 22:44:50,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-inslast-allhead,672000000,5.022206,7.473521
     742023-04-06 22:44:55,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-inselem,343938000,5.113961,14.868846
     752023-04-06 22:45:00,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-inslast-inselem,343938000,5.132823,14.923687
     762023-04-06 22:45:05,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-inslast-allhead,352989000,5.051277,14.310012
     772023-04-06 22:45:10,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-inslast-inselem,343938000,5.079431,14.768450
     782023-04-06 22:45:15,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-inslast-remelem,795200000,5.027511,6.322323
     792023-04-06 22:45:20,2,5 1000 9051 -1 2  ,./perfexp--lq-list--stack-insfirst-inselem,325836000,5.097880,15.645539
     802023-04-06 22:45:25,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-inslast-allhead,325836000,5.039459,15.466244
     812023-04-06 22:45:30,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-inslast-inselem,444950000,5.059145,11.370143
     822023-04-06 22:45:36,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-inslast-inselem,444950000,5.072116,11.399294
     832023-04-06 22:45:41,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-allhead,159326200,5.099274,32.005245
     842023-04-06 22:45:46,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-insfirst-allhead,788100000,5.037081,6.391424
     852023-04-06 22:45:51,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-inslast-allhead,1036600000,5.028854,4.851297
     862023-04-06 22:45:56,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-inslast-allhead,493490000,5.043056,10.219166
     872023-04-06 22:46:01,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-remelem,169890000,5.165830,30.406910
     882023-04-06 22:46:06,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-inslast-remelem,777000000,5.026590,6.469228
     892023-04-06 22:46:11,1,5 10000 809 -1 1  ,./perfexp--lq-list--stack-insfirst-inselem,453040000,5.042693,11.130790
     902023-04-06 22:46:16,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-inslast-inselem,159326200,5.021468,31.516901
     912023-04-06 22:46:21,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-insfirst-allhead,444950000,5.058905,11.369603
     922023-04-06 22:46:26,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-inselem,159326200,5.124781,32.165338
     932023-04-06 22:46:31,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-inslast-allhead,184600000,5.086561,27.554502
     942023-04-06 22:46:37,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-inselem,159326200,5.101698,32.020459
     952023-04-06 22:46:42,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-inslast-remelem,777000000,5.024963,6.467134
     962023-04-06 22:46:47,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-inslast-inselem,901700000,5.038805,5.588117
     972023-04-06 22:46:52,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-insfirst-allhead,325836000,5.086643,15.611053
     982023-04-06 22:46:57,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-remelem,917000000,5.029273,5.484485
     992023-04-06 22:47:02,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-inslast-inselem,159326200,5.146099,32.299138
     1002023-04-06 22:47:07,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-inslast-allhead,646100000,5.036416,7.795103
     1012023-04-06 22:47:12,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-remelem,318652400,5.011899,15.728421
     1022023-04-06 22:47:17,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-remelem,579264000,5.006702,8.643213
     1032023-04-06 22:47:22,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-inselem,477310000,5.036310,10.551445
     1042023-04-06 22:47:27,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-inslast-allhead,159326200,5.051290,31.704076
     1052023-04-06 22:47:32,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-inslast-allhead,509670000,5.059480,9.926972
     1062023-04-06 22:47:37,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-inslast-remelem,534009000,5.021579,9.403548
     1072023-04-06 22:47:42,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-inselem,665000000,5.028019,7.560931
     1082023-04-06 22:47:47,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-inslast-remelem,177500000,5.011349,28.232952
     1092023-04-06 22:47:52,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-inslast-remelem,1242500000,5.025123,4.044365
     1102023-04-06 22:47:57,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-inslast-allhead,325836000,5.033694,15.448551
     1112023-04-06 22:48:02,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-insfirst-allhead,525850000,5.074913,9.650876
     1122023-04-06 22:48:08,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-inslast-remelem,311410300,5.100754,16.379529
     1132023-04-06 22:48:13,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-insfirst-remelem,296926100,5.107471,17.201152
     1142023-04-06 22:48:18,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-allhead,334887000,5.049385,15.077877
     1152023-04-06 22:48:23,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-inslast-remelem,665000000,5.048229,7.591322
     1162023-04-06 22:48:28,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-inslast-inselem,159326200,5.039389,31.629380
     1172023-04-06 22:48:33,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-insfirst-remelem,267957700,5.032279,18.780125
     1182023-04-06 22:48:38,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-inselem,658000000,5.048589,7.672628
     1192023-04-06 22:48:43,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-inslast-remelem,224000000,5.116992,22.843714
     1202023-04-06 22:48:48,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-insfirst-allhead,352989000,5.129190,14.530736
     1212023-04-06 22:48:53,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-inslast-remelem,224000000,5.044124,22.518411
     1222023-04-06 22:48:58,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-inslast-allhead,159326200,5.085806,31.920714
     1232023-04-06 22:49:04,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-inslast-remelem,574390000,5.067621,8.822614
     1242023-04-06 22:49:09,2,5 100 72421 -1 2  ,./perfexp--lq-list--stack-insfirst-inselem,159326200,5.003104,31.401640
     1252023-04-06 22:49:14,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-insfirst-inselem,307734000,5.021786,16.318593
     1262023-04-06 22:49:19,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-insfirst-inselem,973000000,5.029223,5.168780
     1272023-04-06 22:49:24,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-insfirst-inselem,646100000,5.013377,7.759444
     1282023-04-06 22:49:29,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-inslast-inselem,224000000,5.026205,22.438415
     1292023-04-06 22:49:34,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-allhead,162918000,5.122192,31.440307
     1302023-04-06 22:49:39,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-inselem,217000000,5.012642,23.099733
     1312023-04-06 22:49:44,1,5 1000 9051 -1 1  ,./perfexp--lq-list--stack-insfirst-remelem,534009000,5.010162,9.382168
     1322023-04-06 22:49:49,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-inselem,665000000,5.025341,7.556904
     1332023-04-06 22:49:54,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-inslast-inselem,162918000,5.112699,31.382039
     1342023-04-06 22:49:59,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-inslast-remelem,289684000,5.092223,17.578544
     1352023-04-06 22:50:04,1,5 10000 809 -1 1  ,./perfexp--lq-list--stack-insfirst-allhead,509670000,5.018786,9.847129
     1362023-04-06 22:50:09,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-insfirst-inselem,679000000,5.046907,7.432853
     1372023-04-06 22:50:14,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-inslast-allhead,763000000,5.000173,6.553307
     1382023-04-06 22:50:19,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-insfirst-allhead,509670000,5.001591,9.813391
     1392023-04-06 22:50:24,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-insfirst-remelem,260715600,5.115727,19.621868
     1402023-04-06 22:50:30,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-insfirst-inselem,325836000,5.102080,15.658429
     1412023-04-06 22:50:35,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-inslast-remelem,171969000,5.259251,30.582553
     1422023-04-06 22:50:40,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-inslast-allhead,159326200,5.062565,31.774843
     1432023-04-06 22:50:45,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-inslast-remelem,687876000,5.057051,7.351690
     1442023-04-06 22:50:50,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-inselem,159326200,5.115809,32.109025
     1452023-04-06 22:50:55,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-inslast-remelem,973000000,5.015677,5.154858
     1462023-04-06 22:51:00,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-inslast-remelem,260715600,5.002998,19.189485
     1472023-04-06 22:51:05,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-insfirst-allhead,343938000,5.009464,14.565020
     1482023-04-06 22:51:10,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-inslast-allhead,159326200,5.001947,31.394378
     1492023-04-06 22:51:15,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-inslast-remelem,966000000,5.019736,5.196414
     1502023-04-06 22:51:20,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-insfirst-allhead,461130000,5.067126,10.988498
     1512023-04-06 22:51:25,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-inslast-inselem,169890000,5.037162,29.649550
     1522023-04-06 22:51:31,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-inslast-remelem,679560000,5.044672,7.423439
     1532023-04-06 22:51:36,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-remelem,153867000,5.093303,33.101984
     1542023-04-06 22:51:41,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-inslast-remelem,570213000,5.076763,8.903275
     1552023-04-06 22:51:46,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-insfirst-allhead,781000000,5.034261,6.445917
     1562023-04-06 22:51:51,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-insfirst-allhead,352989000,5.119857,14.504296
     1572023-04-06 22:51:56,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-inslast-inselem,568000000,5.020960,8.839718
     1582023-04-06 22:52:01,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-insfirst-inselem,679000000,5.020031,7.393271
     1592023-04-06 22:52:06,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-inslast-inselem,477310000,5.065549,10.612702
     1602023-04-06 22:52:11,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-inslast-allhead,334887000,5.061093,15.112838
     1612023-04-06 22:52:16,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-remelem,171969000,5.199554,30.235415
     1622023-04-06 22:52:21,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-insfirst-remelem,791000000,5.030514,6.359689
     1632023-04-06 22:52:26,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-insfirst-inselem,660300000,5.021934,7.605534
     1642023-04-06 22:52:31,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-inslast-inselem,224000000,5.069797,22.633022
     1652023-04-06 22:52:37,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-insfirst-inselem,766800000,5.034758,6.565934
     1662023-04-06 22:52:42,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-insfirst-inselem,738400000,5.004336,6.777270
     1672023-04-06 22:52:47,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-inselem,665000000,5.024545,7.555707
     1682023-04-06 22:52:52,1,5 1000 9051 -1 1  ,./perfexp--lq-list--stack-insfirst-allhead,343938000,5.070304,14.741913
     1692023-04-06 22:52:57,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-insfirst-remelem,688700000,5.007406,7.270809
     1702023-04-06 22:53:02,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-allhead,184600000,5.064279,27.433797
     1712023-04-06 22:53:07,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-inslast-allhead,1078000000,5.011355,4.648752
     1722023-04-06 22:53:12,4,5 100000 71 -1 4  ,./perfexp--lq-list--stack-insfirst-allhead,809400000,5.030850,6.215530
     1732023-04-06 22:53:17,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-allhead,184600000,5.121858,27.745710
     1742023-04-06 22:53:22,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-inslast-allhead,177980000,5.177338,29.089437
     1752023-04-06 22:53:27,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-insfirst-inselem,298683000,5.103575,17.086928
     1762023-04-06 22:53:32,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-inslast-remelem,959000000,5.004941,5.218917
     1772023-04-06 22:53:37,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-inslast-inselem,453040000,5.084873,11.223894
     1782023-04-06 22:53:43,4,5 1000000 7 -1 4  ,./perfexp--lq-list--stack-insfirst-allhead,917000000,5.007210,5.460425
     1792023-04-06 22:53:48,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-allhead,485400000,5.073608,10.452427
     1802023-04-06 22:53:53,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-inslast-allhead,334887000,5.007885,14.953955
     1812023-04-06 22:53:58,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-allhead,137599900,5.149462,37.423443
     1822023-04-06 22:54:03,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-inslast-inselem,137599900,5.086708,36.967382
     1832023-04-06 22:54:08,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-inselem,343938000,5.092902,14.807616
     1842023-04-06 22:54:13,5,5 100000 71 -1 5  ,./perfexp--lq-list--stack-insfirst-remelem,688700000,5.002389,7.263524
     1852023-04-06 22:54:18,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-inslast-allhead,137599900,5.146658,37.403065
     1862023-04-06 22:54:23,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-inslast-remelem,597366000,5.073255,8.492708
     1872023-04-06 22:54:28,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-insfirst-remelem,759700000,5.005199,6.588389
     1882023-04-06 22:54:33,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-inslast-remelem,347620800,5.035473,14.485534
     1892023-04-06 22:54:38,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-remelem,908800000,5.019250,5.522942
     1902023-04-06 22:54:43,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-allhead,159326200,5.030282,31.572221
     1912023-04-06 22:54:48,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-allhead,177980000,5.213425,29.292196
     1922023-04-06 22:54:54,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-inslast-allhead,469220000,5.071355,10.808054
     1932023-04-06 22:54:59,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-insfirst-remelem,688700000,5.012374,7.278022
     1942023-04-06 22:55:04,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-remelem,720010000,5.044350,7.005944
     1952023-04-06 22:55:09,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-inslast-allhead,624800000,5.034208,8.057311
     1962023-04-06 22:55:14,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-insfirst-remelem,260715600,5.109722,19.598835
     1972023-04-06 22:55:19,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-inslast-inselem,658000000,5.025521,7.637570
     1982023-04-06 22:55:24,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-inslast-remelem,588315000,5.043017,8.571967
     1992023-04-06 22:55:29,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-insfirst-inselem,159326200,5.003525,31.404283
     2002023-04-06 22:55:34,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-remelem,318652400,5.010231,15.723186
     2012023-04-06 22:55:39,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-inselem,137599900,5.150708,37.432498
     2022023-04-06 22:55:44,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-insfirst-inselem,595000000,5.044665,8.478429
     2032023-04-06 22:55:49,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-inslast-remelem,159326200,5.209063,32.694328
     2042023-04-06 22:55:55,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-inslast-allhead,509670000,5.053284,9.914815
     2052023-04-06 22:56:00,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-insfirst-allhead,795200000,5.012552,6.303511
     2062023-04-06 22:56:05,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-insfirst-allhead,766800000,5.033161,6.563851
     2072023-04-06 22:56:10,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-allhead,159326200,5.121738,32.146238
     2082023-04-06 22:56:15,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-inslast-allhead,334887000,5.028414,15.015256
     2092023-04-06 22:56:20,5,5 1000 9051 -1 5  ,./perfexp--lq-list--stack-insfirst-inselem,325836000,5.124252,15.726476
     2102023-04-06 22:56:25,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-inslast-inselem,177980000,5.172291,29.061080
     2112023-04-06 22:56:30,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-remelem,830700000,5.042470,6.070146
     2122023-04-06 22:56:35,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-insfirst-remelem,847000000,5.032186,5.941188
     2132023-04-06 22:56:40,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-inslast-remelem,639000000,5.002609,7.828809
     2142023-04-06 22:56:45,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-inslast-remelem,770000000,5.038757,6.543840
     2152023-04-06 22:56:50,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-allhead,231000000,5.137935,22.242143
     2162023-04-06 22:56:56,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-inslast-allhead,224000000,5.091507,22.729942
     2172023-04-06 22:57:01,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-insfirst-inselem,412590000,5.037820,12.210233
     2182023-04-06 22:57:06,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-remelem,231000000,5.102198,22.087437
     2192023-04-06 22:57:11,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-inslast-allhead,171969000,5.164593,30.032116
     2202023-04-06 22:57:16,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-inslast-remelem,169890000,5.225116,30.755877
     2212023-04-06 22:57:21,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-insfirst-allhead,316785000,5.093369,16.078315
     2222023-04-06 22:57:26,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-inslast-inselem,603500000,5.049990,8.367838
     2232023-04-06 22:57:31,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-inslast-allhead,166568300,5.220664,31.342482
     2242023-04-06 22:57:37,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-inslast-inselem,568000000,5.010944,8.822085
     2252023-04-06 22:57:42,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-inslast-allhead,144842000,5.227036,36.087847
     2262023-04-06 22:57:47,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-remelem,159326200,5.217508,32.747332
     2272023-04-06 22:57:52,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-allhead,137599900,5.146662,37.403094
     2282023-04-06 22:57:57,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-insfirst-remelem,667400000,5.038476,7.549410
     2292023-04-06 22:58:02,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-inslast-allhead,159326200,5.013988,31.469953
     2302023-04-06 22:58:07,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-remelem,1008000000,5.010780,4.971012
     2312023-04-06 22:58:12,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-inslast-remelem,1421000000,5.023422,3.535132
     2322023-04-06 22:58:17,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-insfirst-inselem,553800000,5.060584,9.137927
     2332023-04-06 22:58:23,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-insfirst-inselem,595000000,5.047132,8.482575
     2342023-04-06 22:58:28,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-inslast-remelem,588315000,5.032246,8.553659
     2352023-04-06 22:58:33,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-insfirst-allhead,724200000,5.020706,6.932762
     2362023-04-06 22:58:38,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-inslast-inselem,334887000,5.003484,14.940813
     2372023-04-06 22:58:43,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-insfirst-allhead,840000000,5.042287,6.002723
     2382023-04-06 22:58:48,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-inslast-remelem,224000000,5.088342,22.715813
     2392023-04-06 22:58:53,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-inslast-inselem,169890000,5.058348,29.774254
     2402023-04-06 22:58:58,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-inslast-allhead,695800000,5.026595,7.224195
     2412023-04-06 22:59:03,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-inselem,184600000,5.066927,27.448142
     2422023-04-06 22:59:08,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-inselem,184600000,5.055439,27.385910
     2432023-04-06 22:59:13,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-insfirst-remelem,1309000000,5.009552,3.827007
     2442023-04-06 22:59:18,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-inselem,658000000,5.048553,7.672573
     2452023-04-06 22:59:23,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-inslast-allhead,137599900,5.143656,37.381248
     2462023-04-06 22:59:29,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-allhead,224000000,5.132010,22.910759
     2472023-04-06 22:59:34,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-insfirst-remelem,695800000,5.046242,7.252432
     2482023-04-06 22:59:39,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-insfirst-inselem,603500000,5.003978,8.291596
     2492023-04-06 22:59:44,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-allhead,665000000,5.025093,7.556531
     2502023-04-06 22:59:49,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-remelem,965600000,5.028275,5.207410
     2512023-04-06 22:59:54,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-remelem,687650000,5.005714,7.279450
     2522023-04-06 22:59:59,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-insfirst-remelem,590570000,5.031737,8.520136
     2532023-04-06 23:00:04,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-inslast-remelem,184600000,5.160974,27.957606
     2542023-04-06 23:00:09,5,5 100 72421 -1 5  ,./perfexp--lq-list--stack-insfirst-remelem,333136600,5.090510,15.280549
     2552023-04-06 23:00:14,5,5 100 72421 -1 5  ,./perfexp--lq-list--stack-insfirst-inselem,159326200,5.004048,31.407565
     2562023-04-06 23:00:19,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-insfirst-allhead,444950000,5.073828,11.403142
     2572023-04-06 23:00:24,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-inslast-allhead,224000000,5.001734,22.329170
     2582023-04-06 23:00:29,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-inslast-allhead,477310000,5.050386,10.580935
     2592023-04-06 23:00:34,4,5 1000 9051 -1 4  ,./perfexp--lq-list--stack-insfirst-allhead,343938000,5.050309,14.683777
     2602023-04-06 23:00:40,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-insfirst-allhead,444950000,5.017058,11.275555
     2612023-04-06 23:00:45,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-remelem,994000000,5.019649,5.049949
     2622023-04-06 23:00:50,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-inslast-remelem,153867000,5.201021,33.802056
     2632023-04-06 23:00:55,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-remelem,1001000000,5.015588,5.010577
     2642023-04-06 23:01:00,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-remelem,161800000,5.005496,30.936316
     2652023-04-06 23:01:05,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-inslast-allhead,665000000,5.035214,7.571750
     2662023-04-06 23:01:10,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-inslast-allhead,159326200,5.109530,32.069616
     2672023-04-06 23:01:15,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-allhead,169890000,5.100783,30.024033
     2682023-04-06 23:01:20,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-insfirst-remelem,639000000,5.014872,7.848000
     2692023-04-06 23:01:25,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-inslast-inselem,169890000,5.046345,29.703602
     2702023-04-06 23:01:30,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-insfirst-allhead,896000000,5.013958,5.595935
     2712023-04-06 23:01:35,1,5 1000000 7 -1 1  ,./perfexp--lq-list--stack-insfirst-inselem,581000000,5.047488,8.687587
     2722023-04-06 23:01:40,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-insfirst-inselem,501580000,5.002330,9.973145
     2732023-04-06 23:01:45,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-inslast-remelem,986900000,5.036032,5.102880
     2742023-04-06 23:01:50,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-inselem,166568300,5.162360,30.992452
     2752023-04-06 23:01:55,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-inslast-inselem,325836000,5.137919,15.768420
     2762023-04-06 23:02:01,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-insfirst-remelem,710000000,5.019927,7.070320
     2772023-04-06 23:02:06,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-inslast-allhead,334887000,5.098791,15.225407
     2782023-04-06 23:02:11,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-insfirst-allhead,651000000,5.049504,7.756535
     2792023-04-06 23:02:16,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-insfirst-remelem,515907000,5.019478,9.729424
     2802023-04-06 23:02:21,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-insfirst-allhead,325836000,5.095609,15.638570
     2812023-04-06 23:02:26,5,5 1000000 7 -1 5  ,./perfexp--lq-list--stack-insfirst-inselem,581000000,5.050648,8.693026
     2822023-04-06 23:02:31,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-insfirst-remelem,534009000,5.012189,9.385964
     2832023-04-06 23:02:36,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-inselem,343938000,5.100634,14.830097
     2842023-04-06 23:02:41,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-allhead,177980000,5.039308,28.313900
     2852023-04-06 23:02:46,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-insfirst-inselem,412590000,5.053218,12.247553
     2862023-04-06 23:02:51,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-inselem,162918000,5.104631,31.332517
     2872023-04-06 23:02:56,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-allhead,166568300,5.127294,30.781931
     2882023-04-06 23:03:02,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-inslast-inselem,137599900,5.086178,36.963530
     2892023-04-06 23:03:07,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-inslast-inselem,177500000,5.030765,28.342338
     2902023-04-06 23:03:12,4,5 1000000 7 -1 4  ,./perfexp--lq-list--stack-insfirst-remelem,798000000,5.017055,6.287036
     2912023-04-06 23:03:17,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-insfirst-inselem,660300000,5.001824,7.575078
     2922023-04-06 23:03:22,4,5 10000 809 -1 4  ,./perfexp--lq-list--stack-insfirst-inselem,436860000,5.056530,11.574715
     2932023-04-06 23:03:27,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-allhead,665000000,5.023530,7.554180
     2942023-04-06 23:03:32,1,5 100000 71 -1 1  ,./perfexp--lq-list--stack-insfirst-inselem,553800000,5.027487,9.078164
     2952023-04-06 23:03:37,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-inslast-allhead,672000000,5.030612,7.486030
     2962023-04-06 23:03:42,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-insfirst-allhead,672000000,5.043560,7.505298
     2972023-04-06 23:03:47,2,5 100 72421 -1 2  ,./perfexp--lq-list--stack-insfirst-remelem,333136600,5.084613,15.262847
     2982023-04-06 23:03:52,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-inslast-allhead,738400000,5.043688,6.830563
     2992023-04-06 23:03:57,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-inslast-remelem,171969000,5.223951,30.377283
     3002023-04-06 23:04:02,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-inselem,162918000,5.126779,31.468463
     3012023-04-06 23:04:08,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-inslast-remelem,1421000000,5.023912,3.535476
     3022023-04-06 23:04:13,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-inslast-allhead,658000000,5.020341,7.629698
     3032023-04-06 23:04:18,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-insfirst-remelem,461601000,5.016184,10.866926
     3042023-04-06 23:04:23,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-inslast-allhead,177980000,5.210149,29.273789
     3052023-04-06 23:04:28,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-insfirst-inselem,159326200,5.202610,32.653826
     3062023-04-06 23:04:33,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-inslast-remelem,966000000,5.014821,5.191326
     3072023-04-06 23:04:38,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-inslast-remelem,728100000,5.003623,6.872165
     3082023-04-06 23:04:43,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-inslast-allhead,184600000,5.136308,27.823987
     3092023-04-06 23:04:48,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-allhead,477310000,5.001601,10.478727
     3102023-04-06 23:04:53,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-inslast-allhead,568000000,5.029274,8.854356
     3112023-04-06 23:04:58,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-insfirst-remelem,590570000,5.018292,8.497370
     3122023-04-06 23:05:03,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-allhead,653200000,5.021467,7.687488
     3132023-04-06 23:05:08,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-inslast-inselem,137599900,5.250703,38.159207
     3142023-04-06 23:05:14,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-inslast-allhead,745500000,5.019787,6.733450
     3152023-04-06 23:05:19,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-insfirst-inselem,412590000,5.039837,12.215122
     3162023-04-06 23:05:24,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-inslast-inselem,724200000,5.013341,6.922592
     3172023-04-06 23:05:29,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-inslast-allhead,603500000,5.026221,8.328452
     3182023-04-06 23:05:34,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-remelem,169890000,5.049109,29.719872
     3192023-04-06 23:05:39,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-inslast-remelem,679560000,5.015714,7.380826
     3202023-04-06 23:05:44,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-insfirst-remelem,731300000,5.037151,6.887941
     3212023-04-06 23:05:49,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-inslast-remelem,614840000,5.059492,8.228957
     3222023-04-06 23:05:54,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-remelem,958500000,5.014201,5.231300
     3232023-04-06 23:05:59,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-inslast-inselem,316785000,5.024996,15.862481
     3242023-04-06 23:06:04,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-inslast-remelem,588315000,5.067089,8.612884
     3252023-04-06 23:06:09,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-inslast-allhead,639000000,5.028277,7.868978
     3262023-04-06 23:06:14,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-inslast-allhead,334887000,5.060557,15.111238
     3272023-04-06 23:06:19,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-inslast-inselem,352989000,5.102670,14.455606
     3282023-04-06 23:06:25,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-insfirst-allhead,130357800,5.098607,39.112404
     3292023-04-06 23:06:30,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-inslast-inselem,144842000,5.151602,35.567045
     3302023-04-06 23:06:35,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-insfirst-allhead,795200000,5.020810,6.313896
     3312023-04-06 23:06:40,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-inslast-inselem,658000000,5.025127,7.636971
     3322023-04-06 23:06:45,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-inslast-inselem,162918000,5.129739,31.486631
     3332023-04-06 23:06:50,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-inslast-allhead,159326200,5.168959,32.442618
     3342023-04-06 23:06:55,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-inslast-inselem,745500000,5.024930,6.740349
     3352023-04-06 23:07:00,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-inslast-inselem,159326200,5.104196,32.036137
     3362023-04-06 23:07:06,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-allhead,575100000,5.018488,8.726288
     3372023-04-06 23:07:11,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-inselem,184600000,5.040923,27.307275
     3382023-04-06 23:07:16,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-allhead,162918000,5.129628,31.485950
     3392023-04-06 23:07:21,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-insfirst-allhead,653200000,5.014120,7.676240
     3402023-04-06 23:07:26,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-insfirst-allhead,903000000,5.007293,5.545175
     3412023-04-06 23:07:31,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-inselem,231000000,5.039397,21.815571
     3422023-04-06 23:07:36,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-inslast-inselem,159326200,5.103728,32.033200
     3432023-04-06 23:07:41,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-inslast-remelem,159326200,5.110623,32.076476
     3442023-04-06 23:07:46,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-inslast-inselem,325836000,5.094063,15.633825
     3452023-04-06 23:07:51,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-inslast-allhead,896000000,5.013412,5.595326
     3462023-04-06 23:07:56,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-inslast-remelem,289684000,5.090448,17.572417
     3472023-04-06 23:08:01,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-inslast-remelem,515907000,5.013509,9.717854
     3482023-04-06 23:08:06,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-insfirst-remelem,582480000,5.028441,8.632813
     3492023-04-06 23:08:11,5,5 100 72421 -1 5  ,./perfexp--lq-list--stack-insfirst-allhead,166568300,5.049215,30.313181
     3502023-04-06 23:08:16,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-remelem,289684000,5.110068,17.640146
     3512023-04-06 23:08:22,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-inselem,343938000,5.103078,14.837203
     3522023-04-06 23:08:27,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-inselem,162918000,5.149009,31.604912
     3532023-04-06 23:08:32,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-inslast-remelem,917000000,5.004999,5.458014
     3542023-04-06 23:08:37,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-remelem,695740000,5.052429,7.261950
     3552023-04-06 23:08:42,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-allhead,137599900,5.145265,37.392941
     3562023-04-06 23:08:47,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-inselem,159326200,5.189556,32.571893
     3572023-04-06 23:08:52,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-inslast-remelem,177500000,5.052410,28.464282
     3582023-04-06 23:08:57,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-insfirst-allhead,533940000,5.071980,9.499157
     3592023-04-06 23:09:03,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-allhead,665000000,5.021102,7.550529
     3602023-04-06 23:09:08,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-insfirst-inselem,298683000,5.125385,17.159949
     3612023-04-06 23:09:13,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-remelem,579264000,5.001932,8.634978
     3622023-04-06 23:09:18,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-remelem,184600000,5.103404,27.645742
     3632023-04-06 23:09:23,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-inslast-remelem,318652400,5.032572,15.793297
     3642023-04-06 23:09:28,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-inslast-remelem,171969000,5.132165,29.843547
     3652023-04-06 23:09:33,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-inslast-allhead,169890000,5.106152,30.055636
     3662023-04-06 23:09:38,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-remelem,720010000,5.056537,7.022871
     3672023-04-06 23:09:43,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-inslast-remelem,169890000,5.068533,29.834204
     3682023-04-06 23:09:48,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-inslast-allhead,493490000,5.018832,10.170078
     3692023-04-06 23:09:53,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-inslast-inselem,833000000,5.016267,6.021929
     3702023-04-06 23:09:58,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-inslast-allhead,461130000,5.084745,11.026706
     3712023-04-06 23:10:03,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-inslast-inselem,908800000,5.035999,5.541372
     3722023-04-06 23:10:09,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-inslast-allhead,889000000,5.028819,5.656714
     3732023-04-06 23:10:14,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-inslast-allhead,166568300,5.191809,31.169250
     3742023-04-06 23:10:19,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-inslast-inselem,159326200,5.152530,32.339502
     3752023-04-06 23:10:24,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-inslast-remelem,289684000,5.093276,17.582179
     3762023-04-06 23:10:29,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-inselem,231000000,5.100410,22.079697
     3772023-04-06 23:10:34,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-inslast-allhead,485400000,5.011748,10.324986
     3782023-04-06 23:10:39,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-inslast-remelem,688700000,5.032312,7.306973
     3792023-04-06 23:10:44,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-insfirst-inselem,973000000,5.027293,5.166797
     3802023-04-06 23:10:49,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-inselem,177980000,5.048409,28.365035
     3812023-04-06 23:10:54,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-allhead,159326200,5.095523,31.981702
     3822023-04-06 23:11:00,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-inselem,444950000,5.015660,11.272413
     3832023-04-06 23:11:05,3,5 1000000 7 -1 3  ,./perfexp--lq-list--stack-insfirst-allhead,924000000,5.029412,5.443087
     3842023-04-06 23:11:10,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-inslast-allhead,343938000,5.134039,14.927222
     3852023-04-06 23:11:15,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-insfirst-remelem,333136600,5.076445,15.238329
     3862023-04-06 23:11:20,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-inselem,169890000,5.039287,29.662058
     3872023-04-06 23:11:25,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-insfirst-allhead,166568300,5.122763,30.754729
     3882023-04-06 23:11:30,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-inslast-remelem,318652400,5.029359,15.783214
     3892023-04-06 23:11:35,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-insfirst-allhead,1022000000,5.025006,4.916836
     3902023-04-06 23:11:40,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-inslast-inselem,461130000,5.059408,10.971761
     3912023-04-06 23:11:45,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-allhead,159326200,5.102132,32.023183
     3922023-04-06 23:11:50,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-remelem,728100000,5.037604,6.918835
     3932023-04-06 23:11:56,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-inslast-allhead,334887000,5.067591,15.132242
     3942023-04-06 23:12:01,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-inselem,159326200,5.104270,32.036602
     3952023-04-06 23:12:06,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-inslast-inselem,184600000,5.124046,27.757562
     3962023-04-06 23:12:11,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-inslast-allhead,1078000000,5.014921,4.652060
     3972023-04-06 23:12:16,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-inslast-inselem,624800000,5.051553,8.085072
     3982023-04-06 23:12:21,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-inslast-inselem,833000000,5.018805,6.024976
     3992023-04-06 23:12:26,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-inslast-allhead,343938000,5.055123,14.697774
     4002023-04-06 23:12:31,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-insfirst-allhead,316785000,5.093298,16.078091
     4012023-04-06 23:12:36,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-inslast-allhead,144842000,5.158022,35.611370
     4022023-04-06 23:12:41,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-inslast-allhead,159326200,5.152787,32.341115
     4032023-04-06 23:12:47,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-allhead,181020000,5.246972,28.985593
     4042023-04-06 23:12:52,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-remelem,171969000,5.244708,30.497985
     4052023-04-06 23:12:57,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-inslast-remelem,289684000,5.088471,17.565592
     4062023-04-06 23:13:02,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-remelem,720010000,5.055206,7.021022
     4072023-04-06 23:13:07,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-inslast-allhead,560900000,5.032860,8.972829
     4082023-04-06 23:13:12,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-inslast-allhead,959000000,5.008545,5.222675
     4092023-04-06 23:13:17,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-insfirst-remelem,784000000,5.022341,6.406047
     4102023-04-06 23:13:22,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-inslast-inselem,352989000,5.117729,14.498268
     4112023-04-06 23:13:27,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-inslast-inselem,224000000,5.066051,22.616299
     4122023-04-06 23:13:33,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-remelem,159326200,5.077187,31.866617
     4132023-04-06 23:13:38,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-inslast-inselem,166568300,5.220717,31.342801
     4142023-04-06 23:13:43,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-inslast-inselem,477310000,5.070365,10.622792
     4152023-04-06 23:13:48,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-insfirst-remelem,1309000000,5.007603,3.825518
     4162023-04-06 23:13:53,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-allhead,184600000,5.111904,27.691788
     4172023-04-06 23:13:58,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-remelem,972700000,5.036058,5.177401
     4182023-04-06 23:14:03,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-inslast-remelem,938000000,5.030859,5.363389
     4192023-04-06 23:14:08,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-inselem,231000000,5.144215,22.269329
     4202023-04-06 23:14:13,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-allhead,159326200,5.195831,32.611278
     4212023-04-06 23:14:19,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-insfirst-remelem,710000000,5.050419,7.113266
     4222023-04-06 23:14:24,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-inslast-inselem,477310000,5.056472,10.593685
     4232023-04-06 23:14:29,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-inslast-allhead,646100000,5.033754,7.790983
     4242023-04-06 23:14:34,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-inslast-inselem,169890000,5.007809,29.476773
     4252023-04-06 23:14:39,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-remelem,184600000,5.140697,27.847763
     4262023-04-06 23:14:44,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-remelem,917000000,5.012871,5.466599
     4272023-04-06 23:14:49,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-inslast-remelem,792820000,5.025219,6.338411
     4282023-04-06 23:14:54,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-allhead,184600000,5.077734,27.506685
     4292023-04-06 23:14:59,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-inslast-allhead,231000000,5.142791,22.263165
     4302023-04-06 23:15:04,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-inslast-inselem,334887000,5.004776,14.944671
     4312023-04-06 23:15:09,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-inslast-allhead,144842000,5.161848,35.637785
     4322023-04-06 23:15:15,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-insfirst-inselem,325836000,5.085281,15.606873
     4332023-04-06 23:15:20,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-insfirst-inselem,581000000,5.020173,8.640573
     4342023-04-06 23:15:25,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-inslast-inselem,710000000,5.014337,7.062446
     4352023-04-06 23:15:30,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-allhead,177980000,5.062496,28.444185
     4362023-04-06 23:15:35,1,5 1000000 7 -1 1  ,./perfexp--lq-list--stack-insfirst-allhead,917000000,5.004475,5.457443
     4372023-04-06 23:15:40,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-inslast-remelem,267957700,5.136059,19.167425
     4382023-04-06 23:15:45,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-inslast-remelem,687876000,5.053524,7.346562
     4392023-04-06 23:15:50,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-allhead,444950000,5.008229,11.255712
     4402023-04-06 23:15:55,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-inslast-remelem,159326200,5.159661,32.384259
     4412023-04-06 23:16:00,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-insfirst-allhead,453040000,5.007535,11.053185
     4422023-04-06 23:16:05,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-inselem,224000000,5.009136,22.362214
     4432023-04-06 23:16:10,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-inslast-allhead,453040000,5.019570,11.079750
     4442023-04-06 23:16:15,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-inslast-allhead,159326200,5.106386,32.049883
     4452023-04-06 23:16:20,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-inslast-allhead,162918000,5.082855,31.198855
     4462023-04-06 23:16:26,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-insfirst-remelem,944300000,5.025435,5.321863
     4472023-04-06 23:16:31,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-insfirst-allhead,130357800,5.062806,38.837768
     4482023-04-06 23:16:36,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-remelem,171969000,5.121176,29.779646
     4492023-04-06 23:16:41,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-insfirst-remelem,861000000,5.036872,5.850026
     4502023-04-06 23:16:46,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-inslast-remelem,720010000,5.033713,6.991171
     4512023-04-06 23:16:51,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-insfirst-inselem,766800000,5.001069,6.521999
     4522023-04-06 23:16:56,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-insfirst-allhead,159326200,5.154320,32.350737
     4532023-04-06 23:17:01,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-inslast-inselem,610600000,5.008342,8.202329
     4542023-04-06 23:17:06,3,5 100000 71 -1 3  ,./perfexp--lq-list--stack-insfirst-allhead,802300000,5.014286,6.249889
     4552023-04-06 23:17:11,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-inslast-allhead,231000000,5.088531,22.028273
     4562023-04-06 23:17:16,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-inslast-inselem,343938000,5.070875,14.743573
     4572023-04-06 23:17:21,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-insfirst-allhead,444950000,5.042555,11.332858
     4582023-04-06 23:17:26,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-inslast-remelem,658000000,5.001245,7.600676
     4592023-04-06 23:17:31,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-inslast-remelem,515907000,5.021599,9.733535
     4602023-04-06 23:17:36,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-inselem,159326200,5.186501,32.552719
     4612023-04-06 23:17:42,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-inselem,177980000,5.026446,28.241634
     4622023-04-06 23:17:47,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-inslast-inselem,658000000,5.016281,7.623527
     4632023-04-06 23:17:52,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-inslast-remelem,784000000,5.003437,6.381935
     4642023-04-06 23:17:57,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-inslast-remelem,347620800,5.029484,14.468306
     4652023-04-06 23:18:02,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-inslast-remelem,710000000,5.007576,7.052924
     4662023-04-06 23:18:07,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-inslast-remelem,809400000,5.015371,6.196406
     4672023-04-06 23:18:12,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-insfirst-allhead,788100000,5.040980,6.396371
     4682023-04-06 23:18:17,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-inslast-inselem,461130000,5.057431,10.967473
     4692023-04-06 23:18:22,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-remelem,159326200,5.044365,31.660612
     4702023-04-06 23:18:27,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-allhead,485400000,5.070348,10.445711
     4712023-04-06 23:18:32,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-inslast-inselem,316785000,5.018884,15.843187
     4722023-04-06 23:18:37,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-inselem,560900000,5.062667,9.025971
     4732023-04-06 23:18:42,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-insfirst-inselem,412590000,5.015951,12.157229
     4742023-04-06 23:18:47,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-insfirst-inselem,816500000,5.000448,6.124247
     4752023-04-06 23:18:52,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-inslast-inselem,162918000,5.018924,30.806443
     4762023-04-06 23:18:57,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-inslast-remelem,695740000,5.044067,7.249931
     4772023-04-06 23:19:03,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-inslast-remelem,169890000,5.075488,29.875143
     4782023-04-06 23:19:08,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-inslast-inselem,224000000,5.038191,22.491924
     4792023-04-06 23:19:13,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-insfirst-inselem,325836000,5.103653,15.663257
     4802023-04-06 23:19:18,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-allhead,444950000,5.010533,11.260890
     4812023-04-06 23:19:23,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-inslast-allhead,224000000,5.004062,22.339563
     4822023-04-06 23:19:28,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-inslast-remelem,784000000,5.030273,6.416165
     4832023-04-06 23:19:33,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-insfirst-inselem,485400000,5.050046,10.403885
     4842023-04-06 23:19:38,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-insfirst-inselem,617700000,5.005519,8.103479
     4852023-04-06 23:19:43,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-insfirst-allhead,325836000,5.106682,15.672553
     4862023-04-06 23:19:48,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-insfirst-remelem,681600000,5.046878,7.404457
     4872023-04-06 23:19:53,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-inselem,137599900,5.148273,37.414802
     4882023-04-06 23:19:58,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-inslast-inselem,603500000,5.030745,8.335949
     4892023-04-06 23:20:03,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-inslast-inselem,987000000,5.001494,5.067370
     4902023-04-06 23:20:08,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-inslast-allhead,144842000,5.159197,35.619482
     4912023-04-06 23:20:14,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-inselem,453040000,5.069119,11.189120
     4922023-04-06 23:20:19,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-inslast-inselem,880400000,5.006800,5.686960
     4932023-04-06 23:20:24,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-allhead,224000000,5.105644,22.793054
     4942023-04-06 23:20:29,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-remelem,224000000,5.045045,22.522522
     4952023-04-06 23:20:34,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-inslast-allhead,959000000,5.008714,5.222851
     4962023-04-06 23:20:39,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-inslast-inselem,184600000,5.185437,28.090125
     4972023-04-06 23:20:44,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-insfirst-inselem,420680000,5.058743,12.025157
     4982023-04-06 23:20:49,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-insfirst-remelem,260715600,5.111093,19.604094
     4992023-04-06 23:20:54,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-insfirst-allhead,773900000,5.004333,6.466382
     5002023-04-06 23:20:59,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-insfirst-remelem,812000000,5.021316,6.183887
     5012023-04-06 23:21:04,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-allhead,184600000,5.041771,27.311869
     5022023-04-06 23:21:09,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-inslast-remelem,1414000000,5.000733,3.536586
     5032023-04-06 23:21:14,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-remelem,289684000,5.112781,17.649511
     5042023-04-06 23:21:20,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-insfirst-inselem,539600000,5.009402,9.283547
     5052023-04-06 23:21:25,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-inslast-inselem,325836000,5.128478,15.739446
     5062023-04-06 23:21:30,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-insfirst-allhead,509670000,5.040138,9.889022
     5072023-04-06 23:21:35,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-insfirst-inselem,307734000,5.031918,16.351518
     5082023-04-06 23:21:40,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-remelem,588315000,5.069535,8.617042
     5092023-04-06 23:21:45,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-allhead,181020000,5.196558,28.707093
     5102023-04-06 23:21:50,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-insfirst-remelem,720010000,5.049517,7.013121
     5112023-04-06 23:21:55,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-insfirst-inselem,631900000,5.011261,7.930465
     5122023-04-06 23:22:00,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-inslast-inselem,137599900,5.090919,36.997985
     5132023-04-06 23:22:05,3,5 100000 71 -1 3  ,./perfexp--lq-list--stack-insfirst-remelem,688700000,5.028916,7.302042
     5142023-04-06 23:22:10,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-inslast-inselem,159326200,5.021214,31.515306
     5152023-04-06 23:22:15,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-inslast-allhead,343938000,5.134953,14.929880
     5162023-04-06 23:22:21,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-insfirst-allhead,766800000,5.010735,6.534605
     5172023-04-06 23:22:26,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-remelem,588315000,5.005341,8.507927
     5182023-04-06 23:22:31,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-inslast-inselem,553800000,5.022399,9.068976
     5192023-04-06 23:22:36,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-inselem,217000000,5.090764,23.459742
     5202023-04-06 23:22:41,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-insfirst-allhead,316785000,5.107048,16.121496
     5212023-04-06 23:22:46,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-inselem,603500000,5.007173,8.296890
     5222023-04-06 23:22:51,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-insfirst-remelem,534009000,5.013222,9.387898
     5232023-04-06 23:22:56,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-inslast-inselem,617700000,5.049209,8.174209
     5242023-04-06 23:23:01,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-inslast-inselem,159326200,5.098883,32.002791
     5252023-04-06 23:23:06,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-inslast-allhead,224000000,5.012905,22.379040
     5262023-04-06 23:23:11,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-inslast-inselem,693000000,5.010052,7.229512
     5272023-04-06 23:23:16,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-inslast-inselem,343938000,5.081110,14.773331
     5282023-04-06 23:23:21,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-insfirst-allhead,805000000,5.000210,6.211441
     5292023-04-06 23:23:26,2,5 10000 809 -1 2  ,./perfexp--lq-list--stack-insfirst-inselem,420680000,5.069851,12.051562
     5302023-04-06 23:23:31,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-inselem,177980000,5.051407,28.381880
     5312023-04-06 23:23:36,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-inslast-inselem,987000000,5.007191,5.073142
     5322023-04-06 23:23:41,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-remelem,231000000,5.081453,21.997632
     5332023-04-06 23:23:46,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-remelem,177500000,5.017600,28.268169
     5342023-04-06 23:23:52,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-inselem,343938000,5.100129,14.828629
     5352023-04-06 23:23:57,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-inselem,184600000,5.151028,27.903727
     5362023-04-06 23:24:02,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-remelem,184600000,5.128629,27.782389
     5372023-04-06 23:24:07,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-remelem,910000000,5.002322,5.497057
     5382023-04-06 23:24:12,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-allhead,177980000,5.196302,29.195988
     5392023-04-06 23:24:17,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-insfirst-allhead,509670000,5.014897,9.839498
     5402023-04-06 23:24:22,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-insfirst-remelem,260715600,5.109786,19.599080
     5412023-04-06 23:24:27,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-inslast-inselem,159326200,5.008081,31.432878
     5422023-04-06 23:24:32,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-inslast-inselem,325836000,5.116265,15.701964
     5432023-04-06 23:24:37,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-inslast-remelem,570213000,5.046808,8.850742
     5442023-04-06 23:24:43,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-inslast-allhead,137599900,5.042300,36.644649
     5452023-04-06 23:24:48,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-allhead,665000000,5.022941,7.553295
     5462023-04-06 23:24:53,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-remelem,153867000,5.092858,33.099092
     5472023-04-06 23:24:58,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-insfirst-inselem,966000000,5.015365,5.191889
     5482023-04-06 23:25:03,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-inslast-inselem,177980000,5.188118,29.150006
     5492023-04-06 23:25:08,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-insfirst-remelem,296926100,5.109709,17.208689
     5502023-04-06 23:25:13,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-remelem,184600000,5.118232,27.726067
     5512023-04-06 23:25:18,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-inslast-allhead,177980000,5.168805,29.041493
     5522023-04-06 23:25:23,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-inslast-allhead,159326200,5.074931,31.852457
     5532023-04-06 23:25:28,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-insfirst-remelem,534009000,5.064100,9.483174
     5542023-04-06 23:25:34,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-insfirst-allhead,130357800,5.062901,38.838497
     5552023-04-06 23:25:39,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-inslast-inselem,184600000,5.176605,28.042281
     5562023-04-06 23:25:44,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-inslast-inselem,137599900,5.248929,38.146314
     5572023-04-06 23:25:49,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-inselem,184600000,5.090988,27.578483
     5582023-04-06 23:25:54,2,5 10000 809 -1 2  ,./perfexp--lq-list--stack-insfirst-remelem,590570000,5.053093,8.556298
     5592023-04-06 23:25:59,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-inslast-remelem,614840000,5.005980,8.141923
     5602023-04-06 23:26:04,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-inslast-allhead,171969000,5.032441,29.263652
     5612023-04-06 23:26:09,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-inslast-allhead,485400000,5.027026,10.356461
     5622023-04-06 23:26:14,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-inslast-allhead,695800000,5.023256,7.219396
     5632023-04-06 23:26:19,2,5 100000 71 -1 2  ,./perfexp--lq-list--stack-insfirst-inselem,738400000,5.023025,6.802580
     5642023-04-06 23:26:24,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-allhead,546700000,5.016473,9.175915
     5652023-04-06 23:26:29,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-inselem,181020000,5.192822,28.686455
     5662023-04-06 23:26:35,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-inselem,343938000,5.093426,14.809140
     5672023-04-06 23:26:40,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-remelem,153867000,5.079586,33.012836
     5682023-04-06 23:26:45,5,5 10000 809 -1 5  ,./perfexp--lq-list--stack-insfirst-inselem,509670000,5.077423,9.962177
     5692023-04-06 23:26:50,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-remelem,169890000,5.078467,29.892678
     5702023-04-06 23:26:55,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-inslast-inselem,159326200,5.146163,32.299540
     5712023-04-06 23:27:00,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-inslast-allhead,159326200,5.163047,32.405511
     5722023-04-06 23:27:05,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-insfirst-inselem,568000000,5.058001,8.904931
     5732023-04-06 23:27:11,3,5 10000 809 -1 3  ,./perfexp--lq-list--stack-insfirst-inselem,485400000,5.006967,10.315136
     5742023-04-06 23:27:16,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-inslast-inselem,617700000,5.005977,8.104220
     5752023-04-06 23:27:21,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-insfirst-inselem,588000000,5.020572,8.538388
     5762023-04-06 23:27:26,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-inslast-remelem,777000000,5.025727,6.468117
     5772023-04-06 23:27:31,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-inslast-inselem,553800000,5.014991,9.055599
     5782023-04-06 23:27:36,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-insfirst-remelem,461601000,5.001793,10.835750
     5792023-04-06 23:27:41,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-inslast-remelem,224000000,5.052311,22.554960
     5802023-04-06 23:27:46,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-insfirst-inselem,412590000,5.009318,12.141152
     5812023-04-06 23:27:51,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-inslast-allhead,781000000,5.043798,6.458128
     5822023-04-06 23:27:56,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-remelem,703830000,5.055801,7.183270
     5832023-04-06 23:28:01,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-remelem,184600000,5.103939,27.648640
     5842023-04-06 23:28:06,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-insfirst-allhead,159326200,5.157636,32.371550
     5852023-04-06 23:28:11,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-remelem,318652400,5.003554,15.702232
     5862023-04-06 23:28:16,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-allhead,617700000,5.007486,8.106663
     5872023-04-06 23:28:21,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-remelem,231000000,5.082904,22.003913
     5882023-04-06 23:28:26,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-inslast-remelem,823600000,5.035229,6.113683
     5892023-04-06 23:28:31,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-inslast-allhead,539600000,5.014691,9.293349
     5902023-04-06 23:28:36,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-inslast-allhead,137599900,5.146557,37.402331
     5912023-04-06 23:28:42,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-inslast-allhead,166568300,5.151938,30.929883
     5922023-04-06 23:28:47,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-insfirst-inselem,595000000,5.045803,8.480341
     5932023-04-06 23:28:52,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-inslast-inselem,453040000,5.084859,11.223863
     5942023-04-06 23:28:57,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-inselem,159326200,5.191003,32.580975
     5952023-04-06 23:29:02,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-inslast-remelem,687650000,5.026542,7.309739
     5962023-04-06 23:29:07,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-remelem,159326200,5.092534,31.962941
     5972023-04-06 23:29:12,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-insfirst-remelem,720010000,5.046402,7.008794
     5982023-04-06 23:29:17,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-allhead,184600000,5.093610,27.592687
     5992023-04-06 23:29:22,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-inslast-allhead,343938000,5.130926,14.918171
     6002023-04-06 23:29:28,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-inslast-inselem,144842000,5.154669,35.588220
     6012023-04-06 23:29:33,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-insfirst-allhead,781000000,5.027590,6.437375
     6022023-04-06 23:29:38,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-inslast-allhead,469220000,5.020177,10.698983
     6032023-04-06 23:29:43,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-inslast-allhead,672000000,5.049259,7.513778
     6042023-04-06 23:29:48,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-inslast-remelem,590570000,5.015500,8.492643
     6052023-04-06 23:29:53,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-inslast-remelem,515907000,5.032712,9.755076
     6062023-04-06 23:29:58,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-inslast-inselem,325836000,5.107450,15.674910
     6072023-04-06 23:30:03,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-inslast-remelem,800910000,5.026620,6.276136
     6082023-04-06 23:30:08,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-inslast-remelem,347620800,5.041880,14.503965
     6092023-04-06 23:30:13,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-allhead,231000000,5.013901,21.705199
     6102023-04-06 23:30:18,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-inslast-remelem,171969000,5.137606,29.875187
     6112023-04-06 23:30:23,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-inslast-allhead,770000000,5.003343,6.497848
     6122023-04-06 23:30:28,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-allhead,166568300,5.108504,30.669125
     6132023-04-06 23:30:34,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-inslast-allhead,184600000,5.156994,27.936046
     6142023-04-06 23:30:39,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-insfirst-allhead,819000000,5.014858,6.123148
     6152023-04-06 23:30:44,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-inslast-remelem,1414000000,5.003794,3.538751
     6162023-04-06 23:30:49,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-inselem,231000000,5.035501,21.798706
     6172023-04-06 23:30:54,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-insfirst-inselem,159326200,5.209153,32.694893
     6182023-04-06 23:30:59,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-insfirst-inselem,477310000,5.023267,10.524118
     6192023-04-06 23:31:04,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-insfirst-inselem,325836000,5.101399,15.656339
     6202023-04-06 23:31:09,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-inslast-remelem,667400000,5.022926,7.526110
     6212023-04-06 23:31:14,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-inslast-remelem,325894500,5.091748,15.623915
     6222023-04-06 23:31:19,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-allhead,334887000,5.054765,15.093942
     6232023-04-06 23:31:24,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-remelem,1008000000,5.001067,4.961376
     6242023-04-06 23:31:29,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-insfirst-inselem,679000000,5.016446,7.387991
     6252023-04-06 23:31:35,5,5 1000000 7 -1 5  ,./perfexp--lq-list--stack-insfirst-remelem,798000000,5.020158,6.290925
     6262023-04-06 23:31:40,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-inselem,658000000,5.046821,7.669941
     6272023-04-06 23:31:45,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-insfirst-inselem,469220000,5.064185,10.792773
     6282023-04-06 23:31:50,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-insfirst-inselem,674500000,5.015829,7.436366
     6292023-04-06 23:31:55,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-insfirst-remelem,639110000,5.034318,7.877076
     6302023-04-06 23:32:00,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-inslast-remelem,570213000,5.053420,8.862337
     6312023-04-06 23:32:05,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-inslast-allhead,171969000,5.028685,29.241811
     6322023-04-06 23:32:10,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-inslast-remelem,224000000,5.019890,22.410223
     6332023-04-06 23:32:15,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-insfirst-remelem,582480000,5.025035,8.626966
     6342023-04-06 23:32:20,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-remelem,161800000,5.127857,31.692565
     6352023-04-06 23:32:25,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-inslast-remelem,260715600,5.019198,19.251621
     6362023-04-06 23:32:30,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-allhead,162918000,5.129510,31.485226
     6372023-04-06 23:32:35,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-insfirst-inselem,130357800,5.149737,39.504633
     6382023-04-06 23:32:40,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-remelem,162918000,5.005389,30.723364
     6392023-04-06 23:32:45,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-inslast-allhead,695800000,5.049924,7.257723
     6402023-04-06 23:32:50,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-insfirst-inselem,973000000,5.026228,5.165702
     6412023-04-06 23:32:56,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-inslast-inselem,184600000,5.070150,27.465601
     6422023-04-06 23:33:01,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-inslast-allhead,171969000,5.038940,29.301444
     6432023-04-06 23:33:06,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-insfirst-allhead,352989000,5.128804,14.529643
     6442023-04-06 23:33:11,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-inslast-remelem,1313500000,5.022908,3.824064
     6452023-04-06 23:33:16,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-inslast-inselem,224000000,5.068988,22.629411
     6462023-04-06 23:33:21,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-insfirst-inselem,420680000,5.058039,12.023483
     6472023-04-06 23:33:26,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-inslast-remelem,597366000,5.067353,8.482828
     6482023-04-06 23:33:31,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-inselem,171969000,5.047845,29.353226
     6492023-04-06 23:33:36,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-inslast-remelem,809000000,5.044723,6.235752
     6502023-04-06 23:33:41,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-inslast-remelem,589300000,5.035557,8.544980
     6512023-04-06 23:33:46,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-inslast-remelem,717100000,5.046045,7.036738
     6522023-04-06 23:33:51,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-remelem,597366000,5.069419,8.486286
     6532023-04-06 23:33:56,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-insfirst-remelem,868000000,5.025089,5.789273
     6542023-04-06 23:34:01,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-inslast-inselem,658000000,5.025487,7.637518
     6552023-04-06 23:34:06,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-inslast-remelem,980000000,5.009915,5.112158
     6562023-04-06 23:34:11,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-inslast-remelem,823600000,5.002809,6.074319
     6572023-04-06 23:34:16,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-remelem,231000000,5.141988,22.259688
     6582023-04-06 23:34:22,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-insfirst-remelem,642621000,5.057599,7.870267
     6592023-04-06 23:34:27,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-inslast-inselem,184600000,5.153607,27.917698
     6602023-04-06 23:34:32,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-inslast-inselem,658000000,5.017245,7.624992
     6612023-04-06 23:34:37,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-allhead,485400000,5.077844,10.461154
     6622023-04-06 23:34:42,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-inslast-remelem,217000000,5.099401,23.499544
     6632023-04-06 23:34:47,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-inslast-inselem,658000000,5.013213,7.618865
     6642023-04-06 23:34:52,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-insfirst-remelem,590570000,5.033234,8.522671
     6652023-04-06 23:34:57,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-inslast-inselem,316785000,5.046378,15.929978
     6662023-04-06 23:35:02,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-inslast-remelem,159326200,5.120925,32.141136
     6672023-04-06 23:35:07,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-inslast-allhead,334887000,5.038462,15.045260
     6682023-04-06 23:35:12,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-inslast-inselem,231000000,5.148560,22.288139
     6692023-04-06 23:35:18,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-inselem,169890000,5.124945,30.166255
     6702023-04-06 23:35:23,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-inslast-inselem,553800000,5.003500,9.034850
     6712023-04-06 23:35:28,3,5 1000 9051 -1 3  ,./perfexp--lq-list--stack-insfirst-remelem,534009000,5.006456,9.375228
     6722023-04-06 23:35:33,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-allhead,624800000,5.050627,8.083590
     6732023-04-06 23:35:38,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-insfirst-remelem,642621000,5.039619,7.842288
     6742023-04-06 23:35:43,3,5 1000000 7 -1 3  ,./perfexp--lq-list--stack-insfirst-inselem,574000000,5.031817,8.766232
     6752023-04-06 23:35:48,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-inslast-inselem,137599900,5.246307,38.127259
     6762023-04-06 23:35:53,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-inslast-allhead,501580000,5.012750,9.993919
     6772023-04-06 23:35:58,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-inslast-inselem,325836000,5.131221,15.747864
     6782023-04-06 23:36:03,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-inslast-allhead,159326200,5.111924,32.084641
     6792023-04-06 23:36:09,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-inslast-remelem,606750000,5.003928,8.247100
     6802023-04-06 23:36:14,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-inslast-allhead,582200000,5.022484,8.626733
     6812023-04-06 23:36:19,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-inslast-inselem,166568300,5.222978,31.356375
     6822023-04-06 23:36:24,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-inslast-allhead,162918000,5.101216,31.311556
     6832023-04-06 23:36:29,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-inslast-allhead,959000000,5.005860,5.219875
     6842023-04-06 23:36:34,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-insfirst-inselem,307734000,5.025667,16.331205
     6852023-04-06 23:36:39,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-inslast-remelem,588315000,5.002182,8.502557
     6862023-04-06 23:36:44,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-inslast-remelem,153867000,5.230752,33.995282
     6872023-04-06 23:36:49,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-remelem,152084100,5.127175,33.712762
     6882023-04-06 23:36:54,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-inslast-remelem,784730000,5.021496,6.399011
     6892023-04-06 23:37:00,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-insfirst-allhead,1022000000,5.025863,4.917674
     6902023-04-06 23:37:05,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-inselem,444950000,5.083193,11.424189
     6912023-04-06 23:37:10,4,5 1000 9051 -1 4  ,./perfexp--lq-list--stack-insfirst-inselem,325836000,5.104508,15.665881
     6922023-04-06 23:37:15,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-allhead,224000000,5.044330,22.519330
     6932023-04-06 23:37:20,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-inslast-inselem,658000000,5.008834,7.612210
     6942023-04-06 23:37:25,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-insfirst-allhead,461130000,5.088815,11.035532
     6952023-04-06 23:37:30,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-insfirst-remelem,534009000,5.067296,9.489158
     6962023-04-06 23:37:35,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-inslast-inselem,162918000,5.085345,31.214138
     6972023-04-06 23:37:40,3,5 1000 9051 -1 3  ,./perfexp--lq-list--stack-insfirst-allhead,343938000,5.058624,14.707953
     6982023-04-06 23:37:45,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-inselem,658000000,5.050619,7.675713
     6992023-04-06 23:37:50,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-insfirst-inselem,130357800,5.147518,39.487610
     7002023-04-06 23:37:55,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-inslast-remelem,606750000,5.060103,8.339684
     7012023-04-06 23:38:00,4,5 10000 809 -1 4  ,./perfexp--lq-list--stack-insfirst-allhead,509670000,5.013006,9.835788
     7022023-04-06 23:38:06,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-allhead,665000000,5.030220,7.564241
     7032023-04-06 23:38:11,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-insfirst-allhead,509670000,5.045241,9.899035
     7042023-04-06 23:38:16,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-inslast-remelem,707000000,5.030443,7.115195
     7052023-04-06 23:38:21,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-inslast-allhead,1036600000,5.005349,4.828621
     7062023-04-06 23:38:26,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-insfirst-allhead,166568300,5.122366,30.752346
     7072023-04-06 23:38:31,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-inslast-remelem,720010000,5.032318,6.989233
     7082023-04-06 23:38:36,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-inslast-allhead,1078000000,5.011085,4.648502
     7092023-04-06 23:38:41,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-insfirst-remelem,693000000,5.044421,7.279107
     7102023-04-06 23:38:46,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-inselem,217000000,5.008831,23.082171
     7112023-04-06 23:38:51,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-inslast-inselem,980000000,5.001764,5.103841
     7122023-04-06 23:38:56,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-inslast-allhead,159326200,5.160432,32.389099
     7132023-04-06 23:39:01,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-remelem,994000000,5.009426,5.039664
     7142023-04-06 23:39:06,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-inslast-allhead,1008200000,5.006411,4.965692
     7152023-04-06 23:39:11,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-insfirst-allhead,679000000,5.010746,7.379596
     7162023-04-06 23:39:16,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-remelem,588315000,5.073975,8.624589
     7172023-04-06 23:39:21,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-insfirst-remelem,267957700,5.034365,18.787909
     7182023-04-06 23:39:26,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-insfirst-remelem,534009000,5.054075,9.464400
     7192023-04-06 23:39:31,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-inslast-allhead,665000000,5.000117,7.518973
     7202023-04-06 23:39:36,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-inslast-allhead,137599900,5.044078,36.657570
     7212023-04-06 23:39:42,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-inslast-remelem,224000000,5.024699,22.431692
     7222023-04-06 23:39:47,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-allhead,665000000,5.038271,7.576347
     7232023-04-06 23:39:52,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-inselem,137599900,5.151879,37.441008
     7242023-04-06 23:39:57,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-inslast-inselem,137599900,5.247585,38.136547
     7252023-04-06 23:40:02,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-allhead,159326200,5.203331,32.658351
     7262023-04-06 23:40:07,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-inslast-remelem,347620800,5.038125,14.493163
     7272023-04-06 23:40:12,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-allhead,532500000,5.009917,9.408295
     7282023-04-06 23:40:17,2,5 100000 71 -1 2  ,./perfexp--lq-list--stack-insfirst-remelem,681600000,5.024278,7.371300
     7292023-04-06 23:40:22,5,5 1000 9051 -1 5  ,./perfexp--lq-list--stack-insfirst-remelem,534009000,5.005566,9.373561
     7302023-04-06 23:40:27,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-remelem,588315000,5.056992,8.595722
     7312023-04-06 23:40:32,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-inslast-inselem,144842000,5.153273,35.578582
     7322023-04-06 23:40:38,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-insfirst-allhead,945000000,5.002845,5.294016
     7332023-04-06 23:40:43,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-inslast-allhead,343938000,5.058633,14.707979
     7342023-04-06 23:40:48,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-insfirst-inselem,420680000,5.068194,12.047623
     7352023-04-06 23:40:53,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-inslast-allhead,1078000000,5.010055,4.647546
     7362023-04-06 23:40:58,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-remelem,184600000,5.101831,27.637221
     7372023-04-06 23:41:03,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-insfirst-remelem,854000000,5.009771,5.866242
     7382023-04-06 23:41:08,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-inslast-inselem,316785000,5.026464,15.867115
     7392023-04-06 23:41:13,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-inselem,444950000,5.000762,11.238930
     7402023-04-06 23:41:18,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-inslast-remelem,702900000,5.023292,7.146524
     7412023-04-06 23:41:23,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-insfirst-remelem,582480000,5.024755,8.626485
     7422023-04-06 23:41:28,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-allhead,224000000,5.026874,22.441402
     7432023-04-06 23:41:33,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-insfirst-remelem,534009000,5.029006,9.417456
     7442023-04-06 23:41:38,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-inslast-remelem,159326200,5.174692,32.478601
     7452023-04-06 23:41:43,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-insfirst-remelem,784000000,5.004447,6.383223
     7462023-04-06 23:41:48,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-remelem,224000000,5.007044,22.352875
     7472023-04-06 23:41:53,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-allhead,166568300,5.093894,30.581413
     7482023-04-06 23:41:58,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-inslast-inselem,501580000,5.063699,10.095496
     7492023-04-06 23:42:03,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-insfirst-inselem,672000000,5.002208,7.443762
     7502023-04-06 23:42:09,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-inslast-allhead,700000000,5.035791,7.193987
     7512023-04-06 23:42:14,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-inslast-remelem,1263800000,5.028343,3.978749
     7522023-04-06 23:42:19,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-inslast-remelem,159326200,5.113131,32.092217
     7532023-04-06 23:42:24,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-inslast-remelem,597366000,5.046347,8.447664
     7542023-04-06 23:42:29,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-insfirst-remelem,642621000,5.053251,7.863501
     7552023-04-06 23:42:34,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-inslast-inselem,444950000,5.077268,11.410873
     7562023-04-06 23:42:39,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-inslast-inselem,171969000,5.099023,29.650827
     7572023-04-06 23:42:44,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-inslast-allhead,325836000,5.047047,15.489532
     7582023-04-06 23:42:49,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-allhead,181020000,5.216122,28.815170
     7592023-04-06 23:42:54,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-allhead,181020000,5.222584,28.850867
     7602023-04-06 23:43:00,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-inslast-remelem,534009000,5.024676,9.409347
     7612023-04-06 23:43:05,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-allhead,162918000,5.066455,31.098191
     7622023-04-06 23:43:10,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-inslast-allhead,646100000,5.006395,7.748638
     7632023-04-06 23:43:15,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-inslast-allhead,1022400000,5.033839,4.923551
     7642023-04-06 23:43:20,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-remelem,169890000,5.194201,30.573907
     7652023-04-06 23:43:25,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-insfirst-inselem,617700000,5.004354,8.101593
     7662023-04-06 23:43:30,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-inselem,568000000,5.053840,8.897606
     7672023-04-06 23:43:35,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-inslast-allhead,773900000,5.009564,6.473141
     7682023-04-06 23:43:40,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-inselem,477310000,5.060300,10.601705
     7692023-04-06 23:43:45,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-remelem,766800000,5.029327,6.558851
     7702023-04-06 23:43:50,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-insfirst-inselem,307734000,5.015156,16.297049
     7712023-04-06 23:43:55,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-allhead,343938000,5.030864,14.627241
     7722023-04-06 23:44:00,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-inslast-inselem,546700000,5.028823,9.198506
     7732023-04-06 23:44:06,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-insfirst-allhead,159326200,5.159831,32.385326
     7742023-04-06 23:44:11,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-inselem,184600000,5.013750,27.160076
     7752023-04-06 23:44:16,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-inslast-remelem,184600000,5.191165,28.121154
     7762023-04-06 23:44:21,3,5 100 72421 -1 3  ,./perfexp--lq-list--stack-insfirst-inselem,166568300,5.221509,31.347555
     7772023-04-06 23:44:26,1,5 100000 71 -1 1  ,./perfexp--lq-list--stack-insfirst-remelem,681600000,5.027947,7.376683
     7782023-04-06 23:44:31,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-inslast-allhead,493490000,5.065787,10.265227
     7792023-04-06 23:44:36,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-inslast-inselem,448000000,5.071891,11.321185
     7802023-04-06 23:44:41,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-inslast-remelem,570213000,5.041445,8.841336
     7812023-04-06 23:44:46,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-inselem,224000000,5.075413,22.658094
     7822023-04-06 23:44:51,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-insfirst-allhead,517760000,5.074958,9.801758
     7832023-04-06 23:44:57,1,5 1000 9051 -1 1  ,./perfexp--lq-list--stack-insfirst-inselem,325836000,5.079069,15.587808
     7842023-04-06 23:45:02,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-inslast-remelem,184600000,5.156223,27.931869
     7852023-04-06 23:45:07,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-inslast-remelem,646100000,5.048818,7.814298
     7862023-04-06 23:45:12,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-remelem,153867000,5.084243,33.043102
     7872023-04-06 23:45:17,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-remelem,152084100,5.088762,33.460184
     7882023-04-06 23:45:22,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-inselem,477310000,5.040919,10.561101
     7892023-04-06 23:45:27,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-allhead,166568300,5.107945,30.665769
     7902023-04-06 23:45:32,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-remelem,759700000,5.013032,6.598699
     7912023-04-06 23:45:37,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-inselem,159326200,5.183840,32.536017
     7922023-04-06 23:45:43,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-inslast-inselem,546700000,5.060570,9.256576
     7932023-04-06 23:45:48,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-remelem,773900000,5.016882,6.482597
     7942023-04-06 23:45:53,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-inslast-allhead,137599900,5.146936,37.405085
     7952023-04-06 23:45:58,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-inselem,665000000,5.030136,7.564114
     7962023-04-06 23:46:03,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-allhead,231000000,5.069341,21.945199
     7972023-04-06 23:46:08,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-inslast-remelem,588315000,5.038815,8.564825
     7982023-04-06 23:46:13,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-inslast-remelem,597366000,5.062109,8.474049
     7992023-04-06 23:46:18,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-insfirst-allhead,130357800,5.097324,39.102562
     8002023-04-06 23:46:23,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-inselem,181020000,5.245083,28.975157
     8012023-04-06 23:46:28,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-inslast-remelem,728100000,5.048765,6.934164
     8022023-04-06 23:46:34,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-inslast-remelem,260715600,5.006853,19.204271
     8032023-04-06 23:46:39,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-inslast-remelem,171969000,5.222348,30.367962
     8042023-04-06 23:46:44,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-remelem,917000000,5.014479,5.468352
     8052023-04-06 23:46:49,4,5 100 72421 -1 4  ,./perfexp--lq-list--stack-insfirst-inselem,166568300,5.223544,31.359773
     8062023-04-06 23:46:54,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-inslast-allhead,994000000,5.008805,5.039039
     8072023-04-06 23:46:59,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-inslast-allhead,509670000,5.037473,9.883793
     8082023-04-06 23:47:04,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-allhead,444950000,5.008930,11.257287
     8092023-04-06 23:47:09,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-inslast-remelem,1022400000,5.031635,4.921396
     8102023-04-06 23:47:14,1,5 1000000 7 -1 1  ,./perfexp--lq-list--stack-insfirst-remelem,798000000,5.019472,6.290065
     8112023-04-06 23:47:19,1,5 100 72421 -1 1  ,./perfexp--lq-list--stack-insfirst-remelem,333136600,5.086682,15.269058
     8122023-04-06 23:47:24,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-inselem,444950000,5.009886,11.259436
     8132023-04-06 23:47:29,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-insfirst-allhead,1022000000,5.028409,4.920165
     8142023-04-06 23:47:34,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-inslast-inselem,224000000,5.134726,22.922884
     8152023-04-06 23:47:40,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-insfirst-allhead,166568300,5.129354,30.794299
     8162023-04-06 23:47:45,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-insfirst-remelem,267957700,5.029663,18.770362
     8172023-04-06 23:47:50,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-inslast-allhead,144842000,5.159035,35.618363
     8182023-04-06 23:47:55,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-inslast-remelem,153867000,5.205434,33.830737
     8192023-04-06 23:48:00,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-insfirst-remelem,859100000,5.024798,5.848909
     8202023-04-06 23:48:05,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-inslast-inselem,352989000,5.106726,14.467097
     8212023-04-06 23:48:10,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-inslast-inselem,325836000,5.095977,15.639699
     8222023-04-06 23:48:15,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-inselem,162918000,5.237821,32.150045
     8232023-04-06 23:48:21,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-inslast-allhead,231000000,5.106340,22.105368
     8242023-04-06 23:48:26,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-inslast-inselem,159326200,5.099221,32.004912
     8252023-04-06 23:48:31,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-insfirst-inselem,159326200,5.004885,31.412818
     8262023-04-06 23:48:36,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-insfirst-inselem,130357800,5.103887,39.152908
     8272023-04-06 23:48:41,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-insfirst-allhead,316785000,5.095627,16.085443
     8282023-04-06 23:48:46,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-inslast-allhead,169890000,5.023940,29.571723
     8292023-04-06 23:48:51,3,5 100000 71 -1 3  ,./perfexp--lq-list--stack-insfirst-inselem,724200000,5.040016,6.959426
     8302023-04-06 23:48:56,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-insfirst-allhead,679000000,5.039133,7.421404
     8312023-04-06 23:49:01,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-inslast-remelem,159326200,5.202599,32.653757
     8322023-04-06 23:49:07,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-insfirst-allhead,316785000,5.001730,15.789037
     8332023-04-06 23:49:12,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-inslast-remelem,224000000,5.005996,22.348196
     8342023-04-06 23:49:17,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-inslast-allhead,672000000,5.047250,7.510789
     8352023-04-06 23:49:22,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-inslast-inselem,710000000,5.015764,7.064456
     8362023-04-06 23:49:27,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-insfirst-remelem,642621000,5.038532,7.840597
     8372023-04-06 23:49:32,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-remelem,152084100,5.074580,33.366933
     8382023-04-06 23:49:37,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-allhead,169890000,5.038720,29.658720
     8392023-04-06 23:49:42,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-insfirst-allhead,130357800,5.097956,39.107411
     8402023-04-06 23:49:47,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-inslast-allhead,665000000,5.003770,7.524466
     8412023-04-06 23:49:52,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-inslast-inselem,646100000,5.033712,7.790918
     8422023-04-06 23:49:57,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-inslast-remelem,159326200,5.197406,32.621163
     8432023-04-06 23:50:02,3,5 1000000 7 -1 3  ,./perfexp--lq-list--stack-insfirst-remelem,798000000,5.021226,6.292263
     8442023-04-06 23:50:07,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-insfirst-remelem,267957700,5.036691,18.796590
     8452023-04-06 23:50:12,5,5 10000 809 -1 5  ,./perfexp--lq-list--stack-insfirst-allhead,517760000,5.076458,9.804655
     8462023-04-06 23:50:18,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-inselem,343938000,5.111457,14.861565
     8472023-04-06 23:50:23,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-inslast-remelem,766800000,5.036608,6.568346
     8482023-04-06 23:50:28,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-inslast-allhead,639000000,5.008767,7.838446
     8492023-04-06 23:50:33,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-inselem,343938000,5.096478,14.818014
     8502023-04-06 23:50:38,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-inslast-inselem,224000000,5.053022,22.558134
     8512023-04-06 23:50:43,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-inslast-inselem,588000000,5.043254,8.576963
     8522023-04-06 23:50:48,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-insfirst-allhead,325836000,5.142199,15.781556
     8532023-04-06 23:50:53,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-inslast-inselem,575100000,5.013201,8.717094
     8542023-04-06 23:50:58,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-insfirst-allhead,788100000,5.011622,6.359119
     8552023-04-06 23:51:03,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-inselem,603500000,5.049321,8.366729
     8562023-04-06 23:51:08,2,5 100 72421 -1 2  ,./perfexp--lq-list--stack-insfirst-allhead,166568300,5.050434,30.320499
     8572023-04-06 23:51:13,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-inselem,162918000,5.096707,31.283879
     8582023-04-06 23:51:18,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-insfirst-allhead,805000000,5.003890,6.216012
     8592023-04-06 23:51:23,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-inslast-inselem,137599900,5.089424,36.987120
     8602023-04-06 23:51:29,5,5 10000 809 -1 5  ,./perfexp--lq-list--stack-insfirst-remelem,582480000,5.006380,8.594939
     8612023-04-06 23:51:34,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-inslast-allhead,453040000,5.016531,11.073042
     8622023-04-06 23:51:39,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-inslast-inselem,453040000,5.063734,11.177234
     8632023-04-06 23:51:44,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-allhead,177980000,5.226280,29.364423
     8642023-04-06 23:51:49,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-inslast-allhead,343938000,5.057972,14.706057
     8652023-04-06 23:51:54,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-insfirst-allhead,509670000,5.025430,9.860164
     8662023-04-06 23:51:59,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-inslast-remelem,161800000,5.000954,30.908245
     8672023-04-06 23:52:04,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-allhead,181020000,5.211717,28.790835
     8682023-04-06 23:52:09,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-inslast-allhead,477310000,5.049791,10.579688
     8692023-04-06 23:52:14,1,5 10000 809 -1 1  ,./perfexp--lq-list--stack-insfirst-remelem,590570000,5.016456,8.494261
     8702023-04-06 23:52:19,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-insfirst-remelem,534009000,5.061113,9.477580
     8712023-04-06 23:52:24,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-remelem,169890000,5.017420,29.533345
     8722023-04-06 23:52:29,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-inslast-inselem,485400000,5.081081,10.467822
     8732023-04-06 23:52:34,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-allhead,343938000,5.033256,14.634196
     8742023-04-06 23:52:40,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-inslast-remelem,784000000,5.033145,6.419828
     8752023-04-06 23:52:45,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-inslast-inselem,980000000,5.012630,5.114929
     8762023-04-06 23:52:50,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-insfirst-remelem,791000000,5.040982,6.372923
     8772023-04-06 23:52:55,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-inslast-inselem,444950000,5.091346,11.442513
     8782023-04-06 23:53:00,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-inslast-remelem,752600000,5.007532,6.653643
     8792023-04-06 23:53:05,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-remelem,171969000,5.137818,29.876420
     8802023-04-06 23:53:10,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-inslast-allhead,477310000,5.056730,10.594226
     8812023-04-06 23:53:15,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-insfirst-inselem,539600000,5.044061,9.347778
     8822023-04-06 23:53:20,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-inslast-allhead,889000000,5.018817,5.645463
     8832023-04-06 23:53:25,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-inslast-allhead,485400000,5.004149,10.309330
     8842023-04-06 23:53:30,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-inslast-remelem,687876000,5.062201,7.359177
     8852023-04-06 23:53:35,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-allhead,137599900,5.148068,37.413312
     8862023-04-06 23:53:40,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-insfirst-inselem,289632000,5.012993,17.308146
     8872023-04-06 23:53:45,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-inslast-inselem,575100000,5.045375,8.773039
     8882023-04-06 23:53:50,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-insfirst-allhead,130357800,5.099296,39.117690
     8892023-04-06 23:53:56,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-inslast-inselem,588000000,5.037787,8.567665
     8902023-04-06 23:54:01,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-allhead,184600000,5.105671,27.658023
     8912023-04-06 23:54:06,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-insfirst-remelem,333136600,5.074849,15.233538
     8922023-04-06 23:54:11,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-inslast-remelem,325894500,5.093924,15.630592
     8932023-04-06 23:54:16,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-allhead,343938000,5.031887,14.630215
     8942023-04-06 23:54:21,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-inslast-remelem,965600000,5.024737,5.203746
     8952023-04-06 23:54:26,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-insfirst-allhead,343938000,5.000385,14.538623
     8962023-04-06 23:54:31,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-inslast-allhead,162918000,5.114478,31.392958
     8972023-04-06 23:54:36,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-inslast-remelem,784000000,5.034203,6.421177
     8982023-04-06 23:54:41,2,5 100000 71 -1 2  ,./perfexp--lq-list--stack-insfirst-allhead,773900000,5.039677,6.512052
     8992023-04-06 23:54:46,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-inslast-remelem,325894500,5.097422,15.641326
     9002023-04-06 23:54:51,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-insfirst-remelem,756000000,5.023632,6.645016
     9012023-04-06 23:54:56,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-inslast-remelem,695740000,5.045478,7.251959
     9022023-04-06 23:55:01,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-inslast-remelem,177500000,5.031516,28.346569
     9032023-04-06 23:55:07,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-allhead,159326200,5.042017,31.645875
     9042023-04-06 23:55:12,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-allhead,343938000,5.028640,14.620775
     9052023-04-06 23:55:17,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-inslast-inselem,444950000,5.013986,11.268650
     9062023-04-06 23:55:22,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-insfirst-remelem,267957700,5.032008,18.779113
     9072023-04-06 23:55:27,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-inslast-allhead,352989000,5.053183,14.315412
     9082023-04-06 23:55:32,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-inselem,159326200,5.186497,32.552694
     9092023-04-06 23:55:37,2,5 1000 9051 -1 2  ,./perfexp--lq-list--stack-insfirst-remelem,534009000,5.014736,9.390733
     9102023-04-06 23:55:42,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-inslast-remelem,534009000,5.029801,9.418944
     9112023-04-06 23:55:47,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-inslast-inselem,343938000,5.069517,14.739625
     9122023-04-06 23:55:52,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-inslast-allhead,582200000,5.043558,8.662930
     9132023-04-06 23:55:57,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-remelem,184600000,5.143890,27.865060
     9142023-04-06 23:56:02,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-inslast-allhead,461130000,5.080796,11.018142
     9152023-04-06 23:56:07,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-inslast-inselem,171969000,5.118993,29.766952
     9162023-04-06 23:56:13,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-insfirst-remelem,720010000,5.035548,6.993720
     9172023-04-06 23:56:18,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-inselem,137599900,5.147075,37.406095
     9182023-04-06 23:56:23,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-insfirst-remelem,582480000,5.029466,8.634573
     9192023-04-06 23:56:28,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-inslast-allhead,166568300,5.213374,31.298717
     9202023-04-06 23:56:33,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-insfirst-inselem,130357800,5.104179,39.155148
     9212023-04-06 23:56:38,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-insfirst-remelem,647200000,5.055149,7.810799
     9222023-04-06 23:56:43,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-allhead,334887000,5.047137,15.071164
     9232023-04-06 23:56:48,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-insfirst-inselem,973000000,5.030706,5.170304
     9242023-04-06 23:56:53,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-insfirst-inselem,159326200,5.197585,32.622287
     9252023-04-06 23:56:59,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-insfirst-allhead,444950000,5.057074,11.365488
     9262023-04-06 23:57:04,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-inslast-remelem,177500000,5.028745,28.330958
     9272023-04-06 23:57:09,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-insfirst-allhead,325836000,5.133705,15.755487
     9282023-04-06 23:57:14,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-inselem,181020000,5.216624,28.817943
     9292023-04-06 23:57:19,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-insfirst-inselem,546700000,5.040683,9.220199
     9302023-04-06 23:57:24,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-insfirst-allhead,166568300,5.126525,30.777315
     9312023-04-06 23:57:29,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-inslast-allhead,752600000,5.030341,6.683950
     9322023-04-06 23:57:34,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-insfirst-inselem,781000000,5.002303,6.404997
     9332023-04-06 23:57:39,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-inslast-remelem,311410300,5.110663,16.411349
     9342023-04-06 23:57:44,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-inslast-remelem,260715600,5.004443,19.195027
     9352023-04-06 23:57:49,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-inselem,177980000,5.040817,28.322379
     9362023-04-06 23:57:55,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-inslast-remelem,777000000,5.012582,6.451199
     9372023-04-06 23:58:00,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-insfirst-inselem,130357800,5.143872,39.459641
     9382023-04-06 23:58:05,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-remelem,588315000,5.034068,8.556756
     9392023-04-06 23:58:10,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-inslast-inselem,436860000,5.006743,11.460749
     9402023-04-06 23:58:15,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-insfirst-inselem,159326200,5.004273,31.408977
     9412023-04-06 23:58:20,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-insfirst-remelem,784000000,5.042812,6.432158
     9422023-04-06 23:58:25,5,5 100000 71 -1 5  ,./perfexp--lq-list--stack-insfirst-allhead,788100000,5.002504,6.347550
     9432023-04-06 23:58:30,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-inselem,177500000,5.009520,28.222648
     9442023-04-06 23:58:35,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-inslast-allhead,162918000,5.140808,31.554573
     9452023-04-06 23:58:40,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-inslast-inselem,144842000,5.151509,35.566403
     9462023-04-06 23:58:45,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-inslast-remelem,152084100,5.034474,33.103224
     9472023-04-06 23:58:50,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-inselem,184600000,5.137038,27.827941
     9482023-04-06 23:58:56,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-inselem,477310000,5.038631,10.556307
     9492023-04-06 23:59:01,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-inslast-inselem,171969000,5.114824,29.742709
     9502023-04-06 23:59:06,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-inslast-remelem,515907000,5.030354,9.750505
     9512023-04-06 23:59:11,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-allhead,665000000,5.014697,7.540898
     9522023-04-06 23:59:16,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-allhead,665000000,5.003080,7.523429
     9532023-04-06 23:59:21,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-allhead,169890000,5.029569,29.604856
     9542023-04-06 23:59:26,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-insfirst-allhead,724200000,5.029829,6.945359
     9552023-04-06 23:59:31,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-inslast-allhead,493490000,5.010267,10.152722
     9562023-04-06 23:59:36,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-inslast-remelem,153867000,5.204054,33.821768
     9572023-04-06 23:59:41,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-insfirst-inselem,159326200,5.006861,31.425221
     9582023-04-06 23:59:46,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-inselem,166568300,5.134474,30.825037
     9592023-04-06 23:59:51,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-allhead,177500000,5.021209,28.288501
     9602023-04-06 23:59:56,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-inslast-remelem,959000000,5.000634,5.214425
     9612023-04-07 00:00:01,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-inslast-allhead,177980000,5.123476,28.786808
     9622023-04-07 00:00:07,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-insfirst-remelem,574390000,5.003850,8.711590
     9632023-04-07 00:00:12,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-inslast-remelem,678825000,5.004920,7.372916
     9642023-04-07 00:00:17,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-insfirst-inselem,788100000,5.031101,6.383836
     9652023-04-07 00:00:22,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-inslast-allhead,334887000,5.030583,15.021733
     9662023-04-07 00:00:27,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-insfirst-inselem,298683000,5.139339,17.206667
     9672023-04-07 00:00:32,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-allhead,485400000,5.084587,10.475045
     9682023-04-07 00:00:37,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-inslast-remelem,590570000,5.043516,8.540082
     9692023-04-07 00:00:42,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-allhead,231000000,5.119258,22.161290
     9702023-04-07 00:00:47,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-insfirst-remelem,461601000,5.024322,10.884556
     9712023-04-07 00:00:52,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-insfirst-allhead,461130000,5.076500,11.008826
     9722023-04-07 00:00:57,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-insfirst-inselem,588000000,5.001611,8.506141
     9732023-04-07 00:01:02,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-inselem,169890000,5.145494,30.287209
     9742023-04-07 00:01:07,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-inslast-allhead,672000000,5.044544,7.506762
     9752023-04-07 00:01:12,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-insfirst-remelem,534009000,5.004349,9.371282
     9762023-04-07 00:01:17,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-inslast-inselem,987000000,5.025173,5.091361
     9772023-04-07 00:01:23,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-inslast-remelem,169890000,5.236716,30.824157
     9782023-04-07 00:01:28,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-allhead,334887000,5.055747,15.096874
     9792023-04-07 00:01:33,2,5 1000000 7 -1 2  ,./perfexp--lq-list--stack-insfirst-allhead,924000000,5.034723,5.448834
     9802023-04-07 00:01:38,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-insfirst-remelem,296926100,5.111804,17.215745
     9812023-04-07 00:01:43,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-inslast-remelem,325894500,5.092882,15.627395
     9822023-04-07 00:01:48,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-inslast-inselem,493490000,5.012330,10.156903
     9832023-04-07 00:01:53,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-insfirst-allhead,660300000,5.052296,7.651516
     9842023-04-07 00:01:58,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-inselem,169890000,5.023551,29.569433
     9852023-04-07 00:02:03,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-inslast-inselem,162918000,5.065419,31.091831
     9862023-04-07 00:02:08,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-inslast-inselem,159326200,5.065417,31.792743
     9872023-04-07 00:02:13,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-inselem,610600000,5.045429,8.263067
     9882023-04-07 00:02:18,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-remelem,159326200,5.086272,31.923638
     9892023-04-07 00:02:24,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-insfirst-remelem,773900000,5.011786,6.476012
     9902023-04-07 00:02:29,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-inslast-remelem,695740000,5.035083,7.237018
     9912023-04-07 00:02:34,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-inselem,617700000,5.034056,8.149678
     9922023-04-07 00:02:39,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-insfirst-allhead,316785000,5.101400,16.103667
     9932023-04-07 00:02:44,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-insfirst-allhead,624800000,5.004312,8.009462
     9942023-04-07 00:02:49,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-insfirst-inselem,444950000,5.086458,11.431527
     9952023-04-07 00:02:54,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-inselem,343938000,5.095479,14.815109
     9962023-04-07 00:02:59,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-inslast-allhead,501580000,5.078669,10.125342
     9972023-04-07 00:03:04,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-inslast-allhead,325836000,5.035838,15.455131
     9982023-04-07 00:03:09,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-insfirst-remelem,642621000,5.048161,7.855581
     9992023-04-07 00:03:14,5,5 1000 9051 -1 5  ,./perfexp--lq-list--stack-insfirst-allhead,343938000,5.068172,14.735714
     10002023-04-07 00:03:19,2,5 10000 809 -1 2  ,./perfexp--lq-list--stack-insfirst-allhead,509670000,5.010027,9.829943
     10012023-04-07 00:03:24,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-insfirst-remelem,711920000,5.004285,7.029280
     10022023-04-07 00:03:29,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-inslast-inselem,343938000,5.124094,14.898307
     10032023-04-07 00:03:35,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-remelem,289684000,5.109375,17.637754
     10042023-04-07 00:03:40,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-inslast-inselem,177980000,5.226474,29.365513
     10052023-04-07 00:03:45,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-inslast-remelem,1421000000,5.024039,3.535566
     10062023-04-07 00:03:50,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-inslast-allhead,137599900,5.041139,36.636211
     10072023-04-07 00:03:55,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-inslast-allhead,159326200,5.081520,31.893813
     10082023-04-07 00:04:00,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-insfirst-inselem,581000000,5.046014,8.685050
     10092023-04-07 00:04:05,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-inslast-allhead,493490000,5.016015,10.164370
     10102023-04-07 00:04:10,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-insfirst-inselem,581000000,5.003459,8.611806
     10112023-04-07 00:04:15,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-inslast-inselem,693000000,5.001641,7.217375
     10122023-04-07 00:04:20,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-inslast-allhead,159326200,5.162225,32.400352
     10132023-04-07 00:04:25,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-inslast-remelem,325894500,5.086104,15.606597
     10142023-04-07 00:04:31,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-insfirst-inselem,307734000,5.019841,16.312273
     10152023-04-07 00:04:36,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-inslast-allhead,469220000,5.001562,10.659311
     10162023-04-07 00:04:41,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-insfirst-inselem,130357800,5.142624,39.450067
     10172023-04-07 00:04:46,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-allhead,553800000,5.013626,9.053135
     10182023-04-07 00:04:51,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-insfirst-remelem,333136600,5.076545,15.238629
     10192023-04-07 00:04:56,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-inslast-inselem,169890000,5.071793,29.853393
     10202023-04-07 00:05:01,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-inslast-allhead,501580000,5.064339,10.096772
     10212023-04-07 00:05:06,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-remelem,153867000,5.176563,33.643101
     10222023-04-07 00:05:11,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-allhead,184600000,5.032819,27.263375
     10232023-04-07 00:05:16,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-remelem,224000000,5.024146,22.429223
     10242023-04-07 00:05:21,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-inslast-remelem,588315000,5.050261,8.584281
     10252023-04-07 00:05:26,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-inslast-remelem,980000000,5.025545,5.128107
     10262023-04-07 00:05:32,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-inselem,166568300,5.065528,30.411117
     10272023-04-07 00:05:37,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-remelem,318652400,5.015438,15.739527
     10282023-04-07 00:05:42,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-inslast-remelem,823600000,5.033144,6.111151
     10292023-04-07 00:05:47,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-inslast-allhead,710000000,5.007572,7.052918
     10302023-04-07 00:05:52,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-insfirst-inselem,130357800,5.098879,39.114491
     10312023-04-07 00:05:57,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-inslast-allhead,166568300,5.181296,31.106135
     10322023-04-07 00:06:02,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-insfirst-inselem,159326200,5.206496,32.678216
     10332023-04-07 00:06:07,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-insfirst-remelem,333136600,5.083054,15.258167
     10342023-04-07 00:06:12,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-inslast-inselem,159326200,5.023020,31.526642
     10352023-04-07 00:06:17,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-insfirst-inselem,477310000,5.066548,10.614795
     10362023-04-07 00:06:23,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-inslast-inselem,444950000,5.002215,11.242196
     10372023-04-07 00:06:28,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-insfirst-allhead,731300000,5.007529,6.847435
     10382023-04-07 00:06:33,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-insfirst-inselem,316785000,5.004748,15.798564
     10392023-04-07 00:06:38,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-inslast-inselem,588000000,5.046407,8.582325
     10402023-04-07 00:06:43,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-remelem,917000000,5.029605,5.484847
     10412023-04-07 00:06:48,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-inslast-inselem,833000000,5.018035,6.024052
     10422023-04-07 00:06:53,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-insfirst-allhead,525850000,5.070215,9.641942
     10432023-04-07 00:06:58,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-insfirst-remelem,731300000,5.028043,6.875486
     10442023-04-07 00:07:03,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-inslast-remelem,614840000,5.028645,8.178786
     10452023-04-07 00:07:08,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-inslast-remelem,720010000,5.048400,7.011569
     10462023-04-07 00:07:13,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-inslast-remelem,224000000,5.107446,22.801098
     10472023-04-07 00:07:18,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-inslast-allhead,959000000,5.009608,5.223783
     10482023-04-07 00:07:23,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-remelem,184600000,5.136296,27.823922
     10492023-04-07 00:07:28,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-inslast-remelem,695740000,5.019980,7.215310
     10502023-04-07 00:07:33,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-inslast-allhead,493490000,5.031048,10.194833
     10512023-04-07 00:07:38,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-insfirst-remelem,534009000,5.044507,9.446483
     10522023-04-07 00:07:43,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-inslast-inselem,343938000,5.079265,14.767967
     10532023-04-07 00:07:48,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-inslast-inselem,568000000,5.039315,8.872033
     10542023-04-07 00:07:53,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-insfirst-inselem,436860000,5.036864,11.529698
     10552023-04-07 00:07:58,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-inslast-inselem,724200000,5.004672,6.910621
     10562023-04-07 00:08:03,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-inslast-inselem,159326200,5.152197,32.337412
     10572023-04-07 00:08:09,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-inslast-allhead,137599900,5.043725,36.655005
     10582023-04-07 00:08:14,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-insfirst-remelem,461601000,5.010361,10.854311
     10592023-04-07 00:08:19,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-allhead,444950000,5.008312,11.255898
     10602023-04-07 00:08:24,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-insfirst-allhead,646100000,5.052912,7.820635
     10612023-04-07 00:08:29,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-inslast-inselem,693000000,5.024033,7.249687
     10622023-04-07 00:08:34,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-inslast-inselem,171969000,5.113559,29.735353
     10632023-04-07 00:08:39,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-inslast-remelem,224000000,5.136808,22.932179
     10642023-04-07 00:08:44,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-allhead,224000000,5.087099,22.710263
     10652023-04-07 00:08:49,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-inslast-inselem,693000000,5.001977,7.217860
     10662023-04-07 00:08:54,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-insfirst-allhead,325836000,5.086269,15.609905
     10672023-04-07 00:08:59,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-remelem,152084100,5.070523,33.340257
     10682023-04-07 00:09:04,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-insfirst-inselem,307734000,5.001254,16.251873
     10692023-04-07 00:09:09,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-inselem,181020000,5.244969,28.974528
     10702023-04-07 00:09:15,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-inslast-allhead,159326200,5.076574,31.862770
     10712023-04-07 00:09:20,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-allhead,560900000,5.015707,8.942248
     10722023-04-07 00:09:25,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-inslast-remelem,937200000,5.038076,5.375668
     10732023-04-07 00:09:30,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-inselem,177980000,5.087129,28.582588
     10742023-04-07 00:09:35,4,5 10000 809 -1 4  ,./perfexp--lq-list--stack-insfirst-remelem,590570000,5.057216,8.563280
     10752023-04-07 00:09:40,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-inslast-inselem,159326200,5.148371,32.313399
     10762023-04-07 00:09:45,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-insfirst-inselem,307734000,5.017681,16.305254
     10772023-04-07 00:09:50,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-remelem,703830000,5.001011,7.105425
     10782023-04-07 00:09:55,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-inslast-inselem,159326200,5.146824,32.303689
     10792023-04-07 00:10:00,4,5 100000 71 -1 4  ,./perfexp--lq-list--stack-insfirst-inselem,560900000,5.037575,8.981236
     10802023-04-07 00:10:05,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-insfirst-inselem,159326200,5.206990,32.681317
     10812023-04-07 00:10:11,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-inslast-inselem,177980000,5.212465,29.286802
     10822023-04-07 00:10:16,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-inslast-remelem,980000000,5.014558,5.116896
     10832023-04-07 00:10:21,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-inselem,343938000,5.094368,14.811879
     10842023-04-07 00:10:26,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-inselem,610600000,5.038606,8.251893
     10852023-04-07 00:10:31,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-insfirst-remelem,738400000,5.012787,6.788715
     10862023-04-07 00:10:36,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-inslast-remelem,679560000,5.029846,7.401622
     10872023-04-07 00:10:41,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-inslast-inselem,453040000,5.073771,11.199389
     10882023-04-07 00:10:46,2,5 1000000 7 -1 2  ,./perfexp--lq-list--stack-insfirst-remelem,798000000,5.015579,6.285187
     10892023-04-07 00:10:51,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-inslast-inselem,493490000,5.060374,10.254258
     10902023-04-07 00:10:56,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-inslast-remelem,766800000,5.015732,6.541122
     10912023-04-07 00:11:01,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-inslast-inselem,453040000,5.070851,11.192943
     10922023-04-07 00:11:06,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-insfirst-allhead,509670000,5.009743,9.829386
     10932023-04-07 00:11:11,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-inslast-inselem,610600000,5.024440,8.228693
     10942023-04-07 00:11:16,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-inslast-allhead,759700000,5.040553,6.634926
     10952023-04-07 00:11:21,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-inslast-remelem,159326200,5.193180,32.594639
     10962023-04-07 00:11:27,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-inslast-allhead,343938000,5.052484,14.690101
     10972023-04-07 00:11:32,1,5 100000 71 -1 1  ,./perfexp--lq-list--stack-insfirst-allhead,788100000,5.016808,6.365700
     10982023-04-07 00:11:37,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-insfirst-allhead,660300000,5.045791,7.641664
     10992023-04-07 00:11:42,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-inslast-inselem,159326200,5.146330,32.300588
     11002023-04-07 00:11:47,3,5 10000 809 -1 3  ,./perfexp--lq-list--stack-insfirst-allhead,509670000,5.049794,9.907968
     11012023-04-07 00:11:52,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-inselem,166568300,5.161840,30.989330
     11022023-04-07 00:11:57,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-insfirst-allhead,130357800,5.062710,38.837032
     11032023-04-07 00:12:02,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-inslast-inselem,159326200,5.089807,31.945826
     11042023-04-07 00:12:08,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-remelem,282441900,5.058237,17.908947
     11052023-04-07 00:12:13,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-remelem,224000000,5.036237,22.483201
     11062023-04-07 00:12:18,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-inslast-allhead,177500000,5.014610,28.251324
     11072023-04-07 00:12:23,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-insfirst-remelem,647200000,5.039386,7.786443
     11082023-04-07 00:12:28,2,5 1000 9051 -1 2  ,./perfexp--lq-list--stack-insfirst-allhead,343938000,5.069521,14.739636
     11092023-04-07 00:12:33,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-allhead,159326200,5.100854,32.015161
     11102023-04-07 00:12:38,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-insfirst-allhead,166568300,5.125007,30.768201
     11112023-04-07 00:12:43,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-allhead,177980000,5.117398,28.752658
     11122023-04-07 00:12:48,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-inslast-remelem,590570000,5.052605,8.555472
     11132023-04-07 00:12:53,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-allhead,343938000,5.025513,14.611683
     11142023-04-07 00:12:58,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-inslast-allhead,177980000,5.199746,29.215339
     11152023-04-07 00:13:04,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-inslast-remelem,679560000,5.058526,7.443825
     11162023-04-07 00:13:09,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-insfirst-remelem,710000000,5.003660,7.047408
     11172023-04-07 00:13:14,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-insfirst-inselem,560900000,5.048259,9.000283
     11182023-04-07 00:13:19,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-insfirst-allhead,896000000,5.014332,5.596353
     11192023-04-07 00:13:24,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-inslast-allhead,184600000,5.190548,28.117811
     11202023-04-07 00:13:29,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-remelem,325894500,5.111016,15.683039
     11212023-04-07 00:13:34,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-inslast-allhead,763000000,5.017561,6.576096
     11222023-04-07 00:13:39,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-inslast-inselem,833000000,5.019453,6.025754
     11232023-04-07 00:13:44,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-insfirst-remelem,590570000,5.047563,8.546934
     11242023-04-07 00:13:49,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-insfirst-inselem,436860000,5.034155,11.523497
     11252023-04-07 00:13:54,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-inslast-remelem,570213000,5.051648,8.859230
     11262023-04-07 00:13:59,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-allhead,610600000,5.015572,8.214170
     11272023-04-07 00:14:04,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-insfirst-allhead,1022000000,5.030284,4.922000
     11282023-04-07 00:14:09,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-inslast-remelem,966000000,5.018343,5.194972
     11292023-04-07 00:14:14,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-insfirst-remelem,784000000,5.042359,6.431580
     11302023-04-07 00:14:19,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-inslast-allhead,184600000,5.173540,28.025677
     11312023-04-07 00:14:25,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-inslast-inselem,553800000,5.046826,9.113084
     11322023-04-07 00:14:30,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-inslast-allhead,493490000,5.025143,10.182867
     11332023-04-07 00:14:35,4,5 100000 71 -1 4  ,./perfexp--lq-list--stack-insfirst-remelem,702900000,5.050739,7.185573
     11342023-04-07 00:14:40,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-allhead,162918000,5.172527,31.749267
     11352023-04-07 00:14:45,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-inselem,159326200,5.130366,32.200391
     11362023-04-07 00:14:50,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-remelem,830700000,5.005727,6.025914
     11372023-04-07 00:14:55,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-inslast-allhead,159326200,5.105089,32.041742
     11382023-04-07 00:15:00,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-insfirst-inselem,581000000,5.027483,8.653155
     11392023-04-07 00:15:05,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-inslast-allhead,159326200,5.079283,31.879772
     11402023-04-07 00:15:10,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-inslast-remelem,169890000,5.225200,30.756372
     11412023-04-07 00:15:16,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-inslast-inselem,159326200,5.152960,32.342201
     11422023-04-07 00:15:21,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-inslast-remelem,777000000,5.023512,6.465266
     11432023-04-07 00:15:26,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-inslast-inselem,693000000,5.042654,7.276557
     11442023-04-07 00:15:31,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-allhead,169890000,5.097853,30.006787
     11452023-04-07 00:15:36,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-inslast-remelem,311410300,5.100699,16.379352
     11462023-04-07 00:15:41,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-inslast-inselem,137599900,5.246073,38.125558
     11472023-04-07 00:15:46,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-inslast-inselem,325836000,5.127345,15.735968
     11482023-04-07 00:15:52,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-inslast-allhead,325836000,5.027188,15.428584
     11492023-04-07 00:15:57,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-inslast-inselem,224000000,5.015171,22.389156
     11502023-04-07 00:16:02,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-inslast-inselem,493490000,5.011236,10.154686
     11512023-04-07 00:16:07,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-inselem,546700000,5.018107,9.178904
     11522023-04-07 00:16:12,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-inslast-allhead,882000000,5.002161,5.671384
     11532023-04-07 00:16:17,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-inslast-remelem,792820000,5.043780,6.361822
     11542023-04-07 00:16:22,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-inslast-remelem,318652400,5.040033,15.816711
     11552023-04-07 00:16:27,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-insfirst-inselem,388320000,5.085010,13.094896
     11562023-04-07 00:16:32,3,5 100 72421 -1 3  ,./perfexp--lq-list--stack-insfirst-remelem,333136600,5.078881,15.245641
     11572023-04-07 00:16:37,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-inslast-allhead,868000000,5.019333,5.782642
     11582023-04-07 00:16:42,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-inslast-allhead,177500000,5.028223,28.328017
     11592023-04-07 00:16:47,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-allhead,631900000,5.013989,7.934782
     11602023-04-07 00:16:52,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-inslast-allhead,224000000,5.103798,22.784813
     11612023-04-07 00:16:57,3,5 100 72421 -1 3  ,./perfexp--lq-list--stack-insfirst-allhead,166568300,5.053284,30.337609
     11622023-04-07 00:17:02,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-insfirst-inselem,493490000,5.046497,10.226138
     11632023-04-07 00:17:07,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-inslast-allhead,334887000,5.070579,15.141164
     11642023-04-07 00:17:12,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-inslast-inselem,352989000,5.106015,14.465082
     11652023-04-07 00:17:18,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-inslast-allhead,672000000,5.053260,7.519732
     11662023-04-07 00:17:23,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-inslast-inselem,184600000,5.086013,27.551533
     11672023-04-07 00:17:28,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-inslast-inselem,177500000,5.041333,28.401876
     11682023-04-07 00:17:33,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-insfirst-remelem,944300000,5.027667,5.324226
     11692023-04-07 00:17:38,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-remelem,695740000,5.024660,7.222037
     11702023-04-07 00:17:43,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-insfirst-allhead,130357800,5.060227,38.817984
     11712023-04-07 00:17:48,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-allhead,453040000,5.060348,11.169760
     11722023-04-07 00:17:53,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-inslast-remelem,1263800000,5.002587,3.958369
     11732023-04-07 00:17:58,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-inslast-remelem,169890000,5.032008,29.619212
     11742023-04-07 00:18:03,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-inslast-inselem,469220000,5.038856,10.738792
     11752023-04-07 00:18:08,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-inslast-allhead,184600000,5.132353,27.802562
     11762023-04-07 00:18:13,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-insfirst-inselem,388320000,5.061103,13.033331
     11772023-04-07 00:18:18,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-inselem,169890000,5.089740,29.959032
     11782023-04-07 00:18:23,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-insfirst-allhead,130357800,5.096965,39.099808
     11792023-04-07 00:18:29,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-inslast-inselem,171969000,5.103011,29.674017
     11802023-04-07 00:18:34,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-inselem,658000000,5.036277,7.653916
     11812023-04-07 00:18:39,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-inslast-inselem,177980000,5.212807,29.288723
     11822023-04-07 00:18:44,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-inslast-inselem,477310000,5.072814,10.627923
     11832023-04-07 00:18:49,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-inslast-remelem,311410300,5.096826,16.366915
     11842023-04-07 00:18:54,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-inslast-allhead,169890000,5.016611,29.528583
     11852023-04-07 00:18:59,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-remelem,937200000,5.001450,5.336588
     11862023-04-07 00:19:04,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-inslast-inselem,588000000,5.027147,8.549570
     11872023-04-07 00:19:09,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-inslast-inselem,184600000,5.170569,28.009583
     11882023-04-07 00:19:14,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-inslast-allhead,181020000,5.255817,29.034455
     11892023-04-07 00:19:20,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-inslast-allhead,603500000,5.004894,8.293114
     11902023-04-07 00:19:25,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-inslast-allhead,493490000,5.060646,10.254810
     11912023-04-07 00:19:30,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-insfirst-remelem,609000000,5.021341,8.245223
     11922023-04-07 00:19:35,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-inslast-inselem,334887000,5.004467,14.943748
     11932023-04-07 00:19:40,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-remelem,687650000,5.004454,7.277618
     11942023-04-07 00:19:45,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-remelem,289684000,5.114885,17.656774
     11952023-04-07 00:19:50,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-inslast-inselem,485400000,5.081049,10.467756
     11962023-04-07 00:19:55,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-inslast-remelem,318652400,5.038741,15.812657
     11972023-04-07 00:20:00,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-remelem,588315000,5.013924,8.522516
     11982023-04-07 00:20:05,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-insfirst-allhead,889000000,5.011883,5.637664
     11992023-04-07 00:20:10,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-inslast-inselem,444950000,5.067489,11.388895
     12002023-04-07 00:20:15,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-inslast-allhead,159326200,5.066920,31.802177
     12012023-04-07 00:20:20,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-inslast-allhead,177500000,5.042851,28.410428
     12022023-04-07 00:20:25,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-inslast-allhead,137599900,5.041518,36.638966
     12032023-04-07 00:20:30,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-inslast-remelem,534009000,5.035769,9.430120
     12042023-04-07 00:20:35,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-inslast-allhead,169890000,5.014708,29.517382
     12052023-04-07 00:20:40,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-inslast-remelem,169890000,5.074810,29.871152
     12062023-04-07 00:20:46,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-inslast-inselem,144842000,5.151741,35.568005
     12072023-04-07 00:20:51,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-inslast-remelem,606750000,5.015496,8.266166
     12082023-04-07 00:20:56,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-inslast-allhead,334887000,5.048050,15.073891
     12092023-04-07 00:21:01,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-allhead,665000000,5.000859,7.520089
     12102023-04-07 00:21:06,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-insfirst-inselem,316785000,5.145817,16.243878
     12112023-04-07 00:21:11,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-insfirst-inselem,307734000,5.028541,16.340544
     12122023-04-07 00:21:16,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-insfirst-remelem,574390000,5.000948,8.706537
     12132023-04-07 00:21:21,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-insfirst-allhead,1022000000,5.024777,4.916612
     12142023-04-07 00:21:26,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-inslast-allhead,493490000,5.064331,10.262277
     12152023-04-07 00:21:31,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-inslast-inselem,224000000,5.122860,22.869911
     12162023-04-07 00:21:36,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-inslast-allhead,710000000,5.003407,7.047052
     12172023-04-07 00:21:41,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-inslast-allhead,1078000000,5.014066,4.651267
     12182023-04-07 00:21:46,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-inslast-allhead,224000000,5.121987,22.866013
     12192023-04-07 00:21:51,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-insfirst-remelem,590570000,5.012351,8.487311
     12202023-04-07 00:21:56,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-inslast-remelem,177500000,5.128494,28.892924
     12212023-04-07 00:22:02,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-inselem,184600000,5.024489,27.218250
     12222023-04-07 00:22:07,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-insfirst-allhead,788100000,5.040492,6.395752
     12232023-04-07 00:22:12,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-inslast-allhead,461130000,5.072015,10.999100
     12242023-04-07 00:22:17,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-inslast-allhead,184600000,5.131083,27.795683
     12252023-04-07 00:22:22,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-inselem,166568300,5.142531,30.873407
     12262023-04-07 00:22:27,4,5 100 72421 -1 4  ,./perfexp--lq-list--stack-insfirst-allhead,166568300,5.044477,30.284736
     12272023-04-07 00:22:32,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-inslast-inselem,159326200,5.141698,32.271516
     12282023-04-07 00:22:37,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-insfirst-allhead,325836000,5.094147,15.634083
     12292023-04-07 00:22:42,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-inslast-inselem,477310000,5.069685,10.621368
     12302023-04-07 00:22:47,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-insfirst-inselem,130357800,5.145580,39.472743
     12312023-04-07 00:22:53,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-inselem,184600000,5.108413,27.672876
     12322023-04-07 00:22:58,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-inslast-remelem,318652400,5.036010,15.804086
     12332023-04-07 00:23:03,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-insfirst-allhead,461130000,5.085039,11.027344
     12342023-04-07 00:23:08,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-remelem,184600000,5.172400,28.019502
     12352023-04-07 00:23:13,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-insfirst-remelem,674500000,5.047846,7.483834
     12362023-04-07 00:23:18,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-insfirst-remelem,1309000000,5.005255,3.823724
     12372023-04-07 00:23:23,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-inslast-inselem,658000000,5.016826,7.624356
     12382023-04-07 00:23:28,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-inslast-remelem,515907000,5.025500,9.741097
     12392023-04-07 00:23:33,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-allhead,231000000,5.117156,22.152190
     12402023-04-07 00:23:38,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-inslast-allhead,509670000,5.046288,9.901089
     12412023-04-07 00:23:43,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-insfirst-inselem,166568300,5.221492,31.347453
     12422023-04-07 00:23:49,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-insfirst-remelem,296926100,5.106445,17.197697
     12432023-04-07 00:23:54,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-insfirst-remelem,333136600,5.079056,15.246166
     12442023-04-07 00:23:59,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-inslast-inselem,184600000,5.131130,27.795937
     12452023-04-07 00:24:04,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-inslast-inselem,880400000,5.012434,5.693360
     12462023-04-07 00:24:09,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-inslast-inselem,325836000,5.094942,15.636523
     12472023-04-07 00:24:14,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-inslast-allhead,352989000,5.061654,14.339410
     12482023-04-07 00:24:19,5,5 100000 71 -1 5  ,./perfexp--lq-list--stack-insfirst-inselem,731300000,5.012975,6.854882
     12492023-04-07 00:24:24,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-insfirst-allhead,325836000,5.139636,15.773690
     12502023-04-07 00:24:30,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-allhead,665000000,5.024825,7.556128
     12512023-04-07 00:24:35,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-inslast-allhead,334887000,5.006794,14.950697
     12522023-04-07 00:24:40,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-allhead,334887000,5.056826,15.100096
     12532023-04-07 00:24:45,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-inslast-allhead,352989000,5.047526,14.299386
     12542023-04-07 00:24:50,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-inslast-remelem,903000000,5.002012,5.539327
     12552023-04-07 00:24:55,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-insfirst-remelem,894600000,5.017897,5.609096
     12562023-04-07 00:25:00,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-inselem,546700000,5.050560,9.238266
     12572023-04-07 00:25:05,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-remelem,231000000,5.084063,22.008931
     12582023-04-07 00:25:10,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-inslast-inselem,137599900,5.086801,36.968057
     12592023-04-07 00:25:15,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-insfirst-remelem,720010000,5.029074,6.984728
     12602023-04-07 00:25:20,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-inslast-remelem,534009000,5.024933,9.409828
     12612023-04-07 00:25:25,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-allhead,159326200,5.104904,32.040581
     12622023-04-07 00:25:30,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-inslast-inselem,444950000,5.013109,11.266679
     12632023-04-07 00:25:35,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-inslast-remelem,177500000,5.116110,28.823155
     12642023-04-07 00:25:41,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-inselem,477310000,5.017041,10.511075
     12652023-04-07 00:25:46,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-insfirst-allhead,130357800,5.060870,38.822917
     12662023-04-07 00:25:51,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-insfirst-inselem,307734000,5.017423,16.304416
     12672023-04-07 00:25:56,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-inslast-remelem,289684000,5.096670,17.593895
     12682023-04-07 00:26:01,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-insfirst-inselem,581000000,5.003206,8.611370
     12692023-04-07 00:26:06,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-inslast-remelem,1015300000,5.026273,4.950530
     12702023-04-07 00:26:11,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-insfirst-allhead,159326200,5.149416,32.319957
     12712023-04-07 00:26:16,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-inslast-inselem,316785000,5.019917,15.846448
     12722023-04-07 00:26:21,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-inslast-remelem,687650000,5.023642,7.305522
     12732023-04-07 00:26:26,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-insfirst-allhead,788100000,5.021043,6.371073
     12742023-04-07 00:26:31,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-inslast-remelem,1320600000,5.018016,3.799800
     12752023-04-07 00:26:36,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-inslast-remelem,667400000,5.007560,7.503087
  • driver/cfa.cc

    ra50fdfb r6e1e2d0  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb 14 22:46:38 2023
    13 // Update Count     : 470
     12// Last Modified On : Mon Apr 10 21:16:00 2023
     13// Update Count     : 476
    1414//
    1515
     
    4444        static int flags = 0;
    4545
     46    // This allocation 'leaks' memory from the program to the execution
     47    // environment, as putenv does not manage the storage of the string used
     48    // as an environment variable. This leak is necessary to ensure the
     49    // underlying C string is allocated long enough.
    4650        if ( putenv( (char *)( *new string( string( __CFA_FLAGPREFIX__ + to_string( flags++ ) + "__=" ) + arg ) ).c_str() ) ) {
    4751                cerr << argv[0] << " error, cannot set environment variable." << endl;
     
    198202                                } // if
    199203                        } else if ( arg == "-CFA" ) {
    200                                 CFA_flag = true;                                                // strip the -CFA flag
     204                                CFA_flag = true;                                                // strip -CFA flag
    201205                                link = false;
    202206                                args[nargs++] = "-fsyntax-only";                // stop after stage 2
    203207                        } else if ( arg == "-debug" ) {
    204                                 debug = true;                                                   // strip the debug flag
     208                                debug = true;                                                   // strip debug flag
    205209                        } else if ( arg == "-nodebug" ) {
    206                                 debug = false;                                                  // strip the nodebug flag
     210                                debug = false;                                                  // strip nodebug flag
    207211                        } else if ( arg == "-quiet" ) {
    208                                 quiet = true;                                                   // strip the quiet flag
     212                                quiet = true;                                                   // strip quiet flag
    209213                        } else if ( arg == "-noquiet" ) {
    210                                 quiet = false;                                                  // strip the noquiet flag
     214                                quiet = false;                                                  // strip noquiet flag
     215                        } else if ( arg == "-invariant" ) {
     216                                Putenv( argv, "-" + arg );
     217                        } else if ( arg == "--invariant" ) {
     218                                Putenv( argv, arg );
    211219                        } else if ( arg == "-no-include-stdhdr" ) {
    212                                 noincstd_flag = true;                                   // strip the no-include-stdhdr flag
     220                                noincstd_flag = true;                                   // strip no-include-stdhdr flag
    213221                        } else if ( arg == "-nolib" ) {
    214                                 nolib = true;                                                   // strip the nolib flag
     222                                nolib = true;                                                   // strip nolib flag
    215223                        } else if ( arg == "-help" ) {
    216                                 help = true;                                                    // strip the help flag
     224                                help = true;                                                    // strip help flag
    217225                        } else if ( arg == "-nohelp" ) {
    218                                 help = false;                                                   // strip the nohelp flag
     226                                help = false;                                                   // strip nohelp flag
    219227                        } else if ( arg == "-cfalib") {
    220228                                compiling_libs = true;
     
    274282                                } // if
    275283                        } else if ( prefix( arg, "-B" ) ) {
    276                                 bprefix = arg.substr(2);                                // strip the -B flag
     284                                bprefix = arg.substr(2);                                // strip -B flag
    277285                        } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) {
    278286                                args[nargs++] = argv[i];                                // pass flag along
  • src/AST/Attribute.hpp

    ra50fdfb r6e1e2d0  
    2727class Expr;
    2828
     29/// An entry in an attribute list: `__attribute__(( ... ))`
    2930class Attribute final : public Node {
    3031public:
  • src/AST/Convert.cpp

    ra50fdfb r6e1e2d0  
    559559                auto stmt = new SuspendStmt();
    560560                stmt->then   = get<CompoundStmt>().accept1( node->then   );
    561                 switch(node->type) {
     561                switch (node->kind) {
    562562                        case ast::SuspendStmt::None     : stmt->type = SuspendStmt::None     ; break;
    563563                        case ast::SuspendStmt::Coroutine: stmt->type = SuspendStmt::Coroutine; break;
     
    16951695                        GET_ACCEPT_V(attributes, Attribute),
    16961696                        { old->get_funcSpec().val },
    1697                         old->type->isVarArgs
     1697                        (old->type->isVarArgs) ? ast::VariableArgs : ast::FixedArgs
    16981698                };
    16991699
     
    20012001                        GET_ACCEPT_1(else_, Stmt),
    20022002                        GET_ACCEPT_V(initialization, Stmt),
    2003                         old->isDoWhile,
     2003                        (old->isDoWhile) ? ast::DoWhile : ast::While,
    20042004                        GET_LABELS_V(old->labels)
    20052005                );
     
    21432143        virtual void visit( const SuspendStmt * old ) override final {
    21442144                if ( inCache( old ) ) return;
    2145                 ast::SuspendStmt::Type type;
     2145                ast::SuspendStmt::Kind type;
    21462146                switch (old->type) {
    21472147                        case SuspendStmt::Coroutine: type = ast::SuspendStmt::Coroutine; break;
  • src/AST/Decl.cpp

    ra50fdfb r6e1e2d0  
    5757        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    5858        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
    59         std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
     59        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs )
    6060: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ),
    6161        type_params(std::move(forall)), assertions(),
    6262        params(std::move(params)), returns(std::move(returns)), stmts( stmts ) {
    63         FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(isVarArgs));
     63        FunctionType * ftype = new FunctionType( isVarArgs );
    6464        for (auto & param : this->params) {
    6565                ftype->params.emplace_back(param->get_type());
     
    8181        std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    8282        CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,
    83         std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)
     83        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, ArgumentFlag isVarArgs )
    8484: DeclWithType( location, name, storage, linkage, std::move(attrs), fs ),
    8585                type_params( std::move( forall) ), assertions( std::move( assertions ) ),
    8686                params( std::move(params) ), returns( std::move(returns) ),
    8787                type( nullptr ), stmts( stmts ) {
    88         FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );
     88        FunctionType * type = new FunctionType( isVarArgs );
    8989        for ( auto & param : this->params ) {
    9090                type->params.emplace_back( param->get_type() );
  • src/AST/Decl.hpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:44:00 2022
    13 // Update Count     : 34
     12// Last Modified On : Wed Apr  5 10:42:00 2023
     13// Update Count     : 35
    1414//
    1515
     
    122122};
    123123
     124/// Function variable arguments flag
     125enum ArgumentFlag { FixedArgs, VariableArgs };
     126
    124127/// Object declaration `int foo()`
    125128class FunctionDecl : public DeclWithType {
     
    144147                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    145148                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    146                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
     149                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs );
    147150
    148151        FunctionDecl( const CodeLocation & location, const std::string & name,
     
    150153                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    151154                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    152                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
     155                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs );
    153156
    154157        const Type * get_type() const override;
     
    313316public:
    314317        bool isTyped; // isTyped indicated if the enum has a declaration like:
    315         // enum (type_optional) Name {...} 
     318        // enum (type_optional) Name {...}
    316319        ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum
    317320        enum class EnumHiding { Visible, Hide } hide;
     
    371374};
    372375
     376/// Assembly declaration: `asm ... ( "..." : ... )`
    373377class AsmDecl : public Decl {
    374378public:
  • src/AST/Expr.hpp

    ra50fdfb r6e1e2d0  
    254254};
    255255
     256/// A name qualified by a namespace or type.
    256257class QualifiedNameExpr final : public Expr {
    257258public:
     
    259260        std::string name;
    260261
    261         QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 
     262        QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n )
    262263        : Expr( loc ), type_decl( d ), name( n ) {}
    263264
     
    621622};
    622623
     624/// A name that refers to a generic dimension parameter.
    623625class DimensionExpr final : public Expr {
    624626public:
     
    910912};
    911913
    912 
    913914}
    914915
  • src/AST/Init.hpp

    ra50fdfb r6e1e2d0  
    117117        ptr<Init> init;
    118118
    119         ConstructorInit( 
     119        ConstructorInit(
    120120                const CodeLocation & loc, const Stmt * ctor, const Stmt * dtor, const Init * init )
    121121        : Init( loc, MaybeConstruct ), ctor( ctor ), dtor( dtor ), init( init ) {}
  • src/AST/Inspect.cpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Fri Jun 24 13:16:31 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Oct  3 11:04:00 2022
    13 // Update Count     : 3
     12// Last Modified On : Fri Apr 14 15:09:00 2023
     13// Update Count     : 4
    1414//
    1515
     
    168168}
    169169
     170bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
     171        return obj && obj->name.empty() && obj->bitfieldWidth;
     172}
     173
    170174} // namespace ast
  • src/AST/Inspect.hpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Fri Jun 24 13:16:31 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Sep 22 13:44:00 2022
    13 // Update Count     : 2
     12// Last Modified On : Fri Apr 14 15:09:00 2023
     13// Update Count     : 3
    1414//
    1515
     
    3838const ApplicationExpr * isIntrinsicCallExpr( const Expr * expr );
    3939
     40/// Returns true if obj's name is the empty string and it has a bitfield width.
     41bool isUnnamedBitfield( const ObjectDecl * obj );
     42
    4043}
  • src/AST/Pass.impl.hpp

    ra50fdfb r6e1e2d0  
    20752075        if ( __visit_children() ) {
    20762076                maybe_accept( node, &TupleType::types );
    2077                 maybe_accept( node, &TupleType::members );
    20782077        }
    20792078
  • src/AST/Print.cpp

    ra50fdfb r6e1e2d0  
    766766        virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {
    767767                os << "Suspend Statement";
    768                 switch (node->type) {
    769                         case ast::SuspendStmt::None     : os << " with implicit target"; break;
    770                         case ast::SuspendStmt::Generator: os << " for generator"; break;
    771                         case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
     768                switch (node->kind) {
     769                case ast::SuspendStmt::None     : os << " with implicit target"; break;
     770                case ast::SuspendStmt::Generator: os << " for generator"; break;
     771                case ast::SuspendStmt::Coroutine: os << " for coroutine"; break;
    772772                }
    773773                os << endl;
  • src/AST/Stmt.hpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Wed May  8 13:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr 20 14:34:00 2022
    13 // Update Count     : 36
     12// Last Modified On : Wed Apr  5 10:34:00 2023
     13// Update Count     : 37
    1414//
    1515
     
    205205};
    206206
     207// A while loop or a do-while loop:
     208enum WhileDoKind { While, DoWhile };
     209
    207210// While loop: while (...) ... else ... or do ... while (...) else ...;
    208211class WhileDoStmt final : public Stmt {
     
    212215        ptr<Stmt> else_;
    213216        std::vector<ptr<Stmt>> inits;
    214         bool isDoWhile;
     217        WhileDoKind isDoWhile;
    215218
    216219        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body,
    217                                  const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
     220                                 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
    218221                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    219222
    220223        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, const Stmt * else_,
    221                                  const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
     224                                 const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
    222225                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    223226
     
    364367  public:
    365368        ptr<CompoundStmt> then;
    366         enum Type { None, Coroutine, Generator } type = None;
    367 
    368         SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Type type, const std::vector<Label> && labels = {} )
    369                 : Stmt(loc, std::move(labels)), then(then), type(type) {}
     369        enum Kind { None, Coroutine, Generator } kind = None;
     370
     371        SuspendStmt( const CodeLocation & loc, const CompoundStmt * then, Kind kind, const std::vector<Label> && labels = {} )
     372                : Stmt(loc, std::move(labels)), then(then), kind(kind) {}
    370373
    371374        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    424427};
    425428
     429// Clause in a waitfor statement: waitfor (..., ...) ...
    426430class WaitForClause final : public WhenClause {
    427431  public:
     
    527531        MUTATE_FRIEND
    528532};
     533
    529534} // namespace ast
    530535
  • src/AST/SymbolTable.cpp

    ra50fdfb r6e1e2d0  
    260260void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) {
    261261        // default handling of conflicts is to raise an error
    262         addId( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
     262        addIdCommon( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
    263263}
    264264
    265265void SymbolTable::addDeletedId( const DeclWithType * decl, const Decl * deleter ) {
    266266        // default handling of conflicts is to raise an error
    267         addId( decl, OnConflict::error(), nullptr, deleter );
     267        addIdCommon( decl, OnConflict::error(), nullptr, deleter );
    268268}
    269269
     
    677677}
    678678
    679 void SymbolTable::addId(
    680                 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    681                 const Decl * deleter ) {
     679void SymbolTable::addIdCommon(
     680                const DeclWithType * decl, SymbolTable::OnConflict handleConflicts,
     681                const Expr * baseExpr, const Decl * deleter ) {
    682682        SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
    683683        if (kind == NUMBER_OF_KINDS) { // not a special decl
    684                 addId(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
     684                addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
    685685        }
    686686        else {
     
    695695                        assertf(false, "special decl with non-function type");
    696696                }
    697                 addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
    698         }
    699 }
    700 
    701 void SymbolTable::addId(
    702                 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
    703                 const Decl * deleter ) {
     697                addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
     698        }
     699}
     700
     701void SymbolTable::addIdToTable(
     702                const DeclWithType * decl, const std::string & lookupKey,
     703                IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts,
     704                const Expr * baseExpr, const Decl * deleter ) {
    704705        ++*stats().add_calls;
    705706        const std::string &name = decl->name;
     
    778779void SymbolTable::addMembers(
    779780                const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict handleConflicts ) {
    780         for ( const Decl * decl : aggr->members ) {
    781                 if ( auto dwt = dynamic_cast< const DeclWithType * >( decl ) ) {
    782                         addId( dwt, handleConflicts, expr );
    783                         if ( dwt->name == "" ) {
    784                                 const Type * t = dwt->get_type()->stripReferences();
    785                                 if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
    786                                         if ( ! dynamic_cast<const StructInstType *>(rty)
    787                                                 && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
    788                                         ResolvExpr::Cost cost = ResolvExpr::Cost::zero;
    789                                         ast::ptr<ast::TypeSubstitution> tmp = expr->env;
    790                                         expr = mutate_field(expr, &Expr::env, nullptr);
    791                                         const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );
    792                                         base = mutate_field(base, &Expr::env, tmp);
    793 
    794                                         addMembers(
    795                                                 rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts );
    796                                 }
    797                         }
     781        for ( const ptr<Decl> & decl : aggr->members ) {
     782                auto dwt = decl.as<DeclWithType>();
     783                if ( nullptr == dwt ) continue;
     784                addIdCommon( dwt, handleConflicts, expr );
     785                // Inline through unnamed struct/union members.
     786                if ( "" != dwt->name ) continue;
     787                const Type * t = dwt->get_type()->stripReferences();
     788                if ( auto rty = dynamic_cast<const BaseInstType *>( t ) ) {
     789                        if ( ! dynamic_cast<const StructInstType *>(rty)
     790                                && ! dynamic_cast<const UnionInstType *>(rty) ) continue;
     791                        ResolvExpr::Cost cost = ResolvExpr::Cost::zero;
     792                        ast::ptr<ast::TypeSubstitution> tmp = expr->env;
     793                        expr = mutate_field(expr, &Expr::env, nullptr);
     794                        const Expr * base = ResolvExpr::referenceToRvalueConversion( expr, cost );
     795                        base = mutate_field(base, &Expr::env, tmp);
     796
     797                        addMembers(
     798                                rty->aggr(), new MemberExpr{ base->location, dwt, base }, handleConflicts );
    798799                }
    799800        }
  • src/AST/SymbolTable.hpp

    ra50fdfb r6e1e2d0  
    192192
    193193        /// common code for addId, addDeletedId, etc.
    194         void addId(
    195                 const DeclWithType * decl, OnConflict handleConflicts, const Expr * baseExpr = nullptr,
    196                 const Decl * deleter = nullptr );
     194        void addIdCommon(
     195                const DeclWithType * decl, OnConflict handleConflicts,
     196                const Expr * baseExpr = nullptr, const Decl * deleter = nullptr );
    197197
    198198        /// common code for addId when special decls are placed into separate tables
    199         void addId(
    200                 const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & idTable, OnConflict handleConflicts,
     199        void addIdToTable(
     200                const DeclWithType * decl, const std::string & lookupKey,
     201                IdTable::Ptr & idTable, OnConflict handleConflicts,
    201202                const Expr * baseExpr = nullptr, const Decl * deleter = nullptr);
    202        
     203
    203204        /// adds all of the members of the Aggregate (addWith helper)
    204205        void addMembers( const AggregateDecl * aggr, const Expr * expr, OnConflict handleConflicts );
  • src/AST/Type.cpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Mon May 13 15:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:49:00 2022
    13 // Update Count     : 6
     12// Last Modified On : Thu Apr  6 15:59:00 2023
     13// Update Count     : 7
    1414//
    1515
     
    199199
    200200TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    201 : Type( q ), types( std::move(ts) ), members() {
    202         // This constructor is awkward. `TupleType` needs to contain objects so that members can be
    203         // named, but members without initializer nodes end up getting constructors, which breaks
    204         // things. This happens because the object decls have to be visited so that their types are
    205         // kept in sync with the types listed here. Ultimately, the types listed here should perhaps
    206         // be eliminated and replaced with a list-view over members. The temporary solution is to
    207         // make a `ListInit` with `maybeConstructed = false`, so when the object is visited it is not
    208         // constructed. Potential better solutions include:
    209         //   a) Separate `TupleType` from its declarations, into `TupleDecl` and `Tuple{Inst?}Type`,
    210         //      similar to the aggregate types.
    211         //   b) Separate initializer nodes better, e.g. add a `MaybeConstructed` node that is replaced
    212         //      by `genInit`, rather than the current boolean flag.
    213         members.reserve( types.size() );
    214         for ( const Type * ty : types ) {
    215                 members.emplace_back( new ObjectDecl{
    216                         CodeLocation(), "", ty, new ListInit( CodeLocation(), {}, {}, NoConstruct ),
    217                         Storage::Classes{}, Linkage::Cforall } );
    218         }
    219 }
     201: Type( q ), types( std::move(ts) ) {}
    220202
    221203bool isUnboundType(const Type * type) {
  • src/AST/Type.hpp

    ra50fdfb r6e1e2d0  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Nov 24  9:47:00 2022
    13 // Update Count     : 8
     12// Last Modified On : Thu Apr  6 15:58:00 2023
     13// Update Count     : 9
    1414//
    1515
     
    265265};
    266266
    267 /// Function variable arguments flag
    268 enum ArgumentFlag { FixedArgs, VariableArgs };
    269 
    270267/// Type of a function `[R1, R2](*)(P1, P2, P3)`
    271268class FunctionType final : public Type {
     
    460457public:
    461458        std::vector<ptr<Type>> types;
    462         std::vector<ptr<Decl>> members;
    463459
    464460        TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q = {} );
  • src/Common/CodeLocationTools.cpp

    ra50fdfb r6e1e2d0  
    210210
    211211struct LeafKindVisitor : public ast::Visitor {
    212         LeafKind kind;
     212        LeafKind result;
    213213
    214214#define VISIT(node_type, return_type) \
    215215        const ast::return_type * visit( const ast::node_type * ) final { \
    216                 kind = LeafKind::node_type; \
     216                result = LeafKind::node_type; \
    217217                return nullptr; \
    218218        }
     
    224224
    225225LeafKind get_leaf_kind( ast::Node const * node ) {
    226         LeafKindVisitor visitor;
    227         node->accept( visitor );
    228         return visitor.kind;
     226        return ast::Pass<LeafKindVisitor>::read( node );
    229227}
    230228
  • src/Common/Iterate.hpp

    ra50fdfb r6e1e2d0  
    2020#include <iterator>
    2121
    22 // it's nice to actually be able to increment iterators by an arbitrary amount
     22// Returns an iterator that is it advanced n times.
    2323template< class InputIt, class Distance >
    2424InputIt operator+( InputIt it, Distance n ) {
     
    5050
    5151// -----------------------------------------------------------------------------
     52// Helper struct and function to support
     53// for ( val_and_index : enumerate( container ) ) {}
     54// which iterates through the container and tracks the index as well.
     55
    5256template< typename T >
    5357struct enumerate_t {
     
    109113
    110114// -----------------------------------------------------------------------------
     115// Helper function to transform one iterable container into another.
     116
    111117template< typename OutType, typename Range, typename Functor >
    112118OutType map_range( const Range& range, Functor&& functor ) {
     
    206212// Helper struct and function to support
    207213// for ( val : lazy_map( container1, f ) ) {}
    208 // syntax to have a for each that iterates a container, mapping each element by applying f
     214// syntax to have a for each that iterates a container,
     215// mapping each element by applying f.
     216
    209217template< typename T, typename Func >
    210218struct lambda_iterate_t {
  • src/CompilationState.cc

    ra50fdfb r6e1e2d0  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon Ju1 30 10:47:01 2018
    11 // Last Modified By : Henry Xue
    12 // Last Modified On : Tue Jul 20 04:27:35 2021
    13 // Update Count     : 5
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 10 19:12:50 2023
     13// Update Count     : 6
    1414//
    1515
     
    2727        expraltp = false,
    2828        genericsp = false,
     29        invariant = false,
    2930        libcfap = false,
    3031        nopreludep = false,
  • src/CompilationState.h

    ra50fdfb r6e1e2d0  
    99// Author           : Rob Schluntz
    1010// Created On       : Mon Ju1 30 10:47:01 2018
    11 // Last Modified By : Henry Xue
    12 // Last Modified On : Tue Jul 20 04:27:35 2021
    13 // Update Count     : 5
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 10 19:12:53 2023
     13// Update Count     : 6
    1414//
    1515
     
    2626        expraltp,
    2727        genericsp,
     28        invariant,
    2829        libcfap,
    2930        nopreludep,
  • src/Concurrency/KeywordsNew.cpp

    ra50fdfb r6e1e2d0  
    779779
    780780const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) {
    781         switch ( stmt->type ) {
     781        switch ( stmt->kind ) {
    782782        case ast::SuspendStmt::None:
    783783                // Use the context to determain the implicit target.
  • src/InitTweak/FixInitNew.cpp

    ra50fdfb r6e1e2d0  
    1414#include <utility>                     // for pair
    1515
     16#include "AST/DeclReplacer.hpp"
     17#include "AST/Expr.hpp"
    1618#include "AST/Inspect.hpp"             // for getFunction, getPointerBase, g...
     19#include "AST/Node.hpp"
     20#include "AST/Pass.hpp"
     21#include "AST/Print.hpp"
     22#include "AST/SymbolTable.hpp"
     23#include "AST/Type.hpp"
    1724#include "CodeGen/GenType.h"           // for genPrettyType
    1825#include "CodeGen/OperatorTable.h"
    19 #include "Common/CodeLocationTools.hpp"
    2026#include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
    2127#include "Common/SemanticError.h"      // for SemanticError
     
    2834#include "ResolvExpr/Unify.h"          // for typesCompatible
    2935#include "SymTab/Autogen.h"            // for genImplicitCall
     36#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    3037#include "SymTab/Indexer.h"            // for Indexer
    3138#include "SymTab/Mangler.h"            // for Mangler
     
    4552#include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    4653
    47 #include "AST/Expr.hpp"
    48 #include "AST/Node.hpp"
    49 #include "AST/Pass.hpp"
    50 #include "AST/Print.hpp"
    51 #include "AST/SymbolTable.hpp"
    52 #include "AST/Type.hpp"
    53 #include "AST/DeclReplacer.hpp"
    54 
    5554extern bool ctordtorp; // print all debug
    5655extern bool ctorp; // print ctor debug
     
    6362namespace InitTweak {
    6463namespace {
     64
     65        // Shallow copy the pointer list for return.
     66        std::vector<ast::ptr<ast::TypeDecl>> getGenericParams( const ast::Type * t ) {
     67                if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) {
     68                        return inst->base->params;
     69                }
     70                if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
     71                        return inst->base->params;
     72                }
     73                return {};
     74        }
     75
     76        /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).
     77        ast::FunctionDecl * genDefaultFunc(
     78                        const CodeLocation loc,
     79                        const std::string fname,
     80                        const ast::Type * paramType,
     81                        bool maybePolymorphic = true) {
     82                std::vector<ast::ptr<ast::TypeDecl>> typeParams;
     83                if ( maybePolymorphic ) typeParams = getGenericParams( paramType );
     84                auto dstParam = new ast::ObjectDecl( loc,
     85                        "_dst",
     86                        new ast::ReferenceType( paramType ),
     87                        nullptr,
     88                        {},
     89                        ast::Linkage::Cforall
     90                );
     91                return new ast::FunctionDecl( loc,
     92                        fname,
     93                        std::move(typeParams),
     94                        {dstParam},
     95                        {},
     96                        new ast::CompoundStmt(loc),
     97                        {},
     98                        ast::Linkage::Cforall
     99                );
     100        }
     101
    65102        struct SelfAssignChecker {
    66103                void previsit( const ast::ApplicationExpr * appExpr );
     
    121158                void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    122159
    123           protected:
     160        protected:
    124161                ObjectSet curVars;
    125162        };
     
    202239
    203240                SemanticErrorException errors;
    204           private:
     241        private:
    205242                template< typename... Params >
    206243                void emit( CodeLocation, const Params &... params );
     
    288325                static UniqueName dtorNamer( "__cleanup_dtor" );
    289326                std::string name = dtorNamer.newName();
    290                 ast::FunctionDecl * dtorFunc = SymTab::genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
     327                ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
    291328                stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) );
    292329
     
    10801117        void InsertDtors::previsit( const ast::BranchStmt * stmt ) {
    10811118                switch( stmt->kind ) {
    1082                   case ast::BranchStmt::Continue:
    1083                   case ast::BranchStmt::Break:
     1119                case ast::BranchStmt::Continue:
     1120                case ast::BranchStmt::Break:
    10841121                        // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should
    10851122                        // always be empty), but it serves as a small sanity check.
    1086                   case ast::BranchStmt::Goto:
     1123                case ast::BranchStmt::Goto:
    10871124                        handleGoto( stmt );
    10881125                        break;
    1089                   default:
     1126                default:
    10901127                        assert( false );
    10911128                } // switch
     
    13121349                // xxx - functions returning ast::ptr seems wrong...
    13131350                auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } );
    1314                 // Fix CodeLocation (at least until resolver is fixed).
    1315                 auto fix = localFillCodeLocations( untypedExpr->location, res.release() );
    1316                 return strict_dynamic_cast<const ast::Expr *>( fix );
     1351                return res.release();
    13171352        }
    13181353
  • src/InitTweak/GenInit.cc

    ra50fdfb r6e1e2d0  
    3939#include "ResolvExpr/Resolver.h"
    4040#include "SymTab/Autogen.h"            // for genImplicitCall
     41#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4142#include "SymTab/Mangler.h"            // for Mangler
    4243#include "SynTree/LinkageSpec.h"       // for isOverridable, C
  • src/Parser/DeclarationNode.cc

    ra50fdfb r6e1e2d0  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr  4 10:28:00 2023
    13 // Update Count     : 1392
     12// Last Modified On : Thr Apr 20 11:46:00 2023
     13// Update Count     : 1393
    1414//
     15
     16#include "DeclarationNode.h"
    1517
    1618#include <cassert>                 // for assert, assertf, strict_dynamic_cast
     
    3436#include "Common/UniqueName.h"     // for UniqueName
    3537#include "Common/utility.h"        // for maybeClone
    36 #include "Parser/ParseNode.h"      // for DeclarationNode, ExpressionNode
     38#include "Parser/ExpressionNode.h" // for ExpressionNode
     39#include "Parser/InitializerNode.h"// for InitializerNode
     40#include "Parser/StatementNode.h"  // for StatementNode
    3741#include "TypeData.h"              // for TypeData, TypeData::Aggregate_t
    3842#include "TypedefTable.h"          // for TypedefTable
     
    9991003}
    10001004
    1001 void buildList( const DeclarationNode * firstNode,
     1005// If a typedef wraps an anonymous declaration, name the inner declaration
     1006// so it has a consistent name across translation units.
     1007static void nameTypedefedDecl(
     1008                DeclarationNode * innerDecl,
     1009                const DeclarationNode * outerDecl ) {
     1010        TypeData * outer = outerDecl->type;
     1011        assert( outer );
     1012        // First make sure this is a typedef:
     1013        if ( outer->kind != TypeData::Symbolic || !outer->symbolic.isTypedef ) {
     1014                return;
     1015        }
     1016        TypeData * inner = innerDecl->type;
     1017        assert( inner );
     1018        // Always clear any CVs associated with the aggregate:
     1019        inner->qualifiers.reset();
     1020        // Handle anonymous aggregates: typedef struct { int i; } foo
     1021        if ( inner->kind == TypeData::Aggregate && inner->aggregate.anon ) {
     1022                delete inner->aggregate.name;
     1023                inner->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
     1024                inner->aggregate.anon = false;
     1025                assert( outer->base );
     1026                delete outer->base->aggInst.aggregate->aggregate.name;
     1027                outer->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *outerDecl->name );
     1028                outer->base->aggInst.aggregate->aggregate.anon = false;
     1029                outer->base->aggInst.aggregate->qualifiers.reset();
     1030        // Handle anonymous enumeration: typedef enum { A, B, C } foo
     1031        } else if ( inner->kind == TypeData::Enum && inner->enumeration.anon ) {
     1032                delete inner->enumeration.name;
     1033                inner->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
     1034                inner->enumeration.anon = false;
     1035                assert( outer->base );
     1036                delete outer->base->aggInst.aggregate->enumeration.name;
     1037                outer->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *outerDecl->name );
     1038                outer->base->aggInst.aggregate->enumeration.anon = false;
     1039                // No qualifiers.reset() here.
     1040        }
     1041}
     1042
     1043// This code handles a special issue with the attribute transparent_union.
     1044//
     1045//    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
     1046//
     1047// Here the attribute aligned goes with the typedef_name, so variables declared of this type are
     1048// aligned.  However, the attribute transparent_union must be moved from the typedef_name to
     1049// alias union U.  Currently, this is the only know attribute that must be moved from typedef to
     1050// alias.
     1051static void moveUnionAttribute( ast::Decl * decl, ast::UnionDecl * unionDecl ) {
     1052        if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) {
     1053                // Is the typedef alias a union aggregate?
     1054                if ( nullptr == unionDecl ) return;
     1055
     1056                // If typedef is an alias for a union, then its alias type was hoisted above and remembered.
     1057                if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) {
     1058                        auto instType = ast::mutate( unionInstType );
     1059                        // Remove all transparent_union attributes from typedef and move to alias union.
     1060                        for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) {
     1061                                assert( *attr );
     1062                                if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
     1063                                        unionDecl->attributes.emplace_back( attr->release() );
     1064                                        attr = instType->attributes.erase( attr );
     1065                                } else {
     1066                                        attr++;
     1067                                }
     1068                        }
     1069                        typedefDecl->base = instType;
     1070                }
     1071        }
     1072}
     1073
     1074// Get the non-anonymous name of the instance type of the declaration,
     1075// if one exists.
     1076static const std::string * getInstTypeOfName( ast::Decl * decl ) {
     1077        if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
     1078                if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) {
     1079                        if ( aggr->name.find("anonymous") == std::string::npos ) {
     1080                                return &aggr->name;
     1081                        }
     1082                }
     1083        }
     1084        return nullptr;
     1085}
     1086
     1087void buildList( DeclarationNode * firstNode,
    10021088                std::vector<ast::ptr<ast::Decl>> & outputList ) {
    10031089        SemanticErrorException errors;
    10041090        std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
    10051091
    1006         for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
     1092        for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
    10071093                try {
    1008                         bool extracted = false, anon = false;
    1009                         ast::AggregateDecl * unionDecl = nullptr;
     1094                        bool extracted_named = false;
     1095                        ast::UnionDecl * unionDecl = nullptr;
    10101096
    10111097                        if ( DeclarationNode * extr = cur->extractAggregate() ) {
    1012                                 // Handle the case where a SUE declaration is contained within an object or type declaration.
    1013 
    10141098                                assert( cur->type );
    1015                                 // Replace anonymous SUE name with typedef name to prevent anonymous naming problems across translation units.
    1016                                 if ( cur->type->kind == TypeData::Symbolic && cur->type->symbolic.isTypedef ) {
    1017                                         assert( extr->type );
    1018                                         // Handle anonymous aggregates: typedef struct { int i; } foo
    1019                                         extr->type->qualifiers.reset();         // clear any CVs associated with the aggregate
    1020                                         if ( extr->type->kind == TypeData::Aggregate && extr->type->aggregate.anon ) {
    1021                                                 delete extr->type->aggregate.name;
    1022                                                 extr->type->aggregate.name = new string( "__anonymous_" + *cur->name );
    1023                                                 extr->type->aggregate.anon = false;
    1024                                                 assert( cur->type->base );
    1025                                                 if ( cur->type->base ) {
    1026                                                         delete cur->type->base->aggInst.aggregate->aggregate.name;
    1027                                                         cur->type->base->aggInst.aggregate->aggregate.name = new string( "__anonymous_" + *cur->name );
    1028                                                         cur->type->base->aggInst.aggregate->aggregate.anon = false;
    1029                                                         cur->type->base->aggInst.aggregate->qualifiers.reset();
    1030                                                 } // if
    1031                                         } // if
    1032                                         // Handle anonymous enumeration: typedef enum { A, B, C } foo
    1033                                         if ( extr->type->kind == TypeData::Enum && extr->type->enumeration.anon ) {
    1034                                                 delete extr->type->enumeration.name;
    1035                                                 extr->type->enumeration.name = new string( "__anonymous_" + *cur->name );
    1036                                                 extr->type->enumeration.anon = false;
    1037                                                 assert( cur->type->base );
    1038                                                 if ( cur->type->base ) {
    1039                                                         delete cur->type->base->aggInst.aggregate->enumeration.name;
    1040                                                         cur->type->base->aggInst.aggregate->enumeration.name = new string( "__anonymous_" + *cur->name );
    1041                                                         cur->type->base->aggInst.aggregate->enumeration.anon = false;
    1042                                                 } // if
    1043                                         } // if
    1044                                 } // if
    1045 
    1046                                 ast::Decl * decl = extr->build();
    1047                                 if ( decl ) {
     1099                                nameTypedefedDecl( extr, cur );
     1100
     1101                                if ( ast::Decl * decl = extr->build() ) {
    10481102                                        // Remember the declaration if it is a union aggregate ?
    10491103                                        unionDecl = dynamic_cast<ast::UnionDecl *>( decl );
    10501104
    1051                                         decl->location = cur->location;
    10521105                                        *out++ = decl;
    10531106
    10541107                                        // need to remember the cases where a declaration contains an anonymous aggregate definition
    1055                                         extracted = true;
    10561108                                        assert( extr->type );
    10571109                                        if ( extr->type->kind == TypeData::Aggregate ) {
    10581110                                                // typedef struct { int A } B is the only case?
    1059                                                 anon = extr->type->aggregate.anon;
     1111                                                extracted_named = !extr->type->aggregate.anon;
    10601112                                        } else if ( extr->type->kind == TypeData::Enum ) {
    10611113                                                // typedef enum { A } B is the only case?
    1062                                                 anon = extr->type->enumeration.anon;
     1114                                                extracted_named = !extr->type->enumeration.anon;
     1115                                        } else {
     1116                                                extracted_named = true;
    10631117                                        }
    10641118                                } // if
     
    10661120                        } // if
    10671121
    1068                         ast::Decl * decl = cur->build();
    1069                         if ( decl ) {
    1070                                 if ( auto typedefDecl = dynamic_cast<ast::TypedefDecl *>( decl ) ) {
    1071                                         if ( unionDecl ) {                                      // is the typedef alias a union aggregate ?
    1072                                                 // This code handles a special issue with the attribute transparent_union.
    1073                                                 //
    1074                                                 //    typedef union U { int i; } typedef_name __attribute__(( aligned(16) )) __attribute__(( transparent_union ))
    1075                                                 //
    1076                                                 // Here the attribute aligned goes with the typedef_name, so variables declared of this type are
    1077                                                 // aligned.  However, the attribute transparent_union must be moved from the typedef_name to
    1078                                                 // alias union U.  Currently, this is the only know attribute that must be moved from typedef to
    1079                                                 // alias.
    1080 
    1081                                                 // If typedef is an alias for a union, then its alias type was hoisted above and remembered.
    1082                                                 if ( auto unionInstType = typedefDecl->base.as<ast::UnionInstType>() ) {
    1083                                                         auto instType = ast::mutate( unionInstType );
    1084                                                         // Remove all transparent_union attributes from typedef and move to alias union.
    1085                                                         for ( auto attr = instType->attributes.begin() ; attr != instType->attributes.end() ; ) { // forward order
    1086                                                                 assert( *attr );
    1087                                                                 if ( (*attr)->name == "transparent_union" || (*attr)->name == "__transparent_union__" ) {
    1088                                                                         unionDecl->attributes.emplace_back( attr->release() );
    1089                                                                         attr = instType->attributes.erase( attr );
    1090                                                                 } else {
    1091                                                                         attr++;
    1092                                                                 } // if
    1093                                                         } // for
    1094                                                         typedefDecl->base = instType;
    1095                                                 } // if
    1096                                         } // if
     1122                        if ( ast::Decl * decl = cur->build() ) {
     1123                                moveUnionAttribute( decl, unionDecl );
     1124
     1125                                if ( "" == decl->name && !cur->get_inLine() ) {
     1126                                        // Don't include anonymous declaration for named aggregates,
     1127                                        // but do include them for anonymous aggregates, e.g.:
     1128                                        // struct S {
     1129                                        //   struct T { int x; }; // no anonymous member
     1130                                        //   struct { int y; };   // anonymous member
     1131                                        //   struct T;            // anonymous member
     1132                                        // };
     1133                                        if ( extracted_named ) {
     1134                                                continue;
     1135                                        }
     1136
     1137                                        if ( auto name = getInstTypeOfName( decl ) ) {
     1138                                                // Temporary: warn about anonymous member declarations of named types, since
     1139                                                // this conflicts with the syntax for the forward declaration of an anonymous type.
     1140                                                SemanticWarning( cur->location, Warning::AggrForwardDecl, name->c_str() );
     1141                                        }
    10971142                                } // if
    1098 
    1099                                 // don't include anonymous declaration for named aggregates, but do include them for anonymous aggregates, e.g.:
    1100                                 // struct S {
    1101                                 //   struct T { int x; }; // no anonymous member
    1102                                 //   struct { int y; };   // anonymous member
    1103                                 //   struct T;            // anonymous member
    1104                                 // };
    1105                                 if ( ! (extracted && decl->name == "" && ! anon && ! cur->get_inLine()) ) {
    1106                                         if ( decl->name == "" ) {
    1107                                                 if ( auto dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
    1108                                                         if ( auto aggr = dynamic_cast<ast::BaseInstType const *>( dwt->get_type() ) ) {
    1109                                                                 if ( aggr->name.find("anonymous") == std::string::npos ) {
    1110                                                                         if ( ! cur->get_inLine() ) {
    1111                                                                                 // temporary: warn about anonymous member declarations of named types, since
    1112                                                                                 // this conflicts with the syntax for the forward declaration of an anonymous type
    1113                                                                                 SemanticWarning( cur->location, Warning::AggrForwardDecl, aggr->name.c_str() );
    1114                                                                         } // if
    1115                                                                 } // if
    1116                                                         } // if
    1117                                                 } // if
    1118                                         } // if
    1119                                         decl->location = cur->location;
    1120                                         *out++ = decl;
    1121                                 } // if
     1143                                *out++ = decl;
    11221144                        } // if
    1123                 } catch( SemanticErrorException & e ) {
     1145                } catch ( SemanticErrorException & e ) {
    11241146                        errors.append( e );
    11251147                } // try
     
    11321154
    11331155// currently only builds assertions, function parameters, and return values
    1134 void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
     1156void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
    11351157        SemanticErrorException errors;
    11361158        std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList );
    11371159
    1138         for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
     1160        for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) {
    11391161                try {
    11401162                        ast::Decl * decl = cur->build();
    1141                         assert( decl );
     1163                        assertf( decl, "buildList: build for ast::DeclWithType." );
    11421164                        if ( ast::DeclWithType * dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
    11431165                                dwt->location = cur->location;
     
    11681190                                );
    11691191                                *out++ = obj;
     1192                        } else {
     1193                                assertf( false, "buildList: Could not convert to ast::DeclWithType." );
    11701194                        } // if
    1171                 } catch( SemanticErrorException & e ) {
     1195                } catch ( SemanticErrorException & e ) {
    11721196                        errors.append( e );
    11731197                } // try
     
    11831207        SemanticErrorException errors;
    11841208        std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList );
    1185         const DeclarationNode * cur = firstNode;
    1186 
    1187         while ( cur ) {
     1209
     1210        for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
    11881211                try {
    11891212                        * out++ = cur->buildType();
    1190                 } catch( SemanticErrorException & e ) {
     1213                } catch ( SemanticErrorException & e ) {
    11911214                        errors.append( e );
    11921215                } // try
    1193                 cur = dynamic_cast< DeclarationNode * >( cur->get_next() );
    1194         } // while
     1216        } // for
    11951217
    11961218        if ( ! errors.isEmpty() ) {
  • src/Parser/ExpressionNode.cc

    ra50fdfb r6e1e2d0  
    1313// Update Count     : 1083
    1414//
     15
     16#include "ExpressionNode.h"
    1517
    1618#include <cassert>                 // for assert
     
    2527#include "Common/SemanticError.h"  // for SemanticError
    2628#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild, CodeLo...
    27 #include "ParseNode.h"             // for ExpressionNode, maybeMoveBuildType
     29#include "DeclarationNode.h"       // for DeclarationNode
     30#include "InitializerNode.h"       // for InitializerNode
    2831#include "parserutility.h"         // for notZeroExpr
    2932
     
    699702} // build_binary_val
    700703
    701 ast::Expr * build_binary_ptr( const CodeLocation & location,
    702                 OperKinds op,
    703                 ExpressionNode * expr_node1,
    704                 ExpressionNode * expr_node2 ) {
    705         return build_binary_val( location, op, expr_node1, expr_node2 );
    706 } // build_binary_ptr
    707 
    708704ast::Expr * build_cond( const CodeLocation & location,
    709705                ExpressionNode * expr_node1,
  • src/Parser/InitializerNode.cc

    ra50fdfb r6e1e2d0  
    1414//
    1515
     16#include "InitializerNode.h"
     17
    1618#include <iostream>                // for operator<<, ostream, basic_ostream
    1719#include <list>                    // for list
    1820#include <string>                  // for operator<<, string
    19 
    20 using namespace std;
    2121
    2222#include "AST/Expr.hpp"            // for Expr
     
    2424#include "Common/SemanticError.h"  // for SemanticError
    2525#include "Common/utility.h"        // for maybeBuild
    26 #include "ParseNode.h"             // for InitializerNode, ExpressionNode
     26#include "ExpressionNode.h"        // for ExpressionNode
     27#include "DeclarationNode.h"       // for buildList
     28
     29using namespace std;
    2730
    2831static ast::ConstructFlag toConstructFlag( bool maybeConstructed ) {
  • src/Parser/ParseNode.h

    ra50fdfb r6e1e2d0  
    3838class DeclarationWithType;
    3939class Initializer;
     40class InitializerNode;
    4041class ExpressionNode;
    4142struct StatementNode;
     
    8081}; // ParseNode
    8182
    82 //##############################################################################
    83 
    84 class InitializerNode : public ParseNode {
    85   public:
    86         InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode * des = nullptr );
    87         InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode * des = nullptr );
    88         InitializerNode( bool isDelete );
    89         ~InitializerNode();
    90         virtual InitializerNode * clone() const { assert( false ); return nullptr; }
    91 
    92         ExpressionNode * get_expression() const { return expr; }
    93 
    94         InitializerNode * set_designators( ExpressionNode * des ) { designator = des; return this; }
    95         ExpressionNode * get_designators() const { return designator; }
    96 
    97         InitializerNode * set_maybeConstructed( bool value ) { maybeConstructed = value; return this; }
    98         bool get_maybeConstructed() const { return maybeConstructed; }
    99 
    100         bool get_isDelete() const { return isDelete; }
    101 
    102         InitializerNode * next_init() const { return kids; }
    103 
    104         void print( std::ostream & os, int indent = 0 ) const;
    105         void printOneLine( std::ostream & ) const;
    106 
    107         virtual ast::Init * build() const;
    108   private:
    109         ExpressionNode * expr;
    110         bool aggregate;
    111         ExpressionNode * designator;                                            // may be list
    112         InitializerNode * kids;
    113         bool maybeConstructed;
    114         bool isDelete;
    115 }; // InitializerNode
    116 
    117 //##############################################################################
    118 
    119 class ExpressionNode final : public ParseNode {
    120   public:
    121         ExpressionNode( ast::Expr * expr = nullptr ) : expr( expr ) {}
    122         virtual ~ExpressionNode() {}
    123         virtual ExpressionNode * clone() const override {
    124                 if ( nullptr == expr ) return nullptr;
    125                 return static_cast<ExpressionNode*>(
    126                         (new ExpressionNode( ast::shallowCopy( expr.get() ) ))->set_next( maybeCopy( get_next() ) ));
    127         }
    128 
    129         bool get_extension() const { return extension; }
    130         ExpressionNode * set_extension( bool exten ) { extension = exten; return this; }
    131 
    132         virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {
    133                 os << expr.get();
    134         }
    135         void printOneLine( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const {}
    136 
    137         template<typename T>
    138         bool isExpressionType() const { return nullptr != dynamic_cast<T>(expr.get()); }
    139 
    140         ast::Expr * build() const {
    141                 ast::Expr * node = const_cast<ExpressionNode *>(this)->expr.release();
    142                 node->set_extension( this->get_extension() );
    143                 node->location = this->location;
    144                 return node;
    145         }
    146 
    147         // Public because of lifetime implications (what lifetime implications?)
    148         std::unique_ptr<ast::Expr> expr;
    149   private:
    150         bool extension = false;
    151 }; // ExpressionNode
    152 
    15383// Must harmonize with OperName.
    15484enum class OperKinds {
     
    16999};
    170100
    171 // These 4 routines modify the string:
    172 ast::Expr * build_constantInteger( const CodeLocation &, std::string & );
    173 ast::Expr * build_constantFloat( const CodeLocation &, std::string & );
    174 ast::Expr * build_constantChar( const CodeLocation &, std::string & );
    175 ast::Expr * build_constantStr( const CodeLocation &, std::string & );
    176 ast::Expr * build_field_name_FLOATING_FRACTIONconstant( const CodeLocation &, const std::string & str );
    177 ast::Expr * build_field_name_FLOATING_DECIMALconstant( const CodeLocation &, const std::string & str );
    178 ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation &, const std::string & str );
    179 ast::Expr * build_field_name_fraction_constants( const CodeLocation &, ast::Expr * fieldName, ExpressionNode * fracts );
    180 
    181 ast::NameExpr * build_varref( const CodeLocation &, const std::string * name );
    182 ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const DeclarationNode * decl_node, const ast::NameExpr * name );
    183 ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const ast::EnumDecl * decl, const ast::NameExpr * name );
    184 ast::DimensionExpr * build_dimensionref( const CodeLocation &, const std::string * name );
    185 
    186 ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
    187 ast::Expr * build_keyword_cast( const CodeLocation &, ast::AggregateDecl::Aggregate target, ExpressionNode * expr_node );
    188 ast::Expr * build_virtual_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
    189 ast::Expr * build_fieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );
    190 ast::Expr * build_pfieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );
    191 ast::Expr * build_offsetOf( const CodeLocation &, DeclarationNode * decl_node, ast::NameExpr * member );
    192 ast::Expr * build_and( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
    193 ast::Expr * build_and_or( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ast::LogicalFlag flag );
    194 ast::Expr * build_unary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node );
    195 ast::Expr * build_binary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
    196 ast::Expr * build_binary_ptr( const CodeLocation &, OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
    197 ast::Expr * build_cond( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ExpressionNode * expr_node3 );
    198 ast::Expr * build_tuple( const CodeLocation &, ExpressionNode * expr_node = nullptr );
    199 ast::Expr * build_func( const CodeLocation &, ExpressionNode * function, ExpressionNode * expr_node );
    200 ast::Expr * build_compoundLiteral( const CodeLocation &, DeclarationNode * decl_node, InitializerNode * kids );
    201 
    202 //##############################################################################
    203 
    204 struct TypeData;
    205 
    206 struct DeclarationNode : public ParseNode {
    207         // These enumerations must harmonize with their names in DeclarationNode.cc.
    208         enum BasicType {
    209                 Void, Bool, Char, Int, Int128,
    210                 Float, Double, LongDouble, uuFloat80, uuFloat128,
    211                 uFloat16, uFloat32, uFloat32x, uFloat64, uFloat64x, uFloat128, uFloat128x,
    212                 NoBasicType
    213         };
    214         static const char * basicTypeNames[];
    215         enum ComplexType { Complex, NoComplexType, Imaginary }; // Imaginary unsupported => parse, but make invisible and print error message
    216         static const char * complexTypeNames[];
    217         enum Signedness { Signed, Unsigned, NoSignedness };
    218         static const char * signednessNames[];
    219         enum Length { Short, Long, LongLong, NoLength };
    220         static const char * lengthNames[];
    221         enum BuiltinType { Valist, AutoType, Zero, One, NoBuiltinType };
    222         static const char * builtinTypeNames[];
    223 
    224         static DeclarationNode * newStorageClass( ast::Storage::Classes );
    225         static DeclarationNode * newFuncSpecifier( ast::Function::Specs );
    226         static DeclarationNode * newTypeQualifier( ast::CV::Qualifiers );
    227         static DeclarationNode * newBasicType( BasicType );
    228         static DeclarationNode * newComplexType( ComplexType );
    229         static DeclarationNode * newSignedNess( Signedness );
    230         static DeclarationNode * newLength( Length );
    231         static DeclarationNode * newBuiltinType( BuiltinType );
    232         static DeclarationNode * newForall( DeclarationNode * );
    233         static DeclarationNode * newFromTypedef( const std::string * );
    234         static DeclarationNode * newFromGlobalScope();
    235         static DeclarationNode * newQualifiedType( DeclarationNode *, DeclarationNode * );
    236         static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body );
    237         static DeclarationNode * newAggregate( ast::AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body );
    238         static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, bool typed, DeclarationNode * base = nullptr, EnumHiding hiding = EnumHiding::Visible );
    239         static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant );
    240         static DeclarationNode * newEnumValueGeneric( const std::string * name, InitializerNode * init );
    241         static DeclarationNode * newEnumInLine( const std::string name );
    242         static DeclarationNode * newName( const std::string * );
    243         static DeclarationNode * newFromTypeGen( const std::string *, ExpressionNode * params );
    244         static DeclarationNode * newTypeParam( ast::TypeDecl::Kind, const std::string * );
    245         static DeclarationNode * newTrait( const std::string * name, DeclarationNode * params, DeclarationNode * asserts );
    246         static DeclarationNode * newTraitUse( const std::string * name, ExpressionNode * params );
    247         static DeclarationNode * newTypeDecl( const std::string * name, DeclarationNode * typeParams );
    248         static DeclarationNode * newPointer( DeclarationNode * qualifiers, OperKinds kind );
    249         static DeclarationNode * newArray( ExpressionNode * size, DeclarationNode * qualifiers, bool isStatic );
    250         static DeclarationNode * newVarArray( DeclarationNode * qualifiers );
    251         static DeclarationNode * newBitfield( ExpressionNode * size );
    252         static DeclarationNode * newTuple( DeclarationNode * members );
    253         static DeclarationNode * newTypeof( ExpressionNode * expr, bool basetypeof = false );
    254         static DeclarationNode * newVtableType( DeclarationNode * expr );
    255         static DeclarationNode * newAttribute( const std::string *, ExpressionNode * expr = nullptr ); // gcc attributes
    256         static DeclarationNode * newDirectiveStmt( StatementNode * stmt ); // gcc external directive statement
    257         static DeclarationNode * newAsmStmt( StatementNode * stmt ); // gcc external asm statement
    258         static DeclarationNode * newStaticAssert( ExpressionNode * condition, ast::Expr * message );
    259 
    260         DeclarationNode();
    261         ~DeclarationNode();
    262         DeclarationNode * clone() const override;
    263 
    264         DeclarationNode * addQualifiers( DeclarationNode * );
    265         void checkQualifiers( const TypeData *, const TypeData * );
    266         void checkSpecifiers( DeclarationNode * );
    267         DeclarationNode * copySpecifiers( DeclarationNode * );
    268         DeclarationNode * addType( DeclarationNode * );
    269         DeclarationNode * addTypedef();
    270         DeclarationNode * addEnumBase( DeclarationNode * );
    271         DeclarationNode * addAssertions( DeclarationNode * );
    272         DeclarationNode * addName( std::string * );
    273         DeclarationNode * addAsmName( DeclarationNode * );
    274         DeclarationNode * addBitfield( ExpressionNode * size );
    275         DeclarationNode * addVarArgs();
    276         DeclarationNode * addFunctionBody( StatementNode * body, ExpressionNode * with = nullptr );
    277         DeclarationNode * addOldDeclList( DeclarationNode * list );
    278         DeclarationNode * setBase( TypeData * newType );
    279         DeclarationNode * copyAttribute( DeclarationNode * attr );
    280         DeclarationNode * addPointer( DeclarationNode * qualifiers );
    281         DeclarationNode * addArray( DeclarationNode * array );
    282         DeclarationNode * addNewPointer( DeclarationNode * pointer );
    283         DeclarationNode * addNewArray( DeclarationNode * array );
    284         DeclarationNode * addParamList( DeclarationNode * list );
    285         DeclarationNode * addIdList( DeclarationNode * list ); // old-style functions
    286         DeclarationNode * addInitializer( InitializerNode * init );
    287         DeclarationNode * addTypeInitializer( DeclarationNode * init );
    288 
    289         DeclarationNode * cloneType( std::string * newName );
    290         DeclarationNode * cloneBaseType( DeclarationNode * newdecl );
    291 
    292         DeclarationNode * appendList( DeclarationNode * node ) {
    293                 return (DeclarationNode *)set_last( node );
    294         }
    295 
    296         virtual void print( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
    297         virtual void printList( __attribute__((unused)) std::ostream & os, __attribute__((unused)) int indent = 0 ) const override;
    298 
    299         ast::Decl * build() const;
    300         ast::Type * buildType() const;
    301 
    302         ast::Linkage::Spec get_linkage() const { return linkage; }
    303         DeclarationNode * extractAggregate() const;
    304         bool has_enumeratorValue() const { return (bool)enumeratorValue; }
    305         ExpressionNode * consume_enumeratorValue() const { return const_cast<DeclarationNode *>(this)->enumeratorValue.release(); }
    306 
    307         bool get_extension() const { return extension; }
    308         DeclarationNode * set_extension( bool exten ) { extension = exten; return this; }
    309 
    310         bool get_inLine() const { return inLine; }
    311         DeclarationNode * set_inLine( bool inL ) { inLine = inL; return this; }
    312 
    313         DeclarationNode * get_last() { return (DeclarationNode *)ParseNode::get_last(); }
    314 
    315         struct Variable_t {
    316 //              const std::string * name;
    317                 ast::TypeDecl::Kind tyClass;
    318                 DeclarationNode * assertions;
    319                 DeclarationNode * initializer;
    320         };
    321         Variable_t variable;
    322 
    323         struct StaticAssert_t {
    324                 ExpressionNode * condition;
    325                 ast::Expr * message;
    326         };
    327         StaticAssert_t assert;
    328 
    329         BuiltinType builtin = NoBuiltinType;
    330 
    331         TypeData * type = nullptr;
    332 
    333         bool inLine = false;
    334         bool enumInLine = false;
    335         ast::Function::Specs funcSpecs;
    336         ast::Storage::Classes storageClasses;
    337 
    338         ExpressionNode * bitfieldWidth = nullptr;
    339         std::unique_ptr<ExpressionNode> enumeratorValue;
    340         bool hasEllipsis = false;
    341         ast::Linkage::Spec linkage;
    342         ast::Expr * asmName = nullptr;
    343         std::vector<ast::ptr<ast::Attribute>> attributes;
    344         InitializerNode * initializer = nullptr;
    345         bool extension = false;
    346         std::string error;
    347         StatementNode * asmStmt = nullptr;
    348         StatementNode * directiveStmt = nullptr;
    349 
    350         static UniqueName anonymous;
    351 }; // DeclarationNode
    352 
    353 ast::Type * buildType( TypeData * type );
    354 
    355 static inline ast::Type * maybeMoveBuildType( const DeclarationNode * orig ) {
    356         ast::Type * ret = orig ? orig->buildType() : nullptr;
    357         delete orig;
    358         return ret;
    359 }
    360 
    361 //##############################################################################
    362 
    363 struct StatementNode final : public ParseNode {
    364         StatementNode() :
    365                 stmt( nullptr ), clause( nullptr ) {}
    366         StatementNode( ast::Stmt * stmt ) :
    367                 stmt( stmt ), clause( nullptr ) {}
    368         StatementNode( ast::StmtClause * clause ) :
    369                 stmt( nullptr ), clause( clause ) {}
    370         StatementNode( DeclarationNode * decl );
    371         virtual ~StatementNode() {}
    372 
    373         virtual StatementNode * clone() const final { assert( false ); return nullptr; }
    374         ast::Stmt * build() const { return const_cast<StatementNode *>(this)->stmt.release(); }
    375 
    376         virtual StatementNode * add_label(
    377                         const CodeLocation & location,
    378                         const std::string * name,
    379                         DeclarationNode * attr = nullptr ) {
    380                 stmt->labels.emplace_back( location,
    381                         *name,
    382                         attr ? std::move( attr->attributes )
    383                                 : std::vector<ast::ptr<ast::Attribute>>{} );
    384                 delete attr;
    385                 delete name;
    386                 return this;
    387         }
    388 
    389         virtual StatementNode * append_last_case( StatementNode * );
    390 
    391         virtual void print( std::ostream & os, __attribute__((unused)) int indent = 0 ) const override {
    392                 os << stmt.get() << std::endl;
    393         }
    394 
    395         std::unique_ptr<ast::Stmt> stmt;
    396         std::unique_ptr<ast::StmtClause> clause;
    397 }; // StatementNode
    398 
    399 ast::Stmt * build_expr( CodeLocation const &, ExpressionNode * ctl );
    400 
    401 struct CondCtl {
    402         CondCtl( DeclarationNode * decl, ExpressionNode * condition ) :
    403                 init( decl ? new StatementNode( decl ) : nullptr ), condition( condition ) {}
    404 
    405         StatementNode * init;
    406         ExpressionNode * condition;
    407 };
    408 
    409 struct ForCtrl {
    410         ForCtrl( StatementNode * stmt, ExpressionNode * condition, ExpressionNode * change ) :
    411                 init( stmt ), condition( condition ), change( change ) {}
    412 
    413         StatementNode * init;
    414         ExpressionNode * condition;
    415         ExpressionNode * change;
    416 };
    417 
    418 ast::Stmt * build_if( const CodeLocation &, CondCtl * ctl, StatementNode * then, StatementNode * else_ );
    419 ast::Stmt * build_switch( const CodeLocation &, bool isSwitch, ExpressionNode * ctl, StatementNode * stmt );
    420 ast::CaseClause * build_case( ExpressionNode * ctl );
    421 ast::CaseClause * build_default( const CodeLocation & );
    422 ast::Stmt * build_while( const CodeLocation &, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    423 ast::Stmt * build_do_while( const CodeLocation &, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    424 ast::Stmt * build_for( const CodeLocation &, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ = nullptr );
    425 ast::Stmt * build_branch( const CodeLocation &, ast::BranchStmt::Kind kind );
    426 ast::Stmt * build_branch( const CodeLocation &, std::string * identifier, ast::BranchStmt::Kind kind );
    427 ast::Stmt * build_computedgoto( ExpressionNode * ctl );
    428 ast::Stmt * build_return( const CodeLocation &, ExpressionNode * ctl );
    429 ast::Stmt * build_throw( const CodeLocation &, ExpressionNode * ctl );
    430 ast::Stmt * build_resume( const CodeLocation &, ExpressionNode * ctl );
    431 ast::Stmt * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );
    432 ast::Stmt * build_try( const CodeLocation &, StatementNode * try_, StatementNode * catch_, StatementNode * finally_ );
    433 ast::CatchClause * build_catch( const CodeLocation &, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body );
    434 ast::FinallyClause * build_finally( const CodeLocation &, StatementNode * stmt );
    435 ast::Stmt * build_compound( const CodeLocation &, StatementNode * first );
    436 StatementNode * maybe_build_compound( const CodeLocation &, StatementNode * first );
    437 ast::Stmt * build_asm( const CodeLocation &, bool voltile, ast::Expr * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
    438 ast::Stmt * build_directive( const CodeLocation &, std::string * directive );
    439 ast::SuspendStmt * build_suspend( const CodeLocation &, StatementNode *, ast::SuspendStmt::Type );
    440 ast::WaitForStmt * build_waitfor( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
    441 ast::WaitForStmt * build_waitfor_else( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt );
    442 ast::WaitForStmt * build_waitfor_timeout( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
    443 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
    444 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt );
    445 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation &, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
    446 ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root );
    447 ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
    448 ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
    449 
    450 //##############################################################################
    451 
    452 template<typename AstType, typename NodeType,
    453         template<typename, typename...> class Container, typename... Args>
    454 void buildList( const NodeType * firstNode,
    455                 Container<ast::ptr<AstType>, Args...> & output ) {
    456         SemanticErrorException errors;
    457         std::back_insert_iterator<Container<ast::ptr<AstType>, Args...>> out( output );
    458         const NodeType * cur = firstNode;
    459 
    460         while ( cur ) {
    461                 try {
    462                         if ( auto result = dynamic_cast<AstType *>( maybeBuild( cur ) ) ) {
    463                                 *out++ = result;
    464                         } else {
    465                                 assertf(false, __PRETTY_FUNCTION__ );
    466                                 SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
    467                         } // if
    468                 } catch( SemanticErrorException & e ) {
    469                         errors.append( e );
    470                 } // try
    471                 const ParseNode * temp = cur->get_next();
    472                 // Should not return nullptr, then it is non-homogeneous:
    473                 cur = dynamic_cast<const NodeType *>( temp );
    474                 if ( !cur && temp ) {
    475                         SemanticError( temp->location, "internal error, non-homogeneous nodes founds in buildList processing." );
    476                 } // if
    477         } // while
    478         if ( ! errors.isEmpty() ) {
    479                 throw errors;
    480         } // if
    481 }
    482 
    483 // in DeclarationNode.cc
    484 void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Decl>> & outputList );
    485 void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList );
    486 void buildTypeList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Type>> & outputList );
    487 
    488 template<typename AstType, typename NodeType,
    489         template<typename, typename...> class Container, typename... Args>
    490 void buildMoveList( const NodeType * firstNode,
    491                 Container<ast::ptr<AstType>, Args...> & output ) {
    492         buildList<AstType, NodeType, Container, Args...>( firstNode, output );
    493         delete firstNode;
    494 }
    495 
    496 // in ParseNode.cc
    497101std::ostream & operator<<( std::ostream & out, const ParseNode * node );
    498102
  • src/Parser/RunParser.cpp

    ra50fdfb r6e1e2d0  
    2020#include "CodeTools/TrackLoc.h"             // for fillLocations
    2121#include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
    22 #include "Parser/ParseNode.h"               // for DeclarationNode, buildList
     22#include "Parser/DeclarationNode.h"         // for DeclarationNode, buildList
    2323#include "Parser/TypedefTable.h"            // for TypedefTable
    2424
  • src/Parser/StatementNode.cc

    ra50fdfb r6e1e2d0  
    1111// Created On       : Sat May 16 14:59:41 2015
    1212// Last Modified By : Andrew Beach
    13 // Last Modified On : Tue Apr  4 11:40:00 2023
    14 // Update Count     : 427
     13// Last Modified On : Tue Apr 11 10:16:00 2023
     14// Update Count     : 428
    1515//
     16
     17#include "StatementNode.h"
    1618
    1719#include <cassert>                 // for assert, strict_dynamic_cast, assertf
     
    2325#include "Common/SemanticError.h"  // for SemanticError
    2426#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild
    25 #include "ParseNode.h"             // for StatementNode, ExpressionNode, bui...
     27#include "DeclarationNode.h"       // for DeclarationNode
     28#include "ExpressionNode.h"        // for ExpressionNode
    2629#include "parserutility.h"         // for notZeroExpr
    2730
     
    2932
    3033using namespace std;
     34
     35// Some helpers for cases that really want a single node but check for lists.
     36static const ast::Stmt * buildMoveSingle( StatementNode * node ) {
     37        std::vector<ast::ptr<ast::Stmt>> list;
     38        buildMoveList( node, list );
     39        assertf( list.size() == 1, "CFA Internal Error: Extra/Missing Nodes" );
     40        return list.front().release();
     41}
     42
     43static const ast::Stmt * buildMoveOptional( StatementNode * node ) {
     44        std::vector<ast::ptr<ast::Stmt>> list;
     45        buildMoveList( node, list );
     46        assertf( list.size() <= 1, "CFA Internal Error: Extra Nodes" );
     47        return list.empty() ? nullptr : list.front().release();
     48}
    3149
    3250StatementNode::StatementNode( DeclarationNode * decl ) {
     
    5371} // StatementNode::StatementNode
    5472
    55 StatementNode * StatementNode::append_last_case( StatementNode * stmt ) {
    56         StatementNode * prev = this;
     73StatementNode * StatementNode::add_label(
     74                const CodeLocation & location,
     75                const std::string * name,
     76                DeclarationNode * attr ) {
     77        stmt->labels.emplace_back( location,
     78                *name,
     79                attr ? std::move( attr->attributes )
     80                        : std::vector<ast::ptr<ast::Attribute>>{} );
     81        delete attr;
     82        delete name;
     83        return this;
     84}
     85
     86ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) {
     87        ClauseNode * prev = this;
    5788        // find end of list and maintain previous pointer
    58         for ( StatementNode * curr = prev; curr != nullptr; curr = (StatementNode *)curr->get_next() ) {
    59                 StatementNode * node = strict_dynamic_cast< StatementNode * >(curr);
    60                 assert( nullptr == node->stmt.get() );
     89        for ( ClauseNode * curr = prev; curr != nullptr; curr = (ClauseNode *)curr->get_next() ) {
     90                ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr);
    6191                assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
    6292                prev = curr;
    6393        } // for
     94        ClauseNode * node = dynamic_cast< ClauseNode * >(prev);
    6495        // convert from StatementNode list to Statement list
    65         StatementNode * node = dynamic_cast< StatementNode * >(prev);
    6696        std::vector<ast::ptr<ast::Stmt>> stmts;
    6797        buildMoveList( stmt, stmts );
     
    73103        stmts.clear();
    74104        return this;
    75 } // StatementNode::append_last_case
     105} // ClauseNode::append_last_case
    76106
    77107ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) {
     
    97127                for ( ast::ptr<ast::Stmt> & stmt : inits ) {
    98128                        // build the && of all of the declared variables compared against 0
    99                         //auto declStmt = strict_dynamic_cast<ast::DeclStmt *>( stmt );
    100129                        auto declStmt = stmt.strict_as<ast::DeclStmt>();
    101                         //ast::DeclWithType * dwt = strict_dynamic_cast<ast::DeclWithType *>( declStmt->decl );
    102130                        auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
    103131                        ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
     
    113141        ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    114142
    115         std::vector<ast::ptr<ast::Stmt>> aststmt;
    116         buildMoveList( then, aststmt );
    117         assert( aststmt.size() == 1 );
    118         ast::Stmt const * astthen = aststmt.front().release();
    119 
    120         ast::Stmt const * astelse = nullptr;
    121         if ( else_ ) {
    122                 std::vector<ast::ptr<ast::Stmt>> aststmt;
    123                 buildMoveList( else_, aststmt );
    124                 assert( aststmt.size() == 1 );
    125                 astelse = aststmt.front().release();
    126         } // if
     143        ast::Stmt const * astthen = buildMoveSingle( then );
     144        ast::Stmt const * astelse = buildMoveOptional( else_ );
    127145
    128146        return new ast::IfStmt( location, astcond, astthen, astelse,
     
    131149} // build_if
    132150
    133 // Temporary work around. Split StmtClause off from StatementNode.
    134 template<typename clause_t>
    135 static void buildMoveClauseList( StatementNode * firstNode,
    136                 std::vector<ast::ptr<clause_t>> & output ) {
    137         SemanticErrorException errors;
    138         std::back_insert_iterator<std::vector<ast::ptr<clause_t>>>
    139                 out( output );
    140         StatementNode * cur = firstNode;
    141 
    142         while ( cur ) {
    143                 try {
    144                         auto clause = cur->clause.release();
    145                         if ( auto result = dynamic_cast<clause_t *>( clause ) ) {
    146                                 *out++ = result;
    147                         } else {
    148                                 assertf(false, __PRETTY_FUNCTION__ );
    149                                 SemanticError( cur->location, "type specifier declaration in forall clause is currently unimplemented." );
    150                         } // if
    151                 } catch( SemanticErrorException & e ) {
    152                         errors.append( e );
    153                 } // try
    154                 ParseNode * temp = cur->get_next();
    155                 // Should not return nullptr, then it is non-homogeneous:
    156                 cur = dynamic_cast<StatementNode *>( temp );
    157                 if ( !cur && temp ) {
    158                         SemanticError( temp->location, "internal error, non-homogeneous nodes founds in buildList processing." );
    159                 } // if
    160         } // while
    161         if ( ! errors.isEmpty() ) {
    162                 throw errors;
    163         } // if
    164         // Usually in the wrapper.
    165         delete firstNode;
    166 }
    167 
    168 ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) {
     151ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) {
    169152        std::vector<ast::ptr<ast::CaseClause>> aststmt;
    170         buildMoveClauseList( stmt, aststmt );
     153        buildMoveList( stmt, aststmt );
    171154        // If it is not a switch it is a choose statement.
    172155        if ( ! isSwitch ) {
     
    190173} // build_switch
    191174
    192 ast::CaseClause * build_case( ExpressionNode * ctl ) {
     175ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) {
    193176        // stmt starts empty and then added to
    194177        auto expr = maybeMoveBuild( ctl );
    195         return new ast::CaseClause( expr->location, expr, {} );
     178        return new ast::CaseClause( location, expr, {} );
    196179} // build_case
    197180
     
    205188        ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    206189
    207         std::vector<ast::ptr<ast::Stmt>> aststmt;                                               // loop body, compound created if empty
    208         buildMoveList( stmt, aststmt );
    209         assert( aststmt.size() == 1 );
    210 
    211         std::vector<ast::ptr<ast::Stmt>> astelse;                                               // else clause, maybe empty
    212         buildMoveList( else_, astelse );
    213         assert( astelse.size() <= 1 );
    214 
    215190        return new ast::WhileDoStmt( location,
    216191                astcond,
    217                 aststmt.front(),
    218                 astelse.empty() ? nullptr : astelse.front().release(),
     192                buildMoveSingle( stmt ),
     193                buildMoveOptional( else_ ),
    219194                std::move( astinit ),
    220                 false
     195                ast::While
    221196        );
    222197} // build_while
    223198
    224199ast::Stmt * build_do_while( const CodeLocation & location, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ ) {
    225         std::vector<ast::ptr<ast::Stmt>> aststmt;                                               // loop body, compound created if empty
    226         buildMoveList( stmt, aststmt );
    227         assert( aststmt.size() == 1 );                                          // compound created if empty
    228 
    229         std::vector<ast::ptr<ast::Stmt>> astelse;                                               // else clause, maybe empty
    230         buildMoveList( else_, astelse );
    231         assert( astelse.size() <= 1 );
    232 
    233200        // do-while cannot have declarations in the contitional, so init is always empty
    234201        return new ast::WhileDoStmt( location,
    235202                notZeroExpr( maybeMoveBuild( ctl ) ),
    236                 aststmt.front(),
    237                 astelse.empty() ? nullptr : astelse.front().release(),
     203                buildMoveSingle( stmt ),
     204                buildMoveOptional( else_ ),
    238205                {},
    239                 true
     206                ast::DoWhile
    240207        );
    241208} // build_do_while
     
    251218        astincr = maybeMoveBuild( forctl->change );
    252219        delete forctl;
    253 
    254         std::vector<ast::ptr<ast::Stmt>> aststmt;                                               // loop body, compound created if empty
    255         buildMoveList( stmt, aststmt );
    256         assert( aststmt.size() == 1 );
    257 
    258         std::vector<ast::ptr<ast::Stmt>> astelse;                                               // else clause, maybe empty
    259         buildMoveList( else_, astelse );
    260         assert( astelse.size() <= 1 );
    261220
    262221        return new ast::ForStmt( location,
     
    264223                astcond,
    265224                astincr,
    266                 aststmt.front(),
    267                 astelse.empty() ? nullptr : astelse.front().release()
     225                buildMoveSingle( stmt ),
     226                buildMoveOptional( else_ )
    268227        );
    269228} // build_for
     
    326285} // build_resume_at
    327286
    328 ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, StatementNode * catch_, StatementNode * finally_ ) {
     287ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) {
    329288        std::vector<ast::ptr<ast::CatchClause>> aststmt;
    330         buildMoveClauseList( catch_, aststmt );
     289        buildMoveList( catch_, aststmt );
    331290        ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
    332291        ast::FinallyClause * finallyBlock = nullptr;
     
    342301
    343302ast::CatchClause * build_catch( const CodeLocation & location, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body ) {
    344         std::vector<ast::ptr<ast::Stmt>> aststmt;
    345         buildMoveList( body, aststmt );
    346         assert( aststmt.size() == 1 );
    347303        return new ast::CatchClause( location,
    348304                kind,
    349305                maybeMoveBuild( decl ),
    350306                maybeMoveBuild( cond ),
    351                 aststmt.front().release()
     307                buildMoveSingle( body )
    352308        );
    353309} // build_catch
    354310
    355311ast::FinallyClause * build_finally( const CodeLocation & location, StatementNode * stmt ) {
    356         std::vector<ast::ptr<ast::Stmt>> aststmt;
    357         buildMoveList( stmt, aststmt );
    358         assert( aststmt.size() == 1 );
    359312        return new ast::FinallyClause( location,
    360                 aststmt.front().strict_as<ast::CompoundStmt>()
     313                strict_dynamic_cast<const ast::CompoundStmt *>(
     314                        buildMoveSingle( stmt )
     315                )
    361316        );
    362317} // build_finally
    363318
    364 ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Type type ) {
    365         std::vector<ast::ptr<ast::Stmt>> stmts;
    366         buildMoveList( then, stmts );
    367         ast::CompoundStmt const * then2 = nullptr;
    368         if(!stmts.empty()) {
    369                 assert( stmts.size() == 1 );
    370                 then2 = stmts.front().strict_as<ast::CompoundStmt>();
    371         }
    372         auto node = new ast::SuspendStmt( location, then2, ast::SuspendStmt::None );
    373         node->type = type;
    374         return node;
     319ast::SuspendStmt * build_suspend( const CodeLocation & location, StatementNode * then, ast::SuspendStmt::Kind kind ) {
     320        return new ast::SuspendStmt( location,
     321                strict_dynamic_cast<const ast::CompoundStmt *, nullptr>(
     322                        buildMoveOptional( then )
     323                ),
     324                kind
     325        );
    375326} // build_suspend
    376327
     
    525476
    526477// Question
    527 ast::Stmt * build_asm( const CodeLocation & location, bool voltile, ast::Expr * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
     478ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    528479        std::vector<ast::ptr<ast::Expr>> out, in;
    529480        std::vector<ast::ptr<ast::ConstantExpr>> clob;
     
    533484        buildMoveList( clobber, clob );
    534485        return new ast::AsmStmt( location,
    535                 voltile,
    536                 instruction,
     486                is_volatile,
     487                maybeMoveBuild( instruction ),
    537488                std::move( out ),
    538489                std::move( in ),
  • src/Parser/TypeData.cc

    ra50fdfb r6e1e2d0  
    2424#include "Common/SemanticError.h"  // for SemanticError
    2525#include "Common/utility.h"        // for splice, spliceBegin
    26 #include "Parser/parserutility.h"  // for maybeCopy, maybeBuild, maybeMoveB...
    27 #include "Parser/ParseNode.h"      // for DeclarationNode, ExpressionNode
     26#include "Parser/ExpressionNode.h" // for ExpressionNode
     27#include "Parser/StatementNode.h"  // for StatementNode
    2828
    2929class Attribute;
     
    13971397                std::move( attributes ),
    13981398                funcSpec,
    1399                 isVarArgs
     1399                (isVarArgs) ? ast::VariableArgs : ast::FixedArgs
    14001400        );
    14011401        buildList( td->function.withExprs, decl->withExprs );
  • src/Parser/TypeData.h

    ra50fdfb r6e1e2d0  
    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 "AST/Type.hpp"                                                                 // for Type
    23 #include "ParseNode.h"                                                                  // for DeclarationNode, DeclarationNode::Ag...
     22#include "AST/Type.hpp"                             // for Type
     23#include "DeclarationNode.h"                        // for DeclarationNode
    2424
    2525struct TypeData {
  • src/Parser/TypedefTable.cc

    ra50fdfb r6e1e2d0  
    1616
    1717#include "TypedefTable.h"
    18 #include <cassert>                                                                              // for assert
    19 #include <iostream>
     18
     19#include <cassert>                                // for assert
     20#include <string>                                 // for string
     21#include <iostream>                               // for iostream
     22
     23#include "ExpressionNode.h"                       // for LabelNode
     24#include "ParserTypes.h"                          // for Token
     25#include "StatementNode.h"                        // for CondCtl, ForCtrl
     26// This (generated) header must come late as it is missing includes.
     27#include "parser.hh"              // for IDENTIFIER, TYPEDEFname, TYPEGENname
     28
    2029using namespace std;
    2130
    2231#if 0
    2332#define debugPrint( code ) code
     33
     34static const char *kindName( int kind ) {
     35        switch ( kind ) {
     36        case IDENTIFIER: return "identifier";
     37        case TYPEDIMname: return "typedim";
     38        case TYPEDEFname: return "typedef";
     39        case TYPEGENname: return "typegen";
     40        default:
     41                cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
     42                abort();
     43        } // switch
     44} // kindName
    2445#else
    2546#define debugPrint( code )
    2647#endif
    27 
    28 using namespace std;                                                                    // string, iostream
    29 
    30 debugPrint(
    31         static const char *kindName( int kind ) {
    32                 switch ( kind ) {
    33                 case IDENTIFIER: return "identifier";
    34                 case TYPEDIMname: return "typedim";
    35                 case TYPEDEFname: return "typedef";
    36                 case TYPEGENname: return "typegen";
    37                 default:
    38                         cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
    39                         abort();
    40                 } // switch
    41         } // kindName
    42 );
    4348
    4449TypedefTable::~TypedefTable() {
     
    7883                typedefTable.addToEnclosingScope( name, kind, "MTD" );
    7984        } // if
     85} // TypedefTable::makeTypedef
     86
     87void TypedefTable::makeTypedef( const string & name ) {
     88        return makeTypedef( name, TYPEDEFname );
    8089} // TypedefTable::makeTypedef
    8190
  • src/Parser/TypedefTable.h

    ra50fdfb r6e1e2d0  
    1919
    2020#include "Common/ScopedMap.h"                                                   // for ScopedMap
    21 #include "ParserTypes.h"
    22 #include "parser.hh"                                                                    // for IDENTIFIER, TYPEDEFname, TYPEGENname
    2321
    2422class TypedefTable {
    2523        struct Note { size_t level; bool forall; };
    2624        typedef ScopedMap< std::string, int, Note > KindTable;
    27         KindTable kindTable;   
     25        KindTable kindTable;
    2826        unsigned int level = 0;
    2927  public:
     
    3331        bool existsCurr( const std::string & identifier ) const;
    3432        int isKind( const std::string & identifier ) const;
    35         void makeTypedef( const std::string & name, int kind = TYPEDEFname );
     33        void makeTypedef( const std::string & name, int kind );
     34        void makeTypedef( const std::string & name );
    3635        void addToScope( const std::string & identifier, int kind, const char * );
    3736        void addToEnclosingScope( const std::string & identifier, int kind, const char * );
  • src/Parser/lex.ll

    ra50fdfb r6e1e2d0  
    4444
    4545#include "config.h"                                                                             // configure info
     46#include "DeclarationNode.h"                            // for DeclarationNode
     47#include "ExpressionNode.h"                             // for LabelNode
     48#include "InitializerNode.h"                            // for InitializerNode
    4649#include "ParseNode.h"
     50#include "ParserTypes.h"                                // for Token
     51#include "StatementNode.h"                              // for CondCtl, ForCtrl
    4752#include "TypedefTable.h"
     53// This (generated) header must come late as it is missing includes.
     54#include "parser.hh"                                    // generated info
    4855
    4956string * build_postfix_name( string * name );
  • src/Parser/module.mk

    ra50fdfb r6e1e2d0  
    2121SRC += \
    2222       Parser/DeclarationNode.cc \
     23       Parser/DeclarationNode.h \
    2324       Parser/ExpressionNode.cc \
     25       Parser/ExpressionNode.h \
    2426       Parser/InitializerNode.cc \
     27       Parser/InitializerNode.h \
    2528       Parser/lex.ll \
    2629       Parser/ParseNode.cc \
     
    3336       Parser/RunParser.hpp \
    3437       Parser/StatementNode.cc \
     38       Parser/StatementNode.h \
    3539       Parser/TypeData.cc \
    3640       Parser/TypeData.h \
  • src/Parser/parser.yy

    ra50fdfb r6e1e2d0  
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Sep  1 20:22:55 2001
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Tue Apr  4 14:02:00 2023
    13 // Update Count     : 6329
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Wed Apr 26 16:45:37 2023
     13// Update Count     : 6330
    1414//
    1515
     
    4848using namespace std;
    4949
    50 #include "SynTree/Declaration.h"
    51 #include "ParseNode.h"
     50#include "SynTree/Type.h"                               // for Type
     51#include "DeclarationNode.h"                            // for DeclarationNode, ...
     52#include "ExpressionNode.h"                             // for ExpressionNode, ...
     53#include "InitializerNode.h"                            // for InitializerNode, ...
     54#include "ParserTypes.h"
     55#include "StatementNode.h"                              // for build_...
    5256#include "TypedefTable.h"
    5357#include "TypeData.h"
    54 #include "SynTree/LinkageSpec.h"
    5558#include "Common/SemanticError.h"                                               // error_str
    5659#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
     
    297300%union {
    298301        Token tok;
    299         ParseNode * pn;
    300         ExpressionNode * en;
     302        ExpressionNode * expr;
    301303        DeclarationNode * decl;
    302304        ast::AggregateDecl::Aggregate aggKey;
    303305        ast::TypeDecl::Kind tclass;
    304         StatementNode * sn;
     306        StatementNode * stmt;
     307        ClauseNode * clause;
    305308        ast::WaitForStmt * wfs;
    306     ast::WaitUntilStmt::ClauseNode * wuscn;
    307         ast::Expr * constant;
     309    ast::WaitUntilStmt::ClauseNode * wucn;
    308310        CondCtl * ifctl;
    309         ForCtrl * fctl;
    310         OperKinds compop;
    311         LabelNode * label;
    312         InitializerNode * in;
    313         OperKinds op;
     311        ForCtrl * forctl;
     312        LabelNode * labels;
     313        InitializerNode * init;
     314        OperKinds oper;
    314315        std::string * str;
    315         bool flag;
    316         EnumHiding hide;
    317         ast::ExceptionKind catch_kind;
     316        bool is_volatile;
     317        EnumHiding enum_hiding;
     318        ast::ExceptionKind except_kind;
    318319        ast::GenericExpr * genexpr;
    319320}
     
    381382%type<tok> identifier                                   identifier_at                           identifier_or_type_name         attr_name
    382383%type<tok> quasi_keyword
    383 %type<constant> string_literal
     384%type<expr> string_literal
    384385%type<str> string_literal_list
    385386
    386 %type<hide> hide_opt                                    visible_hide_opt
     387%type<enum_hiding> hide_opt                                     visible_hide_opt
    387388
    388389// expressions
    389 %type<en> constant
    390 %type<en> tuple                                                 tuple_expression_list
    391 %type<op> ptrref_operator                               unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
    392 %type<en> primary_expression                    postfix_expression                      unary_expression
    393 %type<en> cast_expression_list                  cast_expression                         exponential_expression          multiplicative_expression       additive_expression
    394 %type<en> shift_expression                              relational_expression           equality_expression
    395 %type<en> AND_expression                                exclusive_OR_expression         inclusive_OR_expression
    396 %type<en> logical_AND_expression                logical_OR_expression
    397 %type<en> conditional_expression                constant_expression                     assignment_expression           assignment_expression_opt
    398 %type<en> comma_expression                              comma_expression_opt
    399 %type<en> argument_expression_list_opt  argument_expression_list        argument_expression                     default_initializer_opt
     390%type<expr> constant
     391%type<expr> tuple                                                       tuple_expression_list
     392%type<oper> ptrref_operator                             unary_operator                          assignment_operator                     simple_assignment_operator      compound_assignment_operator
     393%type<expr> primary_expression                  postfix_expression                      unary_expression
     394%type<expr> cast_expression_list                        cast_expression                         exponential_expression          multiplicative_expression       additive_expression
     395%type<expr> shift_expression                            relational_expression           equality_expression
     396%type<expr> AND_expression                              exclusive_OR_expression         inclusive_OR_expression
     397%type<expr> logical_AND_expression              logical_OR_expression
     398%type<expr> conditional_expression              constant_expression                     assignment_expression           assignment_expression_opt
     399%type<expr> comma_expression                            comma_expression_opt
     400%type<expr> argument_expression_list_opt        argument_expression_list        argument_expression                     default_initializer_opt
    400401%type<ifctl> conditional_declaration
    401 %type<fctl> for_control_expression              for_control_expression_list
    402 %type<compop> upupeq updown updowneq downupdowneq
    403 %type<en> subrange
     402%type<forctl> for_control_expression            for_control_expression_list
     403%type<oper> upupeq updown updowneq downupdowneq
     404%type<expr> subrange
    404405%type<decl> asm_name_opt
    405 %type<en> asm_operands_opt                              asm_operands_list                       asm_operand
    406 %type<label> label_list
    407 %type<en> asm_clobbers_list_opt
    408 %type<flag> asm_volatile_opt
    409 %type<en> handler_predicate_opt
     406%type<expr> asm_operands_opt                            asm_operands_list                       asm_operand
     407%type<labels> label_list
     408%type<expr> asm_clobbers_list_opt
     409%type<is_volatile> asm_volatile_opt
     410%type<expr> handler_predicate_opt
    410411%type<genexpr> generic_association              generic_assoc_list
    411412
    412413// statements
    413 %type<sn> statement                                             labeled_statement                       compound_statement
    414 %type<sn> statement_decl                                statement_decl_list                     statement_list_nodecl
    415 %type<sn> selection_statement                   if_statement
    416 %type<sn> switch_clause_list_opt                switch_clause_list
    417 %type<en> case_value
    418 %type<sn> case_clause                                   case_value_list                         case_label                                      case_label_list
    419 %type<sn> iteration_statement                   jump_statement
    420 %type<sn> expression_statement                  asm_statement
    421 %type<sn> with_statement
    422 %type<en> with_clause_opt
    423 %type<sn> exception_statement                   handler_clause                          finally_clause
    424 %type<catch_kind> handler_key
    425 %type<sn> mutex_statement
    426 %type<en> when_clause                                   when_clause_opt                         waitfor         waituntil               timeout
    427 %type<sn> waitfor_statement                             waituntil_statement
     414%type<stmt> statement                                           labeled_statement                       compound_statement
     415%type<stmt> statement_decl                              statement_decl_list                     statement_list_nodecl
     416%type<stmt> selection_statement                 if_statement
     417%type<clause> switch_clause_list_opt            switch_clause_list
     418%type<expr> case_value
     419%type<clause> case_clause                               case_value_list                         case_label                                      case_label_list
     420%type<stmt> iteration_statement                 jump_statement
     421%type<stmt> expression_statement                        asm_statement
     422%type<stmt> with_statement
     423%type<expr> with_clause_opt
     424%type<stmt> exception_statement
     425%type<clause> handler_clause                    finally_clause
     426%type<except_kind> handler_key
     427%type<stmt> mutex_statement
     428%type<expr> when_clause                                 when_clause_opt                         waitfor         waituntil               timeout
     429%type<stmt> waitfor_statement                           waituntil_statement
    428430%type<wfs> wor_waitfor_clause
    429 %type<wuscn> waituntil_clause                   wand_waituntil_clause       wor_waituntil_clause
     431%type<wucn> waituntil_clause                    wand_waituntil_clause       wor_waituntil_clause
    430432
    431433// declarations
     
    439441%type<decl> assertion assertion_list assertion_list_opt
    440442
    441 %type<en> bit_subrange_size_opt bit_subrange_size
     443%type<expr> bit_subrange_size_opt bit_subrange_size
    442444
    443445%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
     
    452454
    453455%type<decl> enumerator_list enum_type enum_type_nobody
    454 %type<in> enumerator_value_opt
     456%type<init> enumerator_value_opt
    455457
    456458%type<decl> external_definition external_definition_list external_definition_list_opt
     
    459461
    460462%type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declarator field_abstract_list_opt field_abstract
    461 %type<en> field field_name_list field_name fraction_constants_opt
     463%type<expr> field field_name_list field_name fraction_constants_opt
    462464
    463465%type<decl> external_function_definition function_definition function_array function_declarator function_no_ptr function_ptr
     
    508510%type<decl> type_parameter type_parameter_list type_initializer_opt
    509511
    510 %type<en> type_parameters_opt type_list array_type_list
     512%type<expr> type_parameters_opt type_list array_type_list
    511513
    512514%type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
     
    519521
    520522// initializers
    521 %type<in>  initializer initializer_list_opt initializer_opt
     523%type<init>  initializer initializer_list_opt initializer_opt
    522524
    523525// designators
    524 %type<en>  designator designator_list designation
     526%type<expr>  designator designator_list designation
    525527
    526528
     
    644646
    645647string_literal:
    646         string_literal_list                                                     { $$ = build_constantStr( yylloc, *$1 ); }
     648        string_literal_list                                                     { $$ = new ExpressionNode( build_constantStr( yylloc, *$1 ) ); }
    647649        ;
    648650
     
    739741                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    740742        | string_literal '[' assignment_expression ']'          // "abc"[3], 3["abc"]
    741                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, new ExpressionNode( $1 ), $3 ) ); }
     743                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    742744        | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call
    743745                {
     
    757759                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    758760        | string_literal '`' identifier                                         // CFA, postfix call
    759                 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), new ExpressionNode( $1 ) ) ); }
     761                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    760762        | postfix_expression '.' identifier
    761763                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
     
    857859        | constant
    858860        | string_literal
    859                 { $$ = new ExpressionNode( $1 ); }
     861                { $$ = $1; }
    860862        | EXTENSION cast_expression                                                     // GCC
    861863                { $$ = $2->set_extension( true ); }
     
    12601262
    12611263case_value_list:                                                                                // CFA
    1262         case_value                                                                      { $$ = new StatementNode( build_case( $1 ) ); }
     1264        case_value                                                                      { $$ = new ClauseNode( build_case( yylloc, $1 ) ); }
    12631265                // convert case list, e.g., "case 1, 3, 5:" into "case 1: case 3: case 5"
    1264         | case_value_list ',' case_value                        { $$ = (StatementNode *)($1->set_last( new StatementNode( build_case( $3 ) ) ) ); }
     1266        | case_value_list ',' case_value                        { $$ = $1->set_last( new ClauseNode( build_case( yylloc, $3 ) ) ); }
    12651267        ;
    12661268
     
    12711273        | CASE case_value_list error                                            // syntax error
    12721274                { SemanticError( yylloc, "Missing colon after case list." ); $$ = nullptr; }
    1273         | DEFAULT ':'                                                           { $$ = new StatementNode( build_default( yylloc ) ); }
     1275        | DEFAULT ':'                                                           { $$ = new ClauseNode( build_default( yylloc ) ); }
    12741276                // A semantic check is required to ensure only one default clause per switch/choose statement.
    12751277        | DEFAULT error                                                                         //  syntax error
     
    12791281case_label_list:                                                                                // CFA
    12801282        case_label
    1281         | case_label_list case_label                            { $$ = (StatementNode *)( $1->set_last( $2 )); }
     1283        | case_label_list case_label                            { $$ = $1->set_last( $2 ); }
    12821284        ;
    12831285
     
    12961298                { $$ = $1->append_last_case( new StatementNode( build_compound( yylloc, $2 ) ) ); }
    12971299        | switch_clause_list case_label_list statement_list_nodecl
    1298                 { $$ = (StatementNode *)( $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 ) ) ) ) ); }
     1300                { $$ = $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 ) ) ) ); }
    12991301        ;
    13001302
     
    16791681
    16801682waituntil:
    1681         WAITUNTIL '(' cast_expression ')'
     1683        WAITUNTIL '(' comma_expression ')'
    16821684                { $$ = $3; }
    16831685        ;
     
    17361738handler_clause:
    17371739        handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1738                 { $$ = new StatementNode( build_catch( yylloc, $1, $4, $6, $8 ) ); }
     1740                { $$ = new ClauseNode( build_catch( yylloc, $1, $4, $6, $8 ) ); }
    17391741        | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1740                 { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); }
     1742                { $$ = $1->set_last( new ClauseNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); }
    17411743        ;
    17421744
     
    17551757
    17561758finally_clause:
    1757         FINALLY compound_statement                                      { $$ = new StatementNode( build_finally( yylloc, $2 ) ); }
     1759        FINALLY compound_statement                                      { $$ = new ClauseNode( build_finally( yylloc, $2 ) ); }
    17581760        ;
    17591761
     
    18131815asm_operand:                                                                                    // GCC
    18141816        string_literal '(' constant_expression ')'
    1815                 { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", $1, maybeMoveBuild( $3 ) ) ); }
     1817                { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
    18161818        | '[' IDENTIFIER ']' string_literal '(' constant_expression ')'
    18171819                {
    1818                         $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, $4, maybeMoveBuild( $6 ) ) );
     1820                        $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, maybeMoveBuild( $4 ), maybeMoveBuild( $6 ) ) );
    18191821                        delete $2.str;
    18201822                }
     
    18251827                { $$ = nullptr; }                                                               // use default argument
    18261828        | string_literal
    1827                 { $$ = new ExpressionNode( $1 ); }
     1829                { $$ = $1; }
    18281830        | asm_clobbers_list_opt ',' string_literal
    1829                 { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( $3 ) )); }
     1831                { $$ = (ExpressionNode *)( $1->set_last( $3 ) ); }
    18301832        ;
    18311833
     
    18991901static_assert:
    19001902        STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11
    1901                 { $$ = DeclarationNode::newStaticAssert( $3, $5 ); }
     1903                { $$ = DeclarationNode::newStaticAssert( $3, maybeMoveBuild( $5 ) ); }
    19021904        | STATICASSERT '(' constant_expression ')' ';'          // CFA
    19031905                { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( yylloc, *new string( "\"\"" ) ) ); }
     
    33293331                {
    33303332                        DeclarationNode * name = new DeclarationNode();
    3331                         name->asmName = $3;
     3333                        name->asmName = maybeMoveBuild( $3 );
    33323334                        $$ = name->addQualifiers( $5 );
    33333335                }
  • src/Parser/parserutility.h

    ra50fdfb r6e1e2d0  
    2424
    2525template< typename T >
    26 static inline auto maybeBuild( const T *orig ) -> decltype(orig->build()) {
     26static inline auto maybeBuild( T * orig ) -> decltype(orig->build()) {
    2727        return (orig) ? orig->build() : nullptr;
    2828}
    2929
    3030template< typename T >
    31 static inline auto maybeMoveBuild( const T *orig ) -> decltype(orig->build()) {
     31static inline auto maybeMoveBuild( T * orig ) -> decltype(orig->build()) {
    3232        auto ret = maybeBuild<T>(orig);
    3333        delete orig;
  • src/ResolvExpr/CandidateFinder.cpp

    ra50fdfb r6e1e2d0  
    5555namespace ResolvExpr {
    5656
     57/// Unique identifier for matching expression resolutions to their requesting expression
     58UniqueId globalResnSlot = 0;
     59
     60namespace {
     61        /// First index is which argument, second is which alternative, third is which exploded element
     62        using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
     63
     64        /// Returns a list of alternatives with the minimum cost in the given list
     65        CandidateList findMinCost( const CandidateList & candidates ) {
     66                CandidateList out;
     67                Cost minCost = Cost::infinity;
     68                for ( const CandidateRef & r : candidates ) {
     69                        if ( r->cost < minCost ) {
     70                                minCost = r->cost;
     71                                out.clear();
     72                                out.emplace_back( r );
     73                        } else if ( r->cost == minCost ) {
     74                                out.emplace_back( r );
     75                        }
     76                }
     77                return out;
     78        }
     79
     80        /// Computes conversion cost for a given expression to a given type
     81        const ast::Expr * computeExpressionConversionCost(
     82                const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
     83        ) {
     84                Cost convCost = computeConversionCost(
     85                                arg->result, paramType, arg->get_lvalue(), symtab, env );
     86                outCost += convCost;
     87
     88                // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
     89                // conversion. Ignore poly cost for now, since this requires resolution of the cast to
     90                // infer parameters and this does not currently work for the reason stated below
     91                Cost tmpCost = convCost;
     92                tmpCost.incPoly( -tmpCost.get_polyCost() );
     93                if ( tmpCost != Cost::zero ) {
     94                        ast::ptr< ast::Type > newType = paramType;
     95                        env.apply( newType );
     96                        return new ast::CastExpr{ arg, newType };
     97
     98                        // xxx - *should* be able to resolve this cast, but at the moment pointers are not
     99                        // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
     100                        // once this is fixed it should be possible to resolve the cast.
     101                        // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
     102                        // but it shouldn't be because this makes the conversion from DT* to DT* since
     103                        // commontype(zero_t, DT*) is DT*, rather than nothing
     104
     105                        // CandidateFinder finder{ symtab, env };
     106                        // finder.find( arg, ResolvMode::withAdjustment() );
     107                        // assertf( finder.candidates.size() > 0,
     108                        //      "Somehow castable expression failed to find alternatives." );
     109                        // assertf( finder.candidates.size() == 1,
     110                        //      "Somehow got multiple alternatives for known cast expression." );
     111                        // return finder.candidates.front()->expr;
     112                }
     113
     114                return arg;
     115        }
     116
     117        /// Computes conversion cost for a given candidate
     118        Cost computeApplicationConversionCost(
     119                CandidateRef cand, const ast::SymbolTable & symtab
     120        ) {
     121                auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
     122                auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
     123                auto function = pointer->base.strict_as< ast::FunctionType >();
     124
     125                Cost convCost = Cost::zero;
     126                const auto & params = function->params;
     127                auto param = params.begin();
     128                auto & args = appExpr->args;
     129
     130                for ( unsigned i = 0; i < args.size(); ++i ) {
     131                        const ast::Type * argType = args[i]->result;
     132                        PRINT(
     133                                std::cerr << "arg expression:" << std::endl;
     134                                ast::print( std::cerr, args[i], 2 );
     135                                std::cerr << "--- results are" << std::endl;
     136                                ast::print( std::cerr, argType, 2 );
     137                        )
     138
     139                        if ( param == params.end() ) {
     140                                if ( function->isVarArgs ) {
     141                                        convCost.incUnsafe();
     142                                        PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
     143                                                << convCost << std::endl; ; )
     144                                        // convert reference-typed expressions into value-typed expressions
     145                                        cand->expr = ast::mutate_field_index(
     146                                                appExpr, &ast::ApplicationExpr::args, i,
     147                                                referenceToRvalueConversion( args[i], convCost ) );
     148                                        continue;
     149                                } else return Cost::infinity;
     150                        }
     151
     152                        if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {
     153                                // Default arguments should be free - don't include conversion cost.
     154                                // Unwrap them here because they are not relevant to the rest of the system
     155                                cand->expr = ast::mutate_field_index(
     156                                        appExpr, &ast::ApplicationExpr::args, i, def->expr );
     157                                ++param;
     158                                continue;
     159                        }
     160
     161                        // mark conversion cost and also specialization cost of param type
     162                        // const ast::Type * paramType = (*param)->get_type();
     163                        cand->expr = ast::mutate_field_index(
     164                                appExpr, &ast::ApplicationExpr::args, i,
     165                                computeExpressionConversionCost(
     166                                        args[i], *param, symtab, cand->env, convCost ) );
     167                        convCost.decSpec( specCost( *param ) );
     168                        ++param;  // can't be in for-loop update because of the continue
     169                }
     170
     171                if ( param != params.end() ) return Cost::infinity;
     172
     173                // specialization cost of return types can't be accounted for directly, it disables
     174                // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
     175                //
     176                //   forall(otype OS) {
     177                //     void ?|?(OS&, int);  // with newline
     178                //     OS&  ?|?(OS&, int);  // no newline, always chosen due to more specialization
     179                //   }
     180
     181                // mark type variable and specialization cost of forall clause
     182                convCost.incVar( function->forall.size() );
     183                convCost.decSpec( function->assertions.size() );
     184
     185                return convCost;
     186        }
     187
     188        void makeUnifiableVars(
     189                const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
     190                ast::AssertionSet & need
     191        ) {
     192                for ( auto & tyvar : type->forall ) {
     193                        unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };
     194                }
     195                for ( auto & assn : type->assertions ) {
     196                        need[ assn ].isUsed = true;
     197                }
     198        }
     199
     200        /// Gets a default value from an initializer, nullptr if not present
     201        const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {
     202                if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {
     203                        if ( auto ce = si->value.as< ast::CastExpr >() ) {
     204                                return ce->arg.as< ast::ConstantExpr >();
     205                        } else {
     206                                return si->value.as< ast::ConstantExpr >();
     207                        }
     208                }
     209                return nullptr;
     210        }
     211
     212        /// State to iteratively build a match of parameter expressions to arguments
     213        struct ArgPack {
     214                std::size_t parent;          ///< Index of parent pack
     215                ast::ptr< ast::Expr > expr;  ///< The argument stored here
     216                Cost cost;                   ///< The cost of this argument
     217                ast::TypeEnvironment env;    ///< Environment for this pack
     218                ast::AssertionSet need;      ///< Assertions outstanding for this pack
     219                ast::AssertionSet have;      ///< Assertions found for this pack
     220                ast::OpenVarSet open;        ///< Open variables for this pack
     221                unsigned nextArg;            ///< Index of next argument in arguments list
     222                unsigned tupleStart;         ///< Number of tuples that start at this index
     223                unsigned nextExpl;           ///< Index of next exploded element
     224                unsigned explAlt;            ///< Index of alternative for nextExpl > 0
     225
     226                ArgPack()
     227                : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
     228                  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     229
     230                ArgPack(
     231                        const ast::TypeEnvironment & env, const ast::AssertionSet & need,
     232                        const ast::AssertionSet & have, const ast::OpenVarSet & open )
     233                : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
     234                  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
     235
     236                ArgPack(
     237                        std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
     238                        ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
     239                        unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
     240                        unsigned nextExpl = 0, unsigned explAlt = 0 )
     241                : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),
     242                  have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
     243                  nextExpl( nextExpl ), explAlt( explAlt ) {}
     244
     245                ArgPack(
     246                        const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
     247                        ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
     248                : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),
     249                  need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),
     250                  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
     251
     252                /// true if this pack is in the middle of an exploded argument
     253                bool hasExpl() const { return nextExpl > 0; }
     254
     255                /// Gets the list of exploded candidates for this pack
     256                const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {
     257                        return args[ nextArg-1 ][ explAlt ];
     258                }
     259
     260                /// Ends a tuple expression, consolidating the appropriate args
     261                void endTuple( const std::vector< ArgPack > & packs ) {
     262                        // add all expressions in tuple to list, summing cost
     263                        std::deque< const ast::Expr * > exprs;
     264                        const ArgPack * pack = this;
     265                        if ( expr ) { exprs.emplace_front( expr ); }
     266                        while ( pack->tupleStart == 0 ) {
     267                                pack = &packs[pack->parent];
     268                                exprs.emplace_front( pack->expr );
     269                                cost += pack->cost;
     270                        }
     271                        // reset pack to appropriate tuple
     272                        std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );
     273                        expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };
     274                        tupleStart = pack->tupleStart - 1;
     275                        parent = pack->parent;
     276                }
     277        };
     278
     279        /// Instantiates an argument to match a parameter, returns false if no matching results left
     280        bool instantiateArgument(
     281                const CodeLocation & location,
     282                const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
     283                std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
     284                unsigned nTuples = 0
     285        ) {
     286                if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
     287                        // paramType is a TupleType -- group args into a TupleExpr
     288                        ++nTuples;
     289                        for ( const ast::Type * type : *tupleType ) {
     290                                // xxx - dropping initializer changes behaviour from previous, but seems correct
     291                                // ^^^ need to handle the case where a tuple has a default argument
     292                                if ( ! instantiateArgument( location,
     293                                        type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
     294                                nTuples = 0;
     295                        }
     296                        // re-constitute tuples for final generation
     297                        for ( auto i = genStart; i < results.size(); ++i ) {
     298                                results[i].endTuple( results );
     299                        }
     300                        return true;
     301                } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
     302                        // paramType is a ttype, consumes all remaining arguments
     303
     304                        // completed tuples; will be spliced to end of results to finish
     305                        std::vector< ArgPack > finalResults{};
     306
     307                        // iterate until all results completed
     308                        std::size_t genEnd;
     309                        ++nTuples;
     310                        do {
     311                                genEnd = results.size();
     312
     313                                // add another argument to results
     314                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     315                                        unsigned nextArg = results[i].nextArg;
     316
     317                                        // use next element of exploded tuple if present
     318                                        if ( results[i].hasExpl() ) {
     319                                                const ExplodedArg & expl = results[i].getExpl( args );
     320
     321                                                unsigned nextExpl = results[i].nextExpl + 1;
     322                                                if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     323
     324                                                results.emplace_back(
     325                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
     326                                                        copy( results[i].need ), copy( results[i].have ),
     327                                                        copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
     328                                                        results[i].explAlt );
     329
     330                                                continue;
     331                                        }
     332
     333                                        // finish result when out of arguments
     334                                        if ( nextArg >= args.size() ) {
     335                                                ArgPack newResult{
     336                                                        results[i].env, results[i].need, results[i].have, results[i].open };
     337                                                newResult.nextArg = nextArg;
     338                                                const ast::Type * argType = nullptr;
     339
     340                                                if ( nTuples > 0 || ! results[i].expr ) {
     341                                                        // first iteration or no expression to clone,
     342                                                        // push empty tuple expression
     343                                                        newResult.parent = i;
     344                                                        newResult.expr = new ast::TupleExpr( location, {} );
     345                                                        argType = newResult.expr->result;
     346                                                } else {
     347                                                        // clone result to collect tuple
     348                                                        newResult.parent = results[i].parent;
     349                                                        newResult.cost = results[i].cost;
     350                                                        newResult.tupleStart = results[i].tupleStart;
     351                                                        newResult.expr = results[i].expr;
     352                                                        argType = newResult.expr->result;
     353
     354                                                        if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
     355                                                                // the case where a ttype value is passed directly is special,
     356                                                                // e.g. for argument forwarding purposes
     357                                                                // xxx - what if passing multiple arguments, last of which is
     358                                                                //       ttype?
     359                                                                // xxx - what would happen if unify was changed so that unifying
     360                                                                //       tuple
     361                                                                // types flattened both before unifying lists? then pass in
     362                                                                // TupleType (ttype) below.
     363                                                                --newResult.tupleStart;
     364                                                        } else {
     365                                                                // collapse leftover arguments into tuple
     366                                                                newResult.endTuple( results );
     367                                                                argType = newResult.expr->result;
     368                                                        }
     369                                                }
     370
     371                                                // check unification for ttype before adding to final
     372                                                if (
     373                                                        unify(
     374                                                                ttype, argType, newResult.env, newResult.need, newResult.have,
     375                                                                newResult.open, symtab )
     376                                                ) {
     377                                                        finalResults.emplace_back( std::move( newResult ) );
     378                                                }
     379
     380                                                continue;
     381                                        }
     382
     383                                        // add each possible next argument
     384                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     385                                                const ExplodedArg & expl = args[nextArg][j];
     386
     387                                                // fresh copies of parent parameters for this iteration
     388                                                ast::TypeEnvironment env = results[i].env;
     389                                                ast::OpenVarSet open = results[i].open;
     390
     391                                                env.addActual( expl.env, open );
     392
     393                                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     394                                                if ( expl.exprs.empty() ) {
     395                                                        results.emplace_back(
     396                                                                results[i], std::move( env ), copy( results[i].need ),
     397                                                                copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );
     398
     399                                                        continue;
     400                                                }
     401
     402                                                // add new result
     403                                                results.emplace_back(
     404                                                        i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
     405                                                        copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,
     406                                                        expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
     407                                        }
     408                                }
     409
     410                                // reset for next round
     411                                genStart = genEnd;
     412                                nTuples = 0;
     413                        } while ( genEnd != results.size() );
     414
     415                        // splice final results onto results
     416                        for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
     417                                results.emplace_back( std::move( finalResults[i] ) );
     418                        }
     419                        return ! finalResults.empty();
     420                }
     421
     422                // iterate each current subresult
     423                std::size_t genEnd = results.size();
     424                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     425                        unsigned nextArg = results[i].nextArg;
     426
     427                        // use remainder of exploded tuple if present
     428                        if ( results[i].hasExpl() ) {
     429                                const ExplodedArg & expl = results[i].getExpl( args );
     430                                const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];
     431
     432                                ast::TypeEnvironment env = results[i].env;
     433                                ast::AssertionSet need = results[i].need, have = results[i].have;
     434                                ast::OpenVarSet open = results[i].open;
     435
     436                                const ast::Type * argType = expr->result;
     437
     438                                PRINT(
     439                                        std::cerr << "param type is ";
     440                                        ast::print( std::cerr, paramType );
     441                                        std::cerr << std::endl << "arg type is ";
     442                                        ast::print( std::cerr, argType );
     443                                        std::cerr << std::endl;
     444                                )
     445
     446                                if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
     447                                        unsigned nextExpl = results[i].nextExpl + 1;
     448                                        if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     449
     450                                        results.emplace_back(
     451                                                i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,
     452                                                nTuples, Cost::zero, nextExpl, results[i].explAlt );
     453                                }
     454
     455                                continue;
     456                        }
     457
     458                        // use default initializers if out of arguments
     459                        if ( nextArg >= args.size() ) {
     460                                if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {
     461                                        ast::TypeEnvironment env = results[i].env;
     462                                        ast::AssertionSet need = results[i].need, have = results[i].have;
     463                                        ast::OpenVarSet open = results[i].open;
     464
     465                                        if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
     466                                                results.emplace_back(
     467                                                        i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),
     468                                                        std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );
     469                                        }
     470                                }
     471
     472                                continue;
     473                        }
     474
     475                        // Check each possible next argument
     476                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     477                                const ExplodedArg & expl = args[nextArg][j];
     478
     479                                // fresh copies of parent parameters for this iteration
     480                                ast::TypeEnvironment env = results[i].env;
     481                                ast::AssertionSet need = results[i].need, have = results[i].have;
     482                                ast::OpenVarSet open = results[i].open;
     483
     484                                env.addActual( expl.env, open );
     485
     486                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     487                                if ( expl.exprs.empty() ) {
     488                                        results.emplace_back(
     489                                                results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),
     490                                                nextArg + 1, expl.cost );
     491
     492                                        continue;
     493                                }
     494
     495                                // consider only first exploded arg
     496                                const ast::Expr * expr = expl.exprs.front();
     497                                const ast::Type * argType = expr->result;
     498
     499                                PRINT(
     500                                        std::cerr << "param type is ";
     501                                        ast::print( std::cerr, paramType );
     502                                        std::cerr << std::endl << "arg type is ";
     503                                        ast::print( std::cerr, argType );
     504                                        std::cerr << std::endl;
     505                                )
     506
     507                                // attempt to unify types
     508                                if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
     509                                        // add new result
     510                                        results.emplace_back(
     511                                                i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
     512                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
     513                                }
     514                        }
     515                }
     516
     517                // reset for next parameter
     518                genStart = genEnd;
     519
     520                return genEnd != results.size();  // were any new results added?
     521        }
     522
     523        /// Generate a cast expression from `arg` to `toType`
     524        const ast::Expr * restructureCast(
     525                ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
     526        ) {
     527                if (
     528                        arg->result->size() > 1
     529                        && ! toType->isVoid()
     530                        && ! dynamic_cast< const ast::ReferenceType * >( toType )
     531                ) {
     532                        // Argument is a tuple and the target type is neither void nor a reference. Cast each
     533                        // member of the tuple to its corresponding target type, producing the tuple of those
     534                        // cast expressions. If there are more components of the tuple than components in the
     535                        // target type, then excess components do not come out in the result expression (but
     536                        // UniqueExpr ensures that the side effects will still be produced)
     537                        if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
     538                                // expressions which may contain side effects require a single unique instance of
     539                                // the expression
     540                                arg = new ast::UniqueExpr{ arg->location, arg };
     541                        }
     542                        std::vector< ast::ptr< ast::Expr > > components;
     543                        for ( unsigned i = 0; i < toType->size(); ++i ) {
     544                                // cast each component
     545                                ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
     546                                components.emplace_back(
     547                                        restructureCast( idx, toType->getComponent( i ), isGenerated ) );
     548                        }
     549                        return new ast::TupleExpr{ arg->location, std::move( components ) };
     550                } else {
     551                        // handle normally
     552                        return new ast::CastExpr{ arg->location, arg, toType, isGenerated };
     553                }
     554        }
     555
     556        /// Gets the name from an untyped member expression (must be NameExpr)
     557        const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {
     558                if ( memberExpr->member.as< ast::ConstantExpr >() ) {
     559                        SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
     560                }
     561
     562                return memberExpr->member.strict_as< ast::NameExpr >()->name;
     563        }
     564
     565        /// Actually visits expressions to find their candidate interpretations
     566        class Finder final : public ast::WithShortCircuiting {
     567                const ResolveContext & context;
     568                const ast::SymbolTable & symtab;
     569        public:
     570                // static size_t traceId;
     571                CandidateFinder & selfFinder;
     572                CandidateList & candidates;
     573                const ast::TypeEnvironment & tenv;
     574                ast::ptr< ast::Type > & targetType;
     575
     576                enum Errors {
     577                        NotFound,
     578                        NoMatch,
     579                        ArgsToFew,
     580                        ArgsToMany,
     581                        RetsToFew,
     582                        RetsToMany,
     583                        NoReason
     584                };
     585
     586                struct {
     587                        Errors code = NotFound;
     588                } reason;
     589
     590                Finder( CandidateFinder & f )
     591                : context( f.context ), symtab( context.symtab ), selfFinder( f ),
     592                  candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}
     593
     594                void previsit( const ast::Node * ) { visit_children = false; }
     595
     596                /// Convenience to add candidate to list
     597                template<typename... Args>
     598                void addCandidate( Args &&... args ) {
     599                        candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
     600                        reason.code = NoReason;
     601                }
     602
     603                void postvisit( const ast::ApplicationExpr * applicationExpr ) {
     604                        addCandidate( applicationExpr, tenv );
     605                }
     606
     607                /// Set up candidate assertions for inference
     608                void inferParameters( CandidateRef & newCand, CandidateList & out );
     609
     610                /// Completes a function candidate with arguments located
     611                void validateFunctionCandidate(
     612                        const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
     613                        CandidateList & out );
     614
     615                /// Builds a list of candidates for a function, storing them in out
     616                void makeFunctionCandidates(
     617                        const CodeLocation & location,
     618                        const CandidateRef & func, const ast::FunctionType * funcType,
     619                        const ExplodedArgs_new & args, CandidateList & out );
     620
     621                /// Adds implicit struct-conversions to the alternative list
     622                void addAnonConversions( const CandidateRef & cand );
     623
     624                /// Adds aggregate member interpretations
     625                void addAggMembers(
     626                        const ast::BaseInstType * aggrInst, const ast::Expr * expr,
     627                        const Candidate & cand, const Cost & addedCost, const std::string & name
     628                );
     629
     630                /// Adds tuple member interpretations
     631                void addTupleMembers(
     632                        const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
     633                        const Cost & addedCost, const ast::Expr * member
     634                );
     635
     636                /// true if expression is an lvalue
     637                static bool isLvalue( const ast::Expr * x ) {
     638                        return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
     639                }
     640
     641                void postvisit( const ast::UntypedExpr * untypedExpr );
     642                void postvisit( const ast::VariableExpr * variableExpr );
     643                void postvisit( const ast::ConstantExpr * constantExpr );
     644                void postvisit( const ast::SizeofExpr * sizeofExpr );
     645                void postvisit( const ast::AlignofExpr * alignofExpr );
     646                void postvisit( const ast::AddressExpr * addressExpr );
     647                void postvisit( const ast::LabelAddressExpr * labelExpr );
     648                void postvisit( const ast::CastExpr * castExpr );
     649                void postvisit( const ast::VirtualCastExpr * castExpr );
     650                void postvisit( const ast::KeywordCastExpr * castExpr );
     651                void postvisit( const ast::UntypedMemberExpr * memberExpr );
     652                void postvisit( const ast::MemberExpr * memberExpr );
     653                void postvisit( const ast::NameExpr * nameExpr );
     654                void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr );
     655                void postvisit( const ast::OffsetofExpr * offsetofExpr );
     656                void postvisit( const ast::OffsetPackExpr * offsetPackExpr );
     657                void postvisit( const ast::LogicalExpr * logicalExpr );
     658                void postvisit( const ast::ConditionalExpr * conditionalExpr );
     659                void postvisit( const ast::CommaExpr * commaExpr );
     660                void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr );
     661                void postvisit( const ast::ConstructorExpr * ctorExpr );
     662                void postvisit( const ast::RangeExpr * rangeExpr );
     663                void postvisit( const ast::UntypedTupleExpr * tupleExpr );
     664                void postvisit( const ast::TupleExpr * tupleExpr );
     665                void postvisit( const ast::TupleIndexExpr * tupleExpr );
     666                void postvisit( const ast::TupleAssignExpr * tupleExpr );
     667                void postvisit( const ast::UniqueExpr * unqExpr );
     668                void postvisit( const ast::StmtExpr * stmtExpr );
     669                void postvisit( const ast::UntypedInitExpr * initExpr );
     670
     671                void postvisit( const ast::InitExpr * ) {
     672                        assertf( false, "CandidateFinder should never see a resolved InitExpr." );
     673                }
     674
     675                void postvisit( const ast::DeletedExpr * ) {
     676                        assertf( false, "CandidateFinder should never see a DeletedExpr." );
     677                }
     678
     679                void postvisit( const ast::GenericExpr * ) {
     680                        assertf( false, "_Generic is not yet supported." );
     681                }
     682        };
     683
     684        /// Set up candidate assertions for inference
     685        void Finder::inferParameters( CandidateRef & newCand, CandidateList & out ) {
     686                // Set need bindings for any unbound assertions
     687                UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
     688                for ( auto & assn : newCand->need ) {
     689                        // skip already-matched assertions
     690                        if ( assn.second.resnSlot != 0 ) continue;
     691                        // assign slot for expression if needed
     692                        if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }
     693                        // fix slot to assertion
     694                        assn.second.resnSlot = crntResnSlot;
     695                }
     696                // pair slot to expression
     697                if ( crntResnSlot != 0 ) {
     698                        newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );
     699                }
     700
     701                // add to output list; assertion satisfaction will occur later
     702                out.emplace_back( newCand );
     703        }
     704
     705        /// Completes a function candidate with arguments located
     706        void Finder::validateFunctionCandidate(
     707                const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
     708                CandidateList & out
     709        ) {
     710                ast::ApplicationExpr * appExpr =
     711                        new ast::ApplicationExpr{ func->expr->location, func->expr };
     712                // sum cost and accumulate arguments
     713                std::deque< const ast::Expr * > args;
     714                Cost cost = func->cost;
     715                const ArgPack * pack = &result;
     716                while ( pack->expr ) {
     717                        args.emplace_front( pack->expr );
     718                        cost += pack->cost;
     719                        pack = &results[pack->parent];
     720                }
     721                std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );
     722                appExpr->args = std::move( vargs );
     723                // build and validate new candidate
     724                auto newCand =
     725                        std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
     726                PRINT(
     727                        std::cerr << "instantiate function success: " << appExpr << std::endl;
     728                        std::cerr << "need assertions:" << std::endl;
     729                        ast::print( std::cerr, result.need, 2 );
     730                )
     731                inferParameters( newCand, out );
     732        }
     733
     734        /// Builds a list of candidates for a function, storing them in out
     735        void Finder::makeFunctionCandidates(
     736                const CodeLocation & location,
     737                const CandidateRef & func, const ast::FunctionType * funcType,
     738                const ExplodedArgs_new & args, CandidateList & out
     739        ) {
     740                ast::OpenVarSet funcOpen;
     741                ast::AssertionSet funcNeed, funcHave;
     742                ast::TypeEnvironment funcEnv{ func->env };
     743                makeUnifiableVars( funcType, funcOpen, funcNeed );
     744                // add all type variables as open variables now so that those not used in the
     745                // parameter list are still considered open
     746                funcEnv.add( funcType->forall );
     747
     748                if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
     749                        // attempt to narrow based on expected target type
     750                        const ast::Type * returnType = funcType->returns.front();
     751                        if ( ! unify(
     752                                returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
     753                        ) {
     754                                // unification failed, do not pursue this candidate
     755                                return;
     756                        }
     757                }
     758
     759                // iteratively build matches, one parameter at a time
     760                std::vector< ArgPack > results;
     761                results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );
     762                std::size_t genStart = 0;
     763
     764                // xxx - how to handle default arg after change to ftype representation?
     765                if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
     766                        if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
     767                                // function may have default args only if directly calling by name
     768                                // must use types on candidate however, due to RenameVars substitution
     769                                auto nParams = funcType->params.size();
     770
     771                                for (size_t i=0; i<nParams; ++i) {
     772                                        auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
     773                                        if (!instantiateArgument( location,
     774                                                funcType->params[i], obj->init, args, results, genStart, symtab)) return;
     775                                }
     776                                goto endMatch;
     777                        }
     778                }
     779                for ( const auto & param : funcType->params ) {
     780                        // Try adding the arguments corresponding to the current parameter to the existing
     781                        // matches
     782                        // no default args for indirect calls
     783                        if ( ! instantiateArgument( location,
     784                                param, nullptr, args, results, genStart, symtab ) ) return;
     785                }
     786
     787                endMatch:
     788                if ( funcType->isVarArgs ) {
     789                        // append any unused arguments to vararg pack
     790                        std::size_t genEnd;
     791                        do {
     792                                genEnd = results.size();
     793
     794                                // iterate results
     795                                for ( std::size_t i = genStart; i < genEnd; ++i ) {
     796                                        unsigned nextArg = results[i].nextArg;
     797
     798                                        // use remainder of exploded tuple if present
     799                                        if ( results[i].hasExpl() ) {
     800                                                const ExplodedArg & expl = results[i].getExpl( args );
     801
     802                                                unsigned nextExpl = results[i].nextExpl + 1;
     803                                                if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
     804
     805                                                results.emplace_back(
     806                                                        i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
     807                                                        copy( results[i].need ), copy( results[i].have ),
     808                                                        copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,
     809                                                        results[i].explAlt );
     810
     811                                                continue;
     812                                        }
     813
     814                                        // finish result when out of arguments
     815                                        if ( nextArg >= args.size() ) {
     816                                                validateFunctionCandidate( func, results[i], results, out );
     817
     818                                                continue;
     819                                        }
     820
     821                                        // add each possible next argument
     822                                        for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
     823                                                const ExplodedArg & expl = args[nextArg][j];
     824
     825                                                // fresh copies of parent parameters for this iteration
     826                                                ast::TypeEnvironment env = results[i].env;
     827                                                ast::OpenVarSet open = results[i].open;
     828
     829                                                env.addActual( expl.env, open );
     830
     831                                                // skip empty tuple arguments by (nearly) cloning parent into next gen
     832                                                if ( expl.exprs.empty() ) {
     833                                                        results.emplace_back(
     834                                                                results[i], std::move( env ), copy( results[i].need ),
     835                                                                copy( results[i].have ), std::move( open ), nextArg + 1,
     836                                                                expl.cost );
     837
     838                                                        continue;
     839                                                }
     840
     841                                                // add new result
     842                                                results.emplace_back(
     843                                                        i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
     844                                                        copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,
     845                                                        expl.exprs.size() == 1 ? 0 : 1, j );
     846                                        }
     847                                }
     848
     849                                genStart = genEnd;
     850                        } while( genEnd != results.size() );
     851                } else {
     852                        // filter out the results that don't use all the arguments
     853                        for ( std::size_t i = genStart; i < results.size(); ++i ) {
     854                                ArgPack & result = results[i];
     855                                if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
     856                                        validateFunctionCandidate( func, result, results, out );
     857                                }
     858                        }
     859                }
     860        }
     861
     862        /// Adds implicit struct-conversions to the alternative list
     863        void Finder::addAnonConversions( const CandidateRef & cand ) {
     864                // adds anonymous member interpretations whenever an aggregate value type is seen.
     865                // it's okay for the aggregate expression to have reference type -- cast it to the
     866                // base type to treat the aggregate as the referenced value
     867                ast::ptr< ast::Expr > aggrExpr( cand->expr );
     868                ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
     869                cand->env.apply( aggrType );
     870
     871                if ( aggrType.as< ast::ReferenceType >() ) {
     872                        aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
     873                }
     874
     875                if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
     876                        addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
     877                } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
     878                        addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
     879                }
     880        }
     881
     882        /// Adds aggregate member interpretations
     883        void Finder::addAggMembers(
     884                const ast::BaseInstType * aggrInst, const ast::Expr * expr,
     885                const Candidate & cand, const Cost & addedCost, const std::string & name
     886        ) {
     887                for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
     888                        auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
     889                        CandidateRef newCand = std::make_shared<Candidate>(
     890                                cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
     891                        // add anonymous member interpretations whenever an aggregate value type is seen
     892                        // as a member expression
     893                        addAnonConversions( newCand );
     894                        candidates.emplace_back( std::move( newCand ) );
     895                }
     896        }
     897
     898        /// Adds tuple member interpretations
     899        void Finder::addTupleMembers(
     900                const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
     901                const Cost & addedCost, const ast::Expr * member
     902        ) {
     903                if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
     904                        // get the value of the constant expression as an int, must be between 0 and the
     905                        // length of the tuple to have meaning
     906                        long long val = constantExpr->intValue();
     907                        if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
     908                                addCandidate(
     909                                        cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
     910                                        addedCost );
     911                        }
     912                }
     913        }
     914
     915        void Finder::postvisit( const ast::UntypedExpr * untypedExpr ) {
     916                std::vector< CandidateFinder > argCandidates =
     917                        selfFinder.findSubExprs( untypedExpr->args );
     918
     919                // take care of possible tuple assignments
     920                // if not tuple assignment, handled as normal function call
     921                Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
     922
     923                CandidateFinder funcFinder( context, tenv );
     924                if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
     925                        auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
     926                        if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
     927                                assertf(!argCandidates.empty(), "special function call without argument");
     928                                for (auto & firstArgCand: argCandidates[0]) {
     929                                        ast::ptr<ast::Type> argType = firstArgCand->expr->result;
     930                                        firstArgCand->env.apply(argType);
     931                                        // strip references
     932                                        // xxx - is this correct?
     933                                        while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
     934
     935                                        // convert 1-tuple to plain type
     936                                        if (auto tuple = argType.as<ast::TupleType>()) {
     937                                                if (tuple->size() == 1) {
     938                                                        argType = tuple->types[0];
     939                                                }
     940                                        }
     941
     942                                        // if argType is an unbound type parameter, all special functions need to be searched.
     943                                        if (isUnboundType(argType)) {
     944                                                funcFinder.otypeKeys.clear();
     945                                                break;
     946                                        }
     947
     948                                        if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);                                             
     949                                        // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {
     950                                        //      const ast::EnumDecl * enumDecl = enumInst->base; // Here
     951                                        //      if ( const ast::Type* enumType = enumDecl->base ) {
     952                                        //              // instance of enum (T) is a instance of type (T)
     953                                        //              funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));
     954                                        //      } else {
     955                                        //              // instance of an untyped enum is techically int
     956                                        //              funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));
     957                                        //      }
     958                                        // }
     959                                        else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
     960                                }
     961                        }
     962                }
     963                // if candidates are already produced, do not fail
     964                // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
     965                // this means there exists ctor/assign functions with a tuple as first parameter.
     966                ResolvMode mode = {
     967                        true, // adjust
     968                        !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
     969                        selfFinder.candidates.empty() // failfast if other options are not found
     970                };
     971                funcFinder.find( untypedExpr->func, mode );
     972                // short-circuit if no candidates
     973                // if ( funcFinder.candidates.empty() ) return;
     974
     975                reason.code = NoMatch;
     976
     977                // find function operators
     978                ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}
     979                CandidateFinder opFinder( context, tenv );
     980                // okay if there aren't any function operations
     981                opFinder.find( opExpr, ResolvMode::withoutFailFast() );
     982                PRINT(
     983                        std::cerr << "known function ops:" << std::endl;
     984                        print( std::cerr, opFinder.candidates, 1 );
     985                )
     986
     987                // pre-explode arguments
     988                ExplodedArgs_new argExpansions;
     989                for ( const CandidateFinder & args : argCandidates ) {
     990                        argExpansions.emplace_back();
     991                        auto & argE = argExpansions.back();
     992                        for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
     993                }
     994
     995                // Find function matches
     996                CandidateList found;
     997                SemanticErrorException errors;
     998                for ( CandidateRef & func : funcFinder ) {
     999                        try {
     1000                                PRINT(
     1001                                        std::cerr << "working on alternative:" << std::endl;
     1002                                        print( std::cerr, *func, 2 );
     1003                                )
     1004
     1005                                // check if the type is a pointer to function
     1006                                const ast::Type * funcResult = func->expr->result->stripReferences();
     1007                                if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
     1008                                        if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     1009                                                CandidateRef newFunc{ new Candidate{ *func } };
     1010                                                newFunc->expr =
     1011                                                        referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     1012                                                makeFunctionCandidates( untypedExpr->location,
     1013                                                        newFunc, function, argExpansions, found );
     1014                                        }
     1015                                } else if (
     1016                                        auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
     1017                                ) {
     1018                                        if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
     1019                                                if ( auto function = clz->bound.as< ast::FunctionType >() ) {
     1020                                                        CandidateRef newFunc{ new Candidate{ *func } };
     1021                                                        newFunc->expr =
     1022                                                                referenceToRvalueConversion( newFunc->expr, newFunc->cost );
     1023                                                        makeFunctionCandidates( untypedExpr->location,
     1024                                                                newFunc, function, argExpansions, found );
     1025                                                }
     1026                                        }
     1027                                }
     1028                        } catch ( SemanticErrorException & e ) { errors.append( e ); }
     1029                }
     1030
     1031                // Find matches on function operators `?()`
     1032                if ( ! opFinder.candidates.empty() ) {
     1033                        // add exploded function alternatives to front of argument list
     1034                        std::vector< ExplodedArg > funcE;
     1035                        funcE.reserve( funcFinder.candidates.size() );
     1036                        for ( const CandidateRef & func : funcFinder ) {
     1037                                funcE.emplace_back( *func, symtab );
     1038                        }
     1039                        argExpansions.emplace_front( std::move( funcE ) );
     1040
     1041                        for ( const CandidateRef & op : opFinder ) {
     1042                                try {
     1043                                        // check if type is pointer-to-function
     1044                                        const ast::Type * opResult = op->expr->result->stripReferences();
     1045                                        if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
     1046                                                if ( auto function = pointer->base.as< ast::FunctionType >() ) {
     1047                                                        CandidateRef newOp{ new Candidate{ *op} };
     1048                                                        newOp->expr =
     1049                                                                referenceToRvalueConversion( newOp->expr, newOp->cost );
     1050                                                        makeFunctionCandidates( untypedExpr->location,
     1051                                                                newOp, function, argExpansions, found );
     1052                                                }
     1053                                        }
     1054                                } catch ( SemanticErrorException & e ) { errors.append( e ); }
     1055                        }
     1056                }
     1057
     1058                // Implement SFINAE; resolution errors are only errors if there aren't any non-error
     1059                // candidates
     1060                if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
     1061
     1062                // Compute conversion costs
     1063                for ( CandidateRef & withFunc : found ) {
     1064                        Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
     1065
     1066                        PRINT(
     1067                                auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
     1068                                auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
     1069                                auto function = pointer->base.strict_as< ast::FunctionType >();
     1070
     1071                                std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
     1072                                std::cerr << "parameters are:" << std::endl;
     1073                                ast::printAll( std::cerr, function->params, 2 );
     1074                                std::cerr << "arguments are:" << std::endl;
     1075                                ast::printAll( std::cerr, appExpr->args, 2 );
     1076                                std::cerr << "bindings are:" << std::endl;
     1077                                ast::print( std::cerr, withFunc->env, 2 );
     1078                                std::cerr << "cost is: " << withFunc->cost << std::endl;
     1079                                std::cerr << "cost of conversion is:" << cvtCost << std::endl;
     1080                        )
     1081
     1082                        if ( cvtCost != Cost::infinity ) {
     1083                                withFunc->cvtCost = cvtCost;
     1084                                candidates.emplace_back( std::move( withFunc ) );
     1085                        }
     1086                }
     1087                found = std::move( candidates );
     1088
     1089                // use a new list so that candidates are not examined by addAnonConversions twice
     1090                CandidateList winners = findMinCost( found );
     1091                promoteCvtCost( winners );
     1092
     1093                // function may return a struct/union value, in which case we need to add candidates
     1094                // for implicit conversions to each of the anonymous members, which must happen after
     1095                // `findMinCost`, since anon conversions are never the cheapest
     1096                for ( const CandidateRef & c : winners ) {
     1097                        addAnonConversions( c );
     1098                }
     1099                spliceBegin( candidates, winners );
     1100
     1101                if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
     1102                        // If resolution is unsuccessful with a target type, try again without, since it
     1103                        // will sometimes succeed when it wouldn't with a target type binding.
     1104                        // For example:
     1105                        //   forall( otype T ) T & ?[]( T *, ptrdiff_t );
     1106                        //   const char * x = "hello world";
     1107                        //   unsigned char ch = x[0];
     1108                        // Fails with simple return type binding (xxx -- check this!) as follows:
     1109                        // * T is bound to unsigned char
     1110                        // * (x: const char *) is unified with unsigned char *, which fails
     1111                        // xxx -- fix this better
     1112                        targetType = nullptr;
     1113                        postvisit( untypedExpr );
     1114                }
     1115        }
     1116
     1117        void Finder::postvisit( const ast::AddressExpr * addressExpr ) {
     1118                CandidateFinder finder( context, tenv );
     1119                finder.find( addressExpr->arg );
     1120
     1121                if ( finder.candidates.empty() ) return;
     1122
     1123                reason.code = NoMatch;
     1124
     1125                for ( CandidateRef & r : finder.candidates ) {
     1126                        if ( ! isLvalue( r->expr ) ) continue;
     1127                        addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
     1128                }
     1129        }
     1130
     1131        void Finder::postvisit( const ast::LabelAddressExpr * labelExpr ) {
     1132                addCandidate( labelExpr, tenv );
     1133        }
     1134
     1135        void Finder::postvisit( const ast::CastExpr * castExpr ) {
     1136                ast::ptr< ast::Type > toType = castExpr->result;
     1137                assert( toType );
     1138                toType = resolveTypeof( toType, context );
     1139                toType = adjustExprType( toType, tenv, symtab );
     1140
     1141                CandidateFinder finder( context, tenv, toType );
     1142                finder.find( castExpr->arg, ResolvMode::withAdjustment() );
     1143
     1144                if ( !finder.candidates.empty() ) reason.code = NoMatch;
     1145
     1146                CandidateList matches;
     1147                for ( CandidateRef & cand : finder.candidates ) {
     1148                        ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     1149                        ast::OpenVarSet open( cand->open );
     1150
     1151                        cand->env.extractOpenVars( open );
     1152
     1153                        // It is possible that a cast can throw away some values in a multiply-valued
     1154                        // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
     1155                        // subexpression results that are cast directly. The candidate is invalid if it
     1156                        // has fewer results than there are types to cast to.
     1157                        int discardedValues = cand->expr->result->size() - toType->size();
     1158                        if ( discardedValues < 0 ) continue;
     1159
     1160                        // unification run for side-effects
     1161                        unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
     1162                        Cost thisCost =
     1163                                (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
     1164                                        ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
     1165                                        : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
     1166
     1167                        PRINT(
     1168                                std::cerr << "working on cast with result: " << toType << std::endl;
     1169                                std::cerr << "and expr type: " << cand->expr->result << std::endl;
     1170                                std::cerr << "env: " << cand->env << std::endl;
     1171                        )
     1172                        if ( thisCost != Cost::infinity ) {
     1173                                PRINT(
     1174                                        std::cerr << "has finite cost." << std::endl;
     1175                                )
     1176                                // count one safe conversion for each value that is thrown away
     1177                                thisCost.incSafe( discardedValues );
     1178                                CandidateRef newCand = std::make_shared<Candidate>(
     1179                                        restructureCast( cand->expr, toType, castExpr->isGenerated ),
     1180                                        copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
     1181                                        cand->cost + thisCost );
     1182                                inferParameters( newCand, matches );
     1183                        }
     1184                }
     1185
     1186                // select first on argument cost, then conversion cost
     1187                CandidateList minArgCost = findMinCost( matches );
     1188                promoteCvtCost( minArgCost );
     1189                candidates = findMinCost( minArgCost );
     1190        }
     1191
     1192        void Finder::postvisit( const ast::VirtualCastExpr * castExpr ) {
     1193                assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
     1194                CandidateFinder finder( context, tenv );
     1195                // don't prune here, all alternatives guaranteed to have same type
     1196                finder.find( castExpr->arg, ResolvMode::withoutPrune() );
     1197                for ( CandidateRef & r : finder.candidates ) {
     1198                        addCandidate(
     1199                                *r,
     1200                                new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
     1201                }
     1202        }
     1203
     1204        void Finder::postvisit( const ast::KeywordCastExpr * castExpr ) {
     1205                const auto & loc = castExpr->location;
     1206                assertf( castExpr->result, "Cast target should have been set in Validate." );
     1207                auto ref = castExpr->result.strict_as<ast::ReferenceType>();
     1208                auto inst = ref->base.strict_as<ast::StructInstType>();
     1209                auto target = inst->base.get();
     1210
     1211                CandidateFinder finder( context, tenv );
     1212
     1213                auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
     1214                        for (auto & cand : found) {
     1215                                const ast::Type * expr = cand->expr->result.get();
     1216                                if (expect_ref) {
     1217                                        auto res = dynamic_cast<const ast::ReferenceType*>(expr);
     1218                                        if (!res) { continue; }
     1219                                        expr = res->base.get();
     1220                                }
     1221
     1222                                if (auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
     1223                                        auto td = cand->env.lookup(*insttype);
     1224                                        if (!td) { continue; }
     1225                                        expr = td->bound.get();
     1226                                }
     1227
     1228                                if (auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
     1229                                        if (base->base == target) {
     1230                                                candidates.push_back( std::move(cand) );
     1231                                                reason.code = NoReason;
     1232                                        }
     1233                                }
     1234                        }
     1235                };
     1236
     1237                try {
     1238                        // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd
     1239                        // Clone is purely for memory management
     1240                        std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
     1241
     1242                        // don't prune here, since it's guaranteed all alternatives will have the same type
     1243                        finder.find( tech1.get(), ResolvMode::withoutPrune() );
     1244                        pick_alternatives(finder.candidates, false);
     1245
     1246                        return;
     1247                } catch(SemanticErrorException & ) {}
     1248
     1249                // Fallback : turn (thread&)X into (thread$&)get_thread(X)
     1250                std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
     1251                // don't prune here, since it's guaranteed all alternatives will have the same type
     1252                finder.find( fallback.get(), ResolvMode::withoutPrune() );
     1253
     1254                pick_alternatives(finder.candidates, true);
     1255
     1256                // Whatever happens here, we have no more fallbacks
     1257        }
     1258
     1259        void Finder::postvisit( const ast::UntypedMemberExpr * memberExpr ) {
     1260                CandidateFinder aggFinder( context, tenv );
     1261                aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
     1262                for ( CandidateRef & agg : aggFinder.candidates ) {
     1263                        // it's okay for the aggregate expression to have reference type -- cast it to the
     1264                        // base type to treat the aggregate as the referenced value
     1265                        Cost addedCost = Cost::zero;
     1266                        agg->expr = referenceToRvalueConversion( agg->expr, addedCost );
     1267
     1268                        // find member of the given type
     1269                        if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
     1270                                addAggMembers(
     1271                                        structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
     1272                        } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
     1273                                addAggMembers(
     1274                                        unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
     1275                        } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
     1276                                addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );
     1277                        }
     1278                }
     1279        }
     1280
     1281        void Finder::postvisit( const ast::MemberExpr * memberExpr ) {
     1282                addCandidate( memberExpr, tenv );
     1283        }
     1284
     1285        void Finder::postvisit( const ast::NameExpr * nameExpr ) {
     1286                std::vector< ast::SymbolTable::IdData > declList;
     1287                if (!selfFinder.otypeKeys.empty()) {
     1288                        auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
     1289                        assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
     1290
     1291                        for (auto & otypeKey: selfFinder.otypeKeys) {
     1292                                auto result = symtab.specialLookupId(kind, otypeKey);
     1293                                declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
     1294                        }
     1295                } else {
     1296                        declList = symtab.lookupId( nameExpr->name );
     1297                }
     1298                PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
     1299
     1300                if ( declList.empty() ) return;
     1301
     1302                reason.code = NoMatch;
     1303
     1304                for ( auto & data : declList ) {
     1305                        Cost cost = Cost::zero;
     1306                        ast::Expr * newExpr = data.combine( nameExpr->location, cost );
     1307
     1308                        CandidateRef newCand = std::make_shared<Candidate>(
     1309                                newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
     1310                                cost );
     1311
     1312                        if (newCand->expr->env) {
     1313                                newCand->env.add(*newCand->expr->env);
     1314                                auto mutExpr = newCand->expr.get_and_mutate();
     1315                                mutExpr->env  = nullptr;
     1316                                newCand->expr = mutExpr;
     1317                        }
     1318
     1319                        PRINT(
     1320                                std::cerr << "decl is ";
     1321                                ast::print( std::cerr, data.id );
     1322                                std::cerr << std::endl;
     1323                                std::cerr << "newExpr is ";
     1324                                ast::print( std::cerr, newExpr );
     1325                                std::cerr << std::endl;
     1326                        )
     1327                        newCand->expr = ast::mutate_field(
     1328                                newCand->expr.get(), &ast::Expr::result,
     1329                                renameTyVars( newCand->expr->result ) );
     1330                        // add anonymous member interpretations whenever an aggregate value type is seen
     1331                        // as a name expression
     1332                        addAnonConversions( newCand );
     1333                        candidates.emplace_back( std::move( newCand ) );
     1334                }
     1335        }
     1336
     1337        void Finder::postvisit( const ast::VariableExpr * variableExpr ) {
     1338                // not sufficient to just pass `variableExpr` here, type might have changed since
     1339                // creation
     1340                addCandidate(
     1341                        new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
     1342        }
     1343
     1344        void Finder::postvisit( const ast::ConstantExpr * constantExpr ) {
     1345                addCandidate( constantExpr, tenv );
     1346        }
     1347
     1348        void Finder::postvisit( const ast::SizeofExpr * sizeofExpr ) {
     1349                if ( sizeofExpr->type ) {
     1350                        addCandidate(
     1351                                new ast::SizeofExpr{
     1352                                        sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },
     1353                                tenv );
     1354                } else {
     1355                        // find all candidates for the argument to sizeof
     1356                        CandidateFinder finder( context, tenv );
     1357                        finder.find( sizeofExpr->expr );
     1358                        // find the lowest-cost candidate, otherwise ambiguous
     1359                        CandidateList winners = findMinCost( finder.candidates );
     1360                        if ( winners.size() != 1 ) {
     1361                                SemanticError(
     1362                                        sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
     1363                        }
     1364                        // return the lowest-cost candidate
     1365                        CandidateRef & choice = winners.front();
     1366                        choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1367                        choice->cost = Cost::zero;
     1368                        addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );
     1369                }
     1370        }
     1371
     1372        void Finder::postvisit( const ast::AlignofExpr * alignofExpr ) {
     1373                if ( alignofExpr->type ) {
     1374                        addCandidate(
     1375                                new ast::AlignofExpr{
     1376                                        alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },
     1377                                tenv );
     1378                } else {
     1379                        // find all candidates for the argument to alignof
     1380                        CandidateFinder finder( context, tenv );
     1381                        finder.find( alignofExpr->expr );
     1382                        // find the lowest-cost candidate, otherwise ambiguous
     1383                        CandidateList winners = findMinCost( finder.candidates );
     1384                        if ( winners.size() != 1 ) {
     1385                                SemanticError(
     1386                                        alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
     1387                        }
     1388                        // return the lowest-cost candidate
     1389                        CandidateRef & choice = winners.front();
     1390                        choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1391                        choice->cost = Cost::zero;
     1392                        addCandidate(
     1393                                *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
     1394                }
     1395        }
     1396
     1397        void Finder::postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
     1398                const ast::BaseInstType * aggInst;
     1399                if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
     1400                else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
     1401                else return;
     1402
     1403                for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
     1404                        auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
     1405                        addCandidate(
     1406                                new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
     1407                }
     1408        }
     1409
     1410        void Finder::postvisit( const ast::OffsetofExpr * offsetofExpr ) {
     1411                addCandidate( offsetofExpr, tenv );
     1412        }
     1413
     1414        void Finder::postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {
     1415                addCandidate( offsetPackExpr, tenv );
     1416        }
     1417
     1418        void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) {
     1419                CandidateFinder finder1( context, tenv );
     1420                finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
     1421                if ( finder1.candidates.empty() ) return;
     1422
     1423                CandidateFinder finder2( context, tenv );
     1424                finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
     1425                if ( finder2.candidates.empty() ) return;
     1426
     1427                reason.code = NoMatch;
     1428
     1429                for ( const CandidateRef & r1 : finder1.candidates ) {
     1430                        for ( const CandidateRef & r2 : finder2.candidates ) {
     1431                                ast::TypeEnvironment env{ r1->env };
     1432                                env.simpleCombine( r2->env );
     1433                                ast::OpenVarSet open{ r1->open };
     1434                                mergeOpenVars( open, r2->open );
     1435                                ast::AssertionSet need;
     1436                                mergeAssertionSet( need, r1->need );
     1437                                mergeAssertionSet( need, r2->need );
     1438
     1439                                addCandidate(
     1440                                        new ast::LogicalExpr{
     1441                                                logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
     1442                                        std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );
     1443                        }
     1444                }
     1445        }
     1446
     1447        void Finder::postvisit( const ast::ConditionalExpr * conditionalExpr ) {
     1448                // candidates for condition
     1449                CandidateFinder finder1( context, tenv );
     1450                finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
     1451                if ( finder1.candidates.empty() ) return;
     1452
     1453                // candidates for true result
     1454                CandidateFinder finder2( context, tenv );
     1455                finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
     1456                if ( finder2.candidates.empty() ) return;
     1457
     1458                // candidates for false result
     1459                CandidateFinder finder3( context, tenv );
     1460                finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
     1461                if ( finder3.candidates.empty() ) return;
     1462
     1463                reason.code = NoMatch;
     1464
     1465                for ( const CandidateRef & r1 : finder1.candidates ) {
     1466                        for ( const CandidateRef & r2 : finder2.candidates ) {
     1467                                for ( const CandidateRef & r3 : finder3.candidates ) {
     1468                                        ast::TypeEnvironment env{ r1->env };
     1469                                        env.simpleCombine( r2->env );
     1470                                        env.simpleCombine( r3->env );
     1471                                        ast::OpenVarSet open{ r1->open };
     1472                                        mergeOpenVars( open, r2->open );
     1473                                        mergeOpenVars( open, r3->open );
     1474                                        ast::AssertionSet need;
     1475                                        mergeAssertionSet( need, r1->need );
     1476                                        mergeAssertionSet( need, r2->need );
     1477                                        mergeAssertionSet( need, r3->need );
     1478                                        ast::AssertionSet have;
     1479
     1480                                        // unify true and false results, then infer parameters to produce new
     1481                                        // candidates
     1482                                        ast::ptr< ast::Type > common;
     1483                                        if (
     1484                                                unify(
     1485                                                        r2->expr->result, r3->expr->result, env, need, have, open, symtab,
     1486                                                        common )
     1487                                        ) {
     1488                                                // generate typed expression
     1489                                                ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
     1490                                                        conditionalExpr->location, r1->expr, r2->expr, r3->expr };
     1491                                                newExpr->result = common ? common : r2->expr->result;
     1492                                                // convert both options to result type
     1493                                                Cost cost = r1->cost + r2->cost + r3->cost;
     1494                                                newExpr->arg2 = computeExpressionConversionCost(
     1495                                                        newExpr->arg2, newExpr->result, symtab, env, cost );
     1496                                                newExpr->arg3 = computeExpressionConversionCost(
     1497                                                        newExpr->arg3, newExpr->result, symtab, env, cost );
     1498                                                // output candidate
     1499                                                CandidateRef newCand = std::make_shared<Candidate>(
     1500                                                        newExpr, std::move( env ), std::move( open ), std::move( need ), cost );
     1501                                                inferParameters( newCand, candidates );
     1502                                        }
     1503                                }
     1504                        }
     1505                }
     1506        }
     1507
     1508        void Finder::postvisit( const ast::CommaExpr * commaExpr ) {
     1509                ast::TypeEnvironment env{ tenv };
     1510                ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );
     1511
     1512                CandidateFinder finder2( context, env );
     1513                finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
     1514
     1515                for ( const CandidateRef & r2 : finder2.candidates ) {
     1516                        addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );
     1517                }
     1518        }
     1519
     1520        void Finder::postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {
     1521                addCandidate( ctorExpr, tenv );
     1522        }
     1523
     1524        void Finder::postvisit( const ast::ConstructorExpr * ctorExpr ) {
     1525                CandidateFinder finder( context, tenv );
     1526                finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
     1527                for ( CandidateRef & r : finder.candidates ) {
     1528                        addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );
     1529                }
     1530        }
     1531
     1532        void Finder::postvisit( const ast::RangeExpr * rangeExpr ) {
     1533                // resolve low and high, accept candidates where low and high types unify
     1534                CandidateFinder finder1( context, tenv );
     1535                finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
     1536                if ( finder1.candidates.empty() ) return;
     1537
     1538                CandidateFinder finder2( context, tenv );
     1539                finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
     1540                if ( finder2.candidates.empty() ) return;
     1541
     1542                reason.code = NoMatch;
     1543
     1544                for ( const CandidateRef & r1 : finder1.candidates ) {
     1545                        for ( const CandidateRef & r2 : finder2.candidates ) {
     1546                                ast::TypeEnvironment env{ r1->env };
     1547                                env.simpleCombine( r2->env );
     1548                                ast::OpenVarSet open{ r1->open };
     1549                                mergeOpenVars( open, r2->open );
     1550                                ast::AssertionSet need;
     1551                                mergeAssertionSet( need, r1->need );
     1552                                mergeAssertionSet( need, r2->need );
     1553                                ast::AssertionSet have;
     1554
     1555                                ast::ptr< ast::Type > common;
     1556                                if (
     1557                                        unify(
     1558                                                r1->expr->result, r2->expr->result, env, need, have, open, symtab,
     1559                                                common )
     1560                                ) {
     1561                                        // generate new expression
     1562                                        ast::RangeExpr * newExpr =
     1563                                                new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
     1564                                        newExpr->result = common ? common : r1->expr->result;
     1565                                        // add candidate
     1566                                        CandidateRef newCand = std::make_shared<Candidate>(
     1567                                                newExpr, std::move( env ), std::move( open ), std::move( need ),
     1568                                                r1->cost + r2->cost );
     1569                                        inferParameters( newCand, candidates );
     1570                                }
     1571                        }
     1572                }
     1573        }
     1574
     1575        void Finder::postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
     1576                std::vector< CandidateFinder > subCandidates =
     1577                        selfFinder.findSubExprs( tupleExpr->exprs );
     1578                std::vector< CandidateList > possibilities;
     1579                combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );
     1580
     1581                for ( const CandidateList & subs : possibilities ) {
     1582                        std::vector< ast::ptr< ast::Expr > > exprs;
     1583                        exprs.reserve( subs.size() );
     1584                        for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }
     1585
     1586                        ast::TypeEnvironment env;
     1587                        ast::OpenVarSet open;
     1588                        ast::AssertionSet need;
     1589                        for ( const CandidateRef & sub : subs ) {
     1590                                env.simpleCombine( sub->env );
     1591                                mergeOpenVars( open, sub->open );
     1592                                mergeAssertionSet( need, sub->need );
     1593                        }
     1594
     1595                        addCandidate(
     1596                                new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },
     1597                                std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
     1598                }
     1599        }
     1600
     1601        void Finder::postvisit( const ast::TupleExpr * tupleExpr ) {
     1602                addCandidate( tupleExpr, tenv );
     1603        }
     1604
     1605        void Finder::postvisit( const ast::TupleIndexExpr * tupleExpr ) {
     1606                addCandidate( tupleExpr, tenv );
     1607        }
     1608
     1609        void Finder::postvisit( const ast::TupleAssignExpr * tupleExpr ) {
     1610                addCandidate( tupleExpr, tenv );
     1611        }
     1612
     1613        void Finder::postvisit( const ast::UniqueExpr * unqExpr ) {
     1614                CandidateFinder finder( context, tenv );
     1615                finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
     1616                for ( CandidateRef & r : finder.candidates ) {
     1617                        // ensure that the the id is passed on so that the expressions are "linked"
     1618                        addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );
     1619                }
     1620        }
     1621
     1622        void Finder::postvisit( const ast::StmtExpr * stmtExpr ) {
     1623                addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );
     1624        }
     1625
     1626        void Finder::postvisit( const ast::UntypedInitExpr * initExpr ) {
     1627                // handle each option like a cast
     1628                CandidateList matches;
     1629                PRINT(
     1630                        std::cerr << "untyped init expr: " << initExpr << std::endl;
     1631                )
     1632                // O(n^2) checks of d-types with e-types
     1633                for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {
     1634                        // calculate target type
     1635                        const ast::Type * toType = resolveTypeof( initAlt.type, context );
     1636                        toType = adjustExprType( toType, tenv, symtab );
     1637                        // The call to find must occur inside this loop, otherwise polymorphic return
     1638                        // types are not bound to the initialization type, since return type variables are
     1639                        // only open for the duration of resolving the UntypedExpr.
     1640                        CandidateFinder finder( context, tenv, toType );
     1641                        finder.find( initExpr->expr, ResolvMode::withAdjustment() );
     1642                        for ( CandidateRef & cand : finder.candidates ) {
     1643                                if (reason.code == NotFound) reason.code = NoMatch;
     1644
     1645                                ast::TypeEnvironment env{ cand->env };
     1646                                ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
     1647                                ast::OpenVarSet open{ cand->open };
     1648
     1649                                PRINT(
     1650                                        std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
     1651                                )
     1652
     1653                                // It is possible that a cast can throw away some values in a multiply-valued
     1654                                // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
     1655                                // the subexpression results that are cast directly. The candidate is invalid
     1656                                // if it has fewer results than there are types to cast to.
     1657                                int discardedValues = cand->expr->result->size() - toType->size();
     1658                                if ( discardedValues < 0 ) continue;
     1659
     1660                                // unification run for side-effects
     1661                                bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
     1662                                (void) canUnify;
     1663                                Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1664                                        symtab, env );
     1665                                PRINT(
     1666                                        Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
     1667                                                symtab, env );
     1668                                        std::cerr << "Considering initialization:";
     1669                                        std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
     1670                                        std::cerr << std::endl << "  TO: "   << toType             << std::endl;
     1671                                        std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
     1672                                        std::cerr << std::endl << "  Legacy cost " << legacyCost;
     1673                                        std::cerr << std::endl << "  New cost " << thisCost;
     1674                                        std::cerr << std::endl;
     1675                                )
     1676                                if ( thisCost != Cost::infinity ) {
     1677                                        // count one safe conversion for each value that is thrown away
     1678                                        thisCost.incSafe( discardedValues );
     1679                                        CandidateRef newCand = std::make_shared<Candidate>(
     1680                                                new ast::InitExpr{
     1681                                                        initExpr->location, restructureCast( cand->expr, toType ),
     1682                                                        initAlt.designation },
     1683                                                std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
     1684                                        inferParameters( newCand, matches );
     1685                                }
     1686                        }
     1687                }
     1688
     1689                // select first on argument cost, then conversion cost
     1690                CandidateList minArgCost = findMinCost( matches );
     1691                promoteCvtCost( minArgCost );
     1692                candidates = findMinCost( minArgCost );
     1693        }
     1694
     1695        // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
     1696        /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
     1697        /// return type. Skips ambiguous candidates.
     1698
     1699} // anonymous namespace
     1700
     1701bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
     1702        struct PruneStruct {
     1703                CandidateRef candidate;
     1704                bool ambiguous;
     1705
     1706                PruneStruct() = default;
     1707                PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
     1708        };
     1709
     1710        // find lowest-cost candidate for each type
     1711        std::unordered_map< std::string, PruneStruct > selected;
     1712        // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
     1713        std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
     1714        for ( CandidateRef & candidate : candidates ) {
     1715                std::string mangleName;
     1716                {
     1717                        ast::ptr< ast::Type > newType = candidate->expr->result;
     1718                        assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
     1719                        candidate->env.apply( newType );
     1720                        mangleName = Mangle::mangle( newType );
     1721                }
     1722
     1723                auto found = selected.find( mangleName );
     1724                if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
     1725                        PRINT(
     1726                                std::cerr << "cost " << candidate->cost << " loses to "
     1727                                        << found->second.candidate->cost << std::endl;
     1728                        )
     1729                        continue;
     1730                }
     1731
     1732                // xxx - when do satisfyAssertions produce more than 1 result?
     1733                // this should only happen when initial result type contains
     1734                // unbound type parameters, then it should never be pruned by
     1735                // the previous step, since renameTyVars guarantees the mangled name
     1736                // is unique.
     1737                CandidateList satisfied;
     1738                bool needRecomputeKey = false;
     1739                if (candidate->need.empty()) {
     1740                        satisfied.emplace_back(candidate);
     1741                }
     1742                else {
     1743                        satisfyAssertions(candidate, context.symtab, satisfied, errors);
     1744                        needRecomputeKey = true;
     1745                }
     1746
     1747                for (auto & newCand : satisfied) {
     1748                        // recomputes type key, if satisfyAssertions changed it
     1749                        if (needRecomputeKey)
     1750                        {
     1751                                ast::ptr< ast::Type > newType = newCand->expr->result;
     1752                                assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
     1753                                newCand->env.apply( newType );
     1754                                mangleName = Mangle::mangle( newType );
     1755                        }
     1756                        auto found = selected.find( mangleName );
     1757                        if ( found != selected.end() ) {
     1758                                if ( newCand->cost < found->second.candidate->cost ) {
     1759                                        PRINT(
     1760                                                std::cerr << "cost " << newCand->cost << " beats "
     1761                                                        << found->second.candidate->cost << std::endl;
     1762                                        )
     1763
     1764                                        found->second = PruneStruct{ newCand };
     1765                                } else if ( newCand->cost == found->second.candidate->cost ) {
     1766                                        // if one of the candidates contains a deleted identifier, can pick the other,
     1767                                        // since deleted expressions should not be ambiguous if there is another option
     1768                                        // that is at least as good
     1769                                        if ( findDeletedExpr( newCand->expr ) ) {
     1770                                                // do nothing
     1771                                                PRINT( std::cerr << "candidate is deleted" << std::endl; )
     1772                                        } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
     1773                                                PRINT( std::cerr << "current is deleted" << std::endl; )
     1774                                                found->second = PruneStruct{ newCand };
     1775                                        } else {
     1776                                                PRINT( std::cerr << "marking ambiguous" << std::endl; )
     1777                                                found->second.ambiguous = true;
     1778                                        }
     1779                                } else {
     1780                                        // xxx - can satisfyAssertions increase the cost?
     1781                                        PRINT(
     1782                                                std::cerr << "cost " << newCand->cost << " loses to "
     1783                                                        << found->second.candidate->cost << std::endl;
     1784                                        )
     1785                                }
     1786                        } else {
     1787                                selected.emplace_hint( found, mangleName, newCand );
     1788                        }
     1789                }
     1790        }
     1791
     1792        // report unambiguous min-cost candidates
     1793        // CandidateList out;
     1794        for ( auto & target : selected ) {
     1795                if ( target.second.ambiguous ) continue;
     1796
     1797                CandidateRef cand = target.second.candidate;
     1798
     1799                ast::ptr< ast::Type > newResult = cand->expr->result;
     1800                cand->env.applyFree( newResult );
     1801                cand->expr = ast::mutate_field(
     1802                        cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
     1803
     1804                out.emplace_back( cand );
     1805        }
     1806        // if everything is lost in satisfyAssertions, report the error
     1807        return !selected.empty();
     1808}
     1809
     1810void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
     1811        // Find alternatives for expression
     1812        ast::Pass<Finder> finder{ *this };
     1813        expr->accept( finder );
     1814
     1815        if ( mode.failFast && candidates.empty() ) {
     1816                switch(finder.core.reason.code) {
     1817                case Finder::NotFound:
     1818                        { SemanticError( expr, "No alternatives for expression " ); break; }
     1819                case Finder::NoMatch:
     1820                        { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
     1821                case Finder::ArgsToFew:
     1822                case Finder::ArgsToMany:
     1823                case Finder::RetsToFew:
     1824                case Finder::RetsToMany:
     1825                case Finder::NoReason:
     1826                default:
     1827                        { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
     1828                }
     1829        }
     1830
     1831        /*
     1832        if ( mode.satisfyAssns || mode.prune ) {
     1833                // trim candidates to just those where the assertions are satisfiable
     1834                // - necessary pre-requisite to pruning
     1835                CandidateList satisfied;
     1836                std::vector< std::string > errors;
     1837                for ( CandidateRef & candidate : candidates ) {
     1838                        satisfyAssertions( candidate, localSyms, satisfied, errors );
     1839                }
     1840
     1841                // fail early if none such
     1842                if ( mode.failFast && satisfied.empty() ) {
     1843                        std::ostringstream stream;
     1844                        stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     1845                        for ( const auto& err : errors ) {
     1846                                stream << err;
     1847                        }
     1848                        SemanticError( expr->location, stream.str() );
     1849                }
     1850
     1851                // reset candidates
     1852                candidates = move( satisfied );
     1853        }
     1854        */
     1855
     1856        if ( mode.prune ) {
     1857                // trim candidates to single best one
     1858                PRINT(
     1859                        std::cerr << "alternatives before prune:" << std::endl;
     1860                        print( std::cerr, candidates );
     1861                )
     1862
     1863                CandidateList pruned;
     1864                std::vector<std::string> errors;
     1865                bool found = pruneCandidates( candidates, pruned, errors );
     1866
     1867                if ( mode.failFast && pruned.empty() ) {
     1868                        std::ostringstream stream;
     1869                        if (found) {
     1870                                CandidateList winners = findMinCost( candidates );
     1871                                stream << "Cannot choose between " << winners.size() << " alternatives for "
     1872                                        "expression\n";
     1873                                ast::print( stream, expr );
     1874                                stream << " Alternatives are:\n";
     1875                                print( stream, winners, 1 );
     1876                                SemanticError( expr->location, stream.str() );
     1877                        }
     1878                        else {
     1879                                stream << "No alternatives with satisfiable assertions for " << expr << "\n";
     1880                                for ( const auto& err : errors ) {
     1881                                        stream << err;
     1882                                }
     1883                                SemanticError( expr->location, stream.str() );
     1884                        }
     1885                }
     1886
     1887                auto oldsize = candidates.size();
     1888                candidates = std::move( pruned );
     1889
     1890                PRINT(
     1891                        std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
     1892                )
     1893                PRINT(
     1894                        std::cerr << "there are " << candidates.size() << " alternatives after elimination"
     1895                                << std::endl;
     1896                )
     1897        }
     1898
     1899        // adjust types after pruning so that types substituted by pruneAlternatives are correctly
     1900        // adjusted
     1901        if ( mode.adjust ) {
     1902                for ( CandidateRef & r : candidates ) {
     1903                        r->expr = ast::mutate_field(
     1904                                r->expr.get(), &ast::Expr::result,
     1905                                adjustExprType( r->expr->result, r->env, context.symtab ) );
     1906                }
     1907        }
     1908
     1909        // Central location to handle gcc extension keyword, etc. for all expressions
     1910        for ( CandidateRef & r : candidates ) {
     1911                if ( r->expr->extension != expr->extension ) {
     1912                        r->expr.get_and_mutate()->extension = expr->extension;
     1913                }
     1914        }
     1915}
     1916
     1917std::vector< CandidateFinder > CandidateFinder::findSubExprs(
     1918        const std::vector< ast::ptr< ast::Expr > > & xs
     1919) {
     1920        std::vector< CandidateFinder > out;
     1921
     1922        for ( const auto & x : xs ) {
     1923                out.emplace_back( context, env );
     1924                out.back().find( x, ResolvMode::withAdjustment() );
     1925
     1926                PRINT(
     1927                        std::cerr << "findSubExprs" << std::endl;
     1928                        print( std::cerr, out.back().candidates );
     1929                )
     1930        }
     1931
     1932        return out;
     1933}
     1934
    571935const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) {
    581936        if ( expr->result.as< ast::ReferenceType >() ) {
     
    641942        return expr;
    651943}
    66 
    67 /// Unique identifier for matching expression resolutions to their requesting expression
    68 UniqueId globalResnSlot = 0;
    691944
    701945Cost computeConversionCost(
     
    931968}
    941969
    95 namespace {
    96         /// First index is which argument, second is which alternative, third is which exploded element
    97         using ExplodedArgs_new = std::deque< std::vector< ExplodedArg > >;
    98 
    99         /// Returns a list of alternatives with the minimum cost in the given list
    100         CandidateList findMinCost( const CandidateList & candidates ) {
    101                 CandidateList out;
    102                 Cost minCost = Cost::infinity;
    103                 for ( const CandidateRef & r : candidates ) {
    104                         if ( r->cost < minCost ) {
    105                                 minCost = r->cost;
    106                                 out.clear();
    107                                 out.emplace_back( r );
    108                         } else if ( r->cost == minCost ) {
    109                                 out.emplace_back( r );
    110                         }
    111                 }
    112                 return out;
    113         }
    114 
    115         /// Computes conversion cost for a given expression to a given type
    116         const ast::Expr * computeExpressionConversionCost(
    117                 const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
    118         ) {
    119                 Cost convCost = computeConversionCost(
    120                                 arg->result, paramType, arg->get_lvalue(), symtab, env );
    121                 outCost += convCost;
    122 
    123                 // If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
    124                 // conversion. Ignore poly cost for now, since this requires resolution of the cast to
    125                 // infer parameters and this does not currently work for the reason stated below
    126                 Cost tmpCost = convCost;
    127                 tmpCost.incPoly( -tmpCost.get_polyCost() );
    128                 if ( tmpCost != Cost::zero ) {
    129                         ast::ptr< ast::Type > newType = paramType;
    130                         env.apply( newType );
    131                         return new ast::CastExpr{ arg, newType };
    132 
    133                         // xxx - *should* be able to resolve this cast, but at the moment pointers are not
    134                         // castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
    135                         // once this is fixed it should be possible to resolve the cast.
    136                         // xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
    137                         // but it shouldn't be because this makes the conversion from DT* to DT* since
    138                         // commontype(zero_t, DT*) is DT*, rather than nothing
    139 
    140                         // CandidateFinder finder{ symtab, env };
    141                         // finder.find( arg, ResolvMode::withAdjustment() );
    142                         // assertf( finder.candidates.size() > 0,
    143                         //      "Somehow castable expression failed to find alternatives." );
    144                         // assertf( finder.candidates.size() == 1,
    145                         //      "Somehow got multiple alternatives for known cast expression." );
    146                         // return finder.candidates.front()->expr;
    147                 }
    148 
    149                 return arg;
    150         }
    151 
    152         /// Computes conversion cost for a given candidate
    153         Cost computeApplicationConversionCost(
    154                 CandidateRef cand, const ast::SymbolTable & symtab
    155         ) {
    156                 auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
    157                 auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    158                 auto function = pointer->base.strict_as< ast::FunctionType >();
    159 
    160                 Cost convCost = Cost::zero;
    161                 const auto & params = function->params;
    162                 auto param = params.begin();
    163                 auto & args = appExpr->args;
    164 
    165                 for ( unsigned i = 0; i < args.size(); ++i ) {
    166                         const ast::Type * argType = args[i]->result;
    167                         PRINT(
    168                                 std::cerr << "arg expression:" << std::endl;
    169                                 ast::print( std::cerr, args[i], 2 );
    170                                 std::cerr << "--- results are" << std::endl;
    171                                 ast::print( std::cerr, argType, 2 );
    172                         )
    173 
    174                         if ( param == params.end() ) {
    175                                 if ( function->isVarArgs ) {
    176                                         convCost.incUnsafe();
    177                                         PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
    178                                                 << convCost << std::endl; ; )
    179                                         // convert reference-typed expressions into value-typed expressions
    180                                         cand->expr = ast::mutate_field_index(
    181                                                 appExpr, &ast::ApplicationExpr::args, i,
    182                                                 referenceToRvalueConversion( args[i], convCost ) );
    183                                         continue;
    184                                 } else return Cost::infinity;
    185                         }
    186 
    187                         if ( auto def = args[i].as< ast::DefaultArgExpr >() ) {
    188                                 // Default arguments should be free - don't include conversion cost.
    189                                 // Unwrap them here because they are not relevant to the rest of the system
    190                                 cand->expr = ast::mutate_field_index(
    191                                         appExpr, &ast::ApplicationExpr::args, i, def->expr );
    192                                 ++param;
    193                                 continue;
    194                         }
    195 
    196                         // mark conversion cost and also specialization cost of param type
    197                         // const ast::Type * paramType = (*param)->get_type();
    198                         cand->expr = ast::mutate_field_index(
    199                                 appExpr, &ast::ApplicationExpr::args, i,
    200                                 computeExpressionConversionCost(
    201                                         args[i], *param, symtab, cand->env, convCost ) );
    202                         convCost.decSpec( specCost( *param ) );
    203                         ++param;  // can't be in for-loop update because of the continue
    204                 }
    205 
    206                 if ( param != params.end() ) return Cost::infinity;
    207 
    208                 // specialization cost of return types can't be accounted for directly, it disables
    209                 // otherwise-identical calls, like this example based on auto-newline in the I/O lib:
    210                 //
    211                 //   forall(otype OS) {
    212                 //     void ?|?(OS&, int);  // with newline
    213                 //     OS&  ?|?(OS&, int);  // no newline, always chosen due to more specialization
    214                 //   }
    215 
    216                 // mark type variable and specialization cost of forall clause
    217                 convCost.incVar( function->forall.size() );
    218                 convCost.decSpec( function->assertions.size() );
    219 
    220                 return convCost;
    221         }
    222 
    223         void makeUnifiableVars(
    224                 const ast::FunctionType * type, ast::OpenVarSet & unifiableVars,
    225                 ast::AssertionSet & need
    226         ) {
    227                 for ( auto & tyvar : type->forall ) {
    228                         unifiableVars[ *tyvar ] = ast::TypeData{ tyvar->base };
    229                 }
    230                 for ( auto & assn : type->assertions ) {
    231                         need[ assn ].isUsed = true;
    232                 }
    233         }
    234 
    235         /// Gets a default value from an initializer, nullptr if not present
    236         const ast::ConstantExpr * getDefaultValue( const ast::Init * init ) {
    237                 if ( auto si = dynamic_cast< const ast::SingleInit * >( init ) ) {
    238                         if ( auto ce = si->value.as< ast::CastExpr >() ) {
    239                                 return ce->arg.as< ast::ConstantExpr >();
    240                         } else {
    241                                 return si->value.as< ast::ConstantExpr >();
    242                         }
    243                 }
    244                 return nullptr;
    245         }
    246 
    247         /// State to iteratively build a match of parameter expressions to arguments
    248         struct ArgPack {
    249                 std::size_t parent;          ///< Index of parent pack
    250                 ast::ptr< ast::Expr > expr;  ///< The argument stored here
    251                 Cost cost;                   ///< The cost of this argument
    252                 ast::TypeEnvironment env;    ///< Environment for this pack
    253                 ast::AssertionSet need;      ///< Assertions outstanding for this pack
    254                 ast::AssertionSet have;      ///< Assertions found for this pack
    255                 ast::OpenVarSet open;        ///< Open variables for this pack
    256                 unsigned nextArg;            ///< Index of next argument in arguments list
    257                 unsigned tupleStart;         ///< Number of tuples that start at this index
    258                 unsigned nextExpl;           ///< Index of next exploded element
    259                 unsigned explAlt;            ///< Index of alternative for nextExpl > 0
    260 
    261                 ArgPack()
    262                 : parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
    263                   tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    264 
    265                 ArgPack(
    266                         const ast::TypeEnvironment & env, const ast::AssertionSet & need,
    267                         const ast::AssertionSet & have, const ast::OpenVarSet & open )
    268                 : parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
    269                   open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
    270 
    271                 ArgPack(
    272                         std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
    273                         ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
    274                         unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
    275                         unsigned nextExpl = 0, unsigned explAlt = 0 )
    276                 : parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),
    277                   have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
    278                   nextExpl( nextExpl ), explAlt( explAlt ) {}
    279 
    280                 ArgPack(
    281                         const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
    282                         ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
    283                 : parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),
    284                   need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),
    285                   tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
    286 
    287                 /// true if this pack is in the middle of an exploded argument
    288                 bool hasExpl() const { return nextExpl > 0; }
    289 
    290                 /// Gets the list of exploded candidates for this pack
    291                 const ExplodedArg & getExpl( const ExplodedArgs_new & args ) const {
    292                         return args[ nextArg-1 ][ explAlt ];
    293                 }
    294 
    295                 /// Ends a tuple expression, consolidating the appropriate args
    296                 void endTuple( const std::vector< ArgPack > & packs ) {
    297                         // add all expressions in tuple to list, summing cost
    298                         std::deque< const ast::Expr * > exprs;
    299                         const ArgPack * pack = this;
    300                         if ( expr ) { exprs.emplace_front( expr ); }
    301                         while ( pack->tupleStart == 0 ) {
    302                                 pack = &packs[pack->parent];
    303                                 exprs.emplace_front( pack->expr );
    304                                 cost += pack->cost;
    305                         }
    306                         // reset pack to appropriate tuple
    307                         std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );
    308                         expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };
    309                         tupleStart = pack->tupleStart - 1;
    310                         parent = pack->parent;
    311                 }
    312         };
    313 
    314         /// Instantiates an argument to match a parameter, returns false if no matching results left
    315         bool instantiateArgument(
    316                 const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
    317                 std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
    318                 unsigned nTuples = 0
    319         ) {
    320                 if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
    321                         // paramType is a TupleType -- group args into a TupleExpr
    322                         ++nTuples;
    323                         for ( const ast::Type * type : *tupleType ) {
    324                                 // xxx - dropping initializer changes behaviour from previous, but seems correct
    325                                 // ^^^ need to handle the case where a tuple has a default argument
    326                                 if ( ! instantiateArgument(
    327                                         type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
    328                                 nTuples = 0;
    329                         }
    330                         // re-constitute tuples for final generation
    331                         for ( auto i = genStart; i < results.size(); ++i ) {
    332                                 results[i].endTuple( results );
    333                         }
    334                         return true;
    335                 } else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
    336                         // paramType is a ttype, consumes all remaining arguments
    337 
    338                         // completed tuples; will be spliced to end of results to finish
    339                         std::vector< ArgPack > finalResults{};
    340 
    341                         // iterate until all results completed
    342                         std::size_t genEnd;
    343                         ++nTuples;
    344                         do {
    345                                 genEnd = results.size();
    346 
    347                                 // add another argument to results
    348                                 for ( std::size_t i = genStart; i < genEnd; ++i ) {
    349                                         unsigned nextArg = results[i].nextArg;
    350 
    351                                         // use next element of exploded tuple if present
    352                                         if ( results[i].hasExpl() ) {
    353                                                 const ExplodedArg & expl = results[i].getExpl( args );
    354 
    355                                                 unsigned nextExpl = results[i].nextExpl + 1;
    356                                                 if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    357 
    358                                                 results.emplace_back(
    359                                                         i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    360                                                         copy( results[i].need ), copy( results[i].have ),
    361                                                         copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
    362                                                         results[i].explAlt );
    363 
    364                                                 continue;
    365                                         }
    366 
    367                                         // finish result when out of arguments
    368                                         if ( nextArg >= args.size() ) {
    369                                                 ArgPack newResult{
    370                                                         results[i].env, results[i].need, results[i].have, results[i].open };
    371                                                 newResult.nextArg = nextArg;
    372                                                 const ast::Type * argType = nullptr;
    373 
    374                                                 if ( nTuples > 0 || ! results[i].expr ) {
    375                                                         // first iteration or no expression to clone,
    376                                                         // push empty tuple expression
    377                                                         newResult.parent = i;
    378                                                         newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
    379                                                         argType = newResult.expr->result;
    380                                                 } else {
    381                                                         // clone result to collect tuple
    382                                                         newResult.parent = results[i].parent;
    383                                                         newResult.cost = results[i].cost;
    384                                                         newResult.tupleStart = results[i].tupleStart;
    385                                                         newResult.expr = results[i].expr;
    386                                                         argType = newResult.expr->result;
    387 
    388                                                         if ( results[i].tupleStart > 0 && Tuples::isTtype( argType ) ) {
    389                                                                 // the case where a ttype value is passed directly is special,
    390                                                                 // e.g. for argument forwarding purposes
    391                                                                 // xxx - what if passing multiple arguments, last of which is
    392                                                                 //       ttype?
    393                                                                 // xxx - what would happen if unify was changed so that unifying
    394                                                                 //       tuple
    395                                                                 // types flattened both before unifying lists? then pass in
    396                                                                 // TupleType (ttype) below.
    397                                                                 --newResult.tupleStart;
    398                                                         } else {
    399                                                                 // collapse leftover arguments into tuple
    400                                                                 newResult.endTuple( results );
    401                                                                 argType = newResult.expr->result;
    402                                                         }
    403                                                 }
    404 
    405                                                 // check unification for ttype before adding to final
    406                                                 if (
    407                                                         unify(
    408                                                                 ttype, argType, newResult.env, newResult.need, newResult.have,
    409                                                                 newResult.open, symtab )
    410                                                 ) {
    411                                                         finalResults.emplace_back( std::move( newResult ) );
    412                                                 }
    413 
    414                                                 continue;
    415                                         }
    416 
    417                                         // add each possible next argument
    418                                         for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    419                                                 const ExplodedArg & expl = args[nextArg][j];
    420 
    421                                                 // fresh copies of parent parameters for this iteration
    422                                                 ast::TypeEnvironment env = results[i].env;
    423                                                 ast::OpenVarSet open = results[i].open;
    424 
    425                                                 env.addActual( expl.env, open );
    426 
    427                                                 // skip empty tuple arguments by (nearly) cloning parent into next gen
    428                                                 if ( expl.exprs.empty() ) {
    429                                                         results.emplace_back(
    430                                                                 results[i], std::move( env ), copy( results[i].need ),
    431                                                                 copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );
    432 
    433                                                         continue;
    434                                                 }
    435 
    436                                                 // add new result
    437                                                 results.emplace_back(
    438                                                         i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
    439                                                         copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,
    440                                                         expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    441                                         }
    442                                 }
    443 
    444                                 // reset for next round
    445                                 genStart = genEnd;
    446                                 nTuples = 0;
    447                         } while ( genEnd != results.size() );
    448 
    449                         // splice final results onto results
    450                         for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
    451                                 results.emplace_back( std::move( finalResults[i] ) );
    452                         }
    453                         return ! finalResults.empty();
    454                 }
    455 
    456                 // iterate each current subresult
    457                 std::size_t genEnd = results.size();
    458                 for ( std::size_t i = genStart; i < genEnd; ++i ) {
    459                         unsigned nextArg = results[i].nextArg;
    460 
    461                         // use remainder of exploded tuple if present
    462                         if ( results[i].hasExpl() ) {
    463                                 const ExplodedArg & expl = results[i].getExpl( args );
    464                                 const ast::Expr * expr = expl.exprs[ results[i].nextExpl ];
    465 
    466                                 ast::TypeEnvironment env = results[i].env;
    467                                 ast::AssertionSet need = results[i].need, have = results[i].have;
    468                                 ast::OpenVarSet open = results[i].open;
    469 
    470                                 const ast::Type * argType = expr->result;
    471 
    472                                 PRINT(
    473                                         std::cerr << "param type is ";
    474                                         ast::print( std::cerr, paramType );
    475                                         std::cerr << std::endl << "arg type is ";
    476                                         ast::print( std::cerr, argType );
    477                                         std::cerr << std::endl;
    478                                 )
    479 
    480                                 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
    481                                         unsigned nextExpl = results[i].nextExpl + 1;
    482                                         if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    483 
    484                                         results.emplace_back(
    485                                                 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,
    486                                                 nTuples, Cost::zero, nextExpl, results[i].explAlt );
    487                                 }
    488 
    489                                 continue;
    490                         }
    491 
    492                         // use default initializers if out of arguments
    493                         if ( nextArg >= args.size() ) {
    494                                 if ( const ast::ConstantExpr * cnst = getDefaultValue( init ) ) {
    495                                         ast::TypeEnvironment env = results[i].env;
    496                                         ast::AssertionSet need = results[i].need, have = results[i].have;
    497                                         ast::OpenVarSet open = results[i].open;
    498 
    499                                         if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
    500                                                 results.emplace_back(
    501                                                         i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),
    502                                                         std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );
    503                                         }
    504                                 }
    505 
    506                                 continue;
    507                         }
    508 
    509                         // Check each possible next argument
    510                         for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    511                                 const ExplodedArg & expl = args[nextArg][j];
    512 
    513                                 // fresh copies of parent parameters for this iteration
    514                                 ast::TypeEnvironment env = results[i].env;
    515                                 ast::AssertionSet need = results[i].need, have = results[i].have;
    516                                 ast::OpenVarSet open = results[i].open;
    517 
    518                                 env.addActual( expl.env, open );
    519 
    520                                 // skip empty tuple arguments by (nearly) cloning parent into next gen
    521                                 if ( expl.exprs.empty() ) {
    522                                         results.emplace_back(
    523                                                 results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),
    524                                                 nextArg + 1, expl.cost );
    525 
    526                                         continue;
    527                                 }
    528 
    529                                 // consider only first exploded arg
    530                                 const ast::Expr * expr = expl.exprs.front();
    531                                 const ast::Type * argType = expr->result;
    532 
    533                                 PRINT(
    534                                         std::cerr << "param type is ";
    535                                         ast::print( std::cerr, paramType );
    536                                         std::cerr << std::endl << "arg type is ";
    537                                         ast::print( std::cerr, argType );
    538                                         std::cerr << std::endl;
    539                                 )
    540 
    541                                 // attempt to unify types
    542                                 if ( unify( paramType, argType, env, need, have, open, symtab ) ) {
    543                                         // add new result
    544                                         results.emplace_back(
    545                                                 i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
    546                                                 nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    547                                 }
    548                         }
    549                 }
    550 
    551                 // reset for next parameter
    552                 genStart = genEnd;
    553 
    554                 return genEnd != results.size();  // were any new results added?
    555         }
    556 
    557         /// Generate a cast expression from `arg` to `toType`
    558         const ast::Expr * restructureCast(
    559                 ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
    560         ) {
    561                 if (
    562                         arg->result->size() > 1
    563                         && ! toType->isVoid()
    564                         && ! dynamic_cast< const ast::ReferenceType * >( toType )
    565                 ) {
    566                         // Argument is a tuple and the target type is neither void nor a reference. Cast each
    567                         // member of the tuple to its corresponding target type, producing the tuple of those
    568                         // cast expressions. If there are more components of the tuple than components in the
    569                         // target type, then excess components do not come out in the result expression (but
    570                         // UniqueExpr ensures that the side effects will still be produced)
    571                         if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
    572                                 // expressions which may contain side effects require a single unique instance of
    573                                 // the expression
    574                                 arg = new ast::UniqueExpr{ arg->location, arg };
    575                         }
    576                         std::vector< ast::ptr< ast::Expr > > components;
    577                         for ( unsigned i = 0; i < toType->size(); ++i ) {
    578                                 // cast each component
    579                                 ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
    580                                 components.emplace_back(
    581                                         restructureCast( idx, toType->getComponent( i ), isGenerated ) );
    582                         }
    583                         return new ast::TupleExpr{ arg->location, std::move( components ) };
    584                 } else {
    585                         // handle normally
    586                         return new ast::CastExpr{ arg->location, arg, toType, isGenerated };
    587                 }
    588         }
    589 
    590         /// Gets the name from an untyped member expression (must be NameExpr)
    591         const std::string & getMemberName( const ast::UntypedMemberExpr * memberExpr ) {
    592                 if ( memberExpr->member.as< ast::ConstantExpr >() ) {
    593                         SemanticError( memberExpr, "Indexed access to struct fields unsupported: " );
    594                 }
    595 
    596                 return memberExpr->member.strict_as< ast::NameExpr >()->name;
    597         }
    598 
    599         /// Actually visits expressions to find their candidate interpretations
    600         class Finder final : public ast::WithShortCircuiting {
    601                 const ResolveContext & context;
    602                 const ast::SymbolTable & symtab;
    603         public:
    604                 // static size_t traceId;
    605                 CandidateFinder & selfFinder;
    606                 CandidateList & candidates;
    607                 const ast::TypeEnvironment & tenv;
    608                 ast::ptr< ast::Type > & targetType;
    609 
    610                 enum Errors {
    611                         NotFound,
    612                         NoMatch,
    613                         ArgsToFew,
    614                         ArgsToMany,
    615                         RetsToFew,
    616                         RetsToMany,
    617                         NoReason
    618                 };
    619 
    620                 struct {
    621                         Errors code = NotFound;
    622                 } reason;
    623 
    624                 Finder( CandidateFinder & f )
    625                 : context( f.context ), symtab( context.symtab ), selfFinder( f ),
    626                   candidates( f.candidates ), tenv( f.env ), targetType( f.targetType ) {}
    627 
    628                 void previsit( const ast::Node * ) { visit_children = false; }
    629 
    630                 /// Convenience to add candidate to list
    631                 template<typename... Args>
    632                 void addCandidate( Args &&... args ) {
    633                         candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
    634                         reason.code = NoReason;
    635                 }
    636 
    637                 void postvisit( const ast::ApplicationExpr * applicationExpr ) {
    638                         addCandidate( applicationExpr, tenv );
    639                 }
    640 
    641                 /// Set up candidate assertions for inference
    642                 void inferParameters( CandidateRef & newCand, CandidateList & out ) {
    643                         // Set need bindings for any unbound assertions
    644                         UniqueId crntResnSlot = 0; // matching ID for this expression's assertions
    645                         for ( auto & assn : newCand->need ) {
    646                                 // skip already-matched assertions
    647                                 if ( assn.second.resnSlot != 0 ) continue;
    648                                 // assign slot for expression if needed
    649                                 if ( crntResnSlot == 0 ) { crntResnSlot = ++globalResnSlot; }
    650                                 // fix slot to assertion
    651                                 assn.second.resnSlot = crntResnSlot;
    652                         }
    653                         // pair slot to expression
    654                         if ( crntResnSlot != 0 ) {
    655                                 newCand->expr.get_and_mutate()->inferred.resnSlots().emplace_back( crntResnSlot );
    656                         }
    657 
    658                         // add to output list; assertion satisfaction will occur later
    659                         out.emplace_back( newCand );
    660                 }
    661 
    662                 /// Completes a function candidate with arguments located
    663                 void validateFunctionCandidate(
    664                         const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
    665                         CandidateList & out
    666                 ) {
    667                         ast::ApplicationExpr * appExpr =
    668                                 new ast::ApplicationExpr{ func->expr->location, func->expr };
    669                         // sum cost and accumulate arguments
    670                         std::deque< const ast::Expr * > args;
    671                         Cost cost = func->cost;
    672                         const ArgPack * pack = &result;
    673                         while ( pack->expr ) {
    674                                 args.emplace_front( pack->expr );
    675                                 cost += pack->cost;
    676                                 pack = &results[pack->parent];
    677                         }
    678                         std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );
    679                         appExpr->args = std::move( vargs );
    680                         // build and validate new candidate
    681                         auto newCand =
    682                                 std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
    683                         PRINT(
    684                                 std::cerr << "instantiate function success: " << appExpr << std::endl;
    685                                 std::cerr << "need assertions:" << std::endl;
    686                                 ast::print( std::cerr, result.need, 2 );
    687                         )
    688                         inferParameters( newCand, out );
    689                 }
    690 
    691                 /// Builds a list of candidates for a function, storing them in out
    692                 void makeFunctionCandidates(
    693                         const CandidateRef & func, const ast::FunctionType * funcType,
    694                         const ExplodedArgs_new & args, CandidateList & out
    695                 ) {
    696                         ast::OpenVarSet funcOpen;
    697                         ast::AssertionSet funcNeed, funcHave;
    698                         ast::TypeEnvironment funcEnv{ func->env };
    699                         makeUnifiableVars( funcType, funcOpen, funcNeed );
    700                         // add all type variables as open variables now so that those not used in the
    701                         // parameter list are still considered open
    702                         funcEnv.add( funcType->forall );
    703 
    704                         if ( targetType && ! targetType->isVoid() && ! funcType->returns.empty() ) {
    705                                 // attempt to narrow based on expected target type
    706                                 const ast::Type * returnType = funcType->returns.front();
    707                                 if ( ! unify(
    708                                         returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
    709                                 ) {
    710                                         // unification failed, do not pursue this candidate
    711                                         return;
    712                                 }
    713                         }
    714 
    715                         // iteratively build matches, one parameter at a time
    716                         std::vector< ArgPack > results;
    717                         results.emplace_back( funcEnv, funcNeed, funcHave, funcOpen );
    718                         std::size_t genStart = 0;
    719 
    720                         // xxx - how to handle default arg after change to ftype representation?
    721                         if (const ast::VariableExpr * varExpr = func->expr.as<ast::VariableExpr>()) {
    722                                 if (const ast::FunctionDecl * funcDecl = varExpr->var.as<ast::FunctionDecl>()) {
    723                                         // function may have default args only if directly calling by name
    724                                         // must use types on candidate however, due to RenameVars substitution
    725                                         auto nParams = funcType->params.size();
    726 
    727                                         for (size_t i=0; i<nParams; ++i) {
    728                                                 auto obj = funcDecl->params[i].strict_as<ast::ObjectDecl>();
    729                                                 if (!instantiateArgument(
    730                                                         funcType->params[i], obj->init, args, results, genStart, symtab)) return;
    731                                         }
    732                                         goto endMatch;
    733                                 }
    734                         }
    735                         for ( const auto & param : funcType->params ) {
    736                                 // Try adding the arguments corresponding to the current parameter to the existing
    737                                 // matches
    738                                 // no default args for indirect calls
    739                                 if ( ! instantiateArgument(
    740                                         param, nullptr, args, results, genStart, symtab ) ) return;
    741                         }
    742 
    743                         endMatch:
    744                         if ( funcType->isVarArgs ) {
    745                                 // append any unused arguments to vararg pack
    746                                 std::size_t genEnd;
    747                                 do {
    748                                         genEnd = results.size();
    749 
    750                                         // iterate results
    751                                         for ( std::size_t i = genStart; i < genEnd; ++i ) {
    752                                                 unsigned nextArg = results[i].nextArg;
    753 
    754                                                 // use remainder of exploded tuple if present
    755                                                 if ( results[i].hasExpl() ) {
    756                                                         const ExplodedArg & expl = results[i].getExpl( args );
    757 
    758                                                         unsigned nextExpl = results[i].nextExpl + 1;
    759                                                         if ( nextExpl == expl.exprs.size() ) { nextExpl = 0; }
    760 
    761                                                         results.emplace_back(
    762                                                                 i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
    763                                                                 copy( results[i].need ), copy( results[i].have ),
    764                                                                 copy( results[i].open ), nextArg, 0, Cost::zero, nextExpl,
    765                                                                 results[i].explAlt );
    766 
    767                                                         continue;
    768                                                 }
    769 
    770                                                 // finish result when out of arguments
    771                                                 if ( nextArg >= args.size() ) {
    772                                                         validateFunctionCandidate( func, results[i], results, out );
    773 
    774                                                         continue;
    775                                                 }
    776 
    777                                                 // add each possible next argument
    778                                                 for ( std::size_t j = 0; j < args[nextArg].size(); ++j ) {
    779                                                         const ExplodedArg & expl = args[nextArg][j];
    780 
    781                                                         // fresh copies of parent parameters for this iteration
    782                                                         ast::TypeEnvironment env = results[i].env;
    783                                                         ast::OpenVarSet open = results[i].open;
    784 
    785                                                         env.addActual( expl.env, open );
    786 
    787                                                         // skip empty tuple arguments by (nearly) cloning parent into next gen
    788                                                         if ( expl.exprs.empty() ) {
    789                                                                 results.emplace_back(
    790                                                                         results[i], std::move( env ), copy( results[i].need ),
    791                                                                         copy( results[i].have ), std::move( open ), nextArg + 1,
    792                                                                         expl.cost );
    793 
    794                                                                 continue;
    795                                                         }
    796 
    797                                                         // add new result
    798                                                         results.emplace_back(
    799                                                                 i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
    800                                                                 copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,
    801                                                                 expl.exprs.size() == 1 ? 0 : 1, j );
    802                                                 }
    803                                         }
    804 
    805                                         genStart = genEnd;
    806                                 } while( genEnd != results.size() );
    807                         } else {
    808                                 // filter out the results that don't use all the arguments
    809                                 for ( std::size_t i = genStart; i < results.size(); ++i ) {
    810                                         ArgPack & result = results[i];
    811                                         if ( ! result.hasExpl() && result.nextArg >= args.size() ) {
    812                                                 validateFunctionCandidate( func, result, results, out );
    813                                         }
    814                                 }
    815                         }
    816                 }
    817 
    818                 /// Adds implicit struct-conversions to the alternative list
    819                 void addAnonConversions( const CandidateRef & cand ) {
    820                         // adds anonymous member interpretations whenever an aggregate value type is seen.
    821                         // it's okay for the aggregate expression to have reference type -- cast it to the
    822                         // base type to treat the aggregate as the referenced value
    823                         ast::ptr< ast::Expr > aggrExpr( cand->expr );
    824                         ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
    825                         cand->env.apply( aggrType );
    826 
    827                         if ( aggrType.as< ast::ReferenceType >() ) {
    828                                 aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
    829                         }
    830 
    831                         if ( auto structInst = aggrExpr->result.as< ast::StructInstType >() ) {
    832                                 addAggMembers( structInst, aggrExpr, *cand, Cost::safe, "" );
    833                         } else if ( auto unionInst = aggrExpr->result.as< ast::UnionInstType >() ) {
    834                                 addAggMembers( unionInst, aggrExpr, *cand, Cost::safe, "" );
    835                         }
    836                 }
    837 
    838                 /// Adds aggregate member interpretations
    839                 void addAggMembers(
    840                         const ast::BaseInstType * aggrInst, const ast::Expr * expr,
    841                         const Candidate & cand, const Cost & addedCost, const std::string & name
    842                 ) {
    843                         for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
    844                                 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
    845                                 CandidateRef newCand = std::make_shared<Candidate>(
    846                                         cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
    847                                 // add anonymous member interpretations whenever an aggregate value type is seen
    848                                 // as a member expression
    849                                 addAnonConversions( newCand );
    850                                 candidates.emplace_back( std::move( newCand ) );
    851                         }
    852                 }
    853 
    854                 /// Adds tuple member interpretations
    855                 void addTupleMembers(
    856                         const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
    857                         const Cost & addedCost, const ast::Expr * member
    858                 ) {
    859                         if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
    860                                 // get the value of the constant expression as an int, must be between 0 and the
    861                                 // length of the tuple to have meaning
    862                                 long long val = constantExpr->intValue();
    863                                 if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
    864                                         addCandidate(
    865                                                 cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
    866                                                 addedCost );
    867                                 }
    868                         }
    869                 }
    870 
    871                 void postvisit( const ast::UntypedExpr * untypedExpr ) {
    872                         std::vector< CandidateFinder > argCandidates =
    873                                 selfFinder.findSubExprs( untypedExpr->args );
    874 
    875                         // take care of possible tuple assignments
    876                         // if not tuple assignment, handled as normal function call
    877                         Tuples::handleTupleAssignment( selfFinder, untypedExpr, argCandidates );
    878 
    879                         CandidateFinder funcFinder( context, tenv );
    880                         if (auto nameExpr = untypedExpr->func.as<ast::NameExpr>()) {
    881                                 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    882                                 if (kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS) {
    883                                         assertf(!argCandidates.empty(), "special function call without argument");
    884                                         for (auto & firstArgCand: argCandidates[0]) {
    885                                                 ast::ptr<ast::Type> argType = firstArgCand->expr->result;
    886                                                 firstArgCand->env.apply(argType);
    887                                                 // strip references
    888                                                 // xxx - is this correct?
    889                                                 while (argType.as<ast::ReferenceType>()) argType = argType.as<ast::ReferenceType>()->base;
    890 
    891                                                 // convert 1-tuple to plain type
    892                                                 if (auto tuple = argType.as<ast::TupleType>()) {
    893                                                         if (tuple->size() == 1) {
    894                                                                 argType = tuple->types[0];
    895                                                         }
    896                                                 }
    897 
    898                                                 // if argType is an unbound type parameter, all special functions need to be searched.
    899                                                 if (isUnboundType(argType)) {
    900                                                         funcFinder.otypeKeys.clear();
    901                                                         break;
    902                                                 }
    903 
    904                                                 if (argType.as<ast::PointerType>()) funcFinder.otypeKeys.insert(Mangle::Encoding::pointer);                                             
    905                                                 // else if (const ast::EnumInstType * enumInst = argType.as<ast::EnumInstType>()) {
    906                                                 //      const ast::EnumDecl * enumDecl = enumInst->base; // Here
    907                                                 //      if ( const ast::Type* enumType = enumDecl->base ) {
    908                                                 //              // instance of enum (T) is a instance of type (T)
    909                                                 //              funcFinder.otypeKeys.insert(Mangle::mangle(enumType, Mangle::NoGenericParams | Mangle::Type));
    910                                                 //      } else {
    911                                                 //              // instance of an untyped enum is techically int
    912                                                 //              funcFinder.otypeKeys.insert(Mangle::mangle(enumDecl, Mangle::NoGenericParams | Mangle::Type));
    913                                                 //      }
    914                                                 // }
    915                                                 else funcFinder.otypeKeys.insert(Mangle::mangle(argType, Mangle::NoGenericParams | Mangle::Type));
    916                                         }
    917                                 }
    918                         }
    919                         // if candidates are already produced, do not fail
    920                         // xxx - is it possible that handleTupleAssignment and main finder both produce candidates?
    921                         // this means there exists ctor/assign functions with a tuple as first parameter.
    922                         ResolvMode mode = {
    923                                 true, // adjust
    924                                 !untypedExpr->func.as<ast::NameExpr>(), // prune if not calling by name
    925                                 selfFinder.candidates.empty() // failfast if other options are not found
    926                         };
    927                         funcFinder.find( untypedExpr->func, mode );
    928                         // short-circuit if no candidates
    929                         // if ( funcFinder.candidates.empty() ) return;
    930 
    931                         reason.code = NoMatch;
    932 
    933                         // find function operators
    934                         ast::ptr< ast::Expr > opExpr = new ast::NameExpr{ untypedExpr->location, "?()" }; // ??? why not ?{}
    935                         CandidateFinder opFinder( context, tenv );
    936                         // okay if there aren't any function operations
    937                         opFinder.find( opExpr, ResolvMode::withoutFailFast() );
    938                         PRINT(
    939                                 std::cerr << "known function ops:" << std::endl;
    940                                 print( std::cerr, opFinder.candidates, 1 );
    941                         )
    942 
    943                         // pre-explode arguments
    944                         ExplodedArgs_new argExpansions;
    945                         for ( const CandidateFinder & args : argCandidates ) {
    946                                 argExpansions.emplace_back();
    947                                 auto & argE = argExpansions.back();
    948                                 for ( const CandidateRef & arg : args ) { argE.emplace_back( *arg, symtab ); }
    949                         }
    950 
    951                         // Find function matches
    952                         CandidateList found;
    953                         SemanticErrorException errors;
    954                         for ( CandidateRef & func : funcFinder ) {
    955                                 try {
    956                                         PRINT(
    957                                                 std::cerr << "working on alternative:" << std::endl;
    958                                                 print( std::cerr, *func, 2 );
    959                                         )
    960 
    961                                         // check if the type is a pointer to function
    962                                         const ast::Type * funcResult = func->expr->result->stripReferences();
    963                                         if ( auto pointer = dynamic_cast< const ast::PointerType * >( funcResult ) ) {
    964                                                 if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    965                                                         CandidateRef newFunc{ new Candidate{ *func } };
    966                                                         newFunc->expr =
    967                                                                 referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    968                                                         makeFunctionCandidates( newFunc, function, argExpansions, found );
    969                                                 }
    970                                         } else if (
    971                                                 auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
    972                                         ) {
    973                                                 if ( const ast::EqvClass * clz = func->env.lookup( *inst ) ) {
    974                                                         if ( auto function = clz->bound.as< ast::FunctionType >() ) {
    975                                                                 CandidateRef newFunc{ new Candidate{ *func } };
    976                                                                 newFunc->expr =
    977                                                                         referenceToRvalueConversion( newFunc->expr, newFunc->cost );
    978                                                                 makeFunctionCandidates( newFunc, function, argExpansions, found );
    979                                                         }
    980                                                 }
    981                                         }
    982                                 } catch ( SemanticErrorException & e ) { errors.append( e ); }
    983                         }
    984 
    985                         // Find matches on function operators `?()`
    986                         if ( ! opFinder.candidates.empty() ) {
    987                                 // add exploded function alternatives to front of argument list
    988                                 std::vector< ExplodedArg > funcE;
    989                                 funcE.reserve( funcFinder.candidates.size() );
    990                                 for ( const CandidateRef & func : funcFinder ) {
    991                                         funcE.emplace_back( *func, symtab );
    992                                 }
    993                                 argExpansions.emplace_front( std::move( funcE ) );
    994 
    995                                 for ( const CandidateRef & op : opFinder ) {
    996                                         try {
    997                                                 // check if type is pointer-to-function
    998                                                 const ast::Type * opResult = op->expr->result->stripReferences();
    999                                                 if ( auto pointer = dynamic_cast< const ast::PointerType * >( opResult ) ) {
    1000                                                         if ( auto function = pointer->base.as< ast::FunctionType >() ) {
    1001                                                                 CandidateRef newOp{ new Candidate{ *op} };
    1002                                                                 newOp->expr =
    1003                                                                         referenceToRvalueConversion( newOp->expr, newOp->cost );
    1004                                                                 makeFunctionCandidates( newOp, function, argExpansions, found );
    1005                                                         }
    1006                                                 }
    1007                                         } catch ( SemanticErrorException & e ) { errors.append( e ); }
    1008                                 }
    1009                         }
    1010 
    1011                         // Implement SFINAE; resolution errors are only errors if there aren't any non-error
    1012                         // candidates
    1013                         if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
    1014 
    1015                         // Compute conversion costs
    1016                         for ( CandidateRef & withFunc : found ) {
    1017                                 Cost cvtCost = computeApplicationConversionCost( withFunc, symtab );
    1018 
    1019                                 PRINT(
    1020                                         auto appExpr = withFunc->expr.strict_as< ast::ApplicationExpr >();
    1021                                         auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
    1022                                         auto function = pointer->base.strict_as< ast::FunctionType >();
    1023 
    1024                                         std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
    1025                                         std::cerr << "parameters are:" << std::endl;
    1026                                         ast::printAll( std::cerr, function->params, 2 );
    1027                                         std::cerr << "arguments are:" << std::endl;
    1028                                         ast::printAll( std::cerr, appExpr->args, 2 );
    1029                                         std::cerr << "bindings are:" << std::endl;
    1030                                         ast::print( std::cerr, withFunc->env, 2 );
    1031                                         std::cerr << "cost is: " << withFunc->cost << std::endl;
    1032                                         std::cerr << "cost of conversion is:" << cvtCost << std::endl;
    1033                                 )
    1034 
    1035                                 if ( cvtCost != Cost::infinity ) {
    1036                                         withFunc->cvtCost = cvtCost;
    1037                                         candidates.emplace_back( std::move( withFunc ) );
    1038                                 }
    1039                         }
    1040                         found = std::move( candidates );
    1041 
    1042                         // use a new list so that candidates are not examined by addAnonConversions twice
    1043                         CandidateList winners = findMinCost( found );
    1044                         promoteCvtCost( winners );
    1045 
    1046                         // function may return a struct/union value, in which case we need to add candidates
    1047                         // for implicit conversions to each of the anonymous members, which must happen after
    1048                         // `findMinCost`, since anon conversions are never the cheapest
    1049                         for ( const CandidateRef & c : winners ) {
    1050                                 addAnonConversions( c );
    1051                         }
    1052                         spliceBegin( candidates, winners );
    1053 
    1054                         if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
    1055                                 // If resolution is unsuccessful with a target type, try again without, since it
    1056                                 // will sometimes succeed when it wouldn't with a target type binding.
    1057                                 // For example:
    1058                                 //   forall( otype T ) T & ?[]( T *, ptrdiff_t );
    1059                                 //   const char * x = "hello world";
    1060                                 //   unsigned char ch = x[0];
    1061                                 // Fails with simple return type binding (xxx -- check this!) as follows:
    1062                                 // * T is bound to unsigned char
    1063                                 // * (x: const char *) is unified with unsigned char *, which fails
    1064                                 // xxx -- fix this better
    1065                                 targetType = nullptr;
    1066                                 postvisit( untypedExpr );
    1067                         }
    1068                 }
    1069 
    1070                 /// true if expression is an lvalue
    1071                 static bool isLvalue( const ast::Expr * x ) {
    1072                         return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
    1073                 }
    1074 
    1075                 void postvisit( const ast::AddressExpr * addressExpr ) {
    1076                         CandidateFinder finder( context, tenv );
    1077                         finder.find( addressExpr->arg );
    1078 
    1079                         if( finder.candidates.empty() ) return;
    1080 
    1081                         reason.code = NoMatch;
    1082 
    1083                         for ( CandidateRef & r : finder.candidates ) {
    1084                                 if ( ! isLvalue( r->expr ) ) continue;
    1085                                 addCandidate( *r, new ast::AddressExpr{ addressExpr->location, r->expr } );
    1086                         }
    1087                 }
    1088 
    1089                 void postvisit( const ast::LabelAddressExpr * labelExpr ) {
    1090                         addCandidate( labelExpr, tenv );
    1091                 }
    1092 
    1093                 void postvisit( const ast::CastExpr * castExpr ) {
    1094                         ast::ptr< ast::Type > toType = castExpr->result;
    1095                         assert( toType );
    1096                         toType = resolveTypeof( toType, context );
    1097                         toType = adjustExprType( toType, tenv, symtab );
    1098 
    1099                         CandidateFinder finder( context, tenv, toType );
    1100                         finder.find( castExpr->arg, ResolvMode::withAdjustment() );
    1101 
    1102                         if( !finder.candidates.empty() ) reason.code = NoMatch;
    1103 
    1104                         CandidateList matches;
    1105                         for ( CandidateRef & cand : finder.candidates ) {
    1106                                 ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
    1107                                 ast::OpenVarSet open( cand->open );
    1108 
    1109                                 cand->env.extractOpenVars( open );
    1110 
    1111                                 // It is possible that a cast can throw away some values in a multiply-valued
    1112                                 // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
    1113                                 // subexpression results that are cast directly. The candidate is invalid if it
    1114                                 // has fewer results than there are types to cast to.
    1115                                 int discardedValues = cand->expr->result->size() - toType->size();
    1116                                 if ( discardedValues < 0 ) continue;
    1117 
    1118                                 // unification run for side-effects
    1119                                 unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
    1120                                 Cost thisCost =
    1121                                         (castExpr->isGenerated == ast::GeneratedFlag::GeneratedCast)
    1122                             ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
    1123                             : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
    1124 
    1125                                 PRINT(
    1126                                         std::cerr << "working on cast with result: " << toType << std::endl;
    1127                                         std::cerr << "and expr type: " << cand->expr->result << std::endl;
    1128                                         std::cerr << "env: " << cand->env << std::endl;
    1129                                 )
    1130                                 if ( thisCost != Cost::infinity ) {
    1131                                         PRINT(
    1132                                                 std::cerr << "has finite cost." << std::endl;
    1133                                         )
    1134                                         // count one safe conversion for each value that is thrown away
    1135                                         thisCost.incSafe( discardedValues );
    1136                                         CandidateRef newCand = std::make_shared<Candidate>(
    1137                                                 restructureCast( cand->expr, toType, castExpr->isGenerated ),
    1138                                                 copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
    1139                                                 cand->cost + thisCost );
    1140                                         inferParameters( newCand, matches );
    1141                                 }
    1142                         }
    1143 
    1144                         // select first on argument cost, then conversion cost
    1145                         CandidateList minArgCost = findMinCost( matches );
    1146                         promoteCvtCost( minArgCost );
    1147                         candidates = findMinCost( minArgCost );
    1148                 }
    1149 
    1150                 void postvisit( const ast::VirtualCastExpr * castExpr ) {
    1151                         assertf( castExpr->result, "Implicit virtual cast targets not yet supported." );
    1152                         CandidateFinder finder( context, tenv );
    1153                         // don't prune here, all alternatives guaranteed to have same type
    1154                         finder.find( castExpr->arg, ResolvMode::withoutPrune() );
    1155                         for ( CandidateRef & r : finder.candidates ) {
    1156                                 addCandidate(
    1157                                         *r,
    1158                                         new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
    1159                         }
    1160                 }
    1161 
    1162                 void postvisit( const ast::KeywordCastExpr * castExpr ) {
    1163                         const auto & loc = castExpr->location;
    1164                         assertf( castExpr->result, "Cast target should have been set in Validate." );
    1165                         auto ref = castExpr->result.strict_as<ast::ReferenceType>();
    1166                         auto inst = ref->base.strict_as<ast::StructInstType>();
    1167                         auto target = inst->base.get();
    1168 
    1169                         CandidateFinder finder( context, tenv );
    1170 
    1171                         auto pick_alternatives = [target, this](CandidateList & found, bool expect_ref) {
    1172                                 for(auto & cand : found) {
    1173                                         const ast::Type * expr = cand->expr->result.get();
    1174                                         if(expect_ref) {
    1175                                                 auto res = dynamic_cast<const ast::ReferenceType*>(expr);
    1176                                                 if(!res) { continue; }
    1177                                                 expr = res->base.get();
    1178                                         }
    1179 
    1180                                         if(auto insttype = dynamic_cast<const ast::TypeInstType*>(expr)) {
    1181                                                 auto td = cand->env.lookup(*insttype);
    1182                                                 if(!td) { continue; }
    1183                                                 expr = td->bound.get();
    1184                                         }
    1185 
    1186                                         if(auto base = dynamic_cast<const ast::StructInstType*>(expr)) {
    1187                                                 if(base->base == target) {
    1188                                                         candidates.push_back( std::move(cand) );
    1189                                                         reason.code = NoReason;
    1190                                                 }
    1191                                         }
    1192                                 }
    1193                         };
    1194 
    1195                         try {
    1196                                 // Attempt 1 : turn (thread&)X into (thread$&)X.__thrd
    1197                                 // Clone is purely for memory management
    1198                                 std::unique_ptr<const ast::Expr> tech1 { new ast::UntypedMemberExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.field), castExpr->arg) };
    1199 
    1200                                 // don't prune here, since it's guaranteed all alternatives will have the same type
    1201                                 finder.find( tech1.get(), ResolvMode::withoutPrune() );
    1202                                 pick_alternatives(finder.candidates, false);
    1203 
    1204                                 return;
    1205                         } catch(SemanticErrorException & ) {}
    1206 
    1207                         // Fallback : turn (thread&)X into (thread$&)get_thread(X)
    1208                         std::unique_ptr<const ast::Expr> fallback { ast::UntypedExpr::createDeref(loc,  new ast::UntypedExpr(loc, new ast::NameExpr(loc, castExpr->concrete_target.getter), { castExpr->arg })) };
    1209                         // don't prune here, since it's guaranteed all alternatives will have the same type
    1210                         finder.find( fallback.get(), ResolvMode::withoutPrune() );
    1211 
    1212                         pick_alternatives(finder.candidates, true);
    1213 
    1214                         // Whatever happens here, we have no more fallbacks
    1215                 }
    1216 
    1217                 void postvisit( const ast::UntypedMemberExpr * memberExpr ) {
    1218                         CandidateFinder aggFinder( context, tenv );
    1219                         aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
    1220                         for ( CandidateRef & agg : aggFinder.candidates ) {
    1221                                 // it's okay for the aggregate expression to have reference type -- cast it to the
    1222                                 // base type to treat the aggregate as the referenced value
    1223                                 Cost addedCost = Cost::zero;
    1224                                 agg->expr = referenceToRvalueConversion( agg->expr, addedCost );
    1225 
    1226                                 // find member of the given type
    1227                                 if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
    1228                                         addAggMembers(
    1229                                                 structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    1230                                 } else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
    1231                                         addAggMembers(
    1232                                                 unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
    1233                                 } else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
    1234                                         addTupleMembers( tupleType, agg->expr, *agg, addedCost, memberExpr->member );
    1235                                 }
    1236                         }
    1237                 }
    1238 
    1239                 void postvisit( const ast::MemberExpr * memberExpr ) {
    1240                         addCandidate( memberExpr, tenv );
    1241                 }
    1242 
    1243                 void postvisit( const ast::NameExpr * nameExpr ) {
    1244                         std::vector< ast::SymbolTable::IdData > declList;
    1245                         if (!selfFinder.otypeKeys.empty()) {
    1246                                 auto kind = ast::SymbolTable::getSpecialFunctionKind(nameExpr->name);
    1247                                 assertf(kind != ast::SymbolTable::SpecialFunctionKind::NUMBER_OF_KINDS, "special lookup with non-special target: %s", nameExpr->name.c_str());
    1248 
    1249                                 for (auto & otypeKey: selfFinder.otypeKeys) {
    1250                                         auto result = symtab.specialLookupId(kind, otypeKey);
    1251                                         declList.insert(declList.end(), std::make_move_iterator(result.begin()), std::make_move_iterator(result.end()));
    1252                                 }
    1253                         }
    1254                         else {
    1255                                 declList = symtab.lookupId( nameExpr->name );
    1256                         }
    1257                         PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
    1258 
    1259                         if( declList.empty() ) return;
    1260 
    1261                         reason.code = NoMatch;
    1262 
    1263                         for ( auto & data : declList ) {
    1264                                 Cost cost = Cost::zero;
    1265                                 ast::Expr * newExpr = data.combine( nameExpr->location, cost );
    1266 
    1267                                 CandidateRef newCand = std::make_shared<Candidate>(
    1268                                         newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
    1269                                         cost );
    1270 
    1271                                 if (newCand->expr->env) {
    1272                                         newCand->env.add(*newCand->expr->env);
    1273                                         auto mutExpr = newCand->expr.get_and_mutate();
    1274                                         mutExpr->env  = nullptr;
    1275                                         newCand->expr = mutExpr;
    1276                                 }
    1277 
    1278                                 PRINT(
    1279                                         std::cerr << "decl is ";
    1280                                         ast::print( std::cerr, data.id );
    1281                                         std::cerr << std::endl;
    1282                                         std::cerr << "newExpr is ";
    1283                                         ast::print( std::cerr, newExpr );
    1284                                         std::cerr << std::endl;
    1285                                 )
    1286                                 newCand->expr = ast::mutate_field(
    1287                                         newCand->expr.get(), &ast::Expr::result,
    1288                                         renameTyVars( newCand->expr->result ) );
    1289                                 // add anonymous member interpretations whenever an aggregate value type is seen
    1290                                 // as a name expression
    1291                                 addAnonConversions( newCand );
    1292                                 candidates.emplace_back( std::move( newCand ) );
    1293                         }
    1294                 }
    1295 
    1296                 void postvisit( const ast::VariableExpr * variableExpr ) {
    1297                         // not sufficient to just pass `variableExpr` here, type might have changed since
    1298                         // creation
    1299                         addCandidate(
    1300                                 new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
    1301                 }
    1302 
    1303                 void postvisit( const ast::ConstantExpr * constantExpr ) {
    1304                         addCandidate( constantExpr, tenv );
    1305                 }
    1306 
    1307                 void postvisit( const ast::SizeofExpr * sizeofExpr ) {
    1308                         if ( sizeofExpr->type ) {
    1309                                 addCandidate(
    1310                                         new ast::SizeofExpr{
    1311                                                 sizeofExpr->location, resolveTypeof( sizeofExpr->type, context ) },
    1312                                         tenv );
    1313                         } else {
    1314                                 // find all candidates for the argument to sizeof
    1315                                 CandidateFinder finder( context, tenv );
    1316                                 finder.find( sizeofExpr->expr );
    1317                                 // find the lowest-cost candidate, otherwise ambiguous
    1318                                 CandidateList winners = findMinCost( finder.candidates );
    1319                                 if ( winners.size() != 1 ) {
    1320                                         SemanticError(
    1321                                                 sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
    1322                                 }
    1323                                 // return the lowest-cost candidate
    1324                                 CandidateRef & choice = winners.front();
    1325                                 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    1326                                 choice->cost = Cost::zero;
    1327                                 addCandidate( *choice, new ast::SizeofExpr{ sizeofExpr->location, choice->expr } );
    1328                         }
    1329                 }
    1330 
    1331                 void postvisit( const ast::AlignofExpr * alignofExpr ) {
    1332                         if ( alignofExpr->type ) {
    1333                                 addCandidate(
    1334                                         new ast::AlignofExpr{
    1335                                                 alignofExpr->location, resolveTypeof( alignofExpr->type, context ) },
    1336                                         tenv );
    1337                         } else {
    1338                                 // find all candidates for the argument to alignof
    1339                                 CandidateFinder finder( context, tenv );
    1340                                 finder.find( alignofExpr->expr );
    1341                                 // find the lowest-cost candidate, otherwise ambiguous
    1342                                 CandidateList winners = findMinCost( finder.candidates );
    1343                                 if ( winners.size() != 1 ) {
    1344                                         SemanticError(
    1345                                                 alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
    1346                                 }
    1347                                 // return the lowest-cost candidate
    1348                                 CandidateRef & choice = winners.front();
    1349                                 choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
    1350                                 choice->cost = Cost::zero;
    1351                                 addCandidate(
    1352                                         *choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
    1353                         }
    1354                 }
    1355 
    1356                 void postvisit( const ast::UntypedOffsetofExpr * offsetofExpr ) {
    1357                         const ast::BaseInstType * aggInst;
    1358                         if (( aggInst = offsetofExpr->type.as< ast::StructInstType >() )) ;
    1359                         else if (( aggInst = offsetofExpr->type.as< ast::UnionInstType >() )) ;
    1360                         else return;
    1361 
    1362                         for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
    1363                                 auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
    1364                                 addCandidate(
    1365                                         new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
    1366                         }
    1367                 }
    1368 
    1369                 void postvisit( const ast::OffsetofExpr * offsetofExpr ) {
    1370                         addCandidate( offsetofExpr, tenv );
    1371                 }
    1372 
    1373                 void postvisit( const ast::OffsetPackExpr * offsetPackExpr ) {
    1374                         addCandidate( offsetPackExpr, tenv );
    1375                 }
    1376 
    1377                 void postvisit( const ast::LogicalExpr * logicalExpr ) {
    1378                         CandidateFinder finder1( context, tenv );
    1379                         finder1.find( logicalExpr->arg1, ResolvMode::withAdjustment() );
    1380                         if ( finder1.candidates.empty() ) return;
    1381 
    1382                         CandidateFinder finder2( context, tenv );
    1383                         finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
    1384                         if ( finder2.candidates.empty() ) return;
    1385 
    1386                         reason.code = NoMatch;
    1387 
    1388                         for ( const CandidateRef & r1 : finder1.candidates ) {
    1389                                 for ( const CandidateRef & r2 : finder2.candidates ) {
    1390                                         ast::TypeEnvironment env{ r1->env };
    1391                                         env.simpleCombine( r2->env );
    1392                                         ast::OpenVarSet open{ r1->open };
    1393                                         mergeOpenVars( open, r2->open );
    1394                                         ast::AssertionSet need;
    1395                                         mergeAssertionSet( need, r1->need );
    1396                                         mergeAssertionSet( need, r2->need );
    1397 
    1398                                         addCandidate(
    1399                                                 new ast::LogicalExpr{
    1400                                                         logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
    1401                                                 std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );
    1402                                 }
    1403                         }
    1404                 }
    1405 
    1406                 void postvisit( const ast::ConditionalExpr * conditionalExpr ) {
    1407                         // candidates for condition
    1408                         CandidateFinder finder1( context, tenv );
    1409                         finder1.find( conditionalExpr->arg1, ResolvMode::withAdjustment() );
    1410                         if ( finder1.candidates.empty() ) return;
    1411 
    1412                         // candidates for true result
    1413                         CandidateFinder finder2( context, tenv );
    1414                         finder2.find( conditionalExpr->arg2, ResolvMode::withAdjustment() );
    1415                         if ( finder2.candidates.empty() ) return;
    1416 
    1417                         // candidates for false result
    1418                         CandidateFinder finder3( context, tenv );
    1419                         finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
    1420                         if ( finder3.candidates.empty() ) return;
    1421 
    1422                         reason.code = NoMatch;
    1423 
    1424                         for ( const CandidateRef & r1 : finder1.candidates ) {
    1425                                 for ( const CandidateRef & r2 : finder2.candidates ) {
    1426                                         for ( const CandidateRef & r3 : finder3.candidates ) {
    1427                                                 ast::TypeEnvironment env{ r1->env };
    1428                                                 env.simpleCombine( r2->env );
    1429                                                 env.simpleCombine( r3->env );
    1430                                                 ast::OpenVarSet open{ r1->open };
    1431                                                 mergeOpenVars( open, r2->open );
    1432                                                 mergeOpenVars( open, r3->open );
    1433                                                 ast::AssertionSet need;
    1434                                                 mergeAssertionSet( need, r1->need );
    1435                                                 mergeAssertionSet( need, r2->need );
    1436                                                 mergeAssertionSet( need, r3->need );
    1437                                                 ast::AssertionSet have;
    1438 
    1439                                                 // unify true and false results, then infer parameters to produce new
    1440                                                 // candidates
    1441                                                 ast::ptr< ast::Type > common;
    1442                                                 if (
    1443                                                         unify(
    1444                                                                 r2->expr->result, r3->expr->result, env, need, have, open, symtab,
    1445                                                                 common )
    1446                                                 ) {
    1447                                                         // generate typed expression
    1448                                                         ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
    1449                                                                 conditionalExpr->location, r1->expr, r2->expr, r3->expr };
    1450                                                         newExpr->result = common ? common : r2->expr->result;
    1451                                                         // convert both options to result type
    1452                                                         Cost cost = r1->cost + r2->cost + r3->cost;
    1453                                                         newExpr->arg2 = computeExpressionConversionCost(
    1454                                                                 newExpr->arg2, newExpr->result, symtab, env, cost );
    1455                                                         newExpr->arg3 = computeExpressionConversionCost(
    1456                                                                 newExpr->arg3, newExpr->result, symtab, env, cost );
    1457                                                         // output candidate
    1458                                                         CandidateRef newCand = std::make_shared<Candidate>(
    1459                                                                 newExpr, std::move( env ), std::move( open ), std::move( need ), cost );
    1460                                                         inferParameters( newCand, candidates );
    1461                                                 }
    1462                                         }
    1463                                 }
    1464                         }
    1465                 }
    1466 
    1467                 void postvisit( const ast::CommaExpr * commaExpr ) {
    1468                         ast::TypeEnvironment env{ tenv };
    1469                         ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, context, env );
    1470 
    1471                         CandidateFinder finder2( context, env );
    1472                         finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
    1473 
    1474                         for ( const CandidateRef & r2 : finder2.candidates ) {
    1475                                 addCandidate( *r2, new ast::CommaExpr{ commaExpr->location, arg1, r2->expr } );
    1476                         }
    1477                 }
    1478 
    1479                 void postvisit( const ast::ImplicitCopyCtorExpr * ctorExpr ) {
    1480                         addCandidate( ctorExpr, tenv );
    1481                 }
    1482 
    1483                 void postvisit( const ast::ConstructorExpr * ctorExpr ) {
    1484                         CandidateFinder finder( context, tenv );
    1485                         finder.find( ctorExpr->callExpr, ResolvMode::withoutPrune() );
    1486                         for ( CandidateRef & r : finder.candidates ) {
    1487                                 addCandidate( *r, new ast::ConstructorExpr{ ctorExpr->location, r->expr } );
    1488                         }
    1489                 }
    1490 
    1491                 void postvisit( const ast::RangeExpr * rangeExpr ) {
    1492                         // resolve low and high, accept candidates where low and high types unify
    1493                         CandidateFinder finder1( context, tenv );
    1494                         finder1.find( rangeExpr->low, ResolvMode::withAdjustment() );
    1495                         if ( finder1.candidates.empty() ) return;
    1496 
    1497                         CandidateFinder finder2( context, tenv );
    1498                         finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
    1499                         if ( finder2.candidates.empty() ) return;
    1500 
    1501                         reason.code = NoMatch;
    1502 
    1503                         for ( const CandidateRef & r1 : finder1.candidates ) {
    1504                                 for ( const CandidateRef & r2 : finder2.candidates ) {
    1505                                         ast::TypeEnvironment env{ r1->env };
    1506                                         env.simpleCombine( r2->env );
    1507                                         ast::OpenVarSet open{ r1->open };
    1508                                         mergeOpenVars( open, r2->open );
    1509                                         ast::AssertionSet need;
    1510                                         mergeAssertionSet( need, r1->need );
    1511                                         mergeAssertionSet( need, r2->need );
    1512                                         ast::AssertionSet have;
    1513 
    1514                                         ast::ptr< ast::Type > common;
    1515                                         if (
    1516                                                 unify(
    1517                                                         r1->expr->result, r2->expr->result, env, need, have, open, symtab,
    1518                                                         common )
    1519                                         ) {
    1520                                                 // generate new expression
    1521                                                 ast::RangeExpr * newExpr =
    1522                                                         new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
    1523                                                 newExpr->result = common ? common : r1->expr->result;
    1524                                                 // add candidate
    1525                                                 CandidateRef newCand = std::make_shared<Candidate>(
    1526                                                         newExpr, std::move( env ), std::move( open ), std::move( need ),
    1527                                                         r1->cost + r2->cost );
    1528                                                 inferParameters( newCand, candidates );
    1529                                         }
    1530                                 }
    1531                         }
    1532                 }
    1533 
    1534                 void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
    1535                         std::vector< CandidateFinder > subCandidates =
    1536                                 selfFinder.findSubExprs( tupleExpr->exprs );
    1537                         std::vector< CandidateList > possibilities;
    1538                         combos( subCandidates.begin(), subCandidates.end(), back_inserter( possibilities ) );
    1539 
    1540                         for ( const CandidateList & subs : possibilities ) {
    1541                                 std::vector< ast::ptr< ast::Expr > > exprs;
    1542                                 exprs.reserve( subs.size() );
    1543                                 for ( const CandidateRef & sub : subs ) { exprs.emplace_back( sub->expr ); }
    1544 
    1545                                 ast::TypeEnvironment env;
    1546                                 ast::OpenVarSet open;
    1547                                 ast::AssertionSet need;
    1548                                 for ( const CandidateRef & sub : subs ) {
    1549                                         env.simpleCombine( sub->env );
    1550                                         mergeOpenVars( open, sub->open );
    1551                                         mergeAssertionSet( need, sub->need );
    1552                                 }
    1553 
    1554                                 addCandidate(
    1555                                         new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },
    1556                                         std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
    1557                         }
    1558                 }
    1559 
    1560                 void postvisit( const ast::TupleExpr * tupleExpr ) {
    1561                         addCandidate( tupleExpr, tenv );
    1562                 }
    1563 
    1564                 void postvisit( const ast::TupleIndexExpr * tupleExpr ) {
    1565                         addCandidate( tupleExpr, tenv );
    1566                 }
    1567 
    1568                 void postvisit( const ast::TupleAssignExpr * tupleExpr ) {
    1569                         addCandidate( tupleExpr, tenv );
    1570                 }
    1571 
    1572                 void postvisit( const ast::UniqueExpr * unqExpr ) {
    1573                         CandidateFinder finder( context, tenv );
    1574                         finder.find( unqExpr->expr, ResolvMode::withAdjustment() );
    1575                         for ( CandidateRef & r : finder.candidates ) {
    1576                                 // ensure that the the id is passed on so that the expressions are "linked"
    1577                                 addCandidate( *r, new ast::UniqueExpr{ unqExpr->location, r->expr, unqExpr->id } );
    1578                         }
    1579                 }
    1580 
    1581                 void postvisit( const ast::StmtExpr * stmtExpr ) {
    1582                         addCandidate( resolveStmtExpr( stmtExpr, context ), tenv );
    1583                 }
    1584 
    1585                 void postvisit( const ast::UntypedInitExpr * initExpr ) {
    1586                         // handle each option like a cast
    1587                         CandidateList matches;
    1588                         PRINT(
    1589                                 std::cerr << "untyped init expr: " << initExpr << std::endl;
    1590                         )
    1591                         // O(n^2) checks of d-types with e-types
    1592                         for ( const ast::InitAlternative & initAlt : initExpr->initAlts ) {
    1593                                 // calculate target type
    1594                                 const ast::Type * toType = resolveTypeof( initAlt.type, context );
    1595                                 toType = adjustExprType( toType, tenv, symtab );
    1596                                 // The call to find must occur inside this loop, otherwise polymorphic return
    1597                                 // types are not bound to the initialization type, since return type variables are
    1598                                 // only open for the duration of resolving the UntypedExpr.
    1599                                 CandidateFinder finder( context, tenv, toType );
    1600                                 finder.find( initExpr->expr, ResolvMode::withAdjustment() );
    1601                                 for ( CandidateRef & cand : finder.candidates ) {
    1602                                         if(reason.code == NotFound) reason.code = NoMatch;
    1603 
    1604                                         ast::TypeEnvironment env{ cand->env };
    1605                                         ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
    1606                                         ast::OpenVarSet open{ cand->open };
    1607 
    1608                                         PRINT(
    1609                                                 std::cerr << "  @ " << toType << " " << initAlt.designation << std::endl;
    1610                                         )
    1611 
    1612                                         // It is possible that a cast can throw away some values in a multiply-valued
    1613                                         // expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
    1614                                         // the subexpression results that are cast directly. The candidate is invalid
    1615                                         // if it has fewer results than there are types to cast to.
    1616                                         int discardedValues = cand->expr->result->size() - toType->size();
    1617                                         if ( discardedValues < 0 ) continue;
    1618 
    1619                                         // unification run for side-effects
    1620                                         bool canUnify = unify( toType, cand->expr->result, env, need, have, open, symtab );
    1621                                         (void) canUnify;
    1622                                         Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1623                                                 symtab, env );
    1624                                         PRINT(
    1625                                                 Cost legacyCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
    1626                                                         symtab, env );
    1627                                                 std::cerr << "Considering initialization:";
    1628                                                 std::cerr << std::endl << "  FROM: " << cand->expr->result << std::endl;
    1629                                                 std::cerr << std::endl << "  TO: "   << toType             << std::endl;
    1630                                                 std::cerr << std::endl << "  Unification " << (canUnify ? "succeeded" : "failed");
    1631                                                 std::cerr << std::endl << "  Legacy cost " << legacyCost;
    1632                                                 std::cerr << std::endl << "  New cost " << thisCost;
    1633                                                 std::cerr << std::endl;
    1634                                         )
    1635                                         if ( thisCost != Cost::infinity ) {
    1636                                                 // count one safe conversion for each value that is thrown away
    1637                                                 thisCost.incSafe( discardedValues );
    1638                                                 CandidateRef newCand = std::make_shared<Candidate>(
    1639                                                         new ast::InitExpr{
    1640                                                                 initExpr->location, restructureCast( cand->expr, toType ),
    1641                                                                 initAlt.designation },
    1642                                                         std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
    1643                                                 inferParameters( newCand, matches );
    1644                                         }
    1645                                 }
    1646 
    1647                         }
    1648 
    1649                         // select first on argument cost, then conversion cost
    1650                         CandidateList minArgCost = findMinCost( matches );
    1651                         promoteCvtCost( minArgCost );
    1652                         candidates = findMinCost( minArgCost );
    1653                 }
    1654 
    1655                 void postvisit( const ast::InitExpr * ) {
    1656                         assertf( false, "CandidateFinder should never see a resolved InitExpr." );
    1657                 }
    1658 
    1659                 void postvisit( const ast::DeletedExpr * ) {
    1660                         assertf( false, "CandidateFinder should never see a DeletedExpr." );
    1661                 }
    1662 
    1663                 void postvisit( const ast::GenericExpr * ) {
    1664                         assertf( false, "_Generic is not yet supported." );
    1665                 }
    1666         };
    1667 
    1668         // size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
    1669         /// Prunes a list of candidates down to those that have the minimum conversion cost for a given
    1670         /// return type. Skips ambiguous candidates.
    1671 
    1672 } // anonymous namespace
    1673 
    1674 bool CandidateFinder::pruneCandidates( CandidateList & candidates, CandidateList & out, std::vector<std::string> & errors ) {
    1675         struct PruneStruct {
    1676                 CandidateRef candidate;
    1677                 bool ambiguous;
    1678 
    1679                 PruneStruct() = default;
    1680                 PruneStruct( const CandidateRef & c ) : candidate( c ), ambiguous( false ) {}
    1681         };
    1682 
    1683         // find lowest-cost candidate for each type
    1684         std::unordered_map< std::string, PruneStruct > selected;
    1685         // attempt to skip satisfyAssertions on more expensive alternatives if better options have been found
    1686         std::sort(candidates.begin(), candidates.end(), [](const CandidateRef & x, const CandidateRef & y){return x->cost < y->cost;});
    1687         for ( CandidateRef & candidate : candidates ) {
    1688                 std::string mangleName;
    1689                 {
    1690                         ast::ptr< ast::Type > newType = candidate->expr->result;
    1691                         assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
    1692                         candidate->env.apply( newType );
    1693                         mangleName = Mangle::mangle( newType );
    1694                 }
    1695 
    1696                 auto found = selected.find( mangleName );
    1697                 if (found != selected.end() && found->second.candidate->cost < candidate->cost) {
    1698                         PRINT(
    1699                                 std::cerr << "cost " << candidate->cost << " loses to "
    1700                                         << found->second.candidate->cost << std::endl;
    1701                         )
    1702                         continue;
    1703                 }
    1704 
    1705                 // xxx - when do satisfyAssertions produce more than 1 result?
    1706                 // this should only happen when initial result type contains
    1707                 // unbound type parameters, then it should never be pruned by
    1708                 // the previous step, since renameTyVars guarantees the mangled name
    1709                 // is unique.
    1710                 CandidateList satisfied;
    1711                 bool needRecomputeKey = false;
    1712                 if (candidate->need.empty()) {
    1713                         satisfied.emplace_back(candidate);
    1714                 }
    1715                 else {
    1716                         satisfyAssertions(candidate, context.symtab, satisfied, errors);
    1717                         needRecomputeKey = true;
    1718                 }
    1719 
    1720                 for (auto & newCand : satisfied) {
    1721                         // recomputes type key, if satisfyAssertions changed it
    1722                         if (needRecomputeKey)
    1723                         {
    1724                                 ast::ptr< ast::Type > newType = newCand->expr->result;
    1725                                 assertf(newCand->expr->result, "Result of expression %p for candidate is null", newCand->expr.get());
    1726                                 newCand->env.apply( newType );
    1727                                 mangleName = Mangle::mangle( newType );
    1728                         }
    1729                         auto found = selected.find( mangleName );
    1730                         if ( found != selected.end() ) {
    1731                                 if ( newCand->cost < found->second.candidate->cost ) {
    1732                                         PRINT(
    1733                                                 std::cerr << "cost " << newCand->cost << " beats "
    1734                                                         << found->second.candidate->cost << std::endl;
    1735                                         )
    1736 
    1737                                         found->second = PruneStruct{ newCand };
    1738                                 } else if ( newCand->cost == found->second.candidate->cost ) {
    1739                                         // if one of the candidates contains a deleted identifier, can pick the other,
    1740                                         // since deleted expressions should not be ambiguous if there is another option
    1741                                         // that is at least as good
    1742                                         if ( findDeletedExpr( newCand->expr ) ) {
    1743                                                 // do nothing
    1744                                                 PRINT( std::cerr << "candidate is deleted" << std::endl; )
    1745                                         } else if ( findDeletedExpr( found->second.candidate->expr ) ) {
    1746                                                 PRINT( std::cerr << "current is deleted" << std::endl; )
    1747                                                 found->second = PruneStruct{ newCand };
    1748                                         } else {
    1749                                                 PRINT( std::cerr << "marking ambiguous" << std::endl; )
    1750                                                 found->second.ambiguous = true;
    1751                                         }
    1752                                 } else {
    1753                                         // xxx - can satisfyAssertions increase the cost?
    1754                                         PRINT(
    1755                                                 std::cerr << "cost " << newCand->cost << " loses to "
    1756                                                         << found->second.candidate->cost << std::endl;
    1757                                         )
    1758                                 }
    1759                         } else {
    1760                                 selected.emplace_hint( found, mangleName, newCand );
    1761                         }
    1762                 }
    1763         }
    1764 
    1765         // report unambiguous min-cost candidates
    1766         // CandidateList out;
    1767         for ( auto & target : selected ) {
    1768                 if ( target.second.ambiguous ) continue;
    1769 
    1770                 CandidateRef cand = target.second.candidate;
    1771 
    1772                 ast::ptr< ast::Type > newResult = cand->expr->result;
    1773                 cand->env.applyFree( newResult );
    1774                 cand->expr = ast::mutate_field(
    1775                         cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
    1776 
    1777                 out.emplace_back( cand );
    1778         }
    1779         // if everything is lost in satisfyAssertions, report the error
    1780         return !selected.empty();
    1781 }
    1782 
    1783 void CandidateFinder::find( const ast::Expr * expr, ResolvMode mode ) {
    1784         // Find alternatives for expression
    1785         ast::Pass<Finder> finder{ *this };
    1786         expr->accept( finder );
    1787 
    1788         if ( mode.failFast && candidates.empty() ) {
    1789                 switch(finder.core.reason.code) {
    1790                 case Finder::NotFound:
    1791                         { SemanticError( expr, "No alternatives for expression " ); break; }
    1792                 case Finder::NoMatch:
    1793                         { SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
    1794                 case Finder::ArgsToFew:
    1795                 case Finder::ArgsToMany:
    1796                 case Finder::RetsToFew:
    1797                 case Finder::RetsToMany:
    1798                 case Finder::NoReason:
    1799                 default:
    1800                         { SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
    1801                 }
    1802         }
    1803 
    1804         /*
    1805         if ( mode.satisfyAssns || mode.prune ) {
    1806                 // trim candidates to just those where the assertions are satisfiable
    1807                 // - necessary pre-requisite to pruning
    1808                 CandidateList satisfied;
    1809                 std::vector< std::string > errors;
    1810                 for ( CandidateRef & candidate : candidates ) {
    1811                         satisfyAssertions( candidate, localSyms, satisfied, errors );
    1812                 }
    1813 
    1814                 // fail early if none such
    1815                 if ( mode.failFast && satisfied.empty() ) {
    1816                         std::ostringstream stream;
    1817                         stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    1818                         for ( const auto& err : errors ) {
    1819                                 stream << err;
    1820                         }
    1821                         SemanticError( expr->location, stream.str() );
    1822                 }
    1823 
    1824                 // reset candidates
    1825                 candidates = move( satisfied );
    1826         }
    1827         */
    1828 
    1829         if ( mode.prune ) {
    1830                 // trim candidates to single best one
    1831                 PRINT(
    1832                         std::cerr << "alternatives before prune:" << std::endl;
    1833                         print( std::cerr, candidates );
    1834                 )
    1835 
    1836                 CandidateList pruned;
    1837                 std::vector<std::string> errors;
    1838                 bool found = pruneCandidates( candidates, pruned, errors );
    1839 
    1840                 if ( mode.failFast && pruned.empty() ) {
    1841                         std::ostringstream stream;
    1842                         if (found) {
    1843                                 CandidateList winners = findMinCost( candidates );
    1844                                 stream << "Cannot choose between " << winners.size() << " alternatives for "
    1845                                         "expression\n";
    1846                                 ast::print( stream, expr );
    1847                                 stream << " Alternatives are:\n";
    1848                                 print( stream, winners, 1 );
    1849                                 SemanticError( expr->location, stream.str() );
    1850                         }
    1851                         else {
    1852                                 stream << "No alternatives with satisfiable assertions for " << expr << "\n";
    1853                                 for ( const auto& err : errors ) {
    1854                                         stream << err;
    1855                                 }
    1856                                 SemanticError( expr->location, stream.str() );
    1857                         }
    1858                 }
    1859 
    1860                 auto oldsize = candidates.size();
    1861                 candidates = std::move( pruned );
    1862 
    1863                 PRINT(
    1864                         std::cerr << "there are " << oldsize << " alternatives before elimination" << std::endl;
    1865                 )
    1866                 PRINT(
    1867                         std::cerr << "there are " << candidates.size() << " alternatives after elimination"
    1868                                 << std::endl;
    1869                 )
    1870         }
    1871 
    1872         // adjust types after pruning so that types substituted by pruneAlternatives are correctly
    1873         // adjusted
    1874         if ( mode.adjust ) {
    1875                 for ( CandidateRef & r : candidates ) {
    1876                         r->expr = ast::mutate_field(
    1877                                 r->expr.get(), &ast::Expr::result,
    1878                                 adjustExprType( r->expr->result, r->env, context.symtab ) );
    1879                 }
    1880         }
    1881 
    1882         // Central location to handle gcc extension keyword, etc. for all expressions
    1883         for ( CandidateRef & r : candidates ) {
    1884                 if ( r->expr->extension != expr->extension ) {
    1885                         r->expr.get_and_mutate()->extension = expr->extension;
    1886                 }
    1887         }
    1888 }
    1889 
    1890 std::vector< CandidateFinder > CandidateFinder::findSubExprs(
    1891         const std::vector< ast::ptr< ast::Expr > > & xs
    1892 ) {
    1893         std::vector< CandidateFinder > out;
    1894 
    1895         for ( const auto & x : xs ) {
    1896                 out.emplace_back( context, env );
    1897                 out.back().find( x, ResolvMode::withAdjustment() );
    1898 
    1899                 PRINT(
    1900                         std::cerr << "findSubExprs" << std::endl;
    1901                         print( std::cerr, out.back().candidates );
    1902                 )
    1903         }
    1904 
    1905         return out;
    1906 }
    1907 
    19081970} // namespace ResolvExpr
    19091971
  • src/ResolvExpr/CurrentObject.cc

    ra50fdfb r6e1e2d0  
    99// Author           : Rob Schluntz
    1010// Created On       : Tue Jun 13 15:28:32 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Jul  1 09:16:01 2022
    13 // Update Count     : 15
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Mon Apr 10  9:40:00 2023
     13// Update Count     : 18
    1414//
    1515
     
    593593
    594594namespace ast {
     595        /// Iterates members of a type by initializer.
     596        class MemberIterator {
     597        public:
     598                virtual ~MemberIterator() {}
     599
     600                /// Internal set position based on iterator ranges.
     601                virtual void setPosition(
     602                        std::deque< ptr< Expr > >::const_iterator it,
     603                        std::deque< ptr< Expr > >::const_iterator end ) = 0;
     604
     605                /// Walks the current object using the given designators as a guide.
     606                void setPosition( const std::deque< ptr< Expr > > & designators ) {
     607                        setPosition( designators.begin(), designators.end() );
     608                }
     609
     610                /// Retrieve the list of possible (Type,Designation) pairs for the
     611                /// current position in the current object.
     612                virtual std::deque< InitAlternative > operator* () const = 0;
     613
     614                /// True if the iterator is not currently at the end.
     615                virtual operator bool() const = 0;
     616
     617                /// Moves the iterator by one member in the current object.
     618                virtual MemberIterator & bigStep() = 0;
     619
     620                /// Moves the iterator by one member in the current subobject.
     621                virtual MemberIterator & smallStep() = 0;
     622
     623                /// The type of the current object.
     624                virtual const Type * getType() = 0;
     625
     626                /// The type of the current subobject.
     627                virtual const Type * getNext() = 0;
     628
     629                /// Helper for operator*; aggregates must add designator to each init
     630                /// alternative, but adding designators in operator* creates duplicates.
     631                virtual std::deque< InitAlternative > first() const = 0;
     632        };
     633
    595634        /// create a new MemberIterator that traverses a type correctly
    596635        MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
     
    632671        };
    633672
    634         /// Iterates array types
    635         class ArrayIterator final : public MemberIterator {
     673        /// Iterates over an indexed type:
     674        class IndexIterator : public MemberIterator {
     675        protected:
    636676                CodeLocation location;
    637                 const ArrayType * array = nullptr;
    638                 const Type * base = nullptr;
    639677                size_t index = 0;
    640678                size_t size = 0;
    641                 std::unique_ptr< MemberIterator > memberIter;
    642 
    643                 void setSize( const Expr * expr ) {
    644                         auto res = eval( expr );
    645                         if ( ! res.second ) {
    646                                 SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) );
    647                         }
    648                         size = res.first;
    649                 }
    650 
    651         public:
    652                 ArrayIterator( const CodeLocation & loc, const ArrayType * at ) : location( loc ), array( at ), base( at->base ) {
    653                         PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
    654                         memberIter.reset( createMemberIterator( loc, base ) );
    655                         if ( at->isVarLen ) {
    656                                 SemanticError( location, at, "VLA initialization does not support @=: " );
    657                         }
    658                         setSize( at->dimension );
    659                 }
     679                std::unique_ptr<MemberIterator> memberIter;
     680        public:
     681                IndexIterator( const CodeLocation & loc, size_t size ) :
     682                        location( loc ), size( size )
     683                {}
    660684
    661685                void setPosition( const Expr * expr ) {
     
    666690                        auto arg = eval( expr );
    667691                        index = arg.first;
    668                         return;
    669692
    670693                        // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     
    684707
    685708                void setPosition(
    686                         std::deque< ptr< Expr > >::const_iterator begin,
    687                         std::deque< ptr< Expr > >::const_iterator end
     709                        std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
     710                        std::deque<ast::ptr<ast::Expr>>::const_iterator end
    688711                ) override {
    689712                        if ( begin == end ) return;
     
    696719
    697720                operator bool() const override { return index < size; }
     721        };
     722
     723        /// Iterates over the members of array types:
     724        class ArrayIterator final : public IndexIterator {
     725                const ArrayType * array = nullptr;
     726                const Type * base = nullptr;
     727
     728                size_t getSize( const Expr * expr ) {
     729                        auto res = eval( expr );
     730                        if ( !res.second ) {
     731                                SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) );
     732                        }
     733                        return res.first;
     734                }
     735
     736        public:
     737                ArrayIterator( const CodeLocation & loc, const ArrayType * at ) :
     738                                IndexIterator( loc, getSize( at->dimension) ),
     739                                array( at ), base( at->base ) {
     740                        PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
     741                        memberIter.reset( createMemberIterator( loc, base ) );
     742                        if ( at->isVarLen ) {
     743                                SemanticError( location, at, "VLA initialization does not support @=: " );
     744                        }
     745                }
    698746
    699747                ArrayIterator & bigStep() override {
     
    834882
    835883                const Type * getNext() final {
    836                         return ( memberIter && *memberIter ) ? memberIter->getType() : nullptr;
     884                        bool hasMember = memberIter && *memberIter;
     885                        return hasMember ? memberIter->getType() : nullptr;
    837886                }
    838887
     
    898947        };
    899948
    900         class TupleIterator final : public AggregateIterator {
    901         public:
    902                 TupleIterator( const CodeLocation & loc, const TupleType * inst )
    903                 : AggregateIterator(
    904                         loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members
    905                 ) {}
    906 
    907                 operator bool() const override {
    908                         return curMember != members.end() || (memberIter && *memberIter);
     949        /// Iterates across the positions in a tuple:
     950        class TupleIterator final : public IndexIterator {
     951                ast::TupleType const * const tuple;
     952
     953                const ast::Type * typeAtIndex() const {
     954                        assert( index < size );
     955                        return tuple->types[ index ].get();
     956                }
     957
     958        public:
     959                TupleIterator( const CodeLocation & loc, const TupleType * type )
     960                : IndexIterator( loc, type->size() ), tuple( type ) {
     961                        PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; )
     962                        memberIter.reset( createMemberIterator( loc, typeAtIndex() ) );
    909963                }
    910964
    911965                TupleIterator & bigStep() override {
    912                         PRINT( std::cerr << "bigStep in " << kind << std::endl; )
    913                         atbegin = false;
    914                         memberIter = nullptr;
    915                         curType = nullptr;
    916                         while ( curMember != members.end() ) {
    917                                 ++curMember;
    918                                 if ( init() ) return *this;
    919                         }
     966                        ++index;
     967                        memberIter.reset( index < size ?
     968                                createMemberIterator( location, typeAtIndex() ) : nullptr );
    920969                        return *this;
     970                }
     971
     972                TupleIterator & smallStep() override {
     973                        if ( memberIter ) {
     974                                PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
     975                                memberIter->smallStep();
     976                                if ( !memberIter ) {
     977                                        PRINT( std::cerr << "has valid member iter" << std::endl; )
     978                                        return *this;
     979                                }
     980                        }
     981                        return bigStep();
     982                }
     983
     984                const ast::Type * getType() override {
     985                        return tuple;
     986                }
     987
     988                const ast::Type * getNext() override {
     989                        bool hasMember = memberIter && *memberIter;
     990                        return hasMember ? memberIter->getType() : nullptr;
     991                }
     992
     993                std::deque< InitAlternative > first() const override {
     994                        PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; )
     995                        if ( memberIter && *memberIter ) {
     996                                std::deque< InitAlternative > ret = memberIter->first();
     997                                for ( InitAlternative & alt : ret ) {
     998                                        alt.designation.get_and_mutate()->designators.emplace_front(
     999                                                ConstantExpr::from_ulong( location, index ) );
     1000                                }
     1001                                return ret;
     1002                        }
     1003                        return {};
    9211004                }
    9221005        };
  • src/ResolvExpr/CurrentObject.h

    ra50fdfb r6e1e2d0  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Jun  8 11:07:25 2017
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Sat Jul 22 09:36:48 2017
    13 // Update Count     : 3
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thu Apr  6 16:14:00 2023
     13// Update Count     : 4
    1414//
    1515
     
    6565
    6666        /// Iterates members of a type by initializer
    67         class MemberIterator {
    68         public:
    69                 virtual ~MemberIterator() {}
    70 
    71                 /// Internal set position based on iterator ranges
    72                 virtual void setPosition(
    73                         std::deque< ptr< Expr > >::const_iterator it,
    74                         std::deque< ptr< Expr > >::const_iterator end ) = 0;
    75 
    76                 /// walks the current object using the given designators as a guide
    77                 void setPosition( const std::deque< ptr< Expr > > & designators ) {
    78                         setPosition( designators.begin(), designators.end() );
    79                 }
    80 
    81                 /// retrieve the list of possible (Type,Designation) pairs for the current position in the
    82                 /// current object
    83                 virtual std::deque< InitAlternative > operator* () const = 0;
    84 
    85                 /// true if the iterator is not currently at the end
    86                 virtual operator bool() const = 0;
    87 
    88                 /// moves the iterator by one member in the current object
    89                 virtual MemberIterator & bigStep() = 0;
    90 
    91                 /// moves the iterator by one member in the current subobject
    92                 virtual MemberIterator & smallStep() = 0;
    93 
    94                 /// the type of the current object
    95                 virtual const Type * getType() = 0;
    96 
    97                 /// the type of the current subobject
    98                 virtual const Type * getNext() = 0;
    99        
    100                 /// helper for operator*; aggregates must add designator to each init alternative, but
    101                 /// adding designators in operator* creates duplicates
    102                 virtual std::deque< InitAlternative > first() const = 0;
    103         };
     67        class MemberIterator;
    10468
    10569        /// Builds initializer lists in resolution
  • src/ResolvExpr/ExplodedArg.hpp

    ra50fdfb r6e1e2d0  
    3535        ExplodedArg() : env(), cost( Cost::zero ), exprs() {}
    3636        ExplodedArg( const Candidate & arg, const ast::SymbolTable & symtab );
    37        
     37
    3838        ExplodedArg( ExplodedArg && ) = default;
    3939        ExplodedArg & operator= ( ExplodedArg && ) = default;
  • src/SymTab/Autogen.cc

    ra50fdfb r6e1e2d0  
    1010// Created On       : Thu Mar 03 15:45:56 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Apr 27 14:39:06 2018
    13 // Update Count     : 63
     12// Last Modified On : Fri Apr 14 15:03:00 2023
     13// Update Count     : 64
    1414//
    1515
     
    211211        }
    212212
    213         bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
    214                 return obj && obj->name.empty() && obj->bitfieldWidth;
    215         }
    216 
    217213        /// inserts a forward declaration for functionDecl into declsToAdd
    218214        void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
     
    234230        }
    235231
    236         // shallow copy the pointer list for return
    237         std::vector<ast::ptr<ast::TypeDecl>> getGenericParams (const ast::Type * t) {
    238                 if (auto structInst = dynamic_cast<const ast::StructInstType*>(t)) {
    239                         return structInst->base->params;
    240                 }
    241                 if (auto unionInst = dynamic_cast<const ast::UnionInstType*>(t)) {
    242                         return unionInst->base->params;
    243                 }
    244                 return {};
    245         }
    246 
    247232        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    248233        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
     
    256241                ftype->parameters.push_back( dstParam );
    257242                return ftype;
    258         }
    259 
    260         /// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).
    261         ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) {
    262                 std::vector<ast::ptr<ast::TypeDecl>> typeParams;
    263                 if (maybePolymorphic) typeParams = getGenericParams(paramType);
    264                 auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall);
    265                 return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc), {}, ast::Linkage::Cforall);
    266243        }
    267244
  • src/SymTab/Autogen.h

    ra50fdfb r6e1e2d0  
    99// Author           : Rob Schluntz
    1010// Created On       : Sun May 17 21:53:34 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Dec 13 16:38:06 2019
    13 // Update Count     : 16
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Fri Apr 14 15:06:00 2023
     13// Update Count     : 17
    1414//
    1515
     
    4545        /// returns true if obj's name is the empty string and it has a bitfield width
    4646        bool isUnnamedBitfield( ObjectDecl * obj );
    47         bool isUnnamedBitfield( const ast::ObjectDecl * obj );
    4847
    4948        /// generate the type of an assignment function for paramType.
     
    5554        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true );
    5655
    57         ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true);
    58 
    5956        /// generate the type of a copy constructor for paramType.
    6057        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
     
    6764        template< typename OutputIterator >
    6865        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast = nullptr, bool forward = true );
    69 
    70         template< typename OutIter >
    71         ast::ptr< ast::Stmt > genCall(
    72                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    73                 const CodeLocation & loc, const std::string & fname, OutIter && out,
    74                 const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward );
    7566
    7667        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
     
    121112
    122113                *out++ = new ExprStmt( fExpr );
    123 
    124                 srcParam.clearArrayIndices();
    125 
    126                 return listInit;
    127         }
    128 
    129         /// inserts into out a generated call expression to function fname with arguments dstParam and
    130         /// srcParam. Should only be called with non-array types.
    131         /// optionally returns a statement which must be inserted prior to the containing loop, if
    132         /// there is one
    133         template< typename OutIter >
    134         ast::ptr< ast::Stmt > genScalarCall(
    135                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    136                 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type,
    137                 const ast::Type * addCast = nullptr
    138         ) {
    139                 bool isReferenceCtorDtor = false;
    140                 if ( dynamic_cast< const ast::ReferenceType * >( type ) && CodeGen::isCtorDtor( fname ) ) {
    141                         // reference constructors are essentially application of the rebind operator.
    142                         // apply & to both arguments, do not need a cast
    143                         fname = "?=?";
    144                         dstParam = new ast::AddressExpr{ dstParam };
    145                         addCast = nullptr;
    146                         isReferenceCtorDtor = true;
    147                 }
    148 
    149                 // want to be able to generate assignment, ctor, and dtor generically, so fname is one of
    150                 // "?=?", "?{}", or "^?{}"
    151                 ast::UntypedExpr * fExpr = new ast::UntypedExpr{ loc, new ast::NameExpr{ loc, fname } };
    152 
    153                 if ( addCast ) {
    154                         // cast to T& with qualifiers removed, so that qualified objects can be constructed and
    155                         // destructed with the same functions as non-qualified objects. Unfortunately, lvalue
    156                         // is considered a qualifier - for AddressExpr to resolve, its argument must have an
    157                         // lvalue-qualified type, so remove all qualifiers except lvalue.
    158                         // xxx -- old code actually removed lvalue too...
    159                         ast::ptr< ast::Type > guard = addCast;  // prevent castType from mutating addCast
    160                         ast::ptr< ast::Type > castType = addCast;
    161                         ast::remove_qualifiers(
    162                                 castType,
    163                                 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic );
    164                         dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } };
    165                 }
    166                 fExpr->args.emplace_back( dstParam );
    167 
    168                 ast::ptr<ast::Stmt> listInit = srcParam.buildListInit( fExpr );
    169 
    170                 // fetch next set of arguments
    171                 ++srcParam;
    172 
    173                 // return if adding reference fails -- will happen on default ctor and dtor
    174                 if ( isReferenceCtorDtor && ! srcParam.addReference() ) return listInit;
    175 
    176                 std::vector< ast::ptr< ast::Expr > > args = *srcParam;
    177                 splice( fExpr->args, args );
    178 
    179                 *out++ = new ast::ExprStmt{ loc, fExpr };
    180114
    181115                srcParam.clearArrayIndices();
     
    248182        }
    249183
    250         /// Store in out a loop which calls fname on each element of the array with srcParam and
    251         /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0
    252         template< typename OutIter >
    253         void genArrayCall(
    254                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    255                 const CodeLocation & loc, const std::string & fname, OutIter && out,
    256                 const ast::ArrayType * array, const ast::Type * addCast = nullptr,
    257                 LoopDirection forward = LoopForward
    258         ) {
    259                 static UniqueName indexName( "_index" );
    260 
    261                 // for a flexible array member nothing is done -- user must define own assignment
    262                 if ( ! array->dimension ) return;
    263 
    264                 if ( addCast ) {
    265                         // peel off array layer from cast
    266                         addCast = strict_dynamic_cast< const ast::ArrayType * >( addCast )->base;
    267                 }
    268 
    269                 ast::ptr< ast::Expr > begin, end;
    270                 std::string cmp, update;
    271 
    272                 if ( forward ) {
    273                         // generate: for ( int i = 0; i < N; ++i )
    274                         begin = ast::ConstantExpr::from_int( loc, 0 );
    275                         end = array->dimension;
    276                         cmp = "?<?";
    277                         update = "++?";
    278                 } else {
    279                         // generate: for ( int i = N-1; i >= 0; --i )
    280                         begin = ast::UntypedExpr::createCall( loc, "?-?",
    281                                 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } );
    282                         end = ast::ConstantExpr::from_int( loc, 0 );
    283                         cmp = "?>=?";
    284                         update = "--?";
    285                 }
    286 
    287                 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{
    288                         loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt },
    289                         new ast::SingleInit{ loc, begin } };
    290                 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
    291 
    292                 ast::ptr< ast::Expr > cond = ast::UntypedExpr::createCall(
    293                         loc, cmp, { indexVar, end } );
    294 
    295                 ast::ptr< ast::Expr > inc = ast::UntypedExpr::createCall(
    296                         loc, update, { indexVar } );
    297 
    298                 ast::ptr< ast::Expr > dstIndex = ast::UntypedExpr::createCall(
    299                         loc, "?[?]", { dstParam, indexVar } );
    300 
    301                 // srcParam must keep track of the array indices to build the source parameter and/or
    302                 // array list initializer
    303                 srcParam.addArrayIndex( indexVar, array->dimension );
    304 
    305                 // for stmt's body, eventually containing call
    306                 ast::CompoundStmt * body = new ast::CompoundStmt{ loc };
    307                 ast::ptr< ast::Stmt > listInit = genCall(
    308                         srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast,
    309                         forward );
    310 
    311                 // block containing the stmt and index variable
    312                 ast::CompoundStmt * block = new ast::CompoundStmt{ loc };
    313                 block->push_back( new ast::DeclStmt{ loc, index } );
    314                 if ( listInit ) { block->push_back( listInit ); }
    315                 block->push_back( new ast::ForStmt{ loc, {}, cond, inc, body } );
    316 
    317                 *out++ = block;
    318         }
    319 
    320184        template< typename OutputIterator >
    321185        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
     
    325189                } else {
    326190                        return genScalarCall( srcParam, dstParam, fname, out, type, addCast );
    327                 }
    328         }
    329 
    330         template< typename OutIter >
    331         ast::ptr< ast::Stmt > genCall(
    332                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    333                 const CodeLocation & loc, const std::string & fname, OutIter && out,
    334                 const ast::Type * type, const ast::Type * addCast, LoopDirection forward
    335         ) {
    336                 if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) {
    337                         genArrayCall(
    338                                 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast,
    339                                 forward );
    340                         return {};
    341                 } else {
    342                         return genScalarCall(
    343                                 srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast );
    344191                }
    345192        }
     
    379226        }
    380227
    381         static inline ast::ptr< ast::Stmt > genImplicitCall(
    382                 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam,
    383                 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj,
    384                 LoopDirection forward = LoopForward
    385         ) {
    386                 // unnamed bit fields are not copied as they cannot be accessed
    387                 if ( isUnnamedBitfield( obj ) ) return {};
    388 
    389                 ast::ptr< ast::Type > addCast;
    390                 if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
    391                         assert( dstParam->result );
    392                         addCast = dstParam->result;
    393                 }
    394 
    395                 std::vector< ast::ptr< ast::Stmt > > stmts;
    396                 genCall(
    397                         srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward );
    398 
    399                 if ( stmts.empty() ) {
    400                         return {};
    401                 } else if ( stmts.size() == 1 ) {
    402                         const ast::Stmt * callStmt = stmts.front();
    403                         if ( addCast ) {
    404                                 // implicitly generated ctor/dtor calls should be wrapped so that later passes are
    405                                 // aware they were generated.
    406                                 callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt };
    407                         }
    408                         return callStmt;
    409                 } else {
    410                         assert( false );
    411                         return {};
    412                 }
    413         }
    414228} // namespace SymTab
    415229
  • src/SymTab/module.mk

    ra50fdfb r6e1e2d0  
    2020        SymTab/FixFunction.cc \
    2121        SymTab/FixFunction.h \
     22        SymTab/GenImplicitCall.cpp \
     23        SymTab/GenImplicitCall.hpp \
    2224        SymTab/Indexer.cc \
    2325        SymTab/Indexer.h \
  • src/Validate/Autogen.cpp

    ra50fdfb r6e1e2d0  
    3939#include "InitTweak/GenInit.h"     // for fixReturnStatements
    4040#include "InitTweak/InitTweak.h"   // for isAssignment, isCopyConstructor
     41#include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    4142#include "SymTab/Mangler.h"        // for Mangler
    4243#include "CompilationState.h"
     
    423424        for ( unsigned int index = 0 ; index < fields ; ++index ) {
    424425                auto member = aggr->members[index].strict_as<ast::DeclWithType>();
    425                 if ( SymTab::isUnnamedBitfield(
     426                if ( ast::isUnnamedBitfield(
    426427                                dynamic_cast<const ast::ObjectDecl *>( member ) ) ) {
    427428                        if ( index == fields - 1 ) {
     
    599600                // Not sure why it could be null.
    600601                // Don't make a function for a parameter that is an unnamed bitfield.
    601                 if ( nullptr == field || SymTab::isUnnamedBitfield( field ) ) {
     602                if ( nullptr == field || ast::isUnnamedBitfield( field ) ) {
    602603                        continue;
    603604                // Matching Parameter: Initialize the field by copy.
  • src/main.cc

    ra50fdfb r6e1e2d0  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Feb 16 10:08:00 2023
    13 // Update Count     : 680
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 10 21:12:17 2023
     13// Update Count     : 682
    1414//
    1515
     
    3232
    3333#include "AST/Convert.hpp"
     34#include "AST/Util.hpp"                     // for checkInvariants
    3435#include "CompilationState.h"
    3536#include "../config.h"                      // for CFA_LIBDIR
     
    102103}
    103104
    104 #define PASS( name, pass )                  \
     105// Helpers for checkInvariant:
     106void checkInvariants( std::list< Declaration * > & ) {}
     107using ast::checkInvariants;
     108
     109#define PASS( name, pass, unit, ... )       \
    105110        if ( errorp ) { cerr << name << endl; } \
    106111        NewPass(name);                          \
    107112        Stats::Time::StartBlock(name);          \
    108         pass;                                   \
    109         Stats::Time::StopBlock();
     113        pass(unit,##__VA_ARGS__);               \
     114        Stats::Time::StopBlock();               \
     115        if ( invariant ) {                      \
     116                checkInvariants(unit);              \
     117        }
     118
     119#define DUMP( cond, unit )                  \
     120        if ( cond ) {                           \
     121                dump(unit);                         \
     122                return EXIT_SUCCESS;                \
     123        }
    110124
    111125static bool waiting_for_gdb = false;                                    // flag to set cfa-cpp to wait for gdb on start
     
    298312                transUnit = buildUnit();
    299313
    300                 if ( astp ) {
    301                         dump( std::move( transUnit ) );
    302                         return EXIT_SUCCESS;
    303                 } // if
     314                DUMP( astp, std::move( transUnit ) );
    304315
    305316                Stats::Time::StopBlock();
     
    310321                }
    311322
    312                 PASS( "Hoist Type Decls", Validate::hoistTypeDecls( transUnit ) );
    313                 // Hoist Type Decls pulls some declarations out of contexts where
    314                 // locations are not tracked. Perhaps they should be, but for now
    315                 // the full fill solves it.
    316                 forceFillCodeLocations( transUnit );
    317 
    318                 PASS( "Translate Exception Declarations", ControlStruct::translateExcept( transUnit ) );
    319                 if ( exdeclp ) {
    320                         dump( std::move( transUnit ) );
    321                         return EXIT_SUCCESS;
    322                 }
    323 
    324                 PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign( transUnit ) );
    325                 PASS( "Replace Typedefs", Validate::replaceTypedef( transUnit ) );
    326                 PASS( "Fix Return Types", Validate::fixReturnTypes( transUnit ) );
    327                 PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers( transUnit ) );
    328 
    329                 PASS( "Link Reference To Types", Validate::linkReferenceToTypes( transUnit ) );
    330 
    331                 PASS( "Fix Qualified Types", Validate::fixQualifiedTypes( transUnit ) );
    332                 PASS( "Hoist Struct", Validate::hoistStruct( transUnit ) );
    333                 PASS( "Eliminate Typedef", Validate::eliminateTypedef( transUnit ) );
    334                 PASS( "Validate Generic Parameters", Validate::fillGenericParameters( transUnit ) );
    335                 PASS( "Translate Dimensions", Validate::translateDimensionParameters( transUnit ) );
    336                 PASS( "Check Function Returns", Validate::checkReturnStatements( transUnit ) );
    337                 PASS( "Fix Return Statements", InitTweak::fixReturnStatements( transUnit ) );
    338                 PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords( transUnit ) );
    339                 PASS( "Forall Pointer Decay", Validate::decayForallPointers( transUnit ) );
    340         PASS( "Implement Waituntil", Concurrency::generateWaitUntil( transUnit ) );
    341                 PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls( transUnit ) );
    342 
    343                 PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) );
    344 
    345                 PASS( "Implement Actors", Concurrency::implementActors( transUnit ) );
    346         PASS( "Implement Virtual Destructors", Virtual::implementVirtDtors(transUnit) );
    347                 PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) );
    348                 PASS( "Implement Thread Start", Concurrency::implementThreadStarter( transUnit ) );
    349                 PASS( "Compound Literal", Validate::handleCompoundLiterals( transUnit ) );
    350                 PASS( "Set Length From Initializer", Validate::setLengthFromInitializer( transUnit ) );
    351                 PASS( "Find Global Decls", Validate::findGlobalDecls( transUnit ) );
    352                 PASS( "Fix Label Address", Validate::fixLabelAddresses( transUnit ) );
     323                PASS( "Hoist Type Decls", Validate::hoistTypeDecls, transUnit );
     324
     325                PASS( "Translate Exception Declarations", ControlStruct::translateExcept, transUnit );
     326                DUMP( exdeclp, std::move( transUnit ) );
     327                PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign, transUnit );
     328                PASS( "Replace Typedefs", Validate::replaceTypedef, transUnit );
     329                PASS( "Fix Return Types", Validate::fixReturnTypes, transUnit );
     330                PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers, transUnit );
     331
     332                PASS( "Link Reference To Types", Validate::linkReferenceToTypes, transUnit );
     333
     334                PASS( "Fix Qualified Types", Validate::fixQualifiedTypes, transUnit );
     335                PASS( "Hoist Struct", Validate::hoistStruct, transUnit );
     336                PASS( "Eliminate Typedef", Validate::eliminateTypedef, transUnit );
     337                PASS( "Validate Generic Parameters", Validate::fillGenericParameters, transUnit );
     338                PASS( "Translate Dimensions", Validate::translateDimensionParameters, transUnit );
     339                PASS( "Check Function Returns", Validate::checkReturnStatements, transUnit );
     340                PASS( "Fix Return Statements", InitTweak::fixReturnStatements, transUnit );
     341                PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit );
     342                PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
     343        PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit  );
     344                PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit );
     345
     346                PASS( "Generate Autogen Routines", Validate::autogenerateRoutines, transUnit );
     347
     348                PASS( "Implement Actors", Concurrency::implementActors, transUnit );
     349                PASS( "Implement Virtual Destructors", Virtual::implementVirtDtors, transUnit );
     350                PASS( "Implement Mutex", Concurrency::implementMutex, transUnit );
     351                PASS( "Implement Thread Start", Concurrency::implementThreadStarter, transUnit );
     352                PASS( "Compound Literal", Validate::handleCompoundLiterals, transUnit );
     353                PASS( "Set Length From Initializer", Validate::setLengthFromInitializer, transUnit );
     354                PASS( "Find Global Decls", Validate::findGlobalDecls, transUnit );
     355                PASS( "Fix Label Address", Validate::fixLabelAddresses, transUnit );
    353356
    354357                if ( symtabp ) {
     
    361364                } // if
    362365
    363                 if ( validp ) {
    364                         dump( std::move( transUnit ) );
    365                         return EXIT_SUCCESS;
    366                 } // if
    367 
    368                 PASS( "Translate Throws", ControlStruct::translateThrows( transUnit ) );
    369                 PASS( "Fix Labels", ControlStruct::fixLabels( transUnit ) );
    370                 PASS( "Fix Names", CodeGen::fixNames( transUnit ) );
    371                 PASS( "Gen Init", InitTweak::genInit( transUnit ) );
    372                 PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) );
     366                DUMP( validp, std::move( transUnit ) );
     367
     368                PASS( "Translate Throws", ControlStruct::translateThrows, transUnit );
     369                PASS( "Fix Labels", ControlStruct::fixLabels, transUnit );
     370                PASS( "Fix Names", CodeGen::fixNames, transUnit );
     371                PASS( "Gen Init", InitTweak::genInit, transUnit );
     372                PASS( "Expand Member Tuples" , Tuples::expandMemberTuples, transUnit );
    373373
    374374                if ( libcfap ) {
     
    382382                } // if
    383383
    384                 if ( bresolvep ) {
    385                         dump( std::move( transUnit ) );
    386                         return EXIT_SUCCESS;
    387                 } // if
     384                DUMP( bresolvep, std::move( transUnit ) );
    388385
    389386                if ( resolvprotop ) {
     
    392389                } // if
    393390
    394                 PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
    395                 if ( exprp ) {
    396                         dump( std::move( transUnit ) );
    397                         return EXIT_SUCCESS;
    398                 } // if
    399 
    400                 forceFillCodeLocations( transUnit );
    401 
    402                 PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
     391                PASS( "Resolve", ResolvExpr::resolve, transUnit );
     392                DUMP( exprp, std::move( transUnit ) );
     393
     394                PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() );
    403395
    404396                // fix ObjectDecl - replaces ConstructorInit nodes
    405                 if ( ctorinitp ) {
    406                         dump( std::move( transUnit ) );
    407                         return EXIT_SUCCESS;
    408                 } // if
     397                DUMP( ctorinitp, std::move( transUnit ) );
    409398
    410399                // Currently not working due to unresolved issues with UniqueExpr
    411                 PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( transUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
    412 
    413                 PASS( "Translate Tries", ControlStruct::translateTries( transUnit ) );
    414                 PASS( "Gen Waitfor", Concurrency::generateWaitFor( transUnit ) );
     400                PASS( "Expand Unique Expr", Tuples::expandUniqueExpr, transUnit ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
     401
     402                PASS( "Translate Tries", ControlStruct::translateTries, transUnit );
     403                PASS( "Gen Waitfor", Concurrency::generateWaitFor, transUnit );
    415404
    416405                // Needs to happen before tuple types are expanded.
    417                 PASS( "Convert Specializations",  GenPoly::convertSpecializations( transUnit ) );
    418 
    419                 PASS( "Expand Tuples", Tuples::expandTuples( transUnit ) );
    420 
    421                 if ( tuplep ) {
    422                         dump( std::move( transUnit ) );
    423                         return EXIT_SUCCESS;
    424                 } // if
     406                PASS( "Convert Specializations",  GenPoly::convertSpecializations, transUnit );
     407
     408                PASS( "Expand Tuples", Tuples::expandTuples, transUnit );
     409                DUMP( tuplep, std::move( transUnit ) );
    425410
    426411                // Must come after Translate Tries.
    427                 PASS( "Virtual Expand Casts", Virtual::expandCasts( transUnit ) );
    428 
    429                 PASS( "Instantiate Generics", GenPoly::instantiateGeneric( transUnit ) );
    430                 if ( genericsp ) {
    431                         dump( std::move( transUnit ) );
    432                         return EXIT_SUCCESS;
    433                 } // if
    434 
    435                 PASS( "Convert L-Value", GenPoly::convertLvalue( transUnit ) );
     412                PASS( "Virtual Expand Casts", Virtual::expandCasts, transUnit );
     413
     414                PASS( "Instantiate Generics", GenPoly::instantiateGeneric, transUnit );
     415                DUMP( genericsp, std::move( transUnit ) );
     416
     417                PASS( "Convert L-Value", GenPoly::convertLvalue, transUnit );
    436418
    437419                translationUnit = convert( std::move( transUnit ) );
    438420
    439                 if ( bboxp ) {
    440                         dump( translationUnit );
    441                         return EXIT_SUCCESS;
    442                 } // if
    443                 PASS( "Box", GenPoly::box( translationUnit ) );
    444 
    445                 PASS( "Link-Once", CodeGen::translateLinkOnce( translationUnit ) );
     421                DUMP( bboxp, translationUnit );
     422                PASS( "Box", GenPoly::box, translationUnit );
     423
     424                PASS( "Link-Once", CodeGen::translateLinkOnce, translationUnit );
    446425
    447426                // Code has been lowered to C, now we can start generation.
    448427
    449                 if ( bcodegenp ) {
    450                         dump( translationUnit );
    451                         return EXIT_SUCCESS;
    452                 } // if
     428                DUMP( bcodegenp, translationUnit );
    453429
    454430                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    457433
    458434                CodeTools::fillLocations( translationUnit );
    459                 PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
     435                PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks );
    460436
    461437                CodeGen::FixMain::fix( translationUnit, *output,
     
    505481
    506482
    507 static const char optstring[] = ":c:ghlLmNnpdP:S:twW:D:";
     483static const char optstring[] = ":c:ghilLmNnpdP:S:twW:D:";
    508484
    509485enum { PreludeDir = 128 };
     
    512488        { "gdb", no_argument, nullptr, 'g' },
    513489        { "help", no_argument, nullptr, 'h' },
     490        { "invariant", no_argument, nullptr, 'i' },
    514491        { "libcfa", no_argument, nullptr, 'l' },
    515492        { "linemarks", no_argument, nullptr, 'L' },
    516         { "no-main", no_argument, 0, 'm' },
     493        { "no-main", no_argument, nullptr, 'm' },
    517494        { "no-linemarks", no_argument, nullptr, 'N' },
    518495        { "no-prelude", no_argument, nullptr, 'n' },
     
    533510        "wait for gdb to attach",                                                       // -g
    534511        "print translator help message",                                        // -h
     512        "invariant checking during AST passes",                         // -i
    535513        "generate libcfa.c",                                                            // -l
    536514        "generate line marks",                                                          // -L
     
    626604                        usage( argv );                                                          // no return
    627605                        break;
     606                  case 'i':                                                                             // invariant checking
     607                        invariant = true;
     608                        break;
    628609                  case 'l':                                                                             // generate libcfa.c
    629610                        libcfap = true;
  • tests/.expect/PRNG.x64.txt

    ra50fdfb r6e1e2d0  
     1
     2CFA xoshiro256pp
    13
    24                    PRNG()     PRNG(5)   PRNG(0,5)
     
    5658
    5759Sequential
    58 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     60trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    5961
    6062Concurrent
    61 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    62 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    63 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    64 trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     63trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     64trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     65trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     66trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    6567
    6668                   prng(t)   prng(t,5) prng(t,0,5)
  • tests/.expect/PRNG.x86.txt

    ra50fdfb r6e1e2d0  
     1
     2CFA xoshiro128pp
    13
    24                    PRNG()     PRNG(5)   PRNG(0,5)
     
    5658
    5759Sequential
    58 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     60trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    5961
    6062Concurrent
    61 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    62 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    63 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    64 trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     63trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     64trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     65trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     66trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    6567
    6668                   prng(t)   prng(t,5) prng(t,0,5)
  • tests/Makefile.am

    ra50fdfb r6e1e2d0  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Fri Feb  3 23:06:44 2023
    14 ## Update Count     : 94
     13## Last Modified On : Mon Apr 10 23:24:02 2023
     14## Update Count     : 96
    1515###############################################################################
    1616
     
    184184
    185185SYNTAX_ONLY_CODE = expression typedefRedef variableDeclarator switch numericConstants identFuncDeclarator \
    186         init1 limits nested-types cast labelledExit array quasiKeyword include/stdincludes include/includes builtins/sync warnings/self-assignment
     186        init1 limits nested-types cast labelledExit array quasiKeyword include/stdincludes include/includes builtins/sync warnings/self-assignment concurrent/waitfor/parse
    187187$(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN)
    188188        $(CFACOMPILE_SYNTAX)
  • tests/PRNG.cfa

    ra50fdfb r6e1e2d0  
    88// Created On       : Wed Dec 29 09:38:12 2021
    99// Last Modified By : Peter A. Buhr
    10 // Last Modified On : Wed Dec 21 20:39:59 2022
    11 // Update Count     : 406
     10// Last Modified On : Sun Apr 23 22:02:09 2023
     11// Update Count     : 420
    1212//
    1313
     
    1515#include <stdlib.hfa>                                                                   // PRNG
    1616#include <clock.hfa>
    17 #include <thread.hfa>
    1817#include <limits.hfa>                                                                   // MAX
    1918#include <math.hfa>                                                                             // sqrt
    2019#include <malloc.h>                                                                             // malloc_stats
    2120#include <locale.h>                                                                             // setlocale
     21#include <thread.hfa>
    2222#include <mutex_stmt.hfa>
    2323
    24 #ifdef __x86_64__                                                                               // 64-bit architecture
     24#define xstr(s) str(s)
     25#define str(s) #s
     26
     27#if defined( __x86_64__ ) || defined( __aarch64__ )             // 64-bit architecture
    2528#define PRNG PRNG64
    2629#else                                                                                                   // 32-bit architecture
    2730#define PRNG PRNG32
    2831#endif // __x86_64__
     32
     33//#define TIME
    2934
    3035#ifdef TIME                                                                                             // use -O2 -nodebug
     
    3843#endif // TIME
    3944
    40 void avgstd( unsigned int buckets[] ) {
    41         unsigned int min = MAX, max = 0;
     45static void avgstd( size_t trials, size_t buckets[] ) {
     46        size_t min = MAX, max = 0;
    4247        double sum = 0.0, diff;
    4348        for ( i; BUCKETS ) {
     
    5459        } // for
    5560        double std = sqrt( sum / BUCKETS );
    56         mutex( sout ) sout | "trials"  | TRIALS | "buckets" | BUCKETS
     61        mutex( sout ) sout | "trials"  | trials | "buckets" | BUCKETS
    5762                | "min" | min | "max" | max
    5863                | "avg" | wd(0,1, avg) | "std" | wd(0,1, std) | "rstd" | wd(0,1, (avg == 0 ? 0.0 : std / avg * 100)) | "%";
     
    6469thread T1 {};
    6570void main( T1 & ) {
    66         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
    67         for ( TRIALS / 100 ) {
     71        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
     72        for ( TRIALS / 50 ) {
    6873                buckets[rand() % BUCKETS] += 1;                                 // concurrent
    6974        } // for
    70         avgstd( buckets );
     75        avgstd( TRIALS / 50, buckets );
    7176        free( buckets );
    7277} // main
     
    7681        PRNG prng;
    7782        if ( seed != 0 ) set_seed( prng, seed );
    78         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
     83        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
    7984        for ( TRIALS ) {
    8085                buckets[prng( prng ) % BUCKETS] += 1;                   // concurrent
    8186        } // for
    82         avgstd( buckets );
     87        avgstd( TRIALS, buckets );
    8388        free( buckets );
    8489} // main
     
    8691thread T3 {};
    8792void main( T3 & th ) {
    88         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
    89         for ( TRIALS ) {
     93        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
     94        for ( TRIALS / 5 ) {
    9095                buckets[prng() % BUCKETS] += 1;                                 // concurrent
    9196        } // for
    92         avgstd( buckets );
     97        avgstd( TRIALS / 5, buckets );
    9398        free( buckets );
    9499} // main
     
    96101thread T4 {};
    97102void main( T4 & th ) {
    98         unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
     103        size_t * buckets = calloc( BUCKETS );                           // too big for task stack
    99104        for ( TRIALS ) {
    100                 buckets[prng( th ) % BUCKETS] += 1;     // concurrent
    101         } // for
    102         avgstd( buckets );
     105                buckets[prng( th ) % BUCKETS] += 1;                             // concurrent
     106        } // for
     107        avgstd( TRIALS, buckets );
    103108        free( buckets );
    104109} // main
     
    108113static void dummy( thread$ & th ) __attribute__(( noinline ));
    109114static void dummy( thread$ & th ) {
    110         unsigned int * buckets = (unsigned int *)calloc( BUCKETS, sizeof(unsigned int) ); // too big for task stack
    111         for ( unsigned int i = 0; i < TRIALS; i += 1 ) {
     115        size_t * buckets = (size_t *)calloc( BUCKETS, sizeof(size_t) ); // too big for task stack
     116        for ( size_t i = 0; i < TRIALS; i += 1 ) {
    112117                buckets[prng( th ) % BUCKETS] += 1;                             // sequential
    113118        } // for
    114         avgstd( buckets );
     119        avgstd( TRIALS, buckets );
    115120        free( buckets );
    116121} // dummy
     
    118123
    119124int main() {
    120         // causes leaked storage message
    121         // setlocale( LC_NUMERIC, getenv( "LANG" ) );                   // print digit separator
     125        // setlocale( LC_NUMERIC, getenv( "LANG" ) );           // causes leaked storage message
     126
     127        // only works on the current pthread thread
    122128        // locale_t loc = newlocale( LC_NUMERIC_MASK, getenv( "LANG" ), (locale_t)0p );
    123129        // if ( loc == (locale_t)0p ) abort( "newlocale" );
     
    126132        enum { TASKS = 4 };
    127133        Time start;
     134
    128135#ifdef TIME                                                                                             // too slow for test and generates non-repeatable results
    129136#if 1
    130         unsigned int rseed;
     137        sout | "glib rand" | nl | nl;
     138
     139        size_t rseed;
    131140        if ( seed != 0 ) rseed = seed;
    132141        else rseed = rdtscl();
     
    134143
    135144        sout | sepDisable;
    136         sout | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
     145        sout | nl | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
    137146        for ( 20 ) {
    138147                sout | wd(26, rand()) | nonl;
     
    146155        STARTTIME;
    147156        {
    148                 unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
    149                 for ( i; TRIALS / 10 ) {
     157                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
     158                for ( i; TRIALS / 5 ) {
    150159                        buckets[rand() % BUCKETS] += 1;                         // sequential
    151160                } // for
    152                 avgstd( buckets );
     161                avgstd( TRIALS / 5, buckets );
    153162                free( buckets );
    154163        }
    155         ENDTIME( " x 10 " );
     164        ENDTIME( " x 5 " );
    156165
    157166        sout | nl | "Concurrent";
     
    163172                } // wait for threads to complete
    164173        }
    165         ENDTIME( " x 100 " );
     174        ENDTIME( " x 50 " );
    166175#endif // 0
    167176#endif // TIME
     177
     178        sout | nl | "CFA " xstr(PRNG_NAME);
     179
    168180#if 1
    169181        PRNG prng;
     
    184196        STARTTIME;
    185197        {
    186                 unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
     198                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
    187199                for ( TRIALS ) {
    188200                        buckets[prng( prng ) % BUCKETS] += 1;           // sequential
    189201                } // for
    190                 avgstd( buckets );
     202                avgstd( TRIALS, buckets );
    191203                free( buckets );
    192204        }
     
    219231        STARTTIME;
    220232        {
    221                 unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
    222                 for ( TRIALS ) {
     233                size_t * buckets = calloc( BUCKETS );                   // too big for task stack
     234                for ( TRIALS / 5 ) {
    223235                        buckets[prng() % BUCKETS] += 1;
    224236                } // for
    225                 avgstd( buckets );
     237                avgstd( TRIALS / 5, buckets );
    226238                free( buckets );
    227239        }
    228         ENDTIME();
     240        ENDTIME( " x 5 " );
    229241
    230242        sout | nl | "Concurrent";
     
    236248                } // wait for threads to complete
    237249        }
    238         ENDTIME();
     250        ENDTIME( " x 5 " );
    239251#endif // 0
    240252#if 1
  • tests/concurrent/waitfor/parse.cfa

    ra50fdfb r6e1e2d0  
    1 //----------------------------------------------------------------------------------------
    2 //----------------------------------------------------------------------------------------
     1// 
     2// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
    33//
    4 //              DEPRECATED TEST
    5 //              DIFFERS BETWEEN DEBUG AND RELEASE
    6 //
    7 //----------------------------------------------------------------------------------------
    8 //----------------------------------------------------------------------------------------
     4// The contents of this file are covered under the licence agreement in the
     5// file "LICENCE" distributed with Cforall.
     6//
     7// waitfor.c --
     8//
     9// Author           : Peter A. Buhr
     10// Created On       : Wed Aug 30 17:53:29 2017
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Mon Apr 10 22:52:18 2023
     13// Update Count     : 64
     14//
    915
    1016#include <monitor.hfa>
     
    1218monitor M {};
    1319
    14 M a;
    15 
    16 void f1( M & mutex a );
    17 void f2( M & mutex a );
    18 void f2( M & mutex a, M & mutex b );
    19 void f3( M & mutex a );
    20 void f3( M & mutex a, M & mutex b );
    21 void f3( M & mutex a, M & mutex b, M & mutex c );
    22 
    23 void foo() {
    24 
    25         //---------------------------------------
    26         waitfor( f1 : a ) {
    27                 1;
    28         }
    29 
    30         //---------------------------------------
    31         waitfor( f1 : a ) {
    32                 2;
    33         }
    34         waitfor( f2 : a ) {
    35                 3;
    36         }
    37 
    38         //---------------------------------------
    39         when( 1 < 3 ) waitfor( f2 : a, a ) {
    40                 4;
    41         }
    42         or timeout( 100 ) {
    43                 5;
    44         }
    45 
    46         //---------------------------------------
    47         when( 2 < 3 ) waitfor( f3 : a ) {
    48                 5;
    49         }
     20void notcalled( M & mutex m1, M & mutex m2 ) {
     21        abort();
     22}
     23void or( M & mutex m ) {
     24        abort();
     25}
     26void timeout( M & mutex m ) {
     27        abort();
     28}
     29
     30void fred( M & mutex m, M & mutex or, M & mutex timeout ) {
     31        // test waitfor and when
     32
     33        waitfor( notcalled : m, m );
     34
     35        waitfor( notcalled : m, m ) {
     36        }
     37
     38        waitfor( notcalled : m, m ) {
     39        }
     40
     41        when( true ) waitfor( notcalled : m, m );
     42
     43        when( true ) waitfor( notcalled : m, m ) {
     44        }
     45
     46        waitfor( notcalled : m, m );
     47        or waitfor( notcalled : m, m );
     48
     49        when( true ) waitfor( notcalled : m, m );
     50        or when( true ) waitfor( notcalled : m, m );
     51
     52        waitfor( notcalled : m, m ) {
     53        } or waitfor( notcalled : m, m ) {
     54        }
     55
     56        waitfor( notcalled : m, m ) {
     57        } or waitfor( notcalled : m, m ) {
     58        }
     59
     60        when( true ) waitfor( notcalled : m, m ) {
     61        } or when( true ) waitfor( notcalled : m, m ) {
     62        }
     63
     64        waitfor( notcalled : m, m );
     65        or waitfor( notcalled : m, m ) {
     66        }
     67
     68        when( true ) waitfor( notcalled : m, m );
     69        or when( true ) waitfor( notcalled : m, m ) {
     70        }
     71
     72        waitfor( notcalled : m, m ) {
     73        } or waitfor( notcalled : m, m );
     74
     75        when( true ) waitfor( notcalled : m, m ) {
     76        } or when( true ) waitfor( notcalled : m, m );
     77
     78        // test when, waitfor and else
     79
     80        waitfor( notcalled : m, m );
     81        or else;
     82
     83        when( true ) waitfor( notcalled : m, m );
     84        or else;
     85
     86        when( true ) waitfor( notcalled : m, m );
     87        or else;
     88
     89        waitfor( notcalled : m, m ) {
     90        } or else {
     91        }
     92
     93        when( true ) waitfor( notcalled : m, m ) {
     94        } or else {
     95        }
     96
     97        waitfor( notcalled : m, m );
    5098        or else {
    51                 6;
    52         }
    53 
    54         //---------------------------------------
    55         when( 3 < 3 ) waitfor( f3 : a, a ) {
    56                 7;
    57         }
    58         or when( 4 < 3 ) timeout( 101 ) {
    59                 8;
    60         }
    61         or when( 5 < 3 ) else {
    62                 9;
    63         }
    64 
    65         //---------------------------------------
    66         when( 6 < 3 ) waitfor( f3 : a, a, a ) {
    67                 10;
    68         }
    69         or when( 7 < 3 ) waitfor( f1 : a  ) {
    70                 11;
    71         }
     99        }
     100
     101        when( true ) waitfor( notcalled : m, m );
    72102        or else {
    73                 12;
    74         }
    75 
    76         //---------------------------------------
    77         when( 8 < 3 ) waitfor( f3 : a, a ) {
    78                 13;
    79         }
    80         or waitfor( f1 : a  ) {
    81                 14;
    82         }
    83         or when( 9 < 3 ) timeout( 102 ) {
    84                 15;
    85         }
    86 
    87         //---------------------------------------
    88         when( 10 < 3 ) waitfor( f1 : a ) {
    89                 16;
    90         }
    91         or waitfor( f2 : a, a ) {
    92                 17;
    93         }
    94         or timeout( 103 ) {
    95                 18;
    96         }
    97         or when( 11 < 3 ) else {
    98                 19;
    99         }
    100 }
    101 
    102 int main() {}
     103        }
     104
     105        when( true ) waitfor( notcalled : m, m );
     106        or else {
     107        }
     108
     109        waitfor( notcalled : m, m ) {
     110        } or else;
     111
     112        when( true ) waitfor( notcalled : m, m ) {
     113        } or else;
     114
     115        waitfor( notcalled : m, m );
     116        or when( true ) else;
     117
     118        when( true ) waitfor( notcalled : m, m );
     119        or when( true ) else;
     120
     121        when( true ) waitfor( notcalled : m, m );
     122        or when( true ) else;
     123
     124        waitfor( notcalled : m, m ) {
     125        } or when( true ) else {
     126        }
     127
     128        when( true ) waitfor( notcalled : m, m ) {
     129        } or when( true ) else {
     130        }
     131
     132        waitfor( notcalled : m, m );
     133        or when( true ) else {
     134        }
     135
     136        when( true ) waitfor( notcalled : m, m );
     137        or when( true ) else {
     138        }
     139
     140        when( true ) waitfor( notcalled : m, m );
     141        or when( true ) else {
     142        }
     143
     144        waitfor( notcalled : m, m ) {
     145        } or when( true ) else;
     146
     147        when( true ) waitfor( notcalled : m, m ) {
     148        } or when( true ) else;
     149
     150        // test when, waitfor and timeout
     151
     152        waitfor( notcalled : m, m );
     153        or timeout( 3 );
     154
     155        waitfor( notcalled : m, m );
     156        or timeout( 3 );
     157
     158        when( true ) waitfor( notcalled : m, m );
     159        or timeout( 3 );
     160
     161        waitfor( notcalled : m, m ) {
     162        } or timeout( 3 ) {
     163        }
     164
     165        when( true ) waitfor( notcalled : m, m ) {
     166        } or timeout( 3 ) {
     167        }
     168
     169        when( true ) waitfor( notcalled : m, m ) {
     170        } or timeout( 3 ) {
     171        }
     172
     173        when( true ) waitfor( notcalled : m, m ) {
     174        } or when ( true ) timeout( 3 ) {
     175        }
     176
     177        when( true ) waitfor( notcalled : m, m ) {
     178        } or when ( true ) timeout( 3 ) {
     179        }
     180
     181        waitfor( notcalled : m, m );
     182        or timeout( 3 ) {
     183        }
     184
     185        when( true ) waitfor( notcalled : m, m );
     186        or timeout( 3 ) {
     187        }
     188
     189        when( true ) waitfor( notcalled : m, m );
     190        or when( true ) timeout( 3 ) {
     191        }
     192
     193        waitfor( notcalled : m, m ) {
     194        } or timeout( 3 );
     195
     196        when( true ) waitfor( notcalled : m, m ) {
     197        } or timeout( 3 );
     198
     199        when( true ) waitfor( notcalled : m, m ) {
     200        } or when( true ) timeout( 3 );
     201
     202        // test when, waitfor, timeout and else
     203
     204        waitfor( notcalled : m, m ) {
     205        } or timeout( 3 ) {
     206        } or when( true ) else {}
     207
     208        when( true ) waitfor( notcalled : m, m ) {
     209        } or timeout( 3 ) {
     210        } or when( true ) else {}
     211
     212        waitfor( notcalled : m, m ) {
     213        } or timeout( 3 ) {
     214        } or when( true ) else {}
     215
     216        waitfor( notcalled : m, m ) {
     217        } or when( true ) timeout( 3 ) {
     218        } or when( true ) else {}
     219
     220        when( true ) waitfor( notcalled : m, m ) {
     221        } or timeout( 3 ) {
     222        } or when( true ) else {}
     223
     224        waitfor( notcalled : m, m ) {
     225        } or when( true ) timeout( 3 ) {
     226        } or when( true ) else {}
     227
     228        when( true ) waitfor( notcalled : m, m ) {
     229        } or when( true ) timeout( 3 ) {
     230        } or when( true ) else {}
     231
     232        // test quasi-keywords "or" and "timeout"
     233
     234        int or = 0, timeout = 0;
     235        waitfor( timeout : timeout ) timeout += 1; or timeout( timeout );
     236        waitfor( notcalled : or, or ) or += 1; or timeout( or ) 3;
     237        when( or ) waitfor( or : m ) { 4; } or timeout( or ) or += 1;
     238        when( timeout ) waitfor( notcalled : timeout, timeout ) or += 1; or else timeout += 1;
     239        when( or + timeout ) waitfor( or : m ) 4; or when( or ) timeout( or ) 4; or when( or ) else timeout += 1;
     240        when( 3 ) waitfor( or : or ) 3; or when( or ) waitfor( notcalled : or, or ) 4; or else 4;
     241        when( timeout ) waitfor( or : timeout ) 3; or waitfor( notcalled : timeout, or ) 4; or when( or ) timeout( timeout ) 4;
     242        when( 3 ) waitfor( or : timeout ) or += 1;
     243        or waitfor( or : or ) timeout += 1;
     244        or timeout( timeout ) or += 1;
     245        or when( 3 ) else or += 1;
     246
     247        // test else selection
     248
     249        if ( or > timeout ) waitfor( or : or ) 3;
     250        else waitfor( timeout : timeout ) 4;
     251}
     252
     253//Dummy main
     254int main( int argc, char const * argv[] ) {
     255    #pragma GCC warning "Compiled"                      // force non-empty .expect file, NO TABS!!!
     256}
     257
     258// Local Variables: //
     259// tab-width: 4 //
     260// compile-command: "cfa waitfor.cfa" //
     261// End: //
  • tests/pybin/settings.py

    ra50fdfb r6e1e2d0  
    126126        global archive
    127127        global install
     128        global invariant
    128129
    129130        global continue_
     
    140141        all_install  = [Install(o)      for o in list(dict.fromkeys(options.install))]
    141142        archive      = os.path.abspath(os.path.join(original_path, options.archive_errors)) if options.archive_errors else None
     143        invariant    = options.invariant
    142144        continue_    = options.continue_
    143145        dry_run      = options.dry_run # must be called before tools.config_hash()
  • tests/test.py

    ra50fdfb r6e1e2d0  
    114114        parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no')
    115115        parser.add_argument('--continue', help='When multiple specifications are passed (debug/install/arch), sets whether or not to continue if the last specification failed', type=yes_no, default='yes', dest='continue_')
     116        parser.add_argument('--invariant', help='Tell the compiler to check invariants while running.', action='store_true')
    116117        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=180)
    117118        parser.add_argument('--global-timeout', help='Maximum cumulative duration in seconds after the ALL tests are considered to have timed out', type=int, default=7200)
     
    172173        test.prepare()
    173174
     175        # extra flags for cfa to pass through make.
     176        cfa_flags = 'CFAFLAGS=--invariant' if settings.invariant else None
     177
    174178        # ----------
    175179        # MAKE
     
    177181        # build, skipping to next test on error
    178182        with Timed() as comp_dur:
    179                 make_ret, _, _ = make( test.target(), output_file=subprocess.DEVNULL, error=out_file, error_file = err_file )
     183                make_ret, _, _ = make(test.target(), flags=cfa_flags, output_file=subprocess.DEVNULL, error=out_file, error_file=err_file)
    180184
    181185        # ----------
Note: See TracChangeset for help on using the changeset viewer.