Changes in / [6e1e2d0:a50fdfb]


Ignore:
Files:
1 added
7 deleted
86 edited

Legend:

Unmodified
Added
Removed
  • Jenkins/FullBuild

    r6e1e2d0 ra50fdfb  
    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 ) },
    2322                                        gcc_10_x64_new: { trigger_build( 'gcc-10',  'x64', false ) },
    2423                                        gcc_09_x64_new: { trigger_build( 'gcc-9',   'x64', false ) },
    2524                                        gcc_08_x64_new: { trigger_build( 'gcc-8',   'x64', false ) },
    2625                                        gcc_07_x64_new: { trigger_build( 'gcc-7',   'x64', false ) },
    27                                         // gcc_06_x64_new: { trigger_build( 'gcc-6',   'x64', false ) },
     26                                        gcc_06_x64_new: { trigger_build( 'gcc-6',   'x64', false ) },
    2827                                        clang_x64_new:  { trigger_build( 'clang',   'x64', true  ) },
    2928                                )
     
    4241        }
    4342
    44         // If an exception is caught we need to change the status and remember to
    45         // attach the build log to the email
     43        //If an exception is caught we need to change the status and remember to
     44        //attach the build log to the email
    4645        catch (Exception caughtError) {
    4746                echo('error caught')
     
    7473        // Run the build
    7574        // Don't propagate, it doesn't play nice with our email setup
    76         def result = build job: 'Cforall/master',                       \
     75        def result = build job: 'Cforall/master',               \
    7776                parameters: [                                           \
    7877                        [$class: 'StringParameterValue',                \
     
    8483                        [$class: 'BooleanParameterValue',               \
    8584                          name: 'NewAST',                               \
    86                           value: true],                                 \
     85                          value: true],                                         \
    8786                        [$class: 'BooleanParameterValue',               \
    8887                          name: 'RunAllTests',                          \
    89                           value: true],                                 \
     88                          value: true],                                         \
    9089                        [$class: 'BooleanParameterValue',               \
    9190                          name: 'RunBenchmark',                         \
    92                           value: true],                                 \
     91                          value: true],                                         \
    9392                        [$class: 'BooleanParameterValue',               \
    94                           name: 'BuildDocumentation',                   \
     93                          name: 'BuildDocumentation',           \
    9594                          value: doc],                                  \
    9695                        [$class: 'BooleanParameterValue',               \
    9796                          name: 'Publish',                              \
    98                           value: true],                                 \
     97                          value: true],                                         \
    9998                        [$class: 'BooleanParameterValue',               \
    10099                          name: 'Silent',                               \
    101                           value: true],                                 \
    102                 ],                                                      \
     100                          value: true],                                         \
     101                ],                                                              \
    103102                propagate: false
    104103
     
    112111
    113112def trigger_dist(String commitId, String buildNum) {
    114         def result = build job: 'Cforall_Distribute_Ref',               \
     113        def result = build job: 'Cforall_Distribute_Ref',       \
    115114                parameters: [                                           \
    116115                        string(name: 'GitRef', value: commitId),        \
    117                         string(name: 'Build' , value: buildNum)         \
    118                 ],                                                      \
     116                        string(name: 'Build' , value: buildNum) \
     117                ],                                                              \
    119118                propagate: false
    120119
  • Jenkinsfile

    r6e1e2d0 ra50fdfb  
    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\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',                          \
     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',                                                  \
    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',
    411409
    412410        // It's unfortunate but it looks like we need to checkout the entire repo just to get
  • doc/bibliography/pl.bib

    r6e1e2d0 ra50fdfb  
    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 
    74647455@article{Baker78,
    74657456    keywords    = {Algol display, FUNARG's, Lisp 1.5, deep binding, environment trees, multiprogramming, shallow binding},
  • doc/theses/colby_parsons_MMAth/.gitignore

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

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

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

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

    r6e1e2d0 ra50fdfb  
    1 // sequential equivalent swap
    2 void swap( uint victim_idx, uint my_idx  ) {
    3     // Step 0:
     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
     5static inline work_queue * try_swap_queues( worker & this, unsigned int victim_idx, unsigned int my_idx ) with(this) {
    46    work_queue * my_queue = request_queues[my_idx];
    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;
     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;
    1226}
    1327
     
    2135
    2236bool 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
    2537    work_queue * my_queue = request_queues[my_idx];
    2638    work_queue * vic_queue = request_queues[victim_idx];
    2739
    28     // Step 1:
    2940    // If either queue is 0p then they are in the process of being stolen
    3041    // 0p is CForAll's equivalent of C++'s nullptr
    31     if ( vic_queue == 0p ) return false;
     42    if ( vic_queue == 0p || my_queue == 0p ) return false;
    3243
    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
     44    // Try to set our queue ptr to be 0p.
     45    // If this CAS fails someone moved our queue so return false
    3646    if ( !CAS( &request_queues[my_idx], &my_queue, 0p ) )
    3747        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
     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
    4251    if ( !CAS( &request_queues[victim_idx], &vic_queue, my_queue ) ) {
    4352        request_queues[my_idx] = my_queue; // reset queue ptr back to prev val
     
    4554    }
    4655
    47     // Step 4:
    4856    // Successfully swapped.
    49     // Thief's ptr is 0p so no one will touch it
    50     // Write back without CAS is safe
     57    // Our queue is 0p so no one will touch it so write back without CAS is safe
    5158    request_queues[my_idx] = vic_queue;
    5259    return true;
  • doc/theses/colby_parsons_MMAth/style/style.tex

    r6e1e2d0 ra50fdfb  
    33\lstset{language=CFA}                                   % default language
    44
    5 \newcommand{\newtermFont}{\emph}
    6 \newcommand{\Newterm}[1]{\newtermFont{#1}}
    7 
    85\newcommand{\code}[1]{\lstinline[language=CFA]{#1}}
    96\newcommand{\uC}{$\mu$\CC}
    10 \newcommand{\PAB}[1]{{\color{red}PAB: #1}}
    117
    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

    r6e1e2d0 ra50fdfb  
    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.
     303 The 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         \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).}
     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).}
    778786\end{figure}
    779787
     
    809817
    810818\begin{figure}
    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).}
     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).}
    821833\end{figure}
    822834
     
    828840
    829841\begin{figure}
    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).}
     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).}
    840854\end{figure}
    841855
     
    843857
    844858\begin{figure}
    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).}
     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).}
    855871\end{figure}
    856872
     
    865881
    866882\begin{figure}
    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).}
     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).}
    877895\end{figure}
    878896
     
    895913
    896914\begin{table}[t]
    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}
     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}
    910928\end{table}
    911929
     
    933951
    934952\begin{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: %
     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}
  • doc/theses/colby_parsons_MMAth/text/channels.tex

    r6e1e2d0 ra50fdfb  
    55% ======================================================================
    66
    7 Channels 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.
    8 This model is an alternative to shared-memory concurrency, where threads can communicate directly by changing shared state.
    9 Most modern concurrent programming languages do not subscribe to just one style of communication among threads and provide features that support multiple approaches.
    10 
    11 Channels were first introduced by Kahn~\cite{Kahn74} and extended by Hoare~\cite{Hoare78} (CSP).
    12 Both papers present a pseudo (unimplemented) concurrent language where processes communicate using input/output channels to send data.
    13 Both languages are highly restrictive.
    14 Kahn'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.
    15 Hoare's language restricts ...
     7Channels 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.
     8Channels 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.
     9This is an alternative to shared memory concurrency, where threads can communicate directly by changing shared memory state.
     10Most modern concurrent programming languages do not subscribe to just one style of communication between threads, and provide features that support both.
    1611Channels 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.
    17 Go's restrictions are ...
    18 \CFA channels do not have these restrictions.
    1912
    2013\section{Producer-Consumer Problem}
    21 Most channels in modern programming languages are built on top of a shared memory buffer.
    22 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.
    23 This turns the implementation of a channel into the producer-consumer problem.
    24 The producer-consumer problem, also known as the bounded buffer problem, was introduced by Dijkstra in his book Cooperating Sequential Processes\cite{Dijkstra65}.
    25 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.
    26 The buffer needs to be protected from concurrent access since each item in the buffer should only be produced and consumed once.
     14Most channels in modern programming languages are built on top of a shared memory buffer. 
     15While 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. 
     16This turns the implementation of a channel into the producer-consumer problem. 
     17The producer-consumer problem, also known as the bounded buffer problem, was introduced by Dijkstra in his book Cooperating Sequential Processes\cite{Dijkstra65}. 
     18In 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. 
     19The buffer needs to be protected from concurrent access since each item in the buffer should only be produced and consumed once. 
    2720Additionally, a consumer can only remove from a non-empty buffer and a producer can only insert into a non-full buffer.
    2821
    2922\section{First-Come First-Served}
    30 The channel implementations that will be discussed are \gls{fcfs}.
    31 This 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.
    33 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.
    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.
    35 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.
     23The channel implementations that will be discussed are \gls{fcfs}. 
     24This 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. 
     26Given 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. 
     28Implementing 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. 
    3629As such algorithms that are not \gls{fcfs} may be more performant but that performance comes with the downside of likely introducing starvation and unfairness.
    3730
    3831\section{Channel Implementation}
    39 The channel implementation in \CFA is a near carbon copy of the Go implementation.
    40 Experimentation was conducted that varied the producer-consumer problem algorithm and lock type used inside the channel.
    41 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.
     32The channel implementation in \CFA is a near carbon copy of the Go implementation. 
     33Experimentation was conducted that varied the producer-consumer problem algorithm and lock type used inside the channel. 
     34With 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. 
    4235As such the research contributions added by \CFA's channel implementation lie in the realm of safety and productivity features.
    4336
    4437\section{Safety and Productivity}
    45 Channels in \CFA come with safety and productivity features to aid users.
     38Channels in \CFA come with safety and productivity features to aid users. 
    4639The features include the following.
    4740
    4841\begin{itemize}
    49 \item Toggle-able statistic collection on channel behaviour that counts channel operations, and the number of the operations that block.
     42\item Toggle-able statistic collection on channel behvaiour that counts channel operations, and the number of the operations that block.
    5043Tracking 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.
    51 \item Deadlock detection on deallocation of the channel.
     44\item Deadlock detection on deallocation of the channel. 
    5245If any threads are blocked inside the channel when it terminates it is detected and informs the user, as this would cause a deadlock.
    53 \item A \code{flush} routine that delivers copies of an element to all waiting consumers, flushing the buffer.
    54 Programmers can use this to easily to broadcast data to multiple consumers.
    55 Additionally, 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.
     46\item A \code{flush} routine that delivers copies of an element to all waiting consumers, flushing the buffer. 
     47Programmers can use this to easily to broadcast data to multiple consumers. 
     48Additionally, 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.
    5649\end{itemize}
    5750
    58 The other safety and productivity feature of \CFA channels deals with concurrent termination.
    59 Terminating concurrent programs is often one of the most difficult parts of writing concurrent code, particularly if graceful termination is needed.
    60 The difficulty of graceful termination often arises from the usage of synchronization primitives which need to be handled carefully during shutdown.
    61 It is easy to deadlock during termination if threads are left behind on synchronization primitives.
    62 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.
    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.
    64 Channels are a particularly hard synchronization primitive to terminate since both sending and receiving off a channel can block.
     51The other safety and productivity feature of \CFA channels deals with concurrent termination. 
     52Terminating concurrent programs is often one of the most difficult parts of writing concurrent code, particularly if graceful termination is needed. 
     53The difficulty of graceful termination often arises from the usage of synchronization primitives which need to be handled carefully during shutdown. 
     54It is easy to deadlock during termination if threads are left behind on synchronization primitives. 
     55Additionally, 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. 
     57Channels are a particularly hard synchronization primitive to terminate since both sending and receiving off a channel can block. 
    6558Thus, 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.
    6659
    6760% C_TODO: add reference to select chapter, add citation to go channels info
    68 Go channels provide a set of tools to help with concurrent shutdown.
    69 Channels in Go have a \code{close} operation and a \code{select} statement that both can be used to help threads terminate.
    70 The \code{select} statement will be discussed in \ref{}, where \CFA's \code{waituntil} statement will be compared with the Go \code{select} statement.
    71 The \code{close} operation on a channel in Go changes the state of the channel.
    72 When a channel is closed, sends to the channel will panic and additional calls to \code{close} will panic.
    73 Receives are handled differently where receivers will never block on a closed channel and will continue to remove elements from the channel.
    74 Once a channel is empty, receivers can continue to remove elements, but will receive the zero-value version of the element type.
    75 To aid in avoiding unwanted zero-value elements, Go provides the ability to iterate over a closed channel to remove the remaining elements.
    76 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.
    77 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.
    78 If errors need to occur in Go, return codes are used to pass error information where they are needed.
     61Go channels provide a set of tools to help with concurrent shutdown. 
     62Channels in Go have a \code{close} operation and a \code{select} statement that both can be used to help threads terminate. 
     63The \code{select} statement will be discussed in \ref{}, where \CFA's \code{waituntil} statement will be compared with the Go \code{select} statement. 
     64The \code{close} operation on a channel in Go changes the state of the channel. 
     65When a channel is closed, sends to the channel will panic and additional calls to \code{close} will panic. 
     66Receives are handled differently where receivers will never block on a closed channel and will continue to remove elements from the channel. 
     67Once a channel is empty, receivers can continue to remove elements, but will receive the zero-value version of the element type. 
     68To aid in avoiding unwanted zero-value elements, Go provides the ability to iterate over a closed channel to remove the remaining elements. 
     69These 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. 
     70These 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. 
     71If errors need to occur in Go, return codes are used to pass error information where they are needed. 
    7972Note that panics in Go can be caught, but it is not considered an idiomatic way to write Go programs.
    8073
    81 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.
    82 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.
    83 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.
    84 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.
    85 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.
     74While 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. 
     75Since 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. 
     76However, 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. 
     77This 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. 
     78To 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. 
    8679Due to Go's asymmetric approach to channel shutdown, separate synchronization between producers and consumers of a channel has to occur during shutdown.
    8780
     
    8982As 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.
    9083Resumption exceptions are a style of exception that when caught run the corresponding catch block in the same way that termination exceptions do.
    91 The difference between the exception handling mechanisms arises after the exception is handled.
    92 In termination handling, the control flow continues into the code following the catch after the exception is handled.
    93 In resumption handling, the control flow returns to the site of the \code{throw}, allowing the control to continue where it left off.
    94 Note that in resumption, since control can return to the point of error propagation, the stack is not unwound during resumption propagation.
    95 In \CFA if a resumption is not handled, it is reraised as a termination.
     84The difference between the exception handling mechanisms arises after the exception is handled. 
     85In termination handling, the control flow continues into the code following the catch after the exception is handled. 
     86In resumption handling, the control flow returns to the site of the \code{throw}, allowing the control to continue where it left off. 
     87Note that in resumption, since control can return to the point of error propagation, the stack is not unwound during resumption propagation. 
     88In \CFA if a resumption is not handled, it is reraised as a termination. 
    9689This mechanism can be used to create a flexible and robust termination system for channels.
    9790
    98 When a channel in \CFA is closed, all subsequent calls to the channel will throw a resumption exception at the caller.
    99 If the resumption is handled, then the caller will proceed to attempt to complete their operation.
    100 If the resumption is not handled it is then rethrown as a termination exception.
    101 Or, if the resumption is handled, but the subsequent attempt at an operation would block, a termination exception is thrown.
    102 These termination exceptions allow for non-local transfer that can be used to great effect to eagerly and gracefully shut down a thread.
    103 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.
    104 The resumption exception, \code{channel_closed}, has a couple fields to aid in handling the exception.
    105 The exception contains a pointer to the channel it was thrown from, and a pointer to an element.
    106 In exceptions thrown from remove the element pointer will be null.
    107 In the case of insert the element pointer points to the element that the thread attempted to insert.
    108 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.
    109 Furthermore, due to \CFA's powerful exception system, this data can be used to choose handlers based which channel and operation failed.
    110 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.
    111 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.
     91When a channel in \CFA is closed, all subsequent calls to the channel will throw a resumption exception at the caller. 
     92If the resumption is handled, then the caller will proceed to attempt to complete their operation. 
     93If the resumption is not handled it is then rethrown as a termination exception. 
     94Or, if the resumption is handled, but the subsequent attempt at an operation would block, a termination exception is thrown. 
     95These termination exceptions allow for non-local transfer that can be used to great effect to eagerly and gracefully shut down a thread. 
     96When 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. 
     97The resumption exception, \code{channel_closed}, has a couple fields to aid in handling the exception. 
     98The exception contains a pointer to the channel it was thrown from, and a pointer to an element. 
     99In exceptions thrown from remove the element pointer will be null. 
     100In the case of insert the element pointer points to the element that the thread attempted to insert. 
     101This 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. 
     102Furthermore, due to \CFA's powerful exception system, this data can be used to choose handlers based which channel and operation failed. 
     103Exception 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. 
     104It is worth mentioning that the approach of exceptions for termination may incur a larger performance cost during termination that the approach used in Go. 
    112105This 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.
    113106
    114 To highlight the differences between \CFA's and Go's close semantics, an example program is presented.
    115 The program is a barrier implemented using two channels shown in Listings~\ref{l:cfa_chan_bar} and \ref{l:go_chan_bar}.
    116 Both of these examples are implemented using \CFA syntax so that they can be easily compared.
    117 Listing~\ref{l:go_chan_bar} uses go-style channel close semantics and Listing~\ref{l:cfa_chan_bar} uses \CFA close semantics.
    118 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.
    119 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.
    120 This sentinel value has to be checked at two points.
    121 Furthermore, an additional flag \code{done} is needed to communicate to threads once they have left the barrier that they are done.
    122 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.
    123 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.
    124 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.
     107To highlight the differences between \CFA's and Go's close semantics, an example program is presented. 
     108The program is a barrier implemented using two channels shown in Listings~\ref{l:cfa_chan_bar} and \ref{l:go_chan_bar}. 
     109Both of these exaples are implmented using \CFA syntax so that they can be easily compared.
     110Listing~\ref{l:go_chan_bar} uses go-style channel close semantics and Listing~\ref{l:cfa_chan_bar} uses \CFA close semantics. 
     111In 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. 
     112As 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. 
     113This sentinel value has to be checked at two points. 
     114Furthermore, an additional flag \code{done} is needed to communicate to threads once they have left the barrier that they are done. 
     115This 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. 
     116In 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. 
     117This 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. 
    125118Also 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.
    126119
    127 \begin{cfa}[caption={\CFA channel barrier termination},label={l:cfa_chan_bar}]
     120\begin{cfa}[tabsize=3,caption={\CFA channel barrier termination},label={l:cfa_chan_bar}]
    128121struct barrier {
    129         channel( int ) barWait;
    130         channel( int ) entryWait;
    131         int size;
     122    channel( int ) barWait;
     123    channel( int ) entryWait;
     124    int size;
    132125}
    133126void ?{}(barrier & this, int size) with(this) {
    134         barWait{size};
    135         entryWait{size};
    136         this.size = size;
    137         for ( j; size )
    138                 insert( *entryWait, j );
     127    barWait{size};
     128    entryWait{size};
     129    this.size = size;
     130    for ( j; size )
     131        insert( *entryWait, j );
    139132}
    140133
    141134void flush(barrier & this) with(this) {
    142         close(barWait);
    143         close(entryWait);
     135    close(barWait);
     136    close(entryWait);
    144137}
    145138void wait(barrier & this) with(this) {
    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         }
     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    }
    159152}
    160153barrier b{Tasks};
     
    162155// thread main
    163156void main(Task & this) {
    164         try {
    165                 for ( ;; ) {
    166                         wait( b );
    167                 }
    168         } catch ( channel_closed * e ) {}
     157    try {
     158        for ( ;; ) {
     159            wait( b );
     160        }
     161    } catch ( channel_closed * e ) {}
    169162}
    170163
    171164int main() {
    172         {
    173                 Task t[Tasks];
    174 
    175                 sleep(10`s);
    176                 flush( b );
    177         } // wait for tasks to terminate
    178         return 0;
     165    {
     166        Task t[Tasks];
     167
     168        sleep(10`s);
     169        flush( b );
     170    } // wait for tasks to terminate
     171    return 0;
    179172}
    180173\end{cfa}
    181174
    182 \begin{cfa}[caption={Go channel barrier termination},label={l:go_chan_bar}]
     175\begin{cfa}[tabsize=3,caption={Go channel barrier termination},label={l:go_chan_bar}]
    183176
    184177struct barrier {
    185         channel( int ) barWait;
    186         channel( int ) entryWait;
    187         int size;
     178    channel( int ) barWait;
     179    channel( int ) entryWait;
     180    int size;
    188181}
    189182void ?{}(barrier & this, int size) with(this) {
    190         barWait{size + 1};
    191         entryWait{size + 1};
    192         this.size = size;
    193         for ( j; size )
    194                 insert( *entryWait, j );
     183    barWait{size + 1};
     184    entryWait{size + 1};
     185    this.size = size;
     186    for ( j; size )
     187        insert( *entryWait, j );
    195188}
    196189
    197190void flush(barrier & this) with(this) {
    198         insert( *entryWait, -1 );
    199         insert( *barWait, -1 );
     191    insert( *entryWait, -1 );
     192    insert( *barWait, -1 );
    200193}
    201194void wait(barrier & this) with(this) {
    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         }
     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    }
    223216}
    224217barrier b;
     
    227220// thread main
    228221void main(Task & this) {
    229         for ( ;; ) {
    230                 if ( done ) break;
    231                 wait( b );
    232         }
     222    for ( ;; ) {
     223        if ( done ) break;
     224        wait( b );
     225    }
    233226}
    234227
    235228int main() {
    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;
     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;
    245238}
    246239\end{cfa}
    247240
    248 In Listing~\ref{l:cfa_resume} an example of channel closing with resumption is used.
    249 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.
    250 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.
     241In Listing~\ref{l:cfa_resume} an example of channel closing with resumption is used. 
     242This program uses resumption in the \code{Consumer} thread main to ensure that all elements in the channel are removed before the consumer thread terminates. 
     243The 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. 
    251244If 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.
    252245
    253 \begin{cfa}[caption={\CFA channel resumption usage},label={l:cfa_resume}]
     246\begin{cfa}[tabsize=3,caption={\CFA channel resumption usage},label={l:cfa_resume}]
    254247channel( int ) chan{ 128 };
    255248
    256249// Consumer thread main
    257250void main(Consumer & this) {
    258         size_t runs = 0;
    259         try {
    260                 for ( ;; ) {
    261                         remove( chan );
    262                 }
    263         } catchResume ( channel_closed * e ) {}
    264         catch ( channel_closed * e ) {}
     251    size_t runs = 0;
     252    try {
     253        for ( ;; ) {
     254            remove( chan );
     255        }
     256    } catchResume ( channel_closed * e ) {}
     257    catch ( channel_closed * e ) {}
    265258}
    266259
    267260// Producer thread main
    268261void main(Producer & this) {
    269         int j = 0;
    270         try {
    271                 for ( ;;j++ ) {
    272                         insert( chan, j );
    273                 }
    274         } catch ( channel_closed * e ) {}
     262    int j = 0;
     263    try {
     264        for ( ;;j++ ) {
     265            insert( chan, j );
     266        }
     267    } catch ( channel_closed * e ) {}
    275268}
    276269
    277270int main( int argc, char * argv[] ) {
    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;
     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;
    288281}
    289282\end{cfa}
     
    291284\section{Performance}
    292285
    293 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.
    294 One microbenchmark is conducted to compare Go and \CFA.
    295 The benchmark is a ten second experiment where producers and consumers operate on a channel in parallel and throughput is measured.
    296 The number of cores is varied to measure how throughput scales.
    297 The cores are divided equally between producers and consumers, with one producer or consumer owning each core.
    298 The results of the benchmark are shown in Figure~\ref{f:chanPerf}.
    299 The performance of Go and \CFA channels on this microbenchmark is comparable.
     286Given 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. 
     287One microbenchmark is conducted to compare Go and \CFA. 
     288The benchmark is a ten second experiment where producers and consumers operate on a channel in parallel and throughput is measured. 
     289The number of cores is varied to measure how throughtput scales.
     290The cores are divided equally between producers and consumers, with one producer or consumer owning each core. 
     291The results of the benchmark are shown in Figure~\ref{f:chanPerf}. 
     292The performance of Go and \CFA channels on this microbenchmark is comparable. 
    300293Note, 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.
    301294
    302295
    303296\begin{figure}
    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}
     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}
    315310\end{figure}
    316 
    317 % Local Variables: %
    318 % tab-width: 4 %
    319 % End: %
  • doc/theses/colby_parsons_MMAth/text/mutex_stmt.tex

    r6e1e2d0 ra50fdfb  
    55% ======================================================================
    66
    7 The mutual exclusion problem was introduced by Dijkstra in 1965~\cite{Dijkstra65,Dijkstra65a}.
    8 There are several concurrent processes or threads that communicate by shared variables and from time to time need exclusive access to shared resources.
    9 A 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.
    11 Regions of code where the thread is not interested in the resource are combined into the \Newterm{non-critical section (NCS)}.
     7The mutex statement is a concurrent language feature that aims to support easy lock usage.
     8The mutex statement is in the form of a clause and following statement, similar to a loop or conditional statement.
     9In the clause the mutex statement accepts a number of lockable objects, and then locks them for the duration of the following statement.
     10The locks are acquired in a deadlock free manner and released using \gls{raii}.
     11The mutex statement provides an avenue for easy lock usage in the common case where locks are used to wrap a critical section.
     12Additionally, 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}.
    1213
    13 Exclusive access to a resource is provided by \Newterm{mutual exclusion (MX)}.
    14 MX is implemented by some form of \emph{lock}, where the CS is bracketed by lock procedures @acquire@ and @release@.
    15 Threads execute a loop of the form:
    16 \begin{cfa}
    17 loop of $thread$ p:
    18         NCS;
    19         acquire( lock );  CS;  release( lock ); // protected critical section with MX
    20 end loop.
     14\begin{cfa}[tabsize=3,caption={\CFA mutex statement usage},label={l:cfa_mutex_ex}]
     15owner_lock lock1, lock2, lock3;
     16int count = 0;
     17mutex( lock1, lock2, lock3 ) {
     18    // can use block statement
     19    // ...
     20}
     21mutex( lock2, lock3 ) count++; // or inline statement
    2122\end{cfa}
    22 MX guarantees there is never more than one thread in the CS.
    23 MX 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.
    25 A stronger constraint is that every thread that calls @acquire@ eventually succeeds after some reasonable bounded time.
    2623
    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.
    29 First 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}.
    30 In 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.
     24\section{Other Languages}
     25There are similar concepts to the mutex statement that exist in other languages.
     26Java has a feature called a synchronized statement, which looks identical to \CFA's mutex statement, but it has some differences.
     27The synchronized statement only accepts a single object in its clause.
     28Any 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.
     29In \CC there is a feature in the standard library \code{<mutex>} header called scoped\_lock, which is also similar to the mutex statement.
     30The scoped\_lock is a class that takes in any number of locks in its constructor, and acquires them in a deadlock-free manner.
     31It then releases them when the scoped\_lock object is deallocated, thus using \gls{raii}.
     32An example of \CC scoped\_lock usage is shown in Listing~\ref{l:cc_scoped_lock}.
    3133
    32 Figure~\ref{f:AtomicCounter} shows a \CFA and Java monitor implementing an atomic counter.
    33 A \Newterm{monitor} is a programming technique that implicitly binds mutual exclusion to static function scope by call and return.
    34 Lock mutual exclusion, defined by acquire/release calls, is independent of lexical context (analogous to block versus heap storage allocation).
    35 Restricting acquire and release points in a monitor eases programming, comprehension, and maintenance, at a slight cost in flexibility and efficiency.
    36 Ultimately, 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 };
    46 int ++?( Aint & @mutex@ m ) { return ++m.cnt; }
    47 int ?=?( Aint & @mutex@ l, int r ) { l.cnt = r; }
    48 int ?=?(int & l, Aint & r) { l = r.cnt; }
    49 
    50 int i = 0, j = 0;
    51 Aint x = { 0 }, y = { 0 };      $\C[1.5in]{// no mutex}$
    52 ++x;  ++y;                      $\C{// mutex}$
    53 x = 2;  y = i;          $\C{// mutex}$
    54 i = 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]
    60 class 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 }
    67 int i = 0, j = 0;
    68 Aint x = new Aint( 0 ), y = new Aint( 0 );
    69 x.inc();  y.inc();
    70 x.set( 2 );  y.set( i );
    71 i = 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 
    84 Like 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.
    85 For 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.
    86 Monitor 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@.
    88 Java members are designated MX with \lstinline[language=java]{synchronized}, which applies only to the implicit receiver parameter.
    89 In 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 
    91 As stated, the non-object-oriented nature of \CFA monitors allows a function to acquire multiple mutex objects.
    92 For example, the bank-transfer problem requires locking two bank accounts to safely debit and credit money between accounts.
    93 \begin{cfa}
    94 monitor BankAccount {
    95         int balance;
    96 };
    97 void deposit( BankAccount & mutex b, int deposit ) with( b ) {
    98         balance += deposit;
    99 }
    100 void 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}
    105 The \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}
    109 Restricting implicit lock acquisition to function entry and exit can be awkward for certain problems.
    110 To 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.)
    113 The @read@ and @write@ functions are called with a reader/write lock and any arguments to perform reading or writing.
    114 The @read@ function is not MX because multiple readers can read simultaneously.
    115 MX is acquired within @read@ by calling the (nested) helper functions @StartRead@ and @EndRead@ or executing the mutex statements.
    116 Between the calls or statements, reads can execute simultaneous within the body of @read@.
    117 The @write@ function does not require refactoring because writing is a CS.
    118 The 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]
    125 monitor RWlock { ... };
    126 void 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 }
    133 void 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 
    142 void read( RWlock & rw, ... ) {
    143 
    144 
    145         @mutex@( rw ) { ... }
    146         ... // read without MX
    147         @mutex@{ rw ) { ... }
    148 }
    149 void 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 
    164 This work adds a mutex statement to \CFA, but generalizes it beyond implicit monitor locks.
    165 In detail, the mutex statement has a clause and statement block, similar to a conditional or loop statement.
    166 The clause accepts any number of lockable objects (like a \CFA MX function prototype), and locks them for the duration of the statement.
    167 The locks are acquired in a deadlock free manner and released regardless of how control-flow exits the statement.
    168 The mutex statement provides easy lock usage in the common case of lexically wrapping a CS.
    169 Examples 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}]
    172 owner_lock lock1, lock2, lock3;
    173 @mutex@( lock2, lock3 ) ...;    $\C{// inline statement}$
    174 @mutex@( lock1, lock2, lock3 ) { ... }  $\C{// statement block}$
    175 void 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         }
     34\begin{cfa}[tabsize=3,caption={\CC scoped\_lock usage},label={l:cc_scoped_lock}]
     35std::mutex lock1, lock2, lock3;
     36{
     37    scoped_lock s( lock1, lock2, lock3 )
     38    // locks are released via raii at end of scope
    18139}
    18240\end{cfa}
    18341
    184 \section{Other Languages}
    185 There are similar constructs to the mutex statement in other programming languages.
    186 Java 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.
    187 The \CC standard library has a @scoped_lock@, which is also similar to the mutex statement.
    188 The @scoped_lock@ takes any number of locks in its constructor, and acquires them in a deadlock-free manner.
    189 It then releases them when the @scoped_lock@ object is deallocated using \gls{raii}.
    190 An example of \CC @scoped_lock@ is shown in \VRef[Listing]{l:cc_scoped_lock}.
     42\section{\CFA implementation}
     43The \CFA mutex statement takes some ideas from both the Java and \CC features.
     44The 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.
     45This syntactic choice was made so that the body of the mutex statement is its own scope.
     46Compared 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()}.
     49The scoped\_lock requires an additional routine since it differs from the mutex statement in how it implements deadlock avoidance.
    19150
    192 \begin{cfa}[caption={\CC \lstinline{scoped_lock} usage},label={l:cc_scoped_lock}]
    193 struct BankAccount {
    194         @recursive_mutex m;@            $\C{// must be recursive}$
    195         int balance = 0;
    196 };
    197 void deposit( BankAccount & b, int deposit ) {
    198         @scoped_lock lock( b.m );@      $\C{// RAII acquire}$
    199         b.balance += deposit;
    200 }                                                               $\C{// RAII release}$
    201 void 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}$
     51The parametric polymorphism allows for locking to be defined for types that may want convenient mutual exclusion.
     52An example of one such use case in \CFA is \code{sout}.
     53The 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.
     55In 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.
     56The 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.
     57This is a commonly used feature when producing output from a concurrent context, since producing output is not thread safe by default.
     58This use case is shown in Listing~\ref{l:sout}.
     59
     60\begin{cfa}[tabsize=3,caption={\CFA sout with mutex statement},label={l:sout}]
     61mutex( sout )
     62    sout | "This output is protected by mutual exclusion!";
    20663\end{cfa}
    20764
    208 \section{\CFA implementation}
    209 The \CFA mutex statement takes some ideas from both the Java and \CC features.
    210 Like Java, \CFA introduces a new statement rather than building from existing language features.
    211 (\CFA has sufficient language features to mimic \CC RAII locking.)
    212 This syntactic choice makes MX explicit rather than implicit via object declarations.
    213 Hence, 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.
    214 Furthermore, concurrent safety is provided across an entire program for the complex operation of acquiring multiple locks in a deadlock-free manner.
    215 Unlike Java, \CFA's mutex statement and \CC's @scoped_lock@ both use parametric polymorphism to allow user defined types to work with this feature.
    216 In 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}
    219 forall( L & | sized(L) )
    220 trait 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}}.
     65\section{Deadlock Avoidance}
     66The 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.
     67The 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.
     68This repeats until all locks are acquired successfully.
     69The deadlock avoidance algorithm used by scoped\_lock is shown in Listing~\ref{l:cc_deadlock_avoid}.
     70The algorithm presented is taken directly from the source code of the \code{<mutex>} header, with some renaming and comments for clarity.
    22771
    228 The following shows how the @mutex@ statement is used with \CFA streams to eliminate unpredictable results when printing in a concurrent program.
    229 For example, if two threads execute:
    230 \begin{cfa}
    231 thread$\(_1\)$ : sout | "abc" | "def";
    232 thread$\(_2\)$ : sout | "uvw" | "xyz";
    233 \end{cfa}
    234 any 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@{}}
    238 abc def & abc uvw xyz & uvw abc xyz def & abuvwc dexf &  uvw abc def \\
    239 uvw xyz & def & & yz & xyz
    240 \end{tabular}
    241 \end{cquote}
    242 The 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.
    243 From 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.
    244 This ability improves safety and programmer productivity since it abstracts away the concurrent details.
    245 Hence, a  programmer can easily protect cascaded I/O expressions:
    246 \begin{cfa}
    247 thread$\(_1\)$ : mutex( sout )  sout | "abc" | "def";
    248 thread$\(_2\)$ : mutex( sout )  sout | "uvw" | "xyz";
    249 \end{cfa}
    250 constraining the output to two different lines in either order:
    251 \begin{cquote}
    252 \small\tt
    253 \begin{tabular}{@{}l|l@{}}
    254 abc def & uvw xyz \\
    255 uvw xyz & abc def
    256 \end{tabular}
    257 \end{cquote}
    258 where this level of safe nondeterministic output is acceptable.
    259 Alternatively, multiple I/O statements can be protected using the mutex statement block:
    260 \begin{cfa}
    261 mutex( 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}
    267 The 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}
    270 The 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.
    271 The @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.
    272 This repeats after selecting a new starting point in a cyclic manner until all locks are acquired successfully.
    273 This deadlock avoidance algorithm is shown in Listing~\ref{l:cc_deadlock_avoid}.
    274 The 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}]
     72\begin{cfa}[caption={\CC scoped\_lock deadlock avoidance algorithm},label={l:cc_deadlock_avoid}]
    27773int first = 0;  // first lock to attempt to lock
    27874do {
    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         }
     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    }
    29086// if first lock is still held then all have been acquired
    291 } while ( ! locks[first].owns_lock() );  $\C{// is first lock held?}$
     87} while (!locks[first].owns_lock());  // is first lock held?
    29288\end{cfa}
    29389
    294 While the algorithm in \ref{l:cc_deadlock_avoid} successfully avoids deadlock, there is a livelock scenario.
    295 Assume two threads, $A$ and $B$, create a @scoped_lock@ accessing two locks, $L1$ and $L2$.
    296 A livelock can form as follows.
    297 Thread $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$.
    298 Both threads acquire the first lock in their order and then fail the @try_lock@ since the other lock is held.
    299 Both threads then reset their starting lock to be their second lock and try again.
    300 This 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.
    301 If the threads perform this action in lock-step, they cycle indefinitely without entering the CS, \ie livelock.
    302 Hence, to use @scoped_lock@ safely, a programmer must manually construct and maintain a global ordering of lock arguments passed to @scoped_lock@.
     90The algorithm in \ref{l:cc_deadlock_avoid} successfully avoids deadlock, however there is a potential livelock scenario.
     91Given two threads $A$ and $B$, who create a scoped\_lock with two locks $L1$ and $L2$, a livelock can form as follows.
     92Thread $A$ creates a scoped\_lock with $L1$, $L2$, and $B$ creates a scoped lock with the order $L2$, $L1$.
     93Both threads acquire the first lock in their order and then fail the try\_lock since the other lock is held.
     94They then reset their start lock to be their 2nd lock and try again.
     95This time $A$ has order $L2$, $L1$, and $B$ has order $L1$, $L2$.
     96This is identical to the starting setup, but with the ordering swapped among threads.
     97As such, if they each acquire their first lock before the other acquires their second, they can livelock indefinitely.
    30398
    304 The lock ordering algorithm used in \CFA mutex functions and statements is deadlock and livelock free.
    305 The algorithm uses the lock memory addresses as keys, sorts the keys, and then acquires the locks in sorted order.
    306 For 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;
    307 for 7 or more locks, insertion sort is used.
    308 Since it is extremely rare to hold more than 6 locks at a time, the algorithm is fast and executes in $O(1)$ time.
    309 Furthermore, lock addresses are unique across program execution, even for dynamically allocated locks, so the algorithm is safe across the entire program execution.
     99The lock ordering algorithm used in the mutex statement in \CFA is both deadlock and livelock free.
     100It sorts the locks based on memory address and then acquires them.
     101For locks fewer than 7, it sorts using hard coded sorting methods that perform the minimum number of swaps for a given number of locks.
     102For 7 or more locks insertion sort is used.
     103These sorting algorithms were chosen since it is rare to have to hold more than  a handful of locks at a time.
     104It 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.
     105If 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.
     106Comparitively, 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.
    310107
    311 The 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.
    312 The following scenario is a classic deadlock.
    313 \begin{cquote}
    314 \begin{tabular}{@{}l@{\hspace{30pt}}l@{}}
    315 \begin{cfa}
    316 lock L1, L2; // assume &L1 < &L2
    317         $\textbf{thread\(_1\)}$
    318 acquire( L2 );
    319         acquire( L1 );
    320                 CS
    321         release( L1 );
    322 release( L2 );
    323 \end{cfa}
    324 &
    325 \begin{cfa}
     108\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}
    326120
    327         $\textbf{thread\(_2\)}$
    328 mutex( L1, L2 ) {
     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}
    329131
    330         CS
    331 
    332 }
    333 \end{cfa}
    334 \end{tabular}
    335 \end{cquote}
    336 Comparatively, 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.
    337 The 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.
     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}
     144\end{figure}
    338145
    339146\section{Performance}
    340 Given the two multi-acquisition algorithms in \CC and \CFA, each with differing advantages and disadvantages, it interesting to compare their performance.
    341 Comparison with Java is not possible, since it only takes a single lock.
    342 
    343 The 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.
    344 The baseline helps highlight the cost of the deadlock avoidance/prevention algorithms for each implementation.
    345 
    346 The benchmark used to evaluate the avoidance algorithms repeatedly acquires a fixed number of locks in a random order and then releases them.
    347 The pseudo code for the deadlock avoidance benchmark is shown in \VRef[Listing]{l:deadlock_avoid_pseudo}.
    348 To 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.
    349 The benchmarks are run for a fixed duration of 10 seconds and then terminate.
    350 The total number of times the group of locks is acquired is returned for each thread.
    351 Each variation is run 11 times on 2, 4, 8, 16, 24, 32 cores and with 2, 4, and 8 locks being acquired.
     147Performance is compared between \CC's scoped\_lock and \CFA's mutex statement.
     148Comparison with Java is omitted, since it only takes a single lock.
     149To 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.
     150Each feature is evaluated on a benchmark which acquires a fixed number of locks in a random order and then releases them.
     151A baseline is included that acquires the locks directly without a mutex statement or scoped\_lock in a fixed ordering and then releases them.
     152The baseline helps highlight the cost of the deadlock avoidance/prevention algorithms for each implementation.
     153The 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.
     154Each variation is run 11 times on a variety up to 32 cores and with 2, 4, and 8 locks being acquired.
    352155The median is calculated and is plotted alongside the 95\% confidence intervals for each point.
    353156
    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 
    364 The 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
    368 Supermicro 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
    370 Supermicro 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 
    375 Figure~\ref{f:mutex_bench} shows the results of the benchmark experiments.
    376 \PAB{Make the points in the graphs for each line different.
    377 Also, make the text in the graphs larger.}
    378 The 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.
    379 The avoidance result for both languages is significantly different, where \CFA's mutex statement achieves throughput that is magnitudes higher than \CC's @scoped_lock@.
    380 The slowdown for @scoped_lock@ is likely due to its deadlock-avoidance implementation.
    381 Since it uses a retry based mechanism, it can take a long time for threads to progress.
    382 Additionally the potential for livelock in the algorithm can result in very little throughput under high contention.
    383 For 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.
    384 It 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.
    385 In Figures~\ref{f:mutex_bench8_AMD} and \ref{f:mutex_bench8_Intel} the mutex statement performs better than the baseline.
    386 At 7 locks and above the mutex statement switches from a hard coded sort to insertion sort.
     157Figure~\ref{f:mutex_bench} shows the results of the benchmark.
     158The 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.
     160This is likely due to the scoped\_lock deadlock avoidance implementation.
     161Since it uses a retry based mechanism, it can take a long time for threads to progress.
     162Additionally the potential for livelock in the algorithm can result in very little throughput under high contention.
     163It 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.
     164It 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.
     165In Figures~\ref{f:mutex_bench8_AMD} and \ref{f:mutex_bench8_Intel} the mutex statement performs better than the baseline.
     166At 7 locks and above the mutex statement switches from a hard coded sort to insertion sort.
    387167It 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.
    388 
    389 \begin{figure}
    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}
    415 \end{figure}
    416 
    417 % Local Variables: %
    418 % tab-width: 4 %
    419 % End: %
  • doc/theses/colby_parsons_MMAth/thesis.tex

    r6e1e2d0 ra50fdfb  
    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}
    8687\usepackage{fullpage,times,comment}
    8788\usepackage{textcomp}
    8889\usepackage{graphicx}
    8990\usepackage{tabularx}
    90 \usepackage[labelformat=simple,aboveskip=0pt,farskip=0pt,font=normalsize]{subfig}
    91 \renewcommand\thesubfigure{(\alph{subfigure})}
    9291\input{style}
    9392
  • doc/theses/colby_parsons_MMAth/version.sh

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

    r6e1e2d0 ra50fdfb  
    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 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
     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
    119
    1210CFA = cfa
     
    1412UXX =  ~/u++/u++-7.0.0/bin/u++
    1513
    16 MODE=performance
    17 EXTRA_COMP_FLAGS=
    18 RUN_NUM_REPS=3
    19 RUN_DATA_SIZE_MODE=none
    20 RUN_DURATION_SEC=5
    21 RUN_TASKSET_CPULIST=6
     14MODE = performance
     15RUNARGS=
    2216
    2317ifeq "$(MODE)" "performance"
    24 PERFFLAGS_CFA = -DNDEBUG -O3 -nodebug
     18PERFFLAGS_CFA = -nodebug -O3
    2519PERFFLAGS_CC  = -DNDEBUG -O3
    2620else ifeq "$(MODE)" "correctness"
    27 PERFFLAGS_CFA = -O0 -g -debug
    28 PERFFLAGS_CC  = -O0 -g
     21PERFFLAGS_CFA = -debug -O0 -g
     22PERFFLAGS_CC = -O0 -g
    2923else
    3024$(error Bad MODE ($(MODE)); should be performance or correctness)
     
    3226
    3327PERFFLAGS_CXX = $(PERFFLAGS_CC)
    34 PERFFLAGS_UXX = $(PERFFLAGS_CFA)
    35 
    36 CFLAGS=$(PERFFLAGS_CC) $(EXTRA_COMP_FLAGS)
     28PERFFLAGS_UXX = $(PERFFLAGS_CC)
    3729
    3830SHELL = /usr/bin/bash
     
    109101perfexp--%     driver--%.o     : COMPILER=NO-COMPILER-FOR-$(FX_COARSE)
    110102
    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 
    120103perfexp--% : driver--%.o observation.o
    121         $(COMPILER) $(EXTRA_COMP_FLAGS) $^ -o $@
     104        $(COMPILER) $^ -o $@
    122105
    123106driver--%.o : driver.c
    124         $(COMPILER) $(EXTRA_COMP_FLAGS) -c $< $(OP_DEFINES) -include op-$(OP).h -include fx-$(FX).h -o $@ -MMD
    125 
    126 sayhi:
    127         echo $(PERFPROGS)
     107        $(COMPILER) -c $< $(OP_DEFINES) -include op-$(OP).h -include fx-$(FX).h -o $@ -MMD
    128108
    129109
    130 ifeq "$(RUN_DATA_SIZE_MODE)" "common5"
    131 RUN_DATA_SIZES=\
    132   7-1000000 \
    133   71-100000 \
    134   809-10000 \
    135   9051-1000 \
    136   72421-100
    137 else ifeq "$(RUN_DATA_SIZE_MODE)" "thorough"
    138 RUN_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
    181 else ifeq "$(RUN_DATA_SIZE_MODE)" "manual"
    182 ifeq "$(RUN_DATA_SIZES)" ""
    183 $(error RUN_DATA_SIZE_MODE is manual but RUN_DATA_SIZES not given)
    184 endif
    185 else ifeq "$(RUN_DATA_SIZE_MODE)" "none"
    186 # Assume user manages RUN_ARGS; empty RUN_ARGS just means run with compiled-in defaults
    187 RUN_DATA_SIZES=none
    188 else
    189 $(error Bad RUN_DATA_SIZE_MODE ($(RUN_DATA_SIZE_MODE)); should be common5, thorough or manual)
    190 endif
    191110
     111
     112RUN_NUM_REPS=3
    192113RUN_REP_IDS=$(shell echo {1..$(RUN_NUM_REPS)})              # 1 2 3
    193114RUN_REP_EXTS=$(call cross3,,run,$(RUN_REP_IDS),.1csv)       # run1.1csv run2.1cav run3.1csv
    194115
    195 RUN_LAUNCHES=$(call cross,--,$(RUN_DATA_SIZES),$(RUN_REP_EXTS))
    196 
    197 
    198 
    199 RESULT1S=$(call cross,.,$(CORES),$(RUN_LAUNCHES))   # lq-tailq--stack-inslast-allhead.run2.1csv
    200 
     116RESULT1S=$(call cross,.,$(CORES),$(RUN_REP_EXTS))   # lq-tailq--stack-inslast-allhead.run2.1csv
    201117
    202118RESULT1S_SHUFD=$(shell shuf -e $(RESULT1S))
    203119
    204120%.1csv : CORE=$(basename $(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
     121%.1csv : REP_ID=$(subst .run,,$(suffix $(basename $@)))
    211122%.1csv : REP_TIME=$(shell date '+%F %H:%M:%S')
    212123%.1csv : perfprogs FORCE
    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 
     124        ./perfexp--$(CORE) $(RUNARGS) | xargs -n 1 printf '%s,%s,%s\n' "$(REP_TIME)" "$(REP_ID)" | tee $@
    215125
    216126BATCHTIME=$(shell date '+%F--%H-%M-%S')
     
    236146.PRECIOUS: result--%.1csv driver--%.o perfexp--% %.o
    237147
     148
    238149-include *.d
  • doc/theses/mike_brooks_MMath/benchmarks/list/_classic.c

    r6e1e2d0 ra50fdfb  
    171171#endif
    172172
    173 volatile unsigned int t = 0;
    174 volatile unsigned int i_official = 0;
    175 
    176 #define Repeat( op ) for ( unsigned int i = 0; (i_official = i, i < NoOfNodes); i += 1 ) { op; }
     173
     174#define Repeat( op ) for ( volatile unsigned int i = 0; i < NoOfNodes; i += 1 ) { op; }
    177175
    178176int main() {
     
    194192        TAILQ_INIT(&lst);
    195193        start = clock();
    196         for ( t = 0; t < Times; t += 1 ) {
     194        for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
    197195                Repeat( TAILQ_INSERT_TAIL( &lst, &s[i], x ) );
    198196                Repeat( TAILQ_REMOVE( &lst, TAILQ_FIRST( &lst ), x ) );
     
    206204        std::list<S *> lst;
    207205        start = clock();
    208         for ( t = 0; t < Times; t += 1 ) {
     206        for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
    209207                Repeat( lst.push_back( &s[i] ) );
    210208                Repeat( lst.pop_front() );
     
    218216        uSequence<S> lst;
    219217        start = clock();
    220         for ( t = 0; t < Times; t += 1 ) {
     218        for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
    221219                Repeat( lst.addTail( &s[i] ) );
    222220                Repeat( lst.dropHead() );
     
    230228        dlist(S) lst;
    231229        start = clock();
    232         for ( t = 0; t < Times; t += 1 ) {
     230        for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
    233231                Repeat( insert_last( lst, s[i] ) );
    234232                Repeat( remove( lst`first ) );
     
    242240        Sequence(S) lst;
    243241        start = clock();
    244         for ( t = 0; t < Times; t += 1 ) {
     242        for ( volatile unsigned int t = 0; t < Times; t += 1 ) {
    245243                Repeat( addHead( lst, s[i] ) );
    246244                Repeat( dropTail( lst ) );
  • doc/theses/mike_brooks_MMath/benchmarks/list/driver.c

    r6e1e2d0 ra50fdfb  
    1717
    1818#if defined(NDEBUG) || (defined(__cforall) && !defined(__CFA_DEBUG__))
    19     enum { DefaultNumNodes = 1000, DefaultExperimentDurSec = 1, DefaultCheckDonePeriod = 1000, DefaultExperimentDurOpCount = -1, DefaultSeed = 5 };
     19    enum { DefaultNumNodes = 1000, DefaultExperimentDurSec = 1, DefaultCheckClockFreq = 1000, DefaultExperimentDurOpCount = -1 };
    2020    #define TRACE(tp)
    2121#else
    22     enum { DefaultNumNodes = 10, DefaultExperimentDurSec = 1, DefaultCheckDonePeriod = 2, DefaultExperimentDurOpCount = 20, DefaultSeed = 5 };
     22    enum { DefaultNumNodes = 10, DefaultExperimentDurSec = 1, DefaultCheckClockFreq = 2, DefaultExperimentDurOpCount = 20 };
    2323    static const char * tp_filter
    2424    // = "";
     
    6363    }
    6464
    65     void * bobs_getCurrentLoc() {
    66         return BFX_DEREF_POS(B_UserItem, lst, observedItem);
    67     }
    68     int bobs_getCurrentVal() {
     65    int bobs_getCurrent() {
    6966        B_UserItem * curUI = BFX_DEREF_POS(B_UserItem, lst, observedItem);
    7067        return curUI->userdata[17];
     
    7572)
    7673
    77 unsigned int uDefaultPreemption() {
    78         return 0;
    79 }
    80 
    8174int main(int argc, const char *argv[]) {
    8275
    83     const char * usage_args = "[ExperimentDurSec [CheckDonePeriod [NumNodes [ExperimentDurOpCount [Seed]]]]]";
    84     const int static_arg_posns = 5;
     76
     77    const char * usage_args = "[ExperimentDurSec [CheckClockFreq [NumNodes [ExperimentDurOpCount]]]]";
     78    const int static_arg_posns = 4;
    8579
    8680    unsigned int ExperimentDurSec     = DefaultExperimentDurSec;
    87     unsigned int CheckDonePeriod      = DefaultCheckDonePeriod;
     81    unsigned int CheckClockFreq       = DefaultCheckClockFreq;
    8882    unsigned int NumNodes             = DefaultNumNodes;
    8983    size_t       ExperimentDurOpCount = DefaultExperimentDurOpCount;
    90     unsigned int Seed                 = DefaultSeed;
    9184
    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]);
     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]);
    9890    }
    9991
    100     if (ExperimentDurSec == 0 || CheckDonePeriod == 0 || NumNodes == 0 || ExperimentDurOpCount == 0 || Seed == 0 ) {
     92    if (ExperimentDurSec == 0 || CheckClockFreq == 0 || NumNodes == 0 || ExperimentDurOpCount == 0 ) {
    10193        printf("usage: %s %s\n", argv[0], usage_args);
    10294        return -1;
    10395    }
    10496
    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
     97    ui = (B_UserItem*) malloc( NumNodes * sizeof(B_UserItem) );
     98    memset(ui, 0, NumNodes * sizeof(B_UserItem));
    11199
    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)
     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
    122103    for (int i = 0; i < NumNodes; 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)];
     104        B_UserItem * curUI = & ui[i];
    157105        curUI->userdata[17] = i;
    158106    }
     
    162110    bobs_init(NumNodes);
    163111
    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
     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].
    171115    // Logical insert number 0 and remove number n-1 are given with a distinguished hook.
    172116    // Logical insert numbers [1,n) and remove numbers [0,n-1) are pumped by the basic SUT hooks.
    173117    // 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.)
    176118
    177119    // Default init/teardown is insert/remove
    178120    // Cartridges whose SUT insert/remove actions work on empty lists need not provide special-case ones.
    179121    #ifndef BOP_INIT
    180     #define BOP_INIT(lst, iters, insNo, item) BOP_INSERT(lst, iters, insNo, item)
     122    #define BOP_INIT(lst, ui, iters, i) BOP_INSERT(lst, ui, iters, i)
    181123    #endif
    182124    #ifndef BOP_TEARDOWN
    183     #define BOP_TEARDOWN(lst, iters, remNo) BOP_REMOVE(lst, iters, remNo)
     125    #define BOP_TEARDOWN(lst, ui, iters, i) BOP_REMOVE(lst, ui, iters, i)
    184126    #endif
    185127
     
    187129    clock_t start = clock();
    188130
    189     size_t privateOpsCompleted = 0;
    190 
    191     while (elapsed_sec <= (double) ExperimentDurSec && privateOpsCompleted < ExperimentDurOpCount) {
    192         for ( int t = 0; t < CheckDonePeriod; t += 1 ) {
     131    while (elapsed_sec <= (double) ExperimentDurSec && bobs_ops_completed < ExperimentDurOpCount) {
     132        for ( int t = 0; t < CheckClockFreq; t += 1 ) {
    193133            TRACE('a')
    194134            listedItems[0] =
    195                 BOP_INIT(lst, listedItems, 0, ui[INSERTPOS(0)]);
     135                BOP_INIT(lst, ui, listedItems, 0);
    196136            TRACE('b')
    197137            for ( int privateCurInsert = 1;
     
    201141                TRACE('-')
    202142                listedItems[privateCurInsert] =
    203                     BOP_INSERT( lst, listedItems, privateCurInsert, ui[INSERTPOS(privateCurInsert)] );
     143                    BOP_INSERT( lst, ui, listedItems, privateCurInsert );
    204144                TRACE('+')
    205145            }
     
    210150                ) {
    211151                TRACE('-')
    212                 BOP_REMOVE( lst, listedItems, privateCurRemove-1 );
     152                BOP_REMOVE( lst, ui, listedItems, privateCurRemove-1 );
    213153                TRACE('+')
    214154            }
    215155            TRACE('D')
    216             BOP_TEARDOWN(lst, listedItems, NumNodes-1);
     156            BOP_TEARDOWN(lst, ui, listedItems, NumNodes-1);
    217157            TRACE('d')
    218 
    219             privateOpsCompleted += NumNodes;
    220158
    221159            bobs_prog_rollover_flag = 1;
     
    223161            bobs_prog_inserting = 0;
    224162            bobs_prog_removing = 0;           
    225             bobs_ops_completed = privateOpsCompleted;
     163            bobs_ops_completed += NumNodes;
    226164            TRACE('f')
    227165            bobs_prog_rollover_flag = 0;
    228166            TRACE('g')
    229167        }
    230       #ifndef DISABLE_CLOCK_RECHECK
    231         clock_t end = clock();
    232         elapsed_sec = ((double)(end - start)) / ((double)CLOCKS_PER_SEC);
    233       #endif
    234     }
    235     #ifdef DISABLE_CLOCK_RECHECK
    236     {
    237168        clock_t end = clock();
    238169        elapsed_sec = ((double)(end - start)) / ((double)CLOCKS_PER_SEC);
    239170    }
    240     #endif
    241171
    242172    double mean_op_dur_ns = elapsed_sec / ((double)bobs_ops_completed) * 1000 * 1000 * 1000;
     
    245175    free(ui);
    246176    free(listedItems);
    247     free(insertOrdShuf);
    248177}
  • doc/theses/mike_brooks_MMath/benchmarks/list/observation.c

    r6e1e2d0 ra50fdfb  
    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
    3826
    3927static void printPreds(unsigned int leash) {
     
    4432        return;
    4533    }
    46     SNAP
     34    int userValue = bobs_getCurrent();
    4735    bobs_movePrev();
    4836    printPreds(leash - 1);
    49     SHOW("", "")
     37    printf(" %d", userValue);
    5038}
    5139static void printSuccs(unsigned int leash) {
     
    5644        return;
    5745    }
    58     SNAP
    59     SHOW("", "")
     46    int userValue = bobs_getCurrent();
     47    printf(" %d", userValue);
    6048    bobs_moveNext();
    6149    printSuccs(leash - 1);
     
    7159
    7260    bobs_seek(here);
    73     SNAP
    74     SHOW("<", ">")
     61    int userValue = bobs_getCurrent();
     62    printf(" <%d>", userValue);
    7563
    7664    bobs_moveNext();
  • doc/theses/mike_brooks_MMath/benchmarks/list/observation.h

    r6e1e2d0 ra50fdfb  
    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     void * bobs_getCurrentLoc();
    15     int    bobs_getCurrentVal();
     10    void bobs_seek(unsigned int);
     11    void bobs_moveNext();
     12    void bobs_movePrev();
     13    int  bobs_hasCurrent();
     14    int  bobs_getCurrent();
    1615
    1716    extern volatile size_t       bobs_ops_completed;
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-insfirst-allhead.h

    r6e1e2d0 ra50fdfb  
    33// allhead:  inserts and removes happen via the api-provided "last"/"tail"/"back"/"first"/"tail"/"front"
    44
    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)
     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)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-insfirst-inselem.h

    r6e1e2d0 ra50fdfb  
    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, iters, insNo, item)    BFX_INSERT_FIRST(B_UserItem, lst, (item))
     5#define BOP_INIT(lst, ui, iters, i) BFX_INSERT_FIRST(B_UserItem, lst, ui[i])
    66
    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)
     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)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-insfirst-remelem.h

    r6e1e2d0 ra50fdfb  
    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, iters, remNo)      BFX_REMOVE_LAST(B_UserItem, lst)
     5#define BOP_TEARDOWN(lst, ui, iters, i) BFX_REMOVE_LAST(B_UserItem, lst)
    66
    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)])
     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])
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-inslast-allhead.h

    r6e1e2d0 ra50fdfb  
    33// allhead:  inserts and removes happen via the api-provided "last"/"tail"/"back"/"first"/"tail"/"front"
    44
    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)
     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)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-inslast-inselem.h

    r6e1e2d0 ra50fdfb  
    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, iters, insNo, item)    BFX_INSERT_LAST(B_UserItem, lst, (item))
     5#define BOP_INIT(lst, ui, iters, i) BFX_INSERT_LAST(B_UserItem, lst, ui[i])
    66
    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)
     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)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-queue-inslast-remelem.h

    r6e1e2d0 ra50fdfb  
    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, iters, remNo)    BFX_REMOVE_FIRST(B_UserItem, lst)
     5#define BOP_TEARDOWN(lst, ui, iters, i) BFX_REMOVE_FIRST(B_UserItem, lst)
    66
    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)])
     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])
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-insfirst-allhead.h

    r6e1e2d0 ra50fdfb  
    33// allhead:  inserts and removes happen via the api-provided "first"/"head"/"front"
    44
    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)
     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)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-insfirst-inselem.h

    r6e1e2d0 ra50fdfb  
    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, iters, insNo, item)  BFX_INSERT_FIRST(B_UserItem, lst, (item))
     5#define BOP_INIT(lst, ui, iters, i) BFX_INSERT_FIRST(B_UserItem, lst, ui[i])
    66
    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)
     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)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-insfirst-remelem.h

    r6e1e2d0 ra50fdfb  
    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, iters, remNo)      BFX_REMOVE_FIRST(B_UserItem, lst)
     5#define BOP_TEARDOWN(lst, ui, iters, i) BFX_REMOVE_FIRST(B_UserItem, lst)
    66
    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])
     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])
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-inslast-allhead.h

    r6e1e2d0 ra50fdfb  
    33// allhead:  inserts and removes happen via the api-provided "last"/"tail"/"back"
    44
    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)
     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)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-inslast-inselem.h

    r6e1e2d0 ra50fdfb  
    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, iters, insNo, item)   BFX_INSERT_LAST(B_UserItem, lst, (item))
     5#define BOP_INIT(lst, ui, iters, i) BFX_INSERT_LAST(B_UserItem, lst, ui[i])
    66
    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)
     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)
  • doc/theses/mike_brooks_MMath/benchmarks/list/op-stack-inslast-remelem.h

    r6e1e2d0 ra50fdfb  
    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, iters, remNo)      BFX_REMOVE_LAST(B_UserItem, lst)
     5#define BOP_TEARDOWN(lst, ui, iters, i) BFX_REMOVE_LAST(B_UserItem, lst)
    66
    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])
     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])
  • doc/theses/mike_brooks_MMath/benchmarks/list/results-baseline.csv

    r6e1e2d0 ra50fdfb  
    1 2023-04-06 22:38:43,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-inslast-inselem,159326200,5.104060,32.035284
    2 2023-04-06 22:38:48,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-remelem,224000000,5.117349,22.845308
    3 2023-04-06 22:38:54,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-inslast-allhead,224000000,5.062724,22.601446
    4 2023-04-06 22:38:59,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-allhead,166568300,5.161427,30.986850
    5 2023-04-06 22:39:04,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-remelem,169890000,5.005365,29.462387
    6 2023-04-06 22:39:09,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-inslast-inselem,444950000,5.003260,11.244544
    7 2023-04-06 22:39:14,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-insfirst-inselem,289632000,5.002701,17.272611
    8 2023-04-06 22:39:19,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-inslast-allhead,343938000,5.050625,14.684696
    9 2023-04-06 22:39:24,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-inselem,546700000,5.031248,9.202941
    10 2023-04-06 22:39:29,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-inslast-allhead,177980000,5.214033,29.295612
    11 2023-04-06 22:39:34,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-inslast-remelem,678825000,5.007971,7.377411
    12 2023-04-06 22:39:39,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-inslast-remelem,177500000,5.051343,28.458270
    13 2023-04-06 22:39:44,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-inslast-inselem,617700000,5.012318,8.114486
    14 2023-04-06 22:39:49,2,5 1000000 7 -1 2  ,./perfexp--lq-list--stack-insfirst-inselem,581000000,5.034526,8.665277
    15 2023-04-06 22:39:54,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-insfirst-remelem,1309000000,5.007982,3.825807
    16 2023-04-06 22:39:59,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-inslast-remelem,809400000,5.034582,6.220141
    17 2023-04-06 22:40:04,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-inslast-allhead,352989000,5.080867,14.393839
    18 2023-04-06 22:40:10,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-inslast-inselem,159326200,5.152641,32.340199
    19 2023-04-06 22:40:15,4,5 100 72421 -1 4  ,./perfexp--lq-list--stack-insfirst-remelem,333136600,5.081694,15.254085
    20 2023-04-06 22:40:20,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-inslast-allhead,672000000,5.041239,7.501844
    21 2023-04-06 22:40:25,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-remelem,159326200,5.216693,32.742217
    22 2023-04-06 22:40:30,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-inslast-inselem,908800000,5.036669,5.542109
    23 2023-04-06 22:40:35,1,5 100 72421 -1 1  ,./perfexp--lq-list--stack-insfirst-inselem,166568300,5.225242,31.369967
    24 2023-04-06 22:40:41,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-inslast-allhead,137599900,5.143664,37.381306
    25 2023-04-06 22:40:46,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-inslast-inselem,159326200,5.104856,32.040280
    26 2023-04-06 22:40:51,5,5 1000000 7 -1 5  ,./perfexp--lq-list--stack-insfirst-allhead,917000000,5.030506,5.485830
    27 2023-04-06 22:40:56,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-insfirst-remelem,296926100,5.105027,17.192921
    28 2023-04-06 22:41:01,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-allhead,137599900,5.150764,37.432905
    29 2023-04-06 22:41:06,1,5 100 72421 -1 1  ,./perfexp--lq-list--stack-insfirst-allhead,166568300,5.054932,30.347503
    30 2023-04-06 22:41:11,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-insfirst-inselem,130357800,5.100502,39.126941
    31 2023-04-06 22:41:16,3,5 1000 9051 -1 3  ,./perfexp--lq-list--stack-insfirst-inselem,325836000,5.113777,15.694328
    32 2023-04-06 22:41:22,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-remelem,169890000,5.046006,29.701607
    33 2023-04-06 22:41:27,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-insfirst-inselem,477310000,5.055761,10.592196
    34 2023-04-06 22:41:32,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-remelem,588315000,5.001890,8.502061
    35 2023-04-06 22:41:37,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-inselem,651000000,5.008924,7.694200
    36 2023-04-06 22:41:42,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-insfirst-remelem,590570000,5.038027,8.530787
    37 2023-04-06 22:41:47,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-inslast-remelem,153867000,5.210496,33.863635
    38 2023-04-06 22:41:52,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-insfirst-remelem,859100000,5.034777,5.860525
    39 2023-04-06 22:41:57,3,5 10000 809 -1 3  ,./perfexp--lq-list--stack-insfirst-remelem,590570000,5.065984,8.578126
    40 2023-04-06 22:42:02,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-inslast-inselem,493490000,5.014299,10.160893
    41 2023-04-06 22:42:07,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-allhead,184600000,5.079109,27.514133
    42 2023-04-06 22:42:12,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-inselem,231000000,5.041959,21.826662
    43 2023-04-06 22:42:17,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-inslast-allhead,162918000,5.108416,31.355750
    44 2023-04-06 22:42:22,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-insfirst-remelem,260715600,5.113112,19.611838
    45 2023-04-06 22:42:27,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-inslast-inselem,833000000,5.028245,6.036309
    46 2023-04-06 22:42:33,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-inslast-inselem,352989000,5.105392,14.463318
    47 2023-04-06 22:42:38,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-inslast-allhead,334887000,5.039581,15.048601
    48 2023-04-06 22:42:43,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-insfirst-remelem,763000000,5.016755,6.575039
    49 2023-04-06 22:42:48,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-inslast-allhead,159326200,5.111182,32.079984
    50 2023-04-06 22:42:53,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-inslast-remelem,979800000,5.002241,5.105369
    51 2023-04-06 22:42:58,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-inslast-inselem,316785000,5.008967,15.811882
    52 2023-04-06 22:43:03,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-insfirst-remelem,1316000000,5.025586,3.818834
    53 2023-04-06 22:43:08,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-inslast-allhead,959000000,5.008021,5.222128
    54 2023-04-06 22:43:13,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-insfirst-remelem,461601000,5.006449,10.845837
    55 2023-04-06 22:43:18,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-inslast-inselem,658000000,5.029688,7.643903
    56 2023-04-06 22:43:23,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-inslast-inselem,658000000,5.022354,7.632757
    57 2023-04-06 22:43:28,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-inslast-remelem,347620800,5.032410,14.476723
    58 2023-04-06 22:43:33,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-insfirst-allhead,159326200,5.154973,32.354836
    59 2023-04-06 22:43:38,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-remelem,169890000,5.130552,30.199258
    60 2023-04-06 22:43:43,4,5 1000 9051 -1 4  ,./perfexp--lq-list--stack-insfirst-remelem,543060000,5.083894,9.361570
    61 2023-04-06 22:43:49,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-inslast-remelem,169890000,5.059665,29.782006
    62 2023-04-06 22:43:54,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-insfirst-allhead,910000000,5.002806,5.497589
    63 2023-04-06 22:43:59,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-inslast-remelem,575100000,5.010242,8.711949
    64 2023-04-06 22:44:04,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-insfirst-allhead,728000000,5.022596,6.899170
    65 2023-04-06 22:44:09,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-inslast-remelem,169890000,5.191497,30.557990
    66 2023-04-06 22:44:14,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-inslast-allhead,639000000,5.034492,7.878704
    67 2023-04-06 22:44:19,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-inslast-remelem,311410300,5.098903,16.373585
    68 2023-04-06 22:44:24,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-insfirst-allhead,325836000,5.135714,15.761653
    69 2023-04-06 22:44:29,4,5 1000000 7 -1 4  ,./perfexp--lq-list--stack-insfirst-inselem,581000000,5.051661,8.694769
    70 2023-04-06 22:44:34,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-insfirst-inselem,679000000,5.043664,7.428077
    71 2023-04-06 22:44:39,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-insfirst-inselem,130357800,5.100746,39.128813
    72 2023-04-06 22:44:45,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-inselem,137599900,5.151609,37.439046
    73 2023-04-06 22:44:50,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-inslast-allhead,672000000,5.022206,7.473521
    74 2023-04-06 22:44:55,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-inselem,343938000,5.113961,14.868846
    75 2023-04-06 22:45:00,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-inslast-inselem,343938000,5.132823,14.923687
    76 2023-04-06 22:45:05,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-inslast-allhead,352989000,5.051277,14.310012
    77 2023-04-06 22:45:10,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-inslast-inselem,343938000,5.079431,14.768450
    78 2023-04-06 22:45:15,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-inslast-remelem,795200000,5.027511,6.322323
    79 2023-04-06 22:45:20,2,5 1000 9051 -1 2  ,./perfexp--lq-list--stack-insfirst-inselem,325836000,5.097880,15.645539
    80 2023-04-06 22:45:25,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-inslast-allhead,325836000,5.039459,15.466244
    81 2023-04-06 22:45:30,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-inslast-inselem,444950000,5.059145,11.370143
    82 2023-04-06 22:45:36,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-inslast-inselem,444950000,5.072116,11.399294
    83 2023-04-06 22:45:41,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-allhead,159326200,5.099274,32.005245
    84 2023-04-06 22:45:46,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-insfirst-allhead,788100000,5.037081,6.391424
    85 2023-04-06 22:45:51,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-inslast-allhead,1036600000,5.028854,4.851297
    86 2023-04-06 22:45:56,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-inslast-allhead,493490000,5.043056,10.219166
    87 2023-04-06 22:46:01,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-remelem,169890000,5.165830,30.406910
    88 2023-04-06 22:46:06,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-inslast-remelem,777000000,5.026590,6.469228
    89 2023-04-06 22:46:11,1,5 10000 809 -1 1  ,./perfexp--lq-list--stack-insfirst-inselem,453040000,5.042693,11.130790
    90 2023-04-06 22:46:16,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-inslast-inselem,159326200,5.021468,31.516901
    91 2023-04-06 22:46:21,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-insfirst-allhead,444950000,5.058905,11.369603
    92 2023-04-06 22:46:26,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-inselem,159326200,5.124781,32.165338
    93 2023-04-06 22:46:31,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-inslast-allhead,184600000,5.086561,27.554502
    94 2023-04-06 22:46:37,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-inselem,159326200,5.101698,32.020459
    95 2023-04-06 22:46:42,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-inslast-remelem,777000000,5.024963,6.467134
    96 2023-04-06 22:46:47,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-inslast-inselem,901700000,5.038805,5.588117
    97 2023-04-06 22:46:52,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-insfirst-allhead,325836000,5.086643,15.611053
    98 2023-04-06 22:46:57,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-remelem,917000000,5.029273,5.484485
    99 2023-04-06 22:47:02,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-inslast-inselem,159326200,5.146099,32.299138
    100 2023-04-06 22:47:07,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-inslast-allhead,646100000,5.036416,7.795103
    101 2023-04-06 22:47:12,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-remelem,318652400,5.011899,15.728421
    102 2023-04-06 22:47:17,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-remelem,579264000,5.006702,8.643213
    103 2023-04-06 22:47:22,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-inselem,477310000,5.036310,10.551445
    104 2023-04-06 22:47:27,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-inslast-allhead,159326200,5.051290,31.704076
    105 2023-04-06 22:47:32,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-inslast-allhead,509670000,5.059480,9.926972
    106 2023-04-06 22:47:37,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-inslast-remelem,534009000,5.021579,9.403548
    107 2023-04-06 22:47:42,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-inselem,665000000,5.028019,7.560931
    108 2023-04-06 22:47:47,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-inslast-remelem,177500000,5.011349,28.232952
    109 2023-04-06 22:47:52,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-inslast-remelem,1242500000,5.025123,4.044365
    110 2023-04-06 22:47:57,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-inslast-allhead,325836000,5.033694,15.448551
    111 2023-04-06 22:48:02,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-insfirst-allhead,525850000,5.074913,9.650876
    112 2023-04-06 22:48:08,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-inslast-remelem,311410300,5.100754,16.379529
    113 2023-04-06 22:48:13,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-insfirst-remelem,296926100,5.107471,17.201152
    114 2023-04-06 22:48:18,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-allhead,334887000,5.049385,15.077877
    115 2023-04-06 22:48:23,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-inslast-remelem,665000000,5.048229,7.591322
    116 2023-04-06 22:48:28,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-inslast-inselem,159326200,5.039389,31.629380
    117 2023-04-06 22:48:33,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-insfirst-remelem,267957700,5.032279,18.780125
    118 2023-04-06 22:48:38,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-inselem,658000000,5.048589,7.672628
    119 2023-04-06 22:48:43,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-inslast-remelem,224000000,5.116992,22.843714
    120 2023-04-06 22:48:48,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-insfirst-allhead,352989000,5.129190,14.530736
    121 2023-04-06 22:48:53,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-inslast-remelem,224000000,5.044124,22.518411
    122 2023-04-06 22:48:58,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-inslast-allhead,159326200,5.085806,31.920714
    123 2023-04-06 22:49:04,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-inslast-remelem,574390000,5.067621,8.822614
    124 2023-04-06 22:49:09,2,5 100 72421 -1 2  ,./perfexp--lq-list--stack-insfirst-inselem,159326200,5.003104,31.401640
    125 2023-04-06 22:49:14,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-insfirst-inselem,307734000,5.021786,16.318593
    126 2023-04-06 22:49:19,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-insfirst-inselem,973000000,5.029223,5.168780
    127 2023-04-06 22:49:24,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-insfirst-inselem,646100000,5.013377,7.759444
    128 2023-04-06 22:49:29,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-inslast-inselem,224000000,5.026205,22.438415
    129 2023-04-06 22:49:34,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-allhead,162918000,5.122192,31.440307
    130 2023-04-06 22:49:39,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-inselem,217000000,5.012642,23.099733
    131 2023-04-06 22:49:44,1,5 1000 9051 -1 1  ,./perfexp--lq-list--stack-insfirst-remelem,534009000,5.010162,9.382168
    132 2023-04-06 22:49:49,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-inselem,665000000,5.025341,7.556904
    133 2023-04-06 22:49:54,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-inslast-inselem,162918000,5.112699,31.382039
    134 2023-04-06 22:49:59,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-inslast-remelem,289684000,5.092223,17.578544
    135 2023-04-06 22:50:04,1,5 10000 809 -1 1  ,./perfexp--lq-list--stack-insfirst-allhead,509670000,5.018786,9.847129
    136 2023-04-06 22:50:09,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-insfirst-inselem,679000000,5.046907,7.432853
    137 2023-04-06 22:50:14,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-inslast-allhead,763000000,5.000173,6.553307
    138 2023-04-06 22:50:19,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-insfirst-allhead,509670000,5.001591,9.813391
    139 2023-04-06 22:50:24,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-insfirst-remelem,260715600,5.115727,19.621868
    140 2023-04-06 22:50:30,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-insfirst-inselem,325836000,5.102080,15.658429
    141 2023-04-06 22:50:35,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-inslast-remelem,171969000,5.259251,30.582553
    142 2023-04-06 22:50:40,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-inslast-allhead,159326200,5.062565,31.774843
    143 2023-04-06 22:50:45,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-inslast-remelem,687876000,5.057051,7.351690
    144 2023-04-06 22:50:50,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-inselem,159326200,5.115809,32.109025
    145 2023-04-06 22:50:55,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-inslast-remelem,973000000,5.015677,5.154858
    146 2023-04-06 22:51:00,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-inslast-remelem,260715600,5.002998,19.189485
    147 2023-04-06 22:51:05,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-insfirst-allhead,343938000,5.009464,14.565020
    148 2023-04-06 22:51:10,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-inslast-allhead,159326200,5.001947,31.394378
    149 2023-04-06 22:51:15,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-inslast-remelem,966000000,5.019736,5.196414
    150 2023-04-06 22:51:20,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-insfirst-allhead,461130000,5.067126,10.988498
    151 2023-04-06 22:51:25,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-inslast-inselem,169890000,5.037162,29.649550
    152 2023-04-06 22:51:31,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-inslast-remelem,679560000,5.044672,7.423439
    153 2023-04-06 22:51:36,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-remelem,153867000,5.093303,33.101984
    154 2023-04-06 22:51:41,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-inslast-remelem,570213000,5.076763,8.903275
    155 2023-04-06 22:51:46,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-insfirst-allhead,781000000,5.034261,6.445917
    156 2023-04-06 22:51:51,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-insfirst-allhead,352989000,5.119857,14.504296
    157 2023-04-06 22:51:56,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-inslast-inselem,568000000,5.020960,8.839718
    158 2023-04-06 22:52:01,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-insfirst-inselem,679000000,5.020031,7.393271
    159 2023-04-06 22:52:06,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-inslast-inselem,477310000,5.065549,10.612702
    160 2023-04-06 22:52:11,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-inslast-allhead,334887000,5.061093,15.112838
    161 2023-04-06 22:52:16,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-remelem,171969000,5.199554,30.235415
    162 2023-04-06 22:52:21,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-insfirst-remelem,791000000,5.030514,6.359689
    163 2023-04-06 22:52:26,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-insfirst-inselem,660300000,5.021934,7.605534
    164 2023-04-06 22:52:31,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-inslast-inselem,224000000,5.069797,22.633022
    165 2023-04-06 22:52:37,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-insfirst-inselem,766800000,5.034758,6.565934
    166 2023-04-06 22:52:42,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-insfirst-inselem,738400000,5.004336,6.777270
    167 2023-04-06 22:52:47,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-inselem,665000000,5.024545,7.555707
    168 2023-04-06 22:52:52,1,5 1000 9051 -1 1  ,./perfexp--lq-list--stack-insfirst-allhead,343938000,5.070304,14.741913
    169 2023-04-06 22:52:57,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-insfirst-remelem,688700000,5.007406,7.270809
    170 2023-04-06 22:53:02,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-allhead,184600000,5.064279,27.433797
    171 2023-04-06 22:53:07,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-inslast-allhead,1078000000,5.011355,4.648752
    172 2023-04-06 22:53:12,4,5 100000 71 -1 4  ,./perfexp--lq-list--stack-insfirst-allhead,809400000,5.030850,6.215530
    173 2023-04-06 22:53:17,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-allhead,184600000,5.121858,27.745710
    174 2023-04-06 22:53:22,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-inslast-allhead,177980000,5.177338,29.089437
    175 2023-04-06 22:53:27,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-insfirst-inselem,298683000,5.103575,17.086928
    176 2023-04-06 22:53:32,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-inslast-remelem,959000000,5.004941,5.218917
    177 2023-04-06 22:53:37,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-inslast-inselem,453040000,5.084873,11.223894
    178 2023-04-06 22:53:43,4,5 1000000 7 -1 4  ,./perfexp--lq-list--stack-insfirst-allhead,917000000,5.007210,5.460425
    179 2023-04-06 22:53:48,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-allhead,485400000,5.073608,10.452427
    180 2023-04-06 22:53:53,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-inslast-allhead,334887000,5.007885,14.953955
    181 2023-04-06 22:53:58,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-allhead,137599900,5.149462,37.423443
    182 2023-04-06 22:54:03,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-inslast-inselem,137599900,5.086708,36.967382
    183 2023-04-06 22:54:08,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-inselem,343938000,5.092902,14.807616
    184 2023-04-06 22:54:13,5,5 100000 71 -1 5  ,./perfexp--lq-list--stack-insfirst-remelem,688700000,5.002389,7.263524
    185 2023-04-06 22:54:18,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-inslast-allhead,137599900,5.146658,37.403065
    186 2023-04-06 22:54:23,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-inslast-remelem,597366000,5.073255,8.492708
    187 2023-04-06 22:54:28,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-insfirst-remelem,759700000,5.005199,6.588389
    188 2023-04-06 22:54:33,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-inslast-remelem,347620800,5.035473,14.485534
    189 2023-04-06 22:54:38,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-remelem,908800000,5.019250,5.522942
    190 2023-04-06 22:54:43,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-allhead,159326200,5.030282,31.572221
    191 2023-04-06 22:54:48,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-allhead,177980000,5.213425,29.292196
    192 2023-04-06 22:54:54,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-inslast-allhead,469220000,5.071355,10.808054
    193 2023-04-06 22:54:59,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-insfirst-remelem,688700000,5.012374,7.278022
    194 2023-04-06 22:55:04,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-remelem,720010000,5.044350,7.005944
    195 2023-04-06 22:55:09,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-inslast-allhead,624800000,5.034208,8.057311
    196 2023-04-06 22:55:14,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-insfirst-remelem,260715600,5.109722,19.598835
    197 2023-04-06 22:55:19,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-inslast-inselem,658000000,5.025521,7.637570
    198 2023-04-06 22:55:24,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-inslast-remelem,588315000,5.043017,8.571967
    199 2023-04-06 22:55:29,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-insfirst-inselem,159326200,5.003525,31.404283
    200 2023-04-06 22:55:34,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-remelem,318652400,5.010231,15.723186
    201 2023-04-06 22:55:39,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-inselem,137599900,5.150708,37.432498
    202 2023-04-06 22:55:44,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-insfirst-inselem,595000000,5.044665,8.478429
    203 2023-04-06 22:55:49,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-inslast-remelem,159326200,5.209063,32.694328
    204 2023-04-06 22:55:55,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-inslast-allhead,509670000,5.053284,9.914815
    205 2023-04-06 22:56:00,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-insfirst-allhead,795200000,5.012552,6.303511
    206 2023-04-06 22:56:05,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-insfirst-allhead,766800000,5.033161,6.563851
    207 2023-04-06 22:56:10,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-allhead,159326200,5.121738,32.146238
    208 2023-04-06 22:56:15,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-inslast-allhead,334887000,5.028414,15.015256
    209 2023-04-06 22:56:20,5,5 1000 9051 -1 5  ,./perfexp--lq-list--stack-insfirst-inselem,325836000,5.124252,15.726476
    210 2023-04-06 22:56:25,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-inslast-inselem,177980000,5.172291,29.061080
    211 2023-04-06 22:56:30,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-remelem,830700000,5.042470,6.070146
    212 2023-04-06 22:56:35,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-insfirst-remelem,847000000,5.032186,5.941188
    213 2023-04-06 22:56:40,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-inslast-remelem,639000000,5.002609,7.828809
    214 2023-04-06 22:56:45,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-inslast-remelem,770000000,5.038757,6.543840
    215 2023-04-06 22:56:50,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-allhead,231000000,5.137935,22.242143
    216 2023-04-06 22:56:56,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-inslast-allhead,224000000,5.091507,22.729942
    217 2023-04-06 22:57:01,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-insfirst-inselem,412590000,5.037820,12.210233
    218 2023-04-06 22:57:06,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-remelem,231000000,5.102198,22.087437
    219 2023-04-06 22:57:11,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-inslast-allhead,171969000,5.164593,30.032116
    220 2023-04-06 22:57:16,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-inslast-remelem,169890000,5.225116,30.755877
    221 2023-04-06 22:57:21,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-insfirst-allhead,316785000,5.093369,16.078315
    222 2023-04-06 22:57:26,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-inslast-inselem,603500000,5.049990,8.367838
    223 2023-04-06 22:57:31,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-inslast-allhead,166568300,5.220664,31.342482
    224 2023-04-06 22:57:37,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-inslast-inselem,568000000,5.010944,8.822085
    225 2023-04-06 22:57:42,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-inslast-allhead,144842000,5.227036,36.087847
    226 2023-04-06 22:57:47,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-remelem,159326200,5.217508,32.747332
    227 2023-04-06 22:57:52,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-allhead,137599900,5.146662,37.403094
    228 2023-04-06 22:57:57,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-insfirst-remelem,667400000,5.038476,7.549410
    229 2023-04-06 22:58:02,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-inslast-allhead,159326200,5.013988,31.469953
    230 2023-04-06 22:58:07,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-remelem,1008000000,5.010780,4.971012
    231 2023-04-06 22:58:12,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-inslast-remelem,1421000000,5.023422,3.535132
    232 2023-04-06 22:58:17,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-insfirst-inselem,553800000,5.060584,9.137927
    233 2023-04-06 22:58:23,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-insfirst-inselem,595000000,5.047132,8.482575
    234 2023-04-06 22:58:28,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-inslast-remelem,588315000,5.032246,8.553659
    235 2023-04-06 22:58:33,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-insfirst-allhead,724200000,5.020706,6.932762
    236 2023-04-06 22:58:38,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-inslast-inselem,334887000,5.003484,14.940813
    237 2023-04-06 22:58:43,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-insfirst-allhead,840000000,5.042287,6.002723
    238 2023-04-06 22:58:48,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-inslast-remelem,224000000,5.088342,22.715813
    239 2023-04-06 22:58:53,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-inslast-inselem,169890000,5.058348,29.774254
    240 2023-04-06 22:58:58,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-inslast-allhead,695800000,5.026595,7.224195
    241 2023-04-06 22:59:03,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-inselem,184600000,5.066927,27.448142
    242 2023-04-06 22:59:08,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-inselem,184600000,5.055439,27.385910
    243 2023-04-06 22:59:13,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-insfirst-remelem,1309000000,5.009552,3.827007
    244 2023-04-06 22:59:18,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-inselem,658000000,5.048553,7.672573
    245 2023-04-06 22:59:23,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-inslast-allhead,137599900,5.143656,37.381248
    246 2023-04-06 22:59:29,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-allhead,224000000,5.132010,22.910759
    247 2023-04-06 22:59:34,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-insfirst-remelem,695800000,5.046242,7.252432
    248 2023-04-06 22:59:39,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-insfirst-inselem,603500000,5.003978,8.291596
    249 2023-04-06 22:59:44,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-allhead,665000000,5.025093,7.556531
    250 2023-04-06 22:59:49,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-remelem,965600000,5.028275,5.207410
    251 2023-04-06 22:59:54,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-remelem,687650000,5.005714,7.279450
    252 2023-04-06 22:59:59,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-insfirst-remelem,590570000,5.031737,8.520136
    253 2023-04-06 23:00:04,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-inslast-remelem,184600000,5.160974,27.957606
    254 2023-04-06 23:00:09,5,5 100 72421 -1 5  ,./perfexp--lq-list--stack-insfirst-remelem,333136600,5.090510,15.280549
    255 2023-04-06 23:00:14,5,5 100 72421 -1 5  ,./perfexp--lq-list--stack-insfirst-inselem,159326200,5.004048,31.407565
    256 2023-04-06 23:00:19,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-insfirst-allhead,444950000,5.073828,11.403142
    257 2023-04-06 23:00:24,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-inslast-allhead,224000000,5.001734,22.329170
    258 2023-04-06 23:00:29,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-inslast-allhead,477310000,5.050386,10.580935
    259 2023-04-06 23:00:34,4,5 1000 9051 -1 4  ,./perfexp--lq-list--stack-insfirst-allhead,343938000,5.050309,14.683777
    260 2023-04-06 23:00:40,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-insfirst-allhead,444950000,5.017058,11.275555
    261 2023-04-06 23:00:45,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-remelem,994000000,5.019649,5.049949
    262 2023-04-06 23:00:50,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-inslast-remelem,153867000,5.201021,33.802056
    263 2023-04-06 23:00:55,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-remelem,1001000000,5.015588,5.010577
    264 2023-04-06 23:01:00,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-remelem,161800000,5.005496,30.936316
    265 2023-04-06 23:01:05,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-inslast-allhead,665000000,5.035214,7.571750
    266 2023-04-06 23:01:10,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-inslast-allhead,159326200,5.109530,32.069616
    267 2023-04-06 23:01:15,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-allhead,169890000,5.100783,30.024033
    268 2023-04-06 23:01:20,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-insfirst-remelem,639000000,5.014872,7.848000
    269 2023-04-06 23:01:25,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-inslast-inselem,169890000,5.046345,29.703602
    270 2023-04-06 23:01:30,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-insfirst-allhead,896000000,5.013958,5.595935
    271 2023-04-06 23:01:35,1,5 1000000 7 -1 1  ,./perfexp--lq-list--stack-insfirst-inselem,581000000,5.047488,8.687587
    272 2023-04-06 23:01:40,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-insfirst-inselem,501580000,5.002330,9.973145
    273 2023-04-06 23:01:45,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-inslast-remelem,986900000,5.036032,5.102880
    274 2023-04-06 23:01:50,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-inselem,166568300,5.162360,30.992452
    275 2023-04-06 23:01:55,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-inslast-inselem,325836000,5.137919,15.768420
    276 2023-04-06 23:02:01,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-insfirst-remelem,710000000,5.019927,7.070320
    277 2023-04-06 23:02:06,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-inslast-allhead,334887000,5.098791,15.225407
    278 2023-04-06 23:02:11,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-insfirst-allhead,651000000,5.049504,7.756535
    279 2023-04-06 23:02:16,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-insfirst-remelem,515907000,5.019478,9.729424
    280 2023-04-06 23:02:21,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-insfirst-allhead,325836000,5.095609,15.638570
    281 2023-04-06 23:02:26,5,5 1000000 7 -1 5  ,./perfexp--lq-list--stack-insfirst-inselem,581000000,5.050648,8.693026
    282 2023-04-06 23:02:31,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-insfirst-remelem,534009000,5.012189,9.385964
    283 2023-04-06 23:02:36,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-inselem,343938000,5.100634,14.830097
    284 2023-04-06 23:02:41,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-allhead,177980000,5.039308,28.313900
    285 2023-04-06 23:02:46,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-insfirst-inselem,412590000,5.053218,12.247553
    286 2023-04-06 23:02:51,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-inselem,162918000,5.104631,31.332517
    287 2023-04-06 23:02:56,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-allhead,166568300,5.127294,30.781931
    288 2023-04-06 23:03:02,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-inslast-inselem,137599900,5.086178,36.963530
    289 2023-04-06 23:03:07,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-inslast-inselem,177500000,5.030765,28.342338
    290 2023-04-06 23:03:12,4,5 1000000 7 -1 4  ,./perfexp--lq-list--stack-insfirst-remelem,798000000,5.017055,6.287036
    291 2023-04-06 23:03:17,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-insfirst-inselem,660300000,5.001824,7.575078
    292 2023-04-06 23:03:22,4,5 10000 809 -1 4  ,./perfexp--lq-list--stack-insfirst-inselem,436860000,5.056530,11.574715
    293 2023-04-06 23:03:27,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-allhead,665000000,5.023530,7.554180
    294 2023-04-06 23:03:32,1,5 100000 71 -1 1  ,./perfexp--lq-list--stack-insfirst-inselem,553800000,5.027487,9.078164
    295 2023-04-06 23:03:37,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-inslast-allhead,672000000,5.030612,7.486030
    296 2023-04-06 23:03:42,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-insfirst-allhead,672000000,5.043560,7.505298
    297 2023-04-06 23:03:47,2,5 100 72421 -1 2  ,./perfexp--lq-list--stack-insfirst-remelem,333136600,5.084613,15.262847
    298 2023-04-06 23:03:52,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-inslast-allhead,738400000,5.043688,6.830563
    299 2023-04-06 23:03:57,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-inslast-remelem,171969000,5.223951,30.377283
    300 2023-04-06 23:04:02,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-inselem,162918000,5.126779,31.468463
    301 2023-04-06 23:04:08,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-inslast-remelem,1421000000,5.023912,3.535476
    302 2023-04-06 23:04:13,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-inslast-allhead,658000000,5.020341,7.629698
    303 2023-04-06 23:04:18,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-insfirst-remelem,461601000,5.016184,10.866926
    304 2023-04-06 23:04:23,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-inslast-allhead,177980000,5.210149,29.273789
    305 2023-04-06 23:04:28,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-insfirst-inselem,159326200,5.202610,32.653826
    306 2023-04-06 23:04:33,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-inslast-remelem,966000000,5.014821,5.191326
    307 2023-04-06 23:04:38,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-inslast-remelem,728100000,5.003623,6.872165
    308 2023-04-06 23:04:43,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-inslast-allhead,184600000,5.136308,27.823987
    309 2023-04-06 23:04:48,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-allhead,477310000,5.001601,10.478727
    310 2023-04-06 23:04:53,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-inslast-allhead,568000000,5.029274,8.854356
    311 2023-04-06 23:04:58,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-insfirst-remelem,590570000,5.018292,8.497370
    312 2023-04-06 23:05:03,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-allhead,653200000,5.021467,7.687488
    313 2023-04-06 23:05:08,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-inslast-inselem,137599900,5.250703,38.159207
    314 2023-04-06 23:05:14,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-inslast-allhead,745500000,5.019787,6.733450
    315 2023-04-06 23:05:19,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-insfirst-inselem,412590000,5.039837,12.215122
    316 2023-04-06 23:05:24,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-inslast-inselem,724200000,5.013341,6.922592
    317 2023-04-06 23:05:29,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-inslast-allhead,603500000,5.026221,8.328452
    318 2023-04-06 23:05:34,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-remelem,169890000,5.049109,29.719872
    319 2023-04-06 23:05:39,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-inslast-remelem,679560000,5.015714,7.380826
    320 2023-04-06 23:05:44,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-insfirst-remelem,731300000,5.037151,6.887941
    321 2023-04-06 23:05:49,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-inslast-remelem,614840000,5.059492,8.228957
    322 2023-04-06 23:05:54,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-remelem,958500000,5.014201,5.231300
    323 2023-04-06 23:05:59,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-inslast-inselem,316785000,5.024996,15.862481
    324 2023-04-06 23:06:04,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-inslast-remelem,588315000,5.067089,8.612884
    325 2023-04-06 23:06:09,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-inslast-allhead,639000000,5.028277,7.868978
    326 2023-04-06 23:06:14,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-inslast-allhead,334887000,5.060557,15.111238
    327 2023-04-06 23:06:19,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-inslast-inselem,352989000,5.102670,14.455606
    328 2023-04-06 23:06:25,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-insfirst-allhead,130357800,5.098607,39.112404
    329 2023-04-06 23:06:30,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-inslast-inselem,144842000,5.151602,35.567045
    330 2023-04-06 23:06:35,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-insfirst-allhead,795200000,5.020810,6.313896
    331 2023-04-06 23:06:40,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-inslast-inselem,658000000,5.025127,7.636971
    332 2023-04-06 23:06:45,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-inslast-inselem,162918000,5.129739,31.486631
    333 2023-04-06 23:06:50,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-inslast-allhead,159326200,5.168959,32.442618
    334 2023-04-06 23:06:55,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-inslast-inselem,745500000,5.024930,6.740349
    335 2023-04-06 23:07:00,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-inslast-inselem,159326200,5.104196,32.036137
    336 2023-04-06 23:07:06,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-allhead,575100000,5.018488,8.726288
    337 2023-04-06 23:07:11,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-inselem,184600000,5.040923,27.307275
    338 2023-04-06 23:07:16,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-allhead,162918000,5.129628,31.485950
    339 2023-04-06 23:07:21,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-insfirst-allhead,653200000,5.014120,7.676240
    340 2023-04-06 23:07:26,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-insfirst-allhead,903000000,5.007293,5.545175
    341 2023-04-06 23:07:31,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-inselem,231000000,5.039397,21.815571
    342 2023-04-06 23:07:36,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-inslast-inselem,159326200,5.103728,32.033200
    343 2023-04-06 23:07:41,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-inslast-remelem,159326200,5.110623,32.076476
    344 2023-04-06 23:07:46,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-inslast-inselem,325836000,5.094063,15.633825
    345 2023-04-06 23:07:51,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-inslast-allhead,896000000,5.013412,5.595326
    346 2023-04-06 23:07:56,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-inslast-remelem,289684000,5.090448,17.572417
    347 2023-04-06 23:08:01,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-inslast-remelem,515907000,5.013509,9.717854
    348 2023-04-06 23:08:06,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-insfirst-remelem,582480000,5.028441,8.632813
    349 2023-04-06 23:08:11,5,5 100 72421 -1 5  ,./perfexp--lq-list--stack-insfirst-allhead,166568300,5.049215,30.313181
    350 2023-04-06 23:08:16,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-remelem,289684000,5.110068,17.640146
    351 2023-04-06 23:08:22,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-inselem,343938000,5.103078,14.837203
    352 2023-04-06 23:08:27,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-inselem,162918000,5.149009,31.604912
    353 2023-04-06 23:08:32,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-inslast-remelem,917000000,5.004999,5.458014
    354 2023-04-06 23:08:37,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-remelem,695740000,5.052429,7.261950
    355 2023-04-06 23:08:42,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-allhead,137599900,5.145265,37.392941
    356 2023-04-06 23:08:47,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-inselem,159326200,5.189556,32.571893
    357 2023-04-06 23:08:52,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-inslast-remelem,177500000,5.052410,28.464282
    358 2023-04-06 23:08:57,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-insfirst-allhead,533940000,5.071980,9.499157
    359 2023-04-06 23:09:03,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-allhead,665000000,5.021102,7.550529
    360 2023-04-06 23:09:08,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-insfirst-inselem,298683000,5.125385,17.159949
    361 2023-04-06 23:09:13,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-remelem,579264000,5.001932,8.634978
    362 2023-04-06 23:09:18,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-remelem,184600000,5.103404,27.645742
    363 2023-04-06 23:09:23,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-inslast-remelem,318652400,5.032572,15.793297
    364 2023-04-06 23:09:28,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-inslast-remelem,171969000,5.132165,29.843547
    365 2023-04-06 23:09:33,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-inslast-allhead,169890000,5.106152,30.055636
    366 2023-04-06 23:09:38,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-remelem,720010000,5.056537,7.022871
    367 2023-04-06 23:09:43,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-inslast-remelem,169890000,5.068533,29.834204
    368 2023-04-06 23:09:48,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-inslast-allhead,493490000,5.018832,10.170078
    369 2023-04-06 23:09:53,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-inslast-inselem,833000000,5.016267,6.021929
    370 2023-04-06 23:09:58,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-inslast-allhead,461130000,5.084745,11.026706
    371 2023-04-06 23:10:03,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-inslast-inselem,908800000,5.035999,5.541372
    372 2023-04-06 23:10:09,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-inslast-allhead,889000000,5.028819,5.656714
    373 2023-04-06 23:10:14,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-inslast-allhead,166568300,5.191809,31.169250
    374 2023-04-06 23:10:19,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-inslast-inselem,159326200,5.152530,32.339502
    375 2023-04-06 23:10:24,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-inslast-remelem,289684000,5.093276,17.582179
    376 2023-04-06 23:10:29,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-inselem,231000000,5.100410,22.079697
    377 2023-04-06 23:10:34,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-inslast-allhead,485400000,5.011748,10.324986
    378 2023-04-06 23:10:39,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-inslast-remelem,688700000,5.032312,7.306973
    379 2023-04-06 23:10:44,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-insfirst-inselem,973000000,5.027293,5.166797
    380 2023-04-06 23:10:49,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-inselem,177980000,5.048409,28.365035
    381 2023-04-06 23:10:54,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-allhead,159326200,5.095523,31.981702
    382 2023-04-06 23:11:00,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-inselem,444950000,5.015660,11.272413
    383 2023-04-06 23:11:05,3,5 1000000 7 -1 3  ,./perfexp--lq-list--stack-insfirst-allhead,924000000,5.029412,5.443087
    384 2023-04-06 23:11:10,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-inslast-allhead,343938000,5.134039,14.927222
    385 2023-04-06 23:11:15,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-insfirst-remelem,333136600,5.076445,15.238329
    386 2023-04-06 23:11:20,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-inselem,169890000,5.039287,29.662058
    387 2023-04-06 23:11:25,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-insfirst-allhead,166568300,5.122763,30.754729
    388 2023-04-06 23:11:30,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-inslast-remelem,318652400,5.029359,15.783214
    389 2023-04-06 23:11:35,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-insfirst-allhead,1022000000,5.025006,4.916836
    390 2023-04-06 23:11:40,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-inslast-inselem,461130000,5.059408,10.971761
    391 2023-04-06 23:11:45,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-allhead,159326200,5.102132,32.023183
    392 2023-04-06 23:11:50,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-remelem,728100000,5.037604,6.918835
    393 2023-04-06 23:11:56,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-inslast-allhead,334887000,5.067591,15.132242
    394 2023-04-06 23:12:01,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-inselem,159326200,5.104270,32.036602
    395 2023-04-06 23:12:06,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-inslast-inselem,184600000,5.124046,27.757562
    396 2023-04-06 23:12:11,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-inslast-allhead,1078000000,5.014921,4.652060
    397 2023-04-06 23:12:16,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-inslast-inselem,624800000,5.051553,8.085072
    398 2023-04-06 23:12:21,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-inslast-inselem,833000000,5.018805,6.024976
    399 2023-04-06 23:12:26,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-inslast-allhead,343938000,5.055123,14.697774
    400 2023-04-06 23:12:31,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-insfirst-allhead,316785000,5.093298,16.078091
    401 2023-04-06 23:12:36,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-inslast-allhead,144842000,5.158022,35.611370
    402 2023-04-06 23:12:41,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-inslast-allhead,159326200,5.152787,32.341115
    403 2023-04-06 23:12:47,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-allhead,181020000,5.246972,28.985593
    404 2023-04-06 23:12:52,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-remelem,171969000,5.244708,30.497985
    405 2023-04-06 23:12:57,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-inslast-remelem,289684000,5.088471,17.565592
    406 2023-04-06 23:13:02,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-remelem,720010000,5.055206,7.021022
    407 2023-04-06 23:13:07,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-inslast-allhead,560900000,5.032860,8.972829
    408 2023-04-06 23:13:12,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-inslast-allhead,959000000,5.008545,5.222675
    409 2023-04-06 23:13:17,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-insfirst-remelem,784000000,5.022341,6.406047
    410 2023-04-06 23:13:22,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-inslast-inselem,352989000,5.117729,14.498268
    411 2023-04-06 23:13:27,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-inslast-inselem,224000000,5.066051,22.616299
    412 2023-04-06 23:13:33,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-remelem,159326200,5.077187,31.866617
    413 2023-04-06 23:13:38,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-inslast-inselem,166568300,5.220717,31.342801
    414 2023-04-06 23:13:43,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-inslast-inselem,477310000,5.070365,10.622792
    415 2023-04-06 23:13:48,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-insfirst-remelem,1309000000,5.007603,3.825518
    416 2023-04-06 23:13:53,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-allhead,184600000,5.111904,27.691788
    417 2023-04-06 23:13:58,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-remelem,972700000,5.036058,5.177401
    418 2023-04-06 23:14:03,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-inslast-remelem,938000000,5.030859,5.363389
    419 2023-04-06 23:14:08,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-inselem,231000000,5.144215,22.269329
    420 2023-04-06 23:14:13,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-allhead,159326200,5.195831,32.611278
    421 2023-04-06 23:14:19,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-insfirst-remelem,710000000,5.050419,7.113266
    422 2023-04-06 23:14:24,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-inslast-inselem,477310000,5.056472,10.593685
    423 2023-04-06 23:14:29,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-inslast-allhead,646100000,5.033754,7.790983
    424 2023-04-06 23:14:34,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-inslast-inselem,169890000,5.007809,29.476773
    425 2023-04-06 23:14:39,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-remelem,184600000,5.140697,27.847763
    426 2023-04-06 23:14:44,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-remelem,917000000,5.012871,5.466599
    427 2023-04-06 23:14:49,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-inslast-remelem,792820000,5.025219,6.338411
    428 2023-04-06 23:14:54,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-allhead,184600000,5.077734,27.506685
    429 2023-04-06 23:14:59,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-inslast-allhead,231000000,5.142791,22.263165
    430 2023-04-06 23:15:04,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-inslast-inselem,334887000,5.004776,14.944671
    431 2023-04-06 23:15:09,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-inslast-allhead,144842000,5.161848,35.637785
    432 2023-04-06 23:15:15,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-insfirst-inselem,325836000,5.085281,15.606873
    433 2023-04-06 23:15:20,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-insfirst-inselem,581000000,5.020173,8.640573
    434 2023-04-06 23:15:25,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-inslast-inselem,710000000,5.014337,7.062446
    435 2023-04-06 23:15:30,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-allhead,177980000,5.062496,28.444185
    436 2023-04-06 23:15:35,1,5 1000000 7 -1 1  ,./perfexp--lq-list--stack-insfirst-allhead,917000000,5.004475,5.457443
    437 2023-04-06 23:15:40,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-inslast-remelem,267957700,5.136059,19.167425
    438 2023-04-06 23:15:45,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-inslast-remelem,687876000,5.053524,7.346562
    439 2023-04-06 23:15:50,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-allhead,444950000,5.008229,11.255712
    440 2023-04-06 23:15:55,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-inslast-remelem,159326200,5.159661,32.384259
    441 2023-04-06 23:16:00,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-insfirst-allhead,453040000,5.007535,11.053185
    442 2023-04-06 23:16:05,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-inselem,224000000,5.009136,22.362214
    443 2023-04-06 23:16:10,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-inslast-allhead,453040000,5.019570,11.079750
    444 2023-04-06 23:16:15,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-inslast-allhead,159326200,5.106386,32.049883
    445 2023-04-06 23:16:20,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-inslast-allhead,162918000,5.082855,31.198855
    446 2023-04-06 23:16:26,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-insfirst-remelem,944300000,5.025435,5.321863
    447 2023-04-06 23:16:31,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-insfirst-allhead,130357800,5.062806,38.837768
    448 2023-04-06 23:16:36,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-remelem,171969000,5.121176,29.779646
    449 2023-04-06 23:16:41,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-insfirst-remelem,861000000,5.036872,5.850026
    450 2023-04-06 23:16:46,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-inslast-remelem,720010000,5.033713,6.991171
    451 2023-04-06 23:16:51,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-insfirst-inselem,766800000,5.001069,6.521999
    452 2023-04-06 23:16:56,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-insfirst-allhead,159326200,5.154320,32.350737
    453 2023-04-06 23:17:01,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-inslast-inselem,610600000,5.008342,8.202329
    454 2023-04-06 23:17:06,3,5 100000 71 -1 3  ,./perfexp--lq-list--stack-insfirst-allhead,802300000,5.014286,6.249889
    455 2023-04-06 23:17:11,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-inslast-allhead,231000000,5.088531,22.028273
    456 2023-04-06 23:17:16,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-inslast-inselem,343938000,5.070875,14.743573
    457 2023-04-06 23:17:21,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-insfirst-allhead,444950000,5.042555,11.332858
    458 2023-04-06 23:17:26,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-inslast-remelem,658000000,5.001245,7.600676
    459 2023-04-06 23:17:31,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-inslast-remelem,515907000,5.021599,9.733535
    460 2023-04-06 23:17:36,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-inselem,159326200,5.186501,32.552719
    461 2023-04-06 23:17:42,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-inselem,177980000,5.026446,28.241634
    462 2023-04-06 23:17:47,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-inslast-inselem,658000000,5.016281,7.623527
    463 2023-04-06 23:17:52,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-inslast-remelem,784000000,5.003437,6.381935
    464 2023-04-06 23:17:57,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-inslast-remelem,347620800,5.029484,14.468306
    465 2023-04-06 23:18:02,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-inslast-remelem,710000000,5.007576,7.052924
    466 2023-04-06 23:18:07,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-inslast-remelem,809400000,5.015371,6.196406
    467 2023-04-06 23:18:12,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-insfirst-allhead,788100000,5.040980,6.396371
    468 2023-04-06 23:18:17,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-inslast-inselem,461130000,5.057431,10.967473
    469 2023-04-06 23:18:22,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-remelem,159326200,5.044365,31.660612
    470 2023-04-06 23:18:27,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-allhead,485400000,5.070348,10.445711
    471 2023-04-06 23:18:32,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-inslast-inselem,316785000,5.018884,15.843187
    472 2023-04-06 23:18:37,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-inselem,560900000,5.062667,9.025971
    473 2023-04-06 23:18:42,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-insfirst-inselem,412590000,5.015951,12.157229
    474 2023-04-06 23:18:47,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-insfirst-inselem,816500000,5.000448,6.124247
    475 2023-04-06 23:18:52,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-inslast-inselem,162918000,5.018924,30.806443
    476 2023-04-06 23:18:57,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-inslast-remelem,695740000,5.044067,7.249931
    477 2023-04-06 23:19:03,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-inslast-remelem,169890000,5.075488,29.875143
    478 2023-04-06 23:19:08,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-inslast-inselem,224000000,5.038191,22.491924
    479 2023-04-06 23:19:13,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-insfirst-inselem,325836000,5.103653,15.663257
    480 2023-04-06 23:19:18,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-allhead,444950000,5.010533,11.260890
    481 2023-04-06 23:19:23,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-inslast-allhead,224000000,5.004062,22.339563
    482 2023-04-06 23:19:28,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-inslast-remelem,784000000,5.030273,6.416165
    483 2023-04-06 23:19:33,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-insfirst-inselem,485400000,5.050046,10.403885
    484 2023-04-06 23:19:38,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-insfirst-inselem,617700000,5.005519,8.103479
    485 2023-04-06 23:19:43,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-insfirst-allhead,325836000,5.106682,15.672553
    486 2023-04-06 23:19:48,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-insfirst-remelem,681600000,5.046878,7.404457
    487 2023-04-06 23:19:53,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-inselem,137599900,5.148273,37.414802
    488 2023-04-06 23:19:58,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-inslast-inselem,603500000,5.030745,8.335949
    489 2023-04-06 23:20:03,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-inslast-inselem,987000000,5.001494,5.067370
    490 2023-04-06 23:20:08,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-inslast-allhead,144842000,5.159197,35.619482
    491 2023-04-06 23:20:14,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-inselem,453040000,5.069119,11.189120
    492 2023-04-06 23:20:19,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-inslast-inselem,880400000,5.006800,5.686960
    493 2023-04-06 23:20:24,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-allhead,224000000,5.105644,22.793054
    494 2023-04-06 23:20:29,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-remelem,224000000,5.045045,22.522522
    495 2023-04-06 23:20:34,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-inslast-allhead,959000000,5.008714,5.222851
    496 2023-04-06 23:20:39,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-inslast-inselem,184600000,5.185437,28.090125
    497 2023-04-06 23:20:44,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-insfirst-inselem,420680000,5.058743,12.025157
    498 2023-04-06 23:20:49,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-insfirst-remelem,260715600,5.111093,19.604094
    499 2023-04-06 23:20:54,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-insfirst-allhead,773900000,5.004333,6.466382
    500 2023-04-06 23:20:59,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-insfirst-remelem,812000000,5.021316,6.183887
    501 2023-04-06 23:21:04,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-allhead,184600000,5.041771,27.311869
    502 2023-04-06 23:21:09,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-inslast-remelem,1414000000,5.000733,3.536586
    503 2023-04-06 23:21:14,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-remelem,289684000,5.112781,17.649511
    504 2023-04-06 23:21:20,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-insfirst-inselem,539600000,5.009402,9.283547
    505 2023-04-06 23:21:25,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-inslast-inselem,325836000,5.128478,15.739446
    506 2023-04-06 23:21:30,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-insfirst-allhead,509670000,5.040138,9.889022
    507 2023-04-06 23:21:35,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-insfirst-inselem,307734000,5.031918,16.351518
    508 2023-04-06 23:21:40,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-remelem,588315000,5.069535,8.617042
    509 2023-04-06 23:21:45,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-allhead,181020000,5.196558,28.707093
    510 2023-04-06 23:21:50,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-insfirst-remelem,720010000,5.049517,7.013121
    511 2023-04-06 23:21:55,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-insfirst-inselem,631900000,5.011261,7.930465
    512 2023-04-06 23:22:00,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-inslast-inselem,137599900,5.090919,36.997985
    513 2023-04-06 23:22:05,3,5 100000 71 -1 3  ,./perfexp--lq-list--stack-insfirst-remelem,688700000,5.028916,7.302042
    514 2023-04-06 23:22:10,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-inslast-inselem,159326200,5.021214,31.515306
    515 2023-04-06 23:22:15,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-inslast-allhead,343938000,5.134953,14.929880
    516 2023-04-06 23:22:21,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-insfirst-allhead,766800000,5.010735,6.534605
    517 2023-04-06 23:22:26,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-remelem,588315000,5.005341,8.507927
    518 2023-04-06 23:22:31,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-inslast-inselem,553800000,5.022399,9.068976
    519 2023-04-06 23:22:36,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-inselem,217000000,5.090764,23.459742
    520 2023-04-06 23:22:41,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-insfirst-allhead,316785000,5.107048,16.121496
    521 2023-04-06 23:22:46,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-inselem,603500000,5.007173,8.296890
    522 2023-04-06 23:22:51,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-insfirst-remelem,534009000,5.013222,9.387898
    523 2023-04-06 23:22:56,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-inslast-inselem,617700000,5.049209,8.174209
    524 2023-04-06 23:23:01,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-inslast-inselem,159326200,5.098883,32.002791
    525 2023-04-06 23:23:06,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-inslast-allhead,224000000,5.012905,22.379040
    526 2023-04-06 23:23:11,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-inslast-inselem,693000000,5.010052,7.229512
    527 2023-04-06 23:23:16,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-inslast-inselem,343938000,5.081110,14.773331
    528 2023-04-06 23:23:21,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-insfirst-allhead,805000000,5.000210,6.211441
    529 2023-04-06 23:23:26,2,5 10000 809 -1 2  ,./perfexp--lq-list--stack-insfirst-inselem,420680000,5.069851,12.051562
    530 2023-04-06 23:23:31,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-inselem,177980000,5.051407,28.381880
    531 2023-04-06 23:23:36,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-inslast-inselem,987000000,5.007191,5.073142
    532 2023-04-06 23:23:41,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-remelem,231000000,5.081453,21.997632
    533 2023-04-06 23:23:46,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-remelem,177500000,5.017600,28.268169
    534 2023-04-06 23:23:52,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-inselem,343938000,5.100129,14.828629
    535 2023-04-06 23:23:57,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-inselem,184600000,5.151028,27.903727
    536 2023-04-06 23:24:02,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-remelem,184600000,5.128629,27.782389
    537 2023-04-06 23:24:07,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-remelem,910000000,5.002322,5.497057
    538 2023-04-06 23:24:12,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-allhead,177980000,5.196302,29.195988
    539 2023-04-06 23:24:17,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-insfirst-allhead,509670000,5.014897,9.839498
    540 2023-04-06 23:24:22,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-insfirst-remelem,260715600,5.109786,19.599080
    541 2023-04-06 23:24:27,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-inslast-inselem,159326200,5.008081,31.432878
    542 2023-04-06 23:24:32,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-inslast-inselem,325836000,5.116265,15.701964
    543 2023-04-06 23:24:37,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-inslast-remelem,570213000,5.046808,8.850742
    544 2023-04-06 23:24:43,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-inslast-allhead,137599900,5.042300,36.644649
    545 2023-04-06 23:24:48,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-allhead,665000000,5.022941,7.553295
    546 2023-04-06 23:24:53,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-remelem,153867000,5.092858,33.099092
    547 2023-04-06 23:24:58,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-insfirst-inselem,966000000,5.015365,5.191889
    548 2023-04-06 23:25:03,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-inslast-inselem,177980000,5.188118,29.150006
    549 2023-04-06 23:25:08,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-insfirst-remelem,296926100,5.109709,17.208689
    550 2023-04-06 23:25:13,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-remelem,184600000,5.118232,27.726067
    551 2023-04-06 23:25:18,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-inslast-allhead,177980000,5.168805,29.041493
    552 2023-04-06 23:25:23,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-inslast-allhead,159326200,5.074931,31.852457
    553 2023-04-06 23:25:28,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-insfirst-remelem,534009000,5.064100,9.483174
    554 2023-04-06 23:25:34,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-insfirst-allhead,130357800,5.062901,38.838497
    555 2023-04-06 23:25:39,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-inslast-inselem,184600000,5.176605,28.042281
    556 2023-04-06 23:25:44,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-inslast-inselem,137599900,5.248929,38.146314
    557 2023-04-06 23:25:49,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-inselem,184600000,5.090988,27.578483
    558 2023-04-06 23:25:54,2,5 10000 809 -1 2  ,./perfexp--lq-list--stack-insfirst-remelem,590570000,5.053093,8.556298
    559 2023-04-06 23:25:59,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-inslast-remelem,614840000,5.005980,8.141923
    560 2023-04-06 23:26:04,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-inslast-allhead,171969000,5.032441,29.263652
    561 2023-04-06 23:26:09,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-inslast-allhead,485400000,5.027026,10.356461
    562 2023-04-06 23:26:14,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-inslast-allhead,695800000,5.023256,7.219396
    563 2023-04-06 23:26:19,2,5 100000 71 -1 2  ,./perfexp--lq-list--stack-insfirst-inselem,738400000,5.023025,6.802580
    564 2023-04-06 23:26:24,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-allhead,546700000,5.016473,9.175915
    565 2023-04-06 23:26:29,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-inselem,181020000,5.192822,28.686455
    566 2023-04-06 23:26:35,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-inselem,343938000,5.093426,14.809140
    567 2023-04-06 23:26:40,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-remelem,153867000,5.079586,33.012836
    568 2023-04-06 23:26:45,5,5 10000 809 -1 5  ,./perfexp--lq-list--stack-insfirst-inselem,509670000,5.077423,9.962177
    569 2023-04-06 23:26:50,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-remelem,169890000,5.078467,29.892678
    570 2023-04-06 23:26:55,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-inslast-inselem,159326200,5.146163,32.299540
    571 2023-04-06 23:27:00,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-inslast-allhead,159326200,5.163047,32.405511
    572 2023-04-06 23:27:05,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-insfirst-inselem,568000000,5.058001,8.904931
    573 2023-04-06 23:27:11,3,5 10000 809 -1 3  ,./perfexp--lq-list--stack-insfirst-inselem,485400000,5.006967,10.315136
    574 2023-04-06 23:27:16,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-inslast-inselem,617700000,5.005977,8.104220
    575 2023-04-06 23:27:21,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-insfirst-inselem,588000000,5.020572,8.538388
    576 2023-04-06 23:27:26,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-inslast-remelem,777000000,5.025727,6.468117
    577 2023-04-06 23:27:31,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-inslast-inselem,553800000,5.014991,9.055599
    578 2023-04-06 23:27:36,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-insfirst-remelem,461601000,5.001793,10.835750
    579 2023-04-06 23:27:41,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-inslast-remelem,224000000,5.052311,22.554960
    580 2023-04-06 23:27:46,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-insfirst-inselem,412590000,5.009318,12.141152
    581 2023-04-06 23:27:51,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-inslast-allhead,781000000,5.043798,6.458128
    582 2023-04-06 23:27:56,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-remelem,703830000,5.055801,7.183270
    583 2023-04-06 23:28:01,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-remelem,184600000,5.103939,27.648640
    584 2023-04-06 23:28:06,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-insfirst-allhead,159326200,5.157636,32.371550
    585 2023-04-06 23:28:11,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-remelem,318652400,5.003554,15.702232
    586 2023-04-06 23:28:16,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-allhead,617700000,5.007486,8.106663
    587 2023-04-06 23:28:21,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-remelem,231000000,5.082904,22.003913
    588 2023-04-06 23:28:26,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-inslast-remelem,823600000,5.035229,6.113683
    589 2023-04-06 23:28:31,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-inslast-allhead,539600000,5.014691,9.293349
    590 2023-04-06 23:28:36,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-inslast-allhead,137599900,5.146557,37.402331
    591 2023-04-06 23:28:42,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-inslast-allhead,166568300,5.151938,30.929883
    592 2023-04-06 23:28:47,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-insfirst-inselem,595000000,5.045803,8.480341
    593 2023-04-06 23:28:52,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-inslast-inselem,453040000,5.084859,11.223863
    594 2023-04-06 23:28:57,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-inselem,159326200,5.191003,32.580975
    595 2023-04-06 23:29:02,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-inslast-remelem,687650000,5.026542,7.309739
    596 2023-04-06 23:29:07,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-remelem,159326200,5.092534,31.962941
    597 2023-04-06 23:29:12,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-insfirst-remelem,720010000,5.046402,7.008794
    598 2023-04-06 23:29:17,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-allhead,184600000,5.093610,27.592687
    599 2023-04-06 23:29:22,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-inslast-allhead,343938000,5.130926,14.918171
    600 2023-04-06 23:29:28,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-inslast-inselem,144842000,5.154669,35.588220
    601 2023-04-06 23:29:33,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-insfirst-allhead,781000000,5.027590,6.437375
    602 2023-04-06 23:29:38,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-inslast-allhead,469220000,5.020177,10.698983
    603 2023-04-06 23:29:43,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-inslast-allhead,672000000,5.049259,7.513778
    604 2023-04-06 23:29:48,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-inslast-remelem,590570000,5.015500,8.492643
    605 2023-04-06 23:29:53,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-inslast-remelem,515907000,5.032712,9.755076
    606 2023-04-06 23:29:58,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-inslast-inselem,325836000,5.107450,15.674910
    607 2023-04-06 23:30:03,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-inslast-remelem,800910000,5.026620,6.276136
    608 2023-04-06 23:30:08,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-inslast-remelem,347620800,5.041880,14.503965
    609 2023-04-06 23:30:13,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-allhead,231000000,5.013901,21.705199
    610 2023-04-06 23:30:18,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-inslast-remelem,171969000,5.137606,29.875187
    611 2023-04-06 23:30:23,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-inslast-allhead,770000000,5.003343,6.497848
    612 2023-04-06 23:30:28,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-allhead,166568300,5.108504,30.669125
    613 2023-04-06 23:30:34,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-inslast-allhead,184600000,5.156994,27.936046
    614 2023-04-06 23:30:39,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-insfirst-allhead,819000000,5.014858,6.123148
    615 2023-04-06 23:30:44,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-inslast-remelem,1414000000,5.003794,3.538751
    616 2023-04-06 23:30:49,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-inselem,231000000,5.035501,21.798706
    617 2023-04-06 23:30:54,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-insfirst-inselem,159326200,5.209153,32.694893
    618 2023-04-06 23:30:59,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-insfirst-inselem,477310000,5.023267,10.524118
    619 2023-04-06 23:31:04,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-insfirst-inselem,325836000,5.101399,15.656339
    620 2023-04-06 23:31:09,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-inslast-remelem,667400000,5.022926,7.526110
    621 2023-04-06 23:31:14,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-inslast-remelem,325894500,5.091748,15.623915
    622 2023-04-06 23:31:19,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-allhead,334887000,5.054765,15.093942
    623 2023-04-06 23:31:24,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-remelem,1008000000,5.001067,4.961376
    624 2023-04-06 23:31:29,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-insfirst-inselem,679000000,5.016446,7.387991
    625 2023-04-06 23:31:35,5,5 1000000 7 -1 5  ,./perfexp--lq-list--stack-insfirst-remelem,798000000,5.020158,6.290925
    626 2023-04-06 23:31:40,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-inselem,658000000,5.046821,7.669941
    627 2023-04-06 23:31:45,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-insfirst-inselem,469220000,5.064185,10.792773
    628 2023-04-06 23:31:50,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-insfirst-inselem,674500000,5.015829,7.436366
    629 2023-04-06 23:31:55,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-insfirst-remelem,639110000,5.034318,7.877076
    630 2023-04-06 23:32:00,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-inslast-remelem,570213000,5.053420,8.862337
    631 2023-04-06 23:32:05,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-inslast-allhead,171969000,5.028685,29.241811
    632 2023-04-06 23:32:10,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-inslast-remelem,224000000,5.019890,22.410223
    633 2023-04-06 23:32:15,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-insfirst-remelem,582480000,5.025035,8.626966
    634 2023-04-06 23:32:20,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-remelem,161800000,5.127857,31.692565
    635 2023-04-06 23:32:25,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-inslast-remelem,260715600,5.019198,19.251621
    636 2023-04-06 23:32:30,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-allhead,162918000,5.129510,31.485226
    637 2023-04-06 23:32:35,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-insfirst-inselem,130357800,5.149737,39.504633
    638 2023-04-06 23:32:40,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-remelem,162918000,5.005389,30.723364
    639 2023-04-06 23:32:45,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-inslast-allhead,695800000,5.049924,7.257723
    640 2023-04-06 23:32:50,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-insfirst-inselem,973000000,5.026228,5.165702
    641 2023-04-06 23:32:56,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-inslast-inselem,184600000,5.070150,27.465601
    642 2023-04-06 23:33:01,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-inslast-allhead,171969000,5.038940,29.301444
    643 2023-04-06 23:33:06,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-insfirst-allhead,352989000,5.128804,14.529643
    644 2023-04-06 23:33:11,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--stack-inslast-remelem,1313500000,5.022908,3.824064
    645 2023-04-06 23:33:16,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-inslast-inselem,224000000,5.068988,22.629411
    646 2023-04-06 23:33:21,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-insfirst-inselem,420680000,5.058039,12.023483
    647 2023-04-06 23:33:26,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-inslast-remelem,597366000,5.067353,8.482828
    648 2023-04-06 23:33:31,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-inselem,171969000,5.047845,29.353226
    649 2023-04-06 23:33:36,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-inslast-remelem,809000000,5.044723,6.235752
    650 2023-04-06 23:33:41,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-inslast-remelem,589300000,5.035557,8.544980
    651 2023-04-06 23:33:46,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-inslast-remelem,717100000,5.046045,7.036738
    652 2023-04-06 23:33:51,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-remelem,597366000,5.069419,8.486286
    653 2023-04-06 23:33:56,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-insfirst-remelem,868000000,5.025089,5.789273
    654 2023-04-06 23:34:01,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--stack-inslast-inselem,658000000,5.025487,7.637518
    655 2023-04-06 23:34:06,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-inslast-remelem,980000000,5.009915,5.112158
    656 2023-04-06 23:34:11,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-inslast-remelem,823600000,5.002809,6.074319
    657 2023-04-06 23:34:16,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-remelem,231000000,5.141988,22.259688
    658 2023-04-06 23:34:22,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-insfirst-remelem,642621000,5.057599,7.870267
    659 2023-04-06 23:34:27,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-inslast-inselem,184600000,5.153607,27.917698
    660 2023-04-06 23:34:32,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-inslast-inselem,658000000,5.017245,7.624992
    661 2023-04-06 23:34:37,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-allhead,485400000,5.077844,10.461154
    662 2023-04-06 23:34:42,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-inslast-remelem,217000000,5.099401,23.499544
    663 2023-04-06 23:34:47,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-inslast-inselem,658000000,5.013213,7.618865
    664 2023-04-06 23:34:52,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-insfirst-remelem,590570000,5.033234,8.522671
    665 2023-04-06 23:34:57,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-inslast-inselem,316785000,5.046378,15.929978
    666 2023-04-06 23:35:02,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-inslast-remelem,159326200,5.120925,32.141136
    667 2023-04-06 23:35:07,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-inslast-allhead,334887000,5.038462,15.045260
    668 2023-04-06 23:35:12,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-inslast-inselem,231000000,5.148560,22.288139
    669 2023-04-06 23:35:18,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-inselem,169890000,5.124945,30.166255
    670 2023-04-06 23:35:23,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-inslast-inselem,553800000,5.003500,9.034850
    671 2023-04-06 23:35:28,3,5 1000 9051 -1 3  ,./perfexp--lq-list--stack-insfirst-remelem,534009000,5.006456,9.375228
    672 2023-04-06 23:35:33,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-allhead,624800000,5.050627,8.083590
    673 2023-04-06 23:35:38,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-insfirst-remelem,642621000,5.039619,7.842288
    674 2023-04-06 23:35:43,3,5 1000000 7 -1 3  ,./perfexp--lq-list--stack-insfirst-inselem,574000000,5.031817,8.766232
    675 2023-04-06 23:35:48,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-inslast-inselem,137599900,5.246307,38.127259
    676 2023-04-06 23:35:53,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-inslast-allhead,501580000,5.012750,9.993919
    677 2023-04-06 23:35:58,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-inslast-inselem,325836000,5.131221,15.747864
    678 2023-04-06 23:36:03,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-inslast-allhead,159326200,5.111924,32.084641
    679 2023-04-06 23:36:09,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-inslast-remelem,606750000,5.003928,8.247100
    680 2023-04-06 23:36:14,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-inslast-allhead,582200000,5.022484,8.626733
    681 2023-04-06 23:36:19,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-inslast-inselem,166568300,5.222978,31.356375
    682 2023-04-06 23:36:24,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-inslast-allhead,162918000,5.101216,31.311556
    683 2023-04-06 23:36:29,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-inslast-allhead,959000000,5.005860,5.219875
    684 2023-04-06 23:36:34,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-insfirst-inselem,307734000,5.025667,16.331205
    685 2023-04-06 23:36:39,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-inslast-remelem,588315000,5.002182,8.502557
    686 2023-04-06 23:36:44,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-inslast-remelem,153867000,5.230752,33.995282
    687 2023-04-06 23:36:49,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-remelem,152084100,5.127175,33.712762
    688 2023-04-06 23:36:54,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-inslast-remelem,784730000,5.021496,6.399011
    689 2023-04-06 23:37:00,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-insfirst-allhead,1022000000,5.025863,4.917674
    690 2023-04-06 23:37:05,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-inselem,444950000,5.083193,11.424189
    691 2023-04-06 23:37:10,4,5 1000 9051 -1 4  ,./perfexp--lq-list--stack-insfirst-inselem,325836000,5.104508,15.665881
    692 2023-04-06 23:37:15,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-allhead,224000000,5.044330,22.519330
    693 2023-04-06 23:37:20,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-inslast-inselem,658000000,5.008834,7.612210
    694 2023-04-06 23:37:25,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-insfirst-allhead,461130000,5.088815,11.035532
    695 2023-04-06 23:37:30,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-insfirst-remelem,534009000,5.067296,9.489158
    696 2023-04-06 23:37:35,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-inslast-inselem,162918000,5.085345,31.214138
    697 2023-04-06 23:37:40,3,5 1000 9051 -1 3  ,./perfexp--lq-list--stack-insfirst-allhead,343938000,5.058624,14.707953
    698 2023-04-06 23:37:45,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-inselem,658000000,5.050619,7.675713
    699 2023-04-06 23:37:50,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-insfirst-inselem,130357800,5.147518,39.487610
    700 2023-04-06 23:37:55,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-inslast-remelem,606750000,5.060103,8.339684
    701 2023-04-06 23:38:00,4,5 10000 809 -1 4  ,./perfexp--lq-list--stack-insfirst-allhead,509670000,5.013006,9.835788
    702 2023-04-06 23:38:06,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-allhead,665000000,5.030220,7.564241
    703 2023-04-06 23:38:11,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-insfirst-allhead,509670000,5.045241,9.899035
    704 2023-04-06 23:38:16,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-inslast-remelem,707000000,5.030443,7.115195
    705 2023-04-06 23:38:21,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-inslast-allhead,1036600000,5.005349,4.828621
    706 2023-04-06 23:38:26,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-insfirst-allhead,166568300,5.122366,30.752346
    707 2023-04-06 23:38:31,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-inslast-remelem,720010000,5.032318,6.989233
    708 2023-04-06 23:38:36,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-inslast-allhead,1078000000,5.011085,4.648502
    709 2023-04-06 23:38:41,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-insfirst-remelem,693000000,5.044421,7.279107
    710 2023-04-06 23:38:46,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-inselem,217000000,5.008831,23.082171
    711 2023-04-06 23:38:51,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-inslast-inselem,980000000,5.001764,5.103841
    712 2023-04-06 23:38:56,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-inslast-allhead,159326200,5.160432,32.389099
    713 2023-04-06 23:39:01,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-remelem,994000000,5.009426,5.039664
    714 2023-04-06 23:39:06,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-inslast-allhead,1008200000,5.006411,4.965692
    715 2023-04-06 23:39:11,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-insfirst-allhead,679000000,5.010746,7.379596
    716 2023-04-06 23:39:16,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-remelem,588315000,5.073975,8.624589
    717 2023-04-06 23:39:21,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-insfirst-remelem,267957700,5.034365,18.787909
    718 2023-04-06 23:39:26,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-insfirst-remelem,534009000,5.054075,9.464400
    719 2023-04-06 23:39:31,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-inslast-allhead,665000000,5.000117,7.518973
    720 2023-04-06 23:39:36,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-inslast-allhead,137599900,5.044078,36.657570
    721 2023-04-06 23:39:42,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-inslast-remelem,224000000,5.024699,22.431692
    722 2023-04-06 23:39:47,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-allhead,665000000,5.038271,7.576347
    723 2023-04-06 23:39:52,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-inselem,137599900,5.151879,37.441008
    724 2023-04-06 23:39:57,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--queue-inslast-inselem,137599900,5.247585,38.136547
    725 2023-04-06 23:40:02,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-allhead,159326200,5.203331,32.658351
    726 2023-04-06 23:40:07,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-inslast-remelem,347620800,5.038125,14.493163
    727 2023-04-06 23:40:12,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-allhead,532500000,5.009917,9.408295
    728 2023-04-06 23:40:17,2,5 100000 71 -1 2  ,./perfexp--lq-list--stack-insfirst-remelem,681600000,5.024278,7.371300
    729 2023-04-06 23:40:22,5,5 1000 9051 -1 5  ,./perfexp--lq-list--stack-insfirst-remelem,534009000,5.005566,9.373561
    730 2023-04-06 23:40:27,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-remelem,588315000,5.056992,8.595722
    731 2023-04-06 23:40:32,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-inslast-inselem,144842000,5.153273,35.578582
    732 2023-04-06 23:40:38,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-insfirst-allhead,945000000,5.002845,5.294016
    733 2023-04-06 23:40:43,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-inslast-allhead,343938000,5.058633,14.707979
    734 2023-04-06 23:40:48,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-insfirst-inselem,420680000,5.068194,12.047623
    735 2023-04-06 23:40:53,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-inslast-allhead,1078000000,5.010055,4.647546
    736 2023-04-06 23:40:58,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-remelem,184600000,5.101831,27.637221
    737 2023-04-06 23:41:03,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-insfirst-remelem,854000000,5.009771,5.866242
    738 2023-04-06 23:41:08,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-inslast-inselem,316785000,5.026464,15.867115
    739 2023-04-06 23:41:13,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-inselem,444950000,5.000762,11.238930
    740 2023-04-06 23:41:18,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-inslast-remelem,702900000,5.023292,7.146524
    741 2023-04-06 23:41:23,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-insfirst-remelem,582480000,5.024755,8.626485
    742 2023-04-06 23:41:28,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-allhead,224000000,5.026874,22.441402
    743 2023-04-06 23:41:33,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-insfirst-remelem,534009000,5.029006,9.417456
    744 2023-04-06 23:41:38,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-inslast-remelem,159326200,5.174692,32.478601
    745 2023-04-06 23:41:43,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-insfirst-remelem,784000000,5.004447,6.383223
    746 2023-04-06 23:41:48,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-remelem,224000000,5.007044,22.352875
    747 2023-04-06 23:41:53,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-allhead,166568300,5.093894,30.581413
    748 2023-04-06 23:41:58,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--stack-inslast-inselem,501580000,5.063699,10.095496
    749 2023-04-06 23:42:03,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-insfirst-inselem,672000000,5.002208,7.443762
    750 2023-04-06 23:42:09,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-inslast-allhead,700000000,5.035791,7.193987
    751 2023-04-06 23:42:14,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--stack-inslast-remelem,1263800000,5.028343,3.978749
    752 2023-04-06 23:42:19,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-inslast-remelem,159326200,5.113131,32.092217
    753 2023-04-06 23:42:24,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-inslast-remelem,597366000,5.046347,8.447664
    754 2023-04-06 23:42:29,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-insfirst-remelem,642621000,5.053251,7.863501
    755 2023-04-06 23:42:34,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-inslast-inselem,444950000,5.077268,11.410873
    756 2023-04-06 23:42:39,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-inslast-inselem,171969000,5.099023,29.650827
    757 2023-04-06 23:42:44,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-inslast-allhead,325836000,5.047047,15.489532
    758 2023-04-06 23:42:49,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-allhead,181020000,5.216122,28.815170
    759 2023-04-06 23:42:54,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-allhead,181020000,5.222584,28.850867
    760 2023-04-06 23:43:00,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-inslast-remelem,534009000,5.024676,9.409347
    761 2023-04-06 23:43:05,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-allhead,162918000,5.066455,31.098191
    762 2023-04-06 23:43:10,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-inslast-allhead,646100000,5.006395,7.748638
    763 2023-04-06 23:43:15,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-inslast-allhead,1022400000,5.033839,4.923551
    764 2023-04-06 23:43:20,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-remelem,169890000,5.194201,30.573907
    765 2023-04-06 23:43:25,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-insfirst-inselem,617700000,5.004354,8.101593
    766 2023-04-06 23:43:30,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-inselem,568000000,5.053840,8.897606
    767 2023-04-06 23:43:35,4,5 100000 71 -1 4  ,./perfexp--lq-tailq--queue-inslast-allhead,773900000,5.009564,6.473141
    768 2023-04-06 23:43:40,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-inselem,477310000,5.060300,10.601705
    769 2023-04-06 23:43:45,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-remelem,766800000,5.029327,6.558851
    770 2023-04-06 23:43:50,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-insfirst-inselem,307734000,5.015156,16.297049
    771 2023-04-06 23:43:55,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-allhead,343938000,5.030864,14.627241
    772 2023-04-06 23:44:00,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-inslast-inselem,546700000,5.028823,9.198506
    773 2023-04-06 23:44:06,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-insfirst-allhead,159326200,5.159831,32.385326
    774 2023-04-06 23:44:11,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-inselem,184600000,5.013750,27.160076
    775 2023-04-06 23:44:16,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-inslast-remelem,184600000,5.191165,28.121154
    776 2023-04-06 23:44:21,3,5 100 72421 -1 3  ,./perfexp--lq-list--stack-insfirst-inselem,166568300,5.221509,31.347555
    777 2023-04-06 23:44:26,1,5 100000 71 -1 1  ,./perfexp--lq-list--stack-insfirst-remelem,681600000,5.027947,7.376683
    778 2023-04-06 23:44:31,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-inslast-allhead,493490000,5.065787,10.265227
    779 2023-04-06 23:44:36,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--stack-inslast-inselem,448000000,5.071891,11.321185
    780 2023-04-06 23:44:41,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-inslast-remelem,570213000,5.041445,8.841336
    781 2023-04-06 23:44:46,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-inselem,224000000,5.075413,22.658094
    782 2023-04-06 23:44:51,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-insfirst-allhead,517760000,5.074958,9.801758
    783 2023-04-06 23:44:57,1,5 1000 9051 -1 1  ,./perfexp--lq-list--stack-insfirst-inselem,325836000,5.079069,15.587808
    784 2023-04-06 23:45:02,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-inslast-remelem,184600000,5.156223,27.931869
    785 2023-04-06 23:45:07,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-inslast-remelem,646100000,5.048818,7.814298
    786 2023-04-06 23:45:12,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-remelem,153867000,5.084243,33.043102
    787 2023-04-06 23:45:17,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-remelem,152084100,5.088762,33.460184
    788 2023-04-06 23:45:22,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-inselem,477310000,5.040919,10.561101
    789 2023-04-06 23:45:27,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-allhead,166568300,5.107945,30.665769
    790 2023-04-06 23:45:32,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-remelem,759700000,5.013032,6.598699
    791 2023-04-06 23:45:37,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-inselem,159326200,5.183840,32.536017
    792 2023-04-06 23:45:43,2,5 100000 71 -1 2  ,./perfexp--upp-upp--stack-inslast-inselem,546700000,5.060570,9.256576
    793 2023-04-06 23:45:48,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-remelem,773900000,5.016882,6.482597
    794 2023-04-06 23:45:53,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-inslast-allhead,137599900,5.146936,37.405085
    795 2023-04-06 23:45:58,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-inselem,665000000,5.030136,7.564114
    796 2023-04-06 23:46:03,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-allhead,231000000,5.069341,21.945199
    797 2023-04-06 23:46:08,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-inslast-remelem,588315000,5.038815,8.564825
    798 2023-04-06 23:46:13,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-inslast-remelem,597366000,5.062109,8.474049
    799 2023-04-06 23:46:18,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-insfirst-allhead,130357800,5.097324,39.102562
    800 2023-04-06 23:46:23,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-inselem,181020000,5.245083,28.975157
    801 2023-04-06 23:46:28,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-inslast-remelem,728100000,5.048765,6.934164
    802 2023-04-06 23:46:34,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-inslast-remelem,260715600,5.006853,19.204271
    803 2023-04-06 23:46:39,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--queue-inslast-remelem,171969000,5.222348,30.367962
    804 2023-04-06 23:46:44,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-remelem,917000000,5.014479,5.468352
    805 2023-04-06 23:46:49,4,5 100 72421 -1 4  ,./perfexp--lq-list--stack-insfirst-inselem,166568300,5.223544,31.359773
    806 2023-04-06 23:46:54,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-inslast-allhead,994000000,5.008805,5.039039
    807 2023-04-06 23:46:59,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-inslast-allhead,509670000,5.037473,9.883793
    808 2023-04-06 23:47:04,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-allhead,444950000,5.008930,11.257287
    809 2023-04-06 23:47:09,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-inslast-remelem,1022400000,5.031635,4.921396
    810 2023-04-06 23:47:14,1,5 1000000 7 -1 1  ,./perfexp--lq-list--stack-insfirst-remelem,798000000,5.019472,6.290065
    811 2023-04-06 23:47:19,1,5 100 72421 -1 1  ,./perfexp--lq-list--stack-insfirst-remelem,333136600,5.086682,15.269058
    812 2023-04-06 23:47:24,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-inselem,444950000,5.009886,11.259436
    813 2023-04-06 23:47:29,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-insfirst-allhead,1022000000,5.028409,4.920165
    814 2023-04-06 23:47:34,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--stack-inslast-inselem,224000000,5.134726,22.922884
    815 2023-04-06 23:47:40,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-insfirst-allhead,166568300,5.129354,30.794299
    816 2023-04-06 23:47:45,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-insfirst-remelem,267957700,5.029663,18.770362
    817 2023-04-06 23:47:50,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-inslast-allhead,144842000,5.159035,35.618363
    818 2023-04-06 23:47:55,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-inslast-remelem,153867000,5.205434,33.830737
    819 2023-04-06 23:48:00,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-insfirst-remelem,859100000,5.024798,5.848909
    820 2023-04-06 23:48:05,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-inslast-inselem,352989000,5.106726,14.467097
    821 2023-04-06 23:48:10,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-inslast-inselem,325836000,5.095977,15.639699
    822 2023-04-06 23:48:15,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-inselem,162918000,5.237821,32.150045
    823 2023-04-06 23:48:21,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--stack-inslast-allhead,231000000,5.106340,22.105368
    824 2023-04-06 23:48:26,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-inslast-inselem,159326200,5.099221,32.004912
    825 2023-04-06 23:48:31,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-insfirst-inselem,159326200,5.004885,31.412818
    826 2023-04-06 23:48:36,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-insfirst-inselem,130357800,5.103887,39.152908
    827 2023-04-06 23:48:41,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-insfirst-allhead,316785000,5.095627,16.085443
    828 2023-04-06 23:48:46,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-inslast-allhead,169890000,5.023940,29.571723
    829 2023-04-06 23:48:51,3,5 100000 71 -1 3  ,./perfexp--lq-list--stack-insfirst-inselem,724200000,5.040016,6.959426
    830 2023-04-06 23:48:56,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-insfirst-allhead,679000000,5.039133,7.421404
    831 2023-04-06 23:49:01,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-inslast-remelem,159326200,5.202599,32.653757
    832 2023-04-06 23:49:07,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-insfirst-allhead,316785000,5.001730,15.789037
    833 2023-04-06 23:49:12,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-inslast-remelem,224000000,5.005996,22.348196
    834 2023-04-06 23:49:17,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-inslast-allhead,672000000,5.047250,7.510789
    835 2023-04-06 23:49:22,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-inslast-inselem,710000000,5.015764,7.064456
    836 2023-04-06 23:49:27,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-insfirst-remelem,642621000,5.038532,7.840597
    837 2023-04-06 23:49:32,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-remelem,152084100,5.074580,33.366933
    838 2023-04-06 23:49:37,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-allhead,169890000,5.038720,29.658720
    839 2023-04-06 23:49:42,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-insfirst-allhead,130357800,5.097956,39.107411
    840 2023-04-06 23:49:47,2,5 1000000 7 -1 2  ,./perfexp--cfa-cfa--queue-inslast-allhead,665000000,5.003770,7.524466
    841 2023-04-06 23:49:52,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-inslast-inselem,646100000,5.033712,7.790918
    842 2023-04-06 23:49:57,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-inslast-remelem,159326200,5.197406,32.621163
    843 2023-04-06 23:50:02,3,5 1000000 7 -1 3  ,./perfexp--lq-list--stack-insfirst-remelem,798000000,5.021226,6.292263
    844 2023-04-06 23:50:07,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-insfirst-remelem,267957700,5.036691,18.796590
    845 2023-04-06 23:50:12,5,5 10000 809 -1 5  ,./perfexp--lq-list--stack-insfirst-allhead,517760000,5.076458,9.804655
    846 2023-04-06 23:50:18,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-inselem,343938000,5.111457,14.861565
    847 2023-04-06 23:50:23,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-inslast-remelem,766800000,5.036608,6.568346
    848 2023-04-06 23:50:28,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-inslast-allhead,639000000,5.008767,7.838446
    849 2023-04-06 23:50:33,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-inselem,343938000,5.096478,14.818014
    850 2023-04-06 23:50:38,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-inslast-inselem,224000000,5.053022,22.558134
    851 2023-04-06 23:50:43,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--stack-inslast-inselem,588000000,5.043254,8.576963
    852 2023-04-06 23:50:48,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-insfirst-allhead,325836000,5.142199,15.781556
    853 2023-04-06 23:50:53,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-inslast-inselem,575100000,5.013201,8.717094
    854 2023-04-06 23:50:58,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-insfirst-allhead,788100000,5.011622,6.359119
    855 2023-04-06 23:51:03,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-inselem,603500000,5.049321,8.366729
    856 2023-04-06 23:51:08,2,5 100 72421 -1 2  ,./perfexp--lq-list--stack-insfirst-allhead,166568300,5.050434,30.320499
    857 2023-04-06 23:51:13,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-inselem,162918000,5.096707,31.283879
    858 2023-04-06 23:51:18,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-insfirst-allhead,805000000,5.003890,6.216012
    859 2023-04-06 23:51:23,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-inslast-inselem,137599900,5.089424,36.987120
    860 2023-04-06 23:51:29,5,5 10000 809 -1 5  ,./perfexp--lq-list--stack-insfirst-remelem,582480000,5.006380,8.594939
    861 2023-04-06 23:51:34,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-inslast-allhead,453040000,5.016531,11.073042
    862 2023-04-06 23:51:39,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-inslast-inselem,453040000,5.063734,11.177234
    863 2023-04-06 23:51:44,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-allhead,177980000,5.226280,29.364423
    864 2023-04-06 23:51:49,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-inslast-allhead,343938000,5.057972,14.706057
    865 2023-04-06 23:51:54,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-insfirst-allhead,509670000,5.025430,9.860164
    866 2023-04-06 23:51:59,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-inslast-remelem,161800000,5.000954,30.908245
    867 2023-04-06 23:52:04,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-allhead,181020000,5.211717,28.790835
    868 2023-04-06 23:52:09,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-inslast-allhead,477310000,5.049791,10.579688
    869 2023-04-06 23:52:14,1,5 10000 809 -1 1  ,./perfexp--lq-list--stack-insfirst-remelem,590570000,5.016456,8.494261
    870 2023-04-06 23:52:19,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-insfirst-remelem,534009000,5.061113,9.477580
    871 2023-04-06 23:52:24,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-remelem,169890000,5.017420,29.533345
    872 2023-04-06 23:52:29,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-inslast-inselem,485400000,5.081081,10.467822
    873 2023-04-06 23:52:34,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-allhead,343938000,5.033256,14.634196
    874 2023-04-06 23:52:40,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-inslast-remelem,784000000,5.033145,6.419828
    875 2023-04-06 23:52:45,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-inslast-inselem,980000000,5.012630,5.114929
    876 2023-04-06 23:52:50,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-insfirst-remelem,791000000,5.040982,6.372923
    877 2023-04-06 23:52:55,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-inslast-inselem,444950000,5.091346,11.442513
    878 2023-04-06 23:53:00,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-inslast-remelem,752600000,5.007532,6.653643
    879 2023-04-06 23:53:05,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-remelem,171969000,5.137818,29.876420
    880 2023-04-06 23:53:10,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-inslast-allhead,477310000,5.056730,10.594226
    881 2023-04-06 23:53:15,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-insfirst-inselem,539600000,5.044061,9.347778
    882 2023-04-06 23:53:20,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--queue-inslast-allhead,889000000,5.018817,5.645463
    883 2023-04-06 23:53:25,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-inslast-allhead,485400000,5.004149,10.309330
    884 2023-04-06 23:53:30,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-inslast-remelem,687876000,5.062201,7.359177
    885 2023-04-06 23:53:35,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-allhead,137599900,5.148068,37.413312
    886 2023-04-06 23:53:40,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-insfirst-inselem,289632000,5.012993,17.308146
    887 2023-04-06 23:53:45,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-inslast-inselem,575100000,5.045375,8.773039
    888 2023-04-06 23:53:50,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-insfirst-allhead,130357800,5.099296,39.117690
    889 2023-04-06 23:53:56,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-inslast-inselem,588000000,5.037787,8.567665
    890 2023-04-06 23:54:01,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-allhead,184600000,5.105671,27.658023
    891 2023-04-06 23:54:06,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-insfirst-remelem,333136600,5.074849,15.233538
    892 2023-04-06 23:54:11,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--stack-inslast-remelem,325894500,5.093924,15.630592
    893 2023-04-06 23:54:16,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-allhead,343938000,5.031887,14.630215
    894 2023-04-06 23:54:21,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-inslast-remelem,965600000,5.024737,5.203746
    895 2023-04-06 23:54:26,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--stack-insfirst-allhead,343938000,5.000385,14.538623
    896 2023-04-06 23:54:31,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-inslast-allhead,162918000,5.114478,31.392958
    897 2023-04-06 23:54:36,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-inslast-remelem,784000000,5.034203,6.421177
    898 2023-04-06 23:54:41,2,5 100000 71 -1 2  ,./perfexp--lq-list--stack-insfirst-allhead,773900000,5.039677,6.512052
    899 2023-04-06 23:54:46,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-inslast-remelem,325894500,5.097422,15.641326
    900 2023-04-06 23:54:51,2,5 1000000 7 -1 2  ,./perfexp--upp-upp--stack-insfirst-remelem,756000000,5.023632,6.645016
    901 2023-04-06 23:54:56,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-inslast-remelem,695740000,5.045478,7.251959
    902 2023-04-06 23:55:01,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-inslast-remelem,177500000,5.031516,28.346569
    903 2023-04-06 23:55:07,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-allhead,159326200,5.042017,31.645875
    904 2023-04-06 23:55:12,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-allhead,343938000,5.028640,14.620775
    905 2023-04-06 23:55:17,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-inslast-inselem,444950000,5.013986,11.268650
    906 2023-04-06 23:55:22,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-insfirst-remelem,267957700,5.032008,18.779113
    907 2023-04-06 23:55:27,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-inslast-allhead,352989000,5.053183,14.315412
    908 2023-04-06 23:55:32,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-inselem,159326200,5.186497,32.552694
    909 2023-04-06 23:55:37,2,5 1000 9051 -1 2  ,./perfexp--lq-list--stack-insfirst-remelem,534009000,5.014736,9.390733
    910 2023-04-06 23:55:42,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-inslast-remelem,534009000,5.029801,9.418944
    911 2023-04-06 23:55:47,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-inslast-inselem,343938000,5.069517,14.739625
    912 2023-04-06 23:55:52,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-inslast-allhead,582200000,5.043558,8.662930
    913 2023-04-06 23:55:57,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-remelem,184600000,5.143890,27.865060
    914 2023-04-06 23:56:02,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--queue-inslast-allhead,461130000,5.080796,11.018142
    915 2023-04-06 23:56:07,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-inslast-inselem,171969000,5.118993,29.766952
    916 2023-04-06 23:56:13,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-insfirst-remelem,720010000,5.035548,6.993720
    917 2023-04-06 23:56:18,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-inselem,137599900,5.147075,37.406095
    918 2023-04-06 23:56:23,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-insfirst-remelem,582480000,5.029466,8.634573
    919 2023-04-06 23:56:28,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-inslast-allhead,166568300,5.213374,31.298717
    920 2023-04-06 23:56:33,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-insfirst-inselem,130357800,5.104179,39.155148
    921 2023-04-06 23:56:38,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-insfirst-remelem,647200000,5.055149,7.810799
    922 2023-04-06 23:56:43,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-allhead,334887000,5.047137,15.071164
    923 2023-04-06 23:56:48,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-insfirst-inselem,973000000,5.030706,5.170304
    924 2023-04-06 23:56:53,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-insfirst-inselem,159326200,5.197585,32.622287
    925 2023-04-06 23:56:59,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-insfirst-allhead,444950000,5.057074,11.365488
    926 2023-04-06 23:57:04,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-inslast-remelem,177500000,5.028745,28.330958
    927 2023-04-06 23:57:09,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-insfirst-allhead,325836000,5.133705,15.755487
    928 2023-04-06 23:57:14,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-inselem,181020000,5.216624,28.817943
    929 2023-04-06 23:57:19,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-insfirst-inselem,546700000,5.040683,9.220199
    930 2023-04-06 23:57:24,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-insfirst-allhead,166568300,5.126525,30.777315
    931 2023-04-06 23:57:29,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-inslast-allhead,752600000,5.030341,6.683950
    932 2023-04-06 23:57:34,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-insfirst-inselem,781000000,5.002303,6.404997
    933 2023-04-06 23:57:39,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-inslast-remelem,311410300,5.110663,16.411349
    934 2023-04-06 23:57:44,5,5 100 72421 -1 5  ,./perfexp--upp-upp--queue-inslast-remelem,260715600,5.004443,19.195027
    935 2023-04-06 23:57:49,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-inselem,177980000,5.040817,28.322379
    936 2023-04-06 23:57:55,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-inslast-remelem,777000000,5.012582,6.451199
    937 2023-04-06 23:58:00,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-insfirst-inselem,130357800,5.143872,39.459641
    938 2023-04-06 23:58:05,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-remelem,588315000,5.034068,8.556756
    939 2023-04-06 23:58:10,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-inslast-inselem,436860000,5.006743,11.460749
    940 2023-04-06 23:58:15,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-insfirst-inselem,159326200,5.004273,31.408977
    941 2023-04-06 23:58:20,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-insfirst-remelem,784000000,5.042812,6.432158
    942 2023-04-06 23:58:25,5,5 100000 71 -1 5  ,./perfexp--lq-list--stack-insfirst-allhead,788100000,5.002504,6.347550
    943 2023-04-06 23:58:30,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-inselem,177500000,5.009520,28.222648
    944 2023-04-06 23:58:35,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--stack-inslast-allhead,162918000,5.140808,31.554573
    945 2023-04-06 23:58:40,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-inslast-inselem,144842000,5.151509,35.566403
    946 2023-04-06 23:58:45,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-inslast-remelem,152084100,5.034474,33.103224
    947 2023-04-06 23:58:50,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-insfirst-inselem,184600000,5.137038,27.827941
    948 2023-04-06 23:58:56,5,5 10000 809 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-inselem,477310000,5.038631,10.556307
    949 2023-04-06 23:59:01,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-inslast-inselem,171969000,5.114824,29.742709
    950 2023-04-06 23:59:06,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--queue-inslast-remelem,515907000,5.030354,9.750505
    951 2023-04-06 23:59:11,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-allhead,665000000,5.014697,7.540898
    952 2023-04-06 23:59:16,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-allhead,665000000,5.003080,7.523429
    953 2023-04-06 23:59:21,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-allhead,169890000,5.029569,29.604856
    954 2023-04-06 23:59:26,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-insfirst-allhead,724200000,5.029829,6.945359
    955 2023-04-06 23:59:31,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-inslast-allhead,493490000,5.010267,10.152722
    956 2023-04-06 23:59:36,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-inslast-remelem,153867000,5.204054,33.821768
    957 2023-04-06 23:59:41,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-insfirst-inselem,159326200,5.006861,31.425221
    958 2023-04-06 23:59:46,5,5 100 72421 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-inselem,166568300,5.134474,30.825037
    959 2023-04-06 23:59:51,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-allhead,177500000,5.021209,28.288501
    960 2023-04-06 23:59:56,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--queue-inslast-remelem,959000000,5.000634,5.214425
    961 2023-04-07 00:00:01,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-inslast-allhead,177980000,5.123476,28.786808
    962 2023-04-07 00:00:07,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-insfirst-remelem,574390000,5.003850,8.711590
    963 2023-04-07 00:00:12,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--stack-inslast-remelem,678825000,5.004920,7.372916
    964 2023-04-07 00:00:17,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-insfirst-inselem,788100000,5.031101,6.383836
    965 2023-04-07 00:00:22,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-inslast-allhead,334887000,5.030583,15.021733
    966 2023-04-07 00:00:27,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-insfirst-inselem,298683000,5.139339,17.206667
    967 2023-04-07 00:00:32,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-allhead,485400000,5.084587,10.475045
    968 2023-04-07 00:00:37,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-inslast-remelem,590570000,5.043516,8.540082
    969 2023-04-07 00:00:42,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-allhead,231000000,5.119258,22.161290
    970 2023-04-07 00:00:47,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-insfirst-remelem,461601000,5.024322,10.884556
    971 2023-04-07 00:00:52,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-insfirst-allhead,461130000,5.076500,11.008826
    972 2023-04-07 00:00:57,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-insfirst-inselem,588000000,5.001611,8.506141
    973 2023-04-07 00:01:02,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-inselem,169890000,5.145494,30.287209
    974 2023-04-07 00:01:07,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-inslast-allhead,672000000,5.044544,7.506762
    975 2023-04-07 00:01:12,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-insfirst-remelem,534009000,5.004349,9.371282
    976 2023-04-07 00:01:17,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-inslast-inselem,987000000,5.025173,5.091361
    977 2023-04-07 00:01:23,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--stack-inslast-remelem,169890000,5.236716,30.824157
    978 2023-04-07 00:01:28,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-allhead,334887000,5.055747,15.096874
    979 2023-04-07 00:01:33,2,5 1000000 7 -1 2  ,./perfexp--lq-list--stack-insfirst-allhead,924000000,5.034723,5.448834
    980 2023-04-07 00:01:38,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-insfirst-remelem,296926100,5.111804,17.215745
    981 2023-04-07 00:01:43,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--stack-inslast-remelem,325894500,5.092882,15.627395
    982 2023-04-07 00:01:48,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-inslast-inselem,493490000,5.012330,10.156903
    983 2023-04-07 00:01:53,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-insfirst-allhead,660300000,5.052296,7.651516
    984 2023-04-07 00:01:58,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-insfirst-inselem,169890000,5.023551,29.569433
    985 2023-04-07 00:02:03,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--stack-inslast-inselem,162918000,5.065419,31.091831
    986 2023-04-07 00:02:08,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-inslast-inselem,159326200,5.065417,31.792743
    987 2023-04-07 00:02:13,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-inselem,610600000,5.045429,8.263067
    988 2023-04-07 00:02:18,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-remelem,159326200,5.086272,31.923638
    989 2023-04-07 00:02:24,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-insfirst-remelem,773900000,5.011786,6.476012
    990 2023-04-07 00:02:29,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-inslast-remelem,695740000,5.035083,7.237018
    991 2023-04-07 00:02:34,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-inselem,617700000,5.034056,8.149678
    992 2023-04-07 00:02:39,2,5 1000 9051 -1 2  ,./perfexp--lq-tailq--queue-insfirst-allhead,316785000,5.101400,16.103667
    993 2023-04-07 00:02:44,4,5 100000 71 -1 4  ,./perfexp--upp-upp--queue-insfirst-allhead,624800000,5.004312,8.009462
    994 2023-04-07 00:02:49,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-insfirst-inselem,444950000,5.086458,11.431527
    995 2023-04-07 00:02:54,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-inselem,343938000,5.095479,14.815109
    996 2023-04-07 00:02:59,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-inslast-allhead,501580000,5.078669,10.125342
    997 2023-04-07 00:03:04,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--stack-inslast-allhead,325836000,5.035838,15.455131
    998 2023-04-07 00:03:09,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--queue-insfirst-remelem,642621000,5.048161,7.855581
    999 2023-04-07 00:03:14,5,5 1000 9051 -1 5  ,./perfexp--lq-list--stack-insfirst-allhead,343938000,5.068172,14.735714
    1000 2023-04-07 00:03:19,2,5 10000 809 -1 2  ,./perfexp--lq-list--stack-insfirst-allhead,509670000,5.010027,9.829943
    1001 2023-04-07 00:03:24,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-insfirst-remelem,711920000,5.004285,7.029280
    1002 2023-04-07 00:03:29,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--queue-inslast-inselem,343938000,5.124094,14.898307
    1003 2023-04-07 00:03:35,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-remelem,289684000,5.109375,17.637754
    1004 2023-04-07 00:03:40,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--queue-inslast-inselem,177980000,5.226474,29.365513
    1005 2023-04-07 00:03:45,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-inslast-remelem,1421000000,5.024039,3.535566
    1006 2023-04-07 00:03:50,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-inslast-allhead,137599900,5.041139,36.636211
    1007 2023-04-07 00:03:55,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-inslast-allhead,159326200,5.081520,31.893813
    1008 2023-04-07 00:04:00,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-insfirst-inselem,581000000,5.046014,8.685050
    1009 2023-04-07 00:04:05,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-inslast-allhead,493490000,5.016015,10.164370
    1010 2023-04-07 00:04:10,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-insfirst-inselem,581000000,5.003459,8.611806
    1011 2023-04-07 00:04:15,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-inslast-inselem,693000000,5.001641,7.217375
    1012 2023-04-07 00:04:20,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-inslast-allhead,159326200,5.162225,32.400352
    1013 2023-04-07 00:04:25,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-inslast-remelem,325894500,5.086104,15.606597
    1014 2023-04-07 00:04:31,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-insfirst-inselem,307734000,5.019841,16.312273
    1015 2023-04-07 00:04:36,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-inslast-allhead,469220000,5.001562,10.659311
    1016 2023-04-07 00:04:41,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-insfirst-inselem,130357800,5.142624,39.450067
    1017 2023-04-07 00:04:46,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-allhead,553800000,5.013626,9.053135
    1018 2023-04-07 00:04:51,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--stack-insfirst-remelem,333136600,5.076545,15.238629
    1019 2023-04-07 00:04:56,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-inslast-inselem,169890000,5.071793,29.853393
    1020 2023-04-07 00:05:01,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-inslast-allhead,501580000,5.064339,10.096772
    1021 2023-04-07 00:05:06,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-remelem,153867000,5.176563,33.643101
    1022 2023-04-07 00:05:11,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-allhead,184600000,5.032819,27.263375
    1023 2023-04-07 00:05:16,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-remelem,224000000,5.024146,22.429223
    1024 2023-04-07 00:05:21,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-inslast-remelem,588315000,5.050261,8.584281
    1025 2023-04-07 00:05:26,5,5 1000000 7 -1 5  ,./perfexp--cfa-cfa--queue-inslast-remelem,980000000,5.025545,5.128107
    1026 2023-04-07 00:05:32,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-inselem,166568300,5.065528,30.411117
    1027 2023-04-07 00:05:37,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-remelem,318652400,5.015438,15.739527
    1028 2023-04-07 00:05:42,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-inslast-remelem,823600000,5.033144,6.111151
    1029 2023-04-07 00:05:47,1,5 100000 71 -1 1  ,./perfexp--upp-upp--queue-inslast-allhead,710000000,5.007572,7.052918
    1030 2023-04-07 00:05:52,3,5 100 72421 -1 3  ,./perfexp--upp-upp--queue-insfirst-inselem,130357800,5.098879,39.114491
    1031 2023-04-07 00:05:57,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-inslast-allhead,166568300,5.181296,31.106135
    1032 2023-04-07 00:06:02,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-insfirst-inselem,159326200,5.206496,32.678216
    1033 2023-04-07 00:06:07,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-insfirst-remelem,333136600,5.083054,15.258167
    1034 2023-04-07 00:06:12,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--queue-inslast-inselem,159326200,5.023020,31.526642
    1035 2023-04-07 00:06:17,5,5 10000 809 -1 5  ,./perfexp--upp-upp--stack-insfirst-inselem,477310000,5.066548,10.614795
    1036 2023-04-07 00:06:23,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-inslast-inselem,444950000,5.002215,11.242196
    1037 2023-04-07 00:06:28,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-insfirst-allhead,731300000,5.007529,6.847435
    1038 2023-04-07 00:06:33,5,5 1000 9051 -1 5  ,./perfexp--lq-tailq--stack-insfirst-inselem,316785000,5.004748,15.798564
    1039 2023-04-07 00:06:38,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-inslast-inselem,588000000,5.046407,8.582325
    1040 2023-04-07 00:06:43,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-remelem,917000000,5.029605,5.484847
    1041 2023-04-07 00:06:48,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--queue-inslast-inselem,833000000,5.018035,6.024052
    1042 2023-04-07 00:06:53,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-insfirst-allhead,525850000,5.070215,9.641942
    1043 2023-04-07 00:06:58,5,5 100000 71 -1 5  ,./perfexp--upp-upp--stack-insfirst-remelem,731300000,5.028043,6.875486
    1044 2023-04-07 00:07:03,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-inslast-remelem,614840000,5.028645,8.178786
    1045 2023-04-07 00:07:08,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-inslast-remelem,720010000,5.048400,7.011569
    1046 2023-04-07 00:07:13,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-inslast-remelem,224000000,5.107446,22.801098
    1047 2023-04-07 00:07:18,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--queue-inslast-allhead,959000000,5.009608,5.223783
    1048 2023-04-07 00:07:23,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-remelem,184600000,5.136296,27.823922
    1049 2023-04-07 00:07:28,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-inslast-remelem,695740000,5.019980,7.215310
    1050 2023-04-07 00:07:33,4,5 10000 809 -1 4  ,./perfexp--upp-upp--queue-inslast-allhead,493490000,5.031048,10.194833
    1051 2023-04-07 00:07:38,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-insfirst-remelem,534009000,5.044507,9.446483
    1052 2023-04-07 00:07:43,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--stack-inslast-inselem,343938000,5.079265,14.767967
    1053 2023-04-07 00:07:48,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--queue-inslast-inselem,568000000,5.039315,8.872033
    1054 2023-04-07 00:07:53,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-insfirst-inselem,436860000,5.036864,11.529698
    1055 2023-04-07 00:07:58,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-inslast-inselem,724200000,5.004672,6.910621
    1056 2023-04-07 00:08:03,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-inslast-inselem,159326200,5.152197,32.337412
    1057 2023-04-07 00:08:09,4,5 100 72421 -1 4  ,./perfexp--upp-upp--queue-inslast-allhead,137599900,5.043725,36.655005
    1058 2023-04-07 00:08:14,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-insfirst-remelem,461601000,5.010361,10.854311
    1059 2023-04-07 00:08:19,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-allhead,444950000,5.008312,11.255898
    1060 2023-04-07 00:08:24,5,5 100000 71 -1 5  ,./perfexp--upp-upp--queue-insfirst-allhead,646100000,5.052912,7.820635
    1061 2023-04-07 00:08:29,3,5 1000000 7 -1 3  ,./perfexp--upp-upp--queue-inslast-inselem,693000000,5.024033,7.249687
    1062 2023-04-07 00:08:34,5,5 1000 9051 -1 5  ,./perfexp--cpp-stlref--queue-inslast-inselem,171969000,5.113559,29.735353
    1063 2023-04-07 00:08:39,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-inslast-remelem,224000000,5.136808,22.932179
    1064 2023-04-07 00:08:44,2,5 1000000 7 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-allhead,224000000,5.087099,22.710263
    1065 2023-04-07 00:08:49,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-inslast-inselem,693000000,5.001977,7.217860
    1066 2023-04-07 00:08:54,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-insfirst-allhead,325836000,5.086269,15.609905
    1067 2023-04-07 00:08:59,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-remelem,152084100,5.070523,33.340257
    1068 2023-04-07 00:09:04,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-insfirst-inselem,307734000,5.001254,16.251873
    1069 2023-04-07 00:09:09,3,5 1000 9051 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-inselem,181020000,5.244969,28.974528
    1070 2023-04-07 00:09:15,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-inslast-allhead,159326200,5.076574,31.862770
    1071 2023-04-07 00:09:20,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-allhead,560900000,5.015707,8.942248
    1072 2023-04-07 00:09:25,1,5 100000 71 -1 1  ,./perfexp--upp-upp--stack-inslast-remelem,937200000,5.038076,5.375668
    1073 2023-04-07 00:09:30,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-insfirst-inselem,177980000,5.087129,28.582588
    1074 2023-04-07 00:09:35,4,5 10000 809 -1 4  ,./perfexp--lq-list--stack-insfirst-remelem,590570000,5.057216,8.563280
    1075 2023-04-07 00:09:40,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--stack-inslast-inselem,159326200,5.148371,32.313399
    1076 2023-04-07 00:09:45,1,5 1000 9051 -1 1  ,./perfexp--upp-upp--stack-insfirst-inselem,307734000,5.017681,16.305254
    1077 2023-04-07 00:09:50,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-remelem,703830000,5.001011,7.105425
    1078 2023-04-07 00:09:55,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-inslast-inselem,159326200,5.146824,32.303689
    1079 2023-04-07 00:10:00,4,5 100000 71 -1 4  ,./perfexp--lq-list--stack-insfirst-inselem,560900000,5.037575,8.981236
    1080 2023-04-07 00:10:05,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-insfirst-inselem,159326200,5.206990,32.681317
    1081 2023-04-07 00:10:11,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--stack-inslast-inselem,177980000,5.212465,29.286802
    1082 2023-04-07 00:10:16,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-inslast-remelem,980000000,5.014558,5.116896
    1083 2023-04-07 00:10:21,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--stack-insfirst-inselem,343938000,5.094368,14.811879
    1084 2023-04-07 00:10:26,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-inselem,610600000,5.038606,8.251893
    1085 2023-04-07 00:10:31,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-insfirst-remelem,738400000,5.012787,6.788715
    1086 2023-04-07 00:10:36,3,5 10000 809 -1 3  ,./perfexp--upp-upp--stack-inslast-remelem,679560000,5.029846,7.401622
    1087 2023-04-07 00:10:41,2,5 10000 809 -1 2  ,./perfexp--upp-upp--queue-inslast-inselem,453040000,5.073771,11.199389
    1088 2023-04-07 00:10:46,2,5 1000000 7 -1 2  ,./perfexp--lq-list--stack-insfirst-remelem,798000000,5.015579,6.285187
    1089 2023-04-07 00:10:51,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-inslast-inselem,493490000,5.060374,10.254258
    1090 2023-04-07 00:10:56,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--queue-inslast-remelem,766800000,5.015732,6.541122
    1091 2023-04-07 00:11:01,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-inslast-inselem,453040000,5.070851,11.192943
    1092 2023-04-07 00:11:06,2,5 10000 809 -1 2  ,./perfexp--upp-upp--stack-insfirst-allhead,509670000,5.009743,9.829386
    1093 2023-04-07 00:11:11,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-inslast-inselem,610600000,5.024440,8.228693
    1094 2023-04-07 00:11:16,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-inslast-allhead,759700000,5.040553,6.634926
    1095 2023-04-07 00:11:21,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--stack-inslast-remelem,159326200,5.193180,32.594639
    1096 2023-04-07 00:11:27,5,5 1000 9051 -1 5  ,./perfexp--cfa-cfa--queue-inslast-allhead,343938000,5.052484,14.690101
    1097 2023-04-07 00:11:32,1,5 100000 71 -1 1  ,./perfexp--lq-list--stack-insfirst-allhead,788100000,5.016808,6.365700
    1098 2023-04-07 00:11:37,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-insfirst-allhead,660300000,5.045791,7.641664
    1099 2023-04-07 00:11:42,4,5 100 72421 -1 4  ,./perfexp--upp-upp--stack-inslast-inselem,159326200,5.146330,32.300588
    1100 2023-04-07 00:11:47,3,5 10000 809 -1 3  ,./perfexp--lq-list--stack-insfirst-allhead,509670000,5.049794,9.907968
    1101 2023-04-07 00:11:52,1,5 100 72421 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-inselem,166568300,5.161840,30.989330
    1102 2023-04-07 00:11:57,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-insfirst-allhead,130357800,5.062710,38.837032
    1103 2023-04-07 00:12:02,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--queue-inslast-inselem,159326200,5.089807,31.945826
    1104 2023-04-07 00:12:08,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-remelem,282441900,5.058237,17.908947
    1105 2023-04-07 00:12:13,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-insfirst-remelem,224000000,5.036237,22.483201
    1106 2023-04-07 00:12:18,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-inslast-allhead,177500000,5.014610,28.251324
    1107 2023-04-07 00:12:23,1,5 10000 809 -1 1  ,./perfexp--upp-upp--queue-insfirst-remelem,647200000,5.039386,7.786443
    1108 2023-04-07 00:12:28,2,5 1000 9051 -1 2  ,./perfexp--lq-list--stack-insfirst-allhead,343938000,5.069521,14.739636
    1109 2023-04-07 00:12:33,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-allhead,159326200,5.100854,32.015161
    1110 2023-04-07 00:12:38,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--stack-insfirst-allhead,166568300,5.125007,30.768201
    1111 2023-04-07 00:12:43,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--queue-insfirst-allhead,177980000,5.117398,28.752658
    1112 2023-04-07 00:12:48,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--queue-inslast-remelem,590570000,5.052605,8.555472
    1113 2023-04-07 00:12:53,4,5 1000 9051 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-allhead,343938000,5.025513,14.611683
    1114 2023-04-07 00:12:58,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-inslast-allhead,177980000,5.199746,29.215339
    1115 2023-04-07 00:13:04,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-inslast-remelem,679560000,5.058526,7.443825
    1116 2023-04-07 00:13:09,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-insfirst-remelem,710000000,5.003660,7.047408
    1117 2023-04-07 00:13:14,2,5 100000 71 -1 2  ,./perfexp--upp-upp--queue-insfirst-inselem,560900000,5.048259,9.000283
    1118 2023-04-07 00:13:19,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--stack-insfirst-allhead,896000000,5.014332,5.596353
    1119 2023-04-07 00:13:24,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-inslast-allhead,184600000,5.190548,28.117811
    1120 2023-04-07 00:13:29,3,5 100 72421 -1 3  ,./perfexp--cfa-cfa--stack-insfirst-remelem,325894500,5.111016,15.683039
    1121 2023-04-07 00:13:34,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-inslast-allhead,763000000,5.017561,6.576096
    1122 2023-04-07 00:13:39,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--queue-inslast-inselem,833000000,5.019453,6.025754
    1123 2023-04-07 00:13:44,5,5 10000 809 -1 5  ,./perfexp--lq-tailq--stack-insfirst-remelem,590570000,5.047563,8.546934
    1124 2023-04-07 00:13:49,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--queue-insfirst-inselem,436860000,5.034155,11.523497
    1125 2023-04-07 00:13:54,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--stack-inslast-remelem,570213000,5.051648,8.859230
    1126 2023-04-07 00:13:59,1,5 100000 71 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-allhead,610600000,5.015572,8.214170
    1127 2023-04-07 00:14:04,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-insfirst-allhead,1022000000,5.030284,4.922000
    1128 2023-04-07 00:14:09,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--stack-inslast-remelem,966000000,5.018343,5.194972
    1129 2023-04-07 00:14:14,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--stack-insfirst-remelem,784000000,5.042359,6.431580
    1130 2023-04-07 00:14:19,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--stack-inslast-allhead,184600000,5.173540,28.025677
    1131 2023-04-07 00:14:25,3,5 100000 71 -1 3  ,./perfexp--upp-upp--stack-inslast-inselem,553800000,5.046826,9.113084
    1132 2023-04-07 00:14:30,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-inslast-allhead,493490000,5.025143,10.182867
    1133 2023-04-07 00:14:35,4,5 100000 71 -1 4  ,./perfexp--lq-list--stack-insfirst-remelem,702900000,5.050739,7.185573
    1134 2023-04-07 00:14:40,2,5 1000 9051 -1 2  ,./perfexp--cpp-stlref--stack-insfirst-allhead,162918000,5.172527,31.749267
    1135 2023-04-07 00:14:45,4,5 100 72421 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-inselem,159326200,5.130366,32.200391
    1136 2023-04-07 00:14:50,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-remelem,830700000,5.005727,6.025914
    1137 2023-04-07 00:14:55,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-inslast-allhead,159326200,5.105089,32.041742
    1138 2023-04-07 00:15:00,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-insfirst-inselem,581000000,5.027483,8.653155
    1139 2023-04-07 00:15:05,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-inslast-allhead,159326200,5.079283,31.879772
    1140 2023-04-07 00:15:10,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--stack-inslast-remelem,169890000,5.225200,30.756372
    1141 2023-04-07 00:15:16,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-inslast-inselem,159326200,5.152960,32.342201
    1142 2023-04-07 00:15:21,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-inslast-remelem,777000000,5.023512,6.465266
    1143 2023-04-07 00:15:26,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--queue-inslast-inselem,693000000,5.042654,7.276557
    1144 2023-04-07 00:15:31,1,5 10000 809 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-allhead,169890000,5.097853,30.006787
    1145 2023-04-07 00:15:36,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--queue-inslast-remelem,311410300,5.100699,16.379352
    1146 2023-04-07 00:15:41,5,5 100 72421 -1 5  ,./perfexp--cfa-cfa--queue-inslast-inselem,137599900,5.246073,38.125558
    1147 2023-04-07 00:15:46,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-inslast-inselem,325836000,5.127345,15.735968
    1148 2023-04-07 00:15:52,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-inslast-allhead,325836000,5.027188,15.428584
    1149 2023-04-07 00:15:57,3,5 1000000 7 -1 3  ,./perfexp--cpp-stlref--queue-inslast-inselem,224000000,5.015171,22.389156
    1150 2023-04-07 00:16:02,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-inslast-inselem,493490000,5.011236,10.154686
    1151 2023-04-07 00:16:07,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--queue-insfirst-inselem,546700000,5.018107,9.178904
    1152 2023-04-07 00:16:12,1,5 1000000 7 -1 1  ,./perfexp--upp-upp--queue-inslast-allhead,882000000,5.002161,5.671384
    1153 2023-04-07 00:16:17,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-inslast-remelem,792820000,5.043780,6.361822
    1154 2023-04-07 00:16:22,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-inslast-remelem,318652400,5.040033,15.816711
    1155 2023-04-07 00:16:27,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-insfirst-inselem,388320000,5.085010,13.094896
    1156 2023-04-07 00:16:32,3,5 100 72421 -1 3  ,./perfexp--lq-list--stack-insfirst-remelem,333136600,5.078881,15.245641
    1157 2023-04-07 00:16:37,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--queue-inslast-allhead,868000000,5.019333,5.782642
    1158 2023-04-07 00:16:42,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-inslast-allhead,177500000,5.028223,28.328017
    1159 2023-04-07 00:16:47,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-allhead,631900000,5.013989,7.934782
    1160 2023-04-07 00:16:52,5,5 1000000 7 -1 5  ,./perfexp--cpp-stlref--queue-inslast-allhead,224000000,5.103798,22.784813
    1161 2023-04-07 00:16:57,3,5 100 72421 -1 3  ,./perfexp--lq-list--stack-insfirst-allhead,166568300,5.053284,30.337609
    1162 2023-04-07 00:17:02,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--stack-insfirst-inselem,493490000,5.046497,10.226138
    1163 2023-04-07 00:17:07,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-inslast-allhead,334887000,5.070579,15.141164
    1164 2023-04-07 00:17:12,3,5 1000 9051 -1 3  ,./perfexp--lq-tailq--queue-inslast-inselem,352989000,5.106015,14.465082
    1165 2023-04-07 00:17:18,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-inslast-allhead,672000000,5.053260,7.519732
    1166 2023-04-07 00:17:23,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-inslast-inselem,184600000,5.086013,27.551533
    1167 2023-04-07 00:17:28,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-inslast-inselem,177500000,5.041333,28.401876
    1168 2023-04-07 00:17:33,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--queue-insfirst-remelem,944300000,5.027667,5.324226
    1169 2023-04-07 00:17:38,1,5 10000 809 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-remelem,695740000,5.024660,7.222037
    1170 2023-04-07 00:17:43,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--queue-insfirst-allhead,130357800,5.060227,38.817984
    1171 2023-04-07 00:17:48,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-insfirst-allhead,453040000,5.060348,11.169760
    1172 2023-04-07 00:17:53,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--stack-inslast-remelem,1263800000,5.002587,3.958369
    1173 2023-04-07 00:17:58,3,5 10000 809 -1 3  ,./perfexp--cpp-stlref--queue-inslast-remelem,169890000,5.032008,29.619212
    1174 2023-04-07 00:18:03,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--stack-inslast-inselem,469220000,5.038856,10.738792
    1175 2023-04-07 00:18:08,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--stack-inslast-allhead,184600000,5.132353,27.802562
    1176 2023-04-07 00:18:13,3,5 10000 809 -1 3  ,./perfexp--lq-tailq--queue-insfirst-inselem,388320000,5.061103,13.033331
    1177 2023-04-07 00:18:18,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-inselem,169890000,5.089740,29.959032
    1178 2023-04-07 00:18:23,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-insfirst-allhead,130357800,5.096965,39.099808
    1179 2023-04-07 00:18:29,1,5 1000 9051 -1 1  ,./perfexp--cpp-stlref--queue-inslast-inselem,171969000,5.103011,29.674017
    1180 2023-04-07 00:18:34,3,5 1000000 7 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-inselem,658000000,5.036277,7.653916
    1181 2023-04-07 00:18:39,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-inslast-inselem,177980000,5.212807,29.288723
    1182 2023-04-07 00:18:44,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--stack-inslast-inselem,477310000,5.072814,10.627923
    1183 2023-04-07 00:18:49,4,5 100 72421 -1 4  ,./perfexp--lq-tailq--queue-inslast-remelem,311410300,5.096826,16.366915
    1184 2023-04-07 00:18:54,4,5 10000 809 -1 4  ,./perfexp--cpp-stlref--stack-inslast-allhead,169890000,5.016611,29.528583
    1185 2023-04-07 00:18:59,4,5 100000 71 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-remelem,937200000,5.001450,5.336588
    1186 2023-04-07 00:19:04,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-inslast-inselem,588000000,5.027147,8.549570
    1187 2023-04-07 00:19:09,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--stack-inslast-inselem,184600000,5.170569,28.009583
    1188 2023-04-07 00:19:14,4,5 1000 9051 -1 4  ,./perfexp--cpp-stlref--queue-inslast-allhead,181020000,5.255817,29.034455
    1189 2023-04-07 00:19:20,2,5 100000 71 -1 2  ,./perfexp--cfa-cfa--stack-inslast-allhead,603500000,5.004894,8.293114
    1190 2023-04-07 00:19:25,4,5 10000 809 -1 4  ,./perfexp--upp-upp--stack-inslast-allhead,493490000,5.060646,10.254810
    1191 2023-04-07 00:19:30,4,5 1000000 7 -1 4  ,./perfexp--upp-upp--stack-insfirst-remelem,609000000,5.021341,8.245223
    1192 2023-04-07 00:19:35,2,5 1000 9051 -1 2  ,./perfexp--cfa-cfa--queue-inslast-inselem,334887000,5.004467,14.943748
    1193 2023-04-07 00:19:40,3,5 10000 809 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-remelem,687650000,5.004454,7.277618
    1194 2023-04-07 00:19:45,1,5 100 72421 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-remelem,289684000,5.114885,17.656774
    1195 2023-04-07 00:19:50,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-inslast-inselem,485400000,5.081049,10.467756
    1196 2023-04-07 00:19:55,5,5 100 72421 -1 5  ,./perfexp--upp-upp--stack-inslast-remelem,318652400,5.038741,15.812657
    1197 2023-04-07 00:20:00,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--queue-insfirst-remelem,588315000,5.013924,8.522516
    1198 2023-04-07 00:20:05,5,5 1000000 7 -1 5  ,./perfexp--lq-tailq--stack-insfirst-allhead,889000000,5.011883,5.637664
    1199 2023-04-07 00:20:10,1,5 10000 809 -1 1  ,./perfexp--upp-upp--stack-inslast-inselem,444950000,5.067489,11.388895
    1200 2023-04-07 00:20:15,3,5 100 72421 -1 3  ,./perfexp--cpp-stlref--stack-inslast-allhead,159326200,5.066920,31.802177
    1201 2023-04-07 00:20:20,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--queue-inslast-allhead,177500000,5.042851,28.410428
    1202 2023-04-07 00:20:25,1,5 100 72421 -1 1  ,./perfexp--upp-upp--queue-inslast-allhead,137599900,5.041518,36.638966
    1203 2023-04-07 00:20:30,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-inslast-remelem,534009000,5.035769,9.430120
    1204 2023-04-07 00:20:35,5,5 10000 809 -1 5  ,./perfexp--cpp-stlref--queue-inslast-allhead,169890000,5.014708,29.517382
    1205 2023-04-07 00:20:40,2,5 10000 809 -1 2  ,./perfexp--cpp-stlref--queue-inslast-remelem,169890000,5.074810,29.871152
    1206 2023-04-07 00:20:46,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-inslast-inselem,144842000,5.151741,35.568005
    1207 2023-04-07 00:20:51,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-inslast-remelem,606750000,5.015496,8.266166
    1208 2023-04-07 00:20:56,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-inslast-allhead,334887000,5.048050,15.073891
    1209 2023-04-07 00:21:01,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-allhead,665000000,5.000859,7.520089
    1210 2023-04-07 00:21:06,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--stack-insfirst-inselem,316785000,5.145817,16.243878
    1211 2023-04-07 00:21:11,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--queue-insfirst-inselem,307734000,5.028541,16.340544
    1212 2023-04-07 00:21:16,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-insfirst-remelem,574390000,5.000948,8.706537
    1213 2023-04-07 00:21:21,3,5 1000000 7 -1 3  ,./perfexp--lq-tailq--queue-insfirst-allhead,1022000000,5.024777,4.916612
    1214 2023-04-07 00:21:26,5,5 10000 809 -1 5  ,./perfexp--upp-upp--queue-inslast-allhead,493490000,5.064331,10.262277
    1215 2023-04-07 00:21:31,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--queue-inslast-inselem,224000000,5.122860,22.869911
    1216 2023-04-07 00:21:36,5,5 100000 71 -1 5  ,./perfexp--lq-tailq--queue-inslast-allhead,710000000,5.003407,7.047052
    1217 2023-04-07 00:21:41,4,5 1000000 7 -1 4  ,./perfexp--lq-tailq--stack-inslast-allhead,1078000000,5.014066,4.651267
    1218 2023-04-07 00:21:46,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-inslast-allhead,224000000,5.121987,22.866013
    1219 2023-04-07 00:21:51,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--stack-insfirst-remelem,590570000,5.012351,8.487311
    1220 2023-04-07 00:21:56,1,5 100000 71 -1 1  ,./perfexp--cpp-stlref--queue-inslast-remelem,177500000,5.128494,28.892924
    1221 2023-04-07 00:22:02,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-insfirst-inselem,184600000,5.024489,27.218250
    1222 2023-04-07 00:22:07,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--queue-insfirst-allhead,788100000,5.040492,6.395752
    1223 2023-04-07 00:22:12,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--queue-inslast-allhead,461130000,5.072015,10.999100
    1224 2023-04-07 00:22:17,5,5 100000 71 -1 5  ,./perfexp--cpp-stlref--queue-inslast-allhead,184600000,5.131083,27.795683
    1225 2023-04-07 00:22:22,2,5 100 72421 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-inselem,166568300,5.142531,30.873407
    1226 2023-04-07 00:22:27,4,5 100 72421 -1 4  ,./perfexp--lq-list--stack-insfirst-allhead,166568300,5.044477,30.284736
    1227 2023-04-07 00:22:32,1,5 100 72421 -1 1  ,./perfexp--upp-upp--stack-inslast-inselem,159326200,5.141698,32.271516
    1228 2023-04-07 00:22:37,5,5 1000 9051 -1 5  ,./perfexp--upp-upp--stack-insfirst-allhead,325836000,5.094147,15.634083
    1229 2023-04-07 00:22:42,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-inslast-inselem,477310000,5.069685,10.621368
    1230 2023-04-07 00:22:47,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-insfirst-inselem,130357800,5.145580,39.472743
    1231 2023-04-07 00:22:53,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-inselem,184600000,5.108413,27.672876
    1232 2023-04-07 00:22:58,2,5 100 72421 -1 2  ,./perfexp--upp-upp--stack-inslast-remelem,318652400,5.036010,15.804086
    1233 2023-04-07 00:23:03,1,5 10000 809 -1 1  ,./perfexp--lq-tailq--queue-insfirst-allhead,461130000,5.085039,11.027344
    1234 2023-04-07 00:23:08,2,5 100000 71 -1 2  ,./perfexp--cpp-stlref--queue-insfirst-remelem,184600000,5.172400,28.019502
    1235 2023-04-07 00:23:13,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-insfirst-remelem,674500000,5.047846,7.483834
    1236 2023-04-07 00:23:18,2,5 1000000 7 -1 2  ,./perfexp--lq-tailq--queue-insfirst-remelem,1309000000,5.005255,3.823724
    1237 2023-04-07 00:23:23,4,5 1000000 7 -1 4  ,./perfexp--cfa-cfa--queue-inslast-inselem,658000000,5.016826,7.624356
    1238 2023-04-07 00:23:28,4,5 1000 9051 -1 4  ,./perfexp--upp-upp--queue-inslast-remelem,515907000,5.025500,9.741097
    1239 2023-04-07 00:23:33,1,5 1000000 7 -1 1  ,./perfexp--cpp-stlref--stack-insfirst-allhead,231000000,5.117156,22.152190
    1240 2023-04-07 00:23:38,4,5 10000 809 -1 4  ,./perfexp--lq-tailq--stack-inslast-allhead,509670000,5.046288,9.901089
    1241 2023-04-07 00:23:43,3,5 100 72421 -1 3  ,./perfexp--lq-tailq--stack-insfirst-inselem,166568300,5.221492,31.347453
    1242 2023-04-07 00:23:49,1,5 100 72421 -1 1  ,./perfexp--lq-tailq--queue-insfirst-remelem,296926100,5.106445,17.197697
    1243 2023-04-07 00:23:54,2,5 100 72421 -1 2  ,./perfexp--lq-tailq--stack-insfirst-remelem,333136600,5.079056,15.246166
    1244 2023-04-07 00:23:59,4,5 100000 71 -1 4  ,./perfexp--cpp-stlref--queue-inslast-inselem,184600000,5.131130,27.795937
    1245 2023-04-07 00:24:04,2,5 100000 71 -1 2  ,./perfexp--lq-tailq--stack-inslast-inselem,880400000,5.012434,5.693360
    1246 2023-04-07 00:24:09,2,5 1000 9051 -1 2  ,./perfexp--upp-upp--queue-inslast-inselem,325836000,5.094942,15.636523
    1247 2023-04-07 00:24:14,1,5 1000 9051 -1 1  ,./perfexp--lq-tailq--queue-inslast-allhead,352989000,5.061654,14.339410
    1248 2023-04-07 00:24:19,5,5 100000 71 -1 5  ,./perfexp--lq-list--stack-insfirst-inselem,731300000,5.012975,6.854882
    1249 2023-04-07 00:24:24,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--queue-insfirst-allhead,325836000,5.139636,15.773690
    1250 2023-04-07 00:24:30,1,5 1000000 7 -1 1  ,./perfexp--cfa-cfa--stack-insfirst-allhead,665000000,5.024825,7.556128
    1251 2023-04-07 00:24:35,1,5 1000 9051 -1 1  ,./perfexp--cfa-cfa--stack-inslast-allhead,334887000,5.006794,14.950697
    1252 2023-04-07 00:24:40,3,5 1000 9051 -1 3  ,./perfexp--cfa-cfa--queue-insfirst-allhead,334887000,5.056826,15.100096
    1253 2023-04-07 00:24:45,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-inslast-allhead,352989000,5.047526,14.299386
    1254 2023-04-07 00:24:50,5,5 1000000 7 -1 5  ,./perfexp--upp-upp--stack-inslast-remelem,903000000,5.002012,5.539327
    1255 2023-04-07 00:24:55,1,5 100000 71 -1 1  ,./perfexp--lq-tailq--queue-insfirst-remelem,894600000,5.017897,5.609096
    1256 2023-04-07 00:25:00,5,5 100000 71 -1 5  ,./perfexp--cfa-cfa--queue-insfirst-inselem,546700000,5.050560,9.238266
    1257 2023-04-07 00:25:05,4,5 1000000 7 -1 4  ,./perfexp--cpp-stlref--stack-insfirst-remelem,231000000,5.084063,22.008931
    1258 2023-04-07 00:25:10,2,5 100 72421 -1 2  ,./perfexp--upp-upp--queue-inslast-inselem,137599900,5.086801,36.968057
    1259 2023-04-07 00:25:15,2,5 10000 809 -1 2  ,./perfexp--lq-tailq--queue-insfirst-remelem,720010000,5.029074,6.984728
    1260 2023-04-07 00:25:20,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--queue-inslast-remelem,534009000,5.024933,9.409828
    1261 2023-04-07 00:25:25,4,5 100 72421 -1 4  ,./perfexp--cfa-cfa--stack-insfirst-allhead,159326200,5.104904,32.040581
    1262 2023-04-07 00:25:30,3,5 10000 809 -1 3  ,./perfexp--upp-upp--queue-inslast-inselem,444950000,5.013109,11.266679
    1263 2023-04-07 00:25:35,3,5 100000 71 -1 3  ,./perfexp--cpp-stlref--stack-inslast-remelem,177500000,5.116110,28.823155
    1264 2023-04-07 00:25:41,2,5 10000 809 -1 2  ,./perfexp--cfa-cfa--stack-insfirst-inselem,477310000,5.017041,10.511075
    1265 2023-04-07 00:25:46,5,5 100 72421 -1 5  ,./perfexp--lq-tailq--queue-insfirst-allhead,130357800,5.060870,38.822917
    1266 2023-04-07 00:25:51,3,5 1000 9051 -1 3  ,./perfexp--upp-upp--stack-insfirst-inselem,307734000,5.017423,16.304416
    1267 2023-04-07 00:25:56,2,5 100 72421 -1 2  ,./perfexp--cfa-cfa--queue-inslast-remelem,289684000,5.096670,17.593895
    1268 2023-04-07 00:26:01,1,5 1000000 7 -1 1  ,./perfexp--lq-tailq--stack-insfirst-inselem,581000000,5.003206,8.611370
    1269 2023-04-07 00:26:06,3,5 100000 71 -1 3  ,./perfexp--cfa-cfa--stack-inslast-remelem,1015300000,5.026273,4.950530
    1270 2023-04-07 00:26:11,3,5 100 72421 -1 3  ,./perfexp--upp-upp--stack-insfirst-allhead,159326200,5.149416,32.319957
    1271 2023-04-07 00:26:16,4,5 1000 9051 -1 4  ,./perfexp--lq-tailq--stack-inslast-inselem,316785000,5.019917,15.846448
    1272 2023-04-07 00:26:21,4,5 10000 809 -1 4  ,./perfexp--cfa-cfa--queue-inslast-remelem,687650000,5.023642,7.305522
    1273 2023-04-07 00:26:26,4,5 100000 71 -1 4  ,./perfexp--upp-upp--stack-insfirst-allhead,788100000,5.021043,6.371073
    1274 2023-04-07 00:26:31,3,5 100000 71 -1 3  ,./perfexp--lq-tailq--stack-inslast-remelem,1320600000,5.018016,3.799800
    1275 2023-04-07 00:26:36,3,5 100000 71 -1 3  ,./perfexp--upp-upp--queue-inslast-remelem,667400000,5.007560,7.503087
     12023-04-03 15:39:25,5,./perfexp--lq-tailq--stack-insfirst-inselem,443000000,5.005379,11.298824
     22023-04-03 15:39:30,3,./perfexp--lq-tailq--queue-inslast-allhead,570000000,5.007309,8.784753
     32023-04-03 15:39:35,3,./perfexp--lq-tailq--stack-inslast-inselem,606000000,5.000877,8.252272
     42023-04-03 15:39:40,2,./perfexp--upp-upp--stack-insfirst-remelem,657000000,5.006698,7.620545
     52023-04-03 15:39:45,1,./perfexp--lq-tailq--stack-inslast-allhead,617000000,5.002409,8.107632
     62023-04-03 15:39:50,2,./perfexp--lq-tailq--stack-inslast-inselem,607000000,5.007467,8.249534
     72023-04-03 15:39:55,3,./perfexp--upp-upp--stack-inslast-allhead,572000000,5.002847,8.746236
     82023-04-03 15:40:01,5,./perfexp--lq-tailq--queue-insfirst-allhead,536000000,5.000997,9.330218
     92023-04-03 15:40:06,5,./perfexp--upp-upp--queue-insfirst-allhead,458000000,5.009543,10.937867
     102023-04-03 15:40:11,5,./perfexp--cfa-cfa--queue-inslast-remelem,710000000,5.003976,7.047854
     112023-04-03 15:40:16,1,./perfexp--cpp-stlref--stack-inslast-allhead,166000000,5.002189,30.133669
     122023-04-03 15:40:21,2,./perfexp--cfa-cfa--stack-inslast-allhead,547000000,5.004804,9.149550
     132023-04-03 15:40:26,1,./perfexp--lq-tailq--stack-insfirst-remelem,713000000,5.006425,7.021634
     142023-04-03 15:40:31,4,./perfexp--upp-upp--stack-inslast-allhead,567000000,5.003325,8.824206
     152023-04-03 15:40:36,2,./perfexp--upp-upp--stack-inslast-inselem,489000000,5.000271,10.225503
     162023-04-03 15:40:41,2,./perfexp--cpp-stlref--stack-inslast-remelem,158000000,5.017243,31.754703
     172023-04-03 15:40:46,5,./perfexp--upp-upp--stack-inslast-allhead,549000000,5.005594,9.117658
     182023-04-03 15:40:51,3,./perfexp--upp-upp--queue-inslast-inselem,487000000,5.003425,10.273973
     192023-04-03 15:40:56,4,./perfexp--cfa-cfa--stack-inslast-inselem,538000000,5.004632,9.302290
     202023-04-03 15:41:01,3,./perfexp--cfa-cfa--queue-insfirst-remelem,718000000,5.006064,6.972234
     212023-04-03 15:41:06,3,./perfexp--cpp-stlref--queue-inslast-inselem,167000000,5.027628,30.105557
     222023-04-03 15:41:11,5,./perfexp--cfa-cfa--queue-insfirst-allhead,510000000,5.007280,9.818196
     232023-04-03 15:41:16,5,./perfexp--lq-list--stack-insfirst-inselem,462000000,5.010782,10.845848
     242023-04-03 15:41:21,5,./perfexp--lq-tailq--queue-inslast-allhead,565000000,5.008089,8.863874
     252023-04-03 15:41:26,2,./perfexp--cpp-stlref--queue-insfirst-inselem,167000000,5.002444,29.954754
     262023-04-03 15:41:31,3,./perfexp--cpp-stlref--queue-insfirst-allhead,172000000,5.012068,29.139930
     272023-04-03 15:41:36,2,./perfexp--upp-upp--queue-insfirst-inselem,465000000,5.003175,10.759516
     282023-04-03 15:41:41,4,./perfexp--lq-tailq--queue-inslast-remelem,535000000,5.003059,9.351512
     292023-04-03 15:41:46,4,./perfexp--cpp-stlref--queue-inslast-remelem,166000000,5.000510,30.123554
     302023-04-03 15:41:51,3,./perfexp--lq-tailq--stack-insfirst-remelem,710000000,5.003302,7.046904
     312023-04-03 15:41:56,1,./perfexp--lq-tailq--queue-insfirst-allhead,539000000,5.005817,9.287230
     322023-04-03 15:42:01,5,./perfexp--upp-upp--queue-insfirst-remelem,608000000,5.006322,8.234082
     332023-04-03 15:42:06,2,./perfexp--cpp-stlref--stack-insfirst-inselem,165000000,5.002635,30.319000
     342023-04-03 15:42:11,5,./perfexp--cfa-cfa--queue-insfirst-inselem,510000000,5.009883,9.823300
     352023-04-03 15:42:16,1,./perfexp--cfa-cfa--stack-insfirst-allhead,552000000,5.000119,9.058187
     362023-04-03 15:42:21,1,./perfexp--lq-list--stack-insfirst-remelem,712000000,5.005641,7.030395
     372023-04-03 15:42:26,3,./perfexp--upp-upp--stack-inslast-remelem,685000000,5.000472,7.299959
     382023-04-03 15:42:31,1,./perfexp--lq-tailq--stack-insfirst-inselem,444000000,5.008487,11.280376
     392023-04-03 15:42:37,2,./perfexp--cpp-stlref--stack-inslast-allhead,161000000,5.025004,31.211205
     402023-04-03 15:42:42,3,./perfexp--cfa-cfa--stack-inslast-allhead,545000000,5.002831,9.179506
     412023-04-03 15:42:47,1,./perfexp--upp-upp--stack-inslast-allhead,567000000,5.007839,8.832168
     422023-04-03 15:42:52,5,./perfexp--cpp-stlref--stack-insfirst-inselem,165000000,5.025721,30.458915
     432023-04-03 15:42:57,3,./perfexp--lq-tailq--queue-insfirst-allhead,537000000,5.005007,9.320311
     442023-04-03 15:43:02,5,./perfexp--cfa-cfa--stack-insfirst-remelem,759000000,5.000831,6.588710
     452023-04-03 15:43:07,4,./perfexp--cpp-stlref--queue-insfirst-remelem,170000000,5.016844,29.510847
     462023-04-03 15:43:12,2,./perfexp--upp-upp--queue-insfirst-remelem,664000000,5.002228,7.533476
     472023-04-03 15:43:17,4,./perfexp--lq-tailq--queue-insfirst-allhead,537000000,5.005068,9.320425
     482023-04-03 15:43:22,3,./perfexp--lq-tailq--stack-insfirst-inselem,444000000,5.009009,11.281552
     492023-04-03 15:43:27,5,./perfexp--cfa-cfa--stack-inslast-inselem,538000000,5.000494,9.294599
     502023-04-03 15:43:32,3,./perfexp--cpp-stlref--stack-insfirst-inselem,166000000,5.023027,30.259199
     512023-04-03 15:43:37,2,./perfexp--cpp-stlref--queue-insfirst-allhead,168000000,5.019833,29.879958
     522023-04-03 15:43:42,1,./perfexp--upp-upp--stack-inslast-inselem,491000000,5.000784,10.184896
     532023-04-03 15:43:47,3,./perfexp--cpp-stlref--stack-inslast-remelem,159000000,5.025671,31.607994
     542023-04-03 15:43:52,1,./perfexp--cfa-cfa--stack-inslast-remelem,768000000,5.003314,6.514732
     552023-04-03 15:43:57,5,./perfexp--cfa-cfa--queue-insfirst-remelem,718000000,5.000123,6.963960
     562023-04-03 15:44:02,4,./perfexp--cfa-cfa--queue-inslast-remelem,706000000,5.005028,7.089275
     572023-04-03 15:44:07,1,./perfexp--lq-tailq--stack-insfirst-allhead,594000000,5.002014,8.420899
     582023-04-03 15:44:12,3,./perfexp--lq-tailq--queue-insfirst-inselem,437000000,5.006085,11.455572
     592023-04-03 15:44:17,2,./perfexp--lq-tailq--stack-inslast-remelem,826000000,5.000880,6.054334
     602023-04-03 15:44:22,3,./perfexp--upp-upp--stack-inslast-inselem,492000000,5.009566,10.182045
     612023-04-03 15:44:27,2,./perfexp--upp-upp--stack-inslast-remelem,697000000,5.000839,7.174805
     622023-04-03 15:44:32,2,./perfexp--cfa-cfa--stack-insfirst-remelem,756000000,5.000070,6.613849
     632023-04-03 15:44:37,5,./perfexp--lq-tailq--stack-insfirst-remelem,717000000,5.007000,6.983264
     642023-04-03 15:44:43,4,./perfexp--cfa-cfa--queue-insfirst-inselem,507000000,5.000763,9.863438
     652023-04-03 15:44:48,1,./perfexp--cpp-stlref--queue-inslast-inselem,161000000,5.027524,31.226857
     662023-04-03 15:44:53,4,./perfexp--cfa-cfa--queue-insfirst-allhead,508000000,5.009748,9.861709
     672023-04-03 15:44:58,2,./perfexp--lq-tailq--stack-insfirst-allhead,595000000,5.001977,8.406684
     682023-04-03 15:45:03,4,./perfexp--lq-tailq--queue-insfirst-inselem,431000000,5.000710,11.602575
     692023-04-03 15:45:08,3,./perfexp--upp-upp--stack-insfirst-allhead,601000000,5.002087,8.322940
     702023-04-03 15:45:13,5,./perfexp--lq-tailq--stack-inslast-remelem,828000000,5.002858,6.042099
     712023-04-03 15:45:18,4,./perfexp--upp-upp--stack-insfirst-allhead,520000000,5.008182,9.631119
     722023-04-03 15:45:23,5,./perfexp--lq-tailq--queue-inslast-remelem,529000000,5.000836,9.453376
     732023-04-03 15:45:28,4,./perfexp--cfa-cfa--queue-insfirst-remelem,718000000,5.002385,6.967110
     742023-04-03 15:45:33,4,./perfexp--cpp-stlref--stack-inslast-allhead,162000000,5.021934,30.999593
     752023-04-03 15:45:38,5,./perfexp--cpp-stlref--stack-inslast-inselem,160000000,5.015857,31.349106
     762023-04-03 15:45:43,3,./perfexp--cfa-cfa--stack-inslast-inselem,539000000,5.008154,9.291566
     772023-04-03 15:45:48,3,./perfexp--cpp-stlref--stack-inslast-inselem,163000000,5.010634,30.740086
     782023-04-03 15:45:53,5,./perfexp--cpp-stlref--stack-insfirst-allhead,166000000,5.018746,30.233410
     792023-04-03 15:45:58,1,./perfexp--cfa-cfa--queue-inslast-remelem,710000000,5.006924,7.052006
     802023-04-03 15:46:03,1,./perfexp--cpp-stlref--stack-inslast-remelem,156000000,5.000411,32.053917
     812023-04-03 15:46:08,2,./perfexp--lq-tailq--stack-inslast-allhead,617000000,5.005184,8.112130
     822023-04-03 15:46:13,1,./perfexp--cfa-cfa--queue-insfirst-remelem,719000000,5.003622,6.959140
     832023-04-03 15:46:18,4,./perfexp--lq-tailq--queue-inslast-allhead,564000000,5.000835,8.866729
     842023-04-03 15:46:23,1,./perfexp--lq-tailq--queue-insfirst-remelem,759000000,5.001690,6.589842
     852023-04-03 15:46:28,3,./perfexp--cpp-stlref--queue-insfirst-remelem,169000000,5.025107,29.734361
     862023-04-03 15:46:33,1,./perfexp--cpp-stlref--stack-insfirst-allhead,166000000,5.027112,30.283807
     872023-04-03 15:46:38,1,./perfexp--cpp-stlref--queue-insfirst-remelem,169000000,5.006199,29.622479
     882023-04-03 15:46:44,2,./perfexp--upp-upp--stack-inslast-allhead,566000000,5.000864,8.835449
     892023-04-03 15:46:49,2,./perfexp--cfa-cfa--queue-inslast-allhead,517000000,5.009262,9.689095
     902023-04-03 15:46:54,2,./perfexp--lq-tailq--stack-insfirst-inselem,445000000,5.000014,11.235987
     912023-04-03 15:46:59,3,./perfexp--lq-list--stack-insfirst-remelem,713000000,5.003234,7.017158
     922023-04-03 15:47:04,3,./perfexp--lq-tailq--queue-insfirst-remelem,759000000,5.001448,6.589523
     932023-04-03 15:47:09,4,./perfexp--cpp-stlref--stack-inslast-inselem,164000000,5.002294,30.501793
     942023-04-03 15:47:14,3,./perfexp--cpp-stlref--stack-insfirst-allhead,166000000,5.015560,30.214217
     952023-04-03 15:47:19,2,./perfexp--lq-tailq--queue-inslast-remelem,533000000,5.003926,9.388229
     962023-04-03 15:47:24,2,./perfexp--cpp-stlref--stack-inslast-inselem,164000000,5.013968,30.572976
     972023-04-03 15:47:29,3,./perfexp--lq-tailq--stack-inslast-remelem,833000000,5.003961,6.007156
     982023-04-03 15:47:34,2,./perfexp--cfa-cfa--stack-insfirst-allhead,552000000,5.005105,9.067219
     992023-04-03 15:47:39,5,./perfexp--upp-upp--queue-inslast-allhead,539000000,5.003768,9.283429
     1002023-04-03 15:47:44,2,./perfexp--cpp-stlref--queue-inslast-remelem,163000000,5.022589,30.813429
     1012023-04-03 15:47:49,5,./perfexp--cpp-stlref--queue-inslast-inselem,165000000,5.027219,30.467994
     1022023-04-03 15:47:54,5,./perfexp--cpp-stlref--queue-inslast-allhead,170000000,5.024832,29.557835
     1032023-04-03 15:47:59,3,./perfexp--cpp-stlref--queue-inslast-remelem,165000000,5.027366,30.468885
     1042023-04-03 15:48:04,1,./perfexp--cfa-cfa--stack-inslast-inselem,536000000,5.005369,9.338375
     1052023-04-03 15:48:09,1,./perfexp--cpp-stlref--queue-inslast-remelem,162000000,5.023907,31.011772
     1062023-04-03 15:48:14,4,./perfexp--cpp-stlref--stack-insfirst-inselem,165000000,5.002599,30.318782
     1072023-04-03 15:48:19,4,./perfexp--cfa-cfa--queue-inslast-inselem,519000000,5.007842,9.649021
     1082023-04-03 15:48:24,4,./perfexp--cpp-stlref--queue-insfirst-inselem,170000000,5.028952,29.582071
     1092023-04-03 15:48:29,1,./perfexp--lq-tailq--queue-insfirst-inselem,433000000,5.010306,11.571145
     1102023-04-03 15:48:34,2,./perfexp--cfa-cfa--queue-inslast-remelem,709000000,5.006604,7.061501
     1112023-04-03 15:48:39,4,./perfexp--upp-upp--stack-inslast-inselem,491000000,5.004649,10.192768
     1122023-04-03 15:48:44,4,./perfexp--lq-tailq--stack-inslast-inselem,606000000,5.003287,8.256249
     1132023-04-03 15:48:49,5,./perfexp--lq-tailq--queue-inslast-inselem,557000000,5.007731,8.990540
     1142023-04-03 15:48:54,4,./perfexp--upp-upp--queue-insfirst-inselem,460000000,5.002636,10.875296
     1152023-04-03 15:48:59,4,./perfexp--upp-upp--queue-inslast-allhead,537000000,5.005155,9.320587
     1162023-04-03 15:49:04,2,./perfexp--upp-upp--queue-inslast-allhead,538000000,5.007986,9.308524
     1172023-04-03 15:49:10,5,./perfexp--upp-upp--stack-insfirst-inselem,526000000,5.007934,9.520787
     1182023-04-03 15:49:15,5,./perfexp--cpp-stlref--stack-inslast-allhead,165000000,5.014335,30.389909
     1192023-04-03 15:49:20,5,./perfexp--cpp-stlref--stack-insfirst-remelem,156000000,5.013451,32.137506
     1202023-04-03 15:49:25,3,./perfexp--cfa-cfa--stack-insfirst-inselem,548000000,5.000615,9.125210
     1212023-04-03 15:49:30,4,./perfexp--cfa-cfa--stack-inslast-remelem,769000000,5.001464,6.503854
     1222023-04-03 15:49:35,1,./perfexp--upp-upp--queue-inslast-remelem,603000000,5.003718,8.298040
     1232023-04-03 15:49:40,2,./perfexp--cpp-stlref--queue-inslast-inselem,164000000,5.012683,30.565140
     1242023-04-03 15:49:45,5,./perfexp--upp-upp--stack-insfirst-remelem,642000000,5.004144,7.794617
     1252023-04-03 15:49:50,4,./perfexp--upp-upp--queue-inslast-remelem,606000000,5.001222,8.252842
     1262023-04-03 15:49:55,2,./perfexp--cpp-stlref--stack-insfirst-remelem,158000000,5.016260,31.748481
     1272023-04-03 15:50:00,5,./perfexp--cfa-cfa--queue-inslast-allhead,518000000,5.003133,9.658558
     1282023-04-03 15:50:05,2,./perfexp--upp-upp--queue-inslast-remelem,610000000,5.003194,8.201957
     1292023-04-03 15:50:10,4,./perfexp--lq-tailq--stack-inslast-remelem,829000000,5.004086,6.036292
     1302023-04-03 15:50:15,5,./perfexp--lq-tailq--stack-insfirst-allhead,596000000,5.008331,8.403240
     1312023-04-03 15:50:20,3,./perfexp--cpp-stlref--stack-insfirst-remelem,157000000,5.028128,32.026293
     1322023-04-03 15:50:25,1,./perfexp--cfa-cfa--stack-inslast-allhead,545000000,5.003736,9.181167
     1332023-04-03 15:50:30,2,./perfexp--cpp-stlref--stack-insfirst-allhead,166000000,5.011507,30.189801
     1342023-04-03 15:50:35,2,./perfexp--lq-list--stack-insfirst-inselem,441000000,5.004092,11.347147
     1352023-04-03 15:50:40,1,./perfexp--lq-tailq--stack-inslast-remelem,831000000,5.002214,6.019511
     1362023-04-03 15:50:45,2,./perfexp--cfa-cfa--stack-insfirst-inselem,549000000,5.006757,9.119776
     1372023-04-03 15:50:51,4,./perfexp--upp-upp--stack-inslast-remelem,707000000,5.000598,7.072982
     1382023-04-03 15:50:56,2,./perfexp--cfa-cfa--queue-inslast-inselem,519000000,5.000666,9.635195
     1392023-04-03 15:51:01,4,./perfexp--lq-tailq--stack-insfirst-remelem,715000000,5.002704,6.996789
     1402023-04-03 15:51:06,3,./perfexp--cfa-cfa--stack-inslast-remelem,772000000,5.003203,6.480833
     1412023-04-03 15:51:11,1,./perfexp--upp-upp--stack-insfirst-inselem,524000000,5.006068,9.553565
     1422023-04-03 15:51:16,2,./perfexp--upp-upp--queue-insfirst-allhead,510000000,5.009613,9.822771
     1432023-04-03 15:51:21,3,./perfexp--lq-tailq--queue-inslast-remelem,530000000,5.006810,9.446811
     1442023-04-03 15:51:26,4,./perfexp--cpp-stlref--stack-insfirst-remelem,159000000,5.007889,31.496157
     1452023-04-03 15:51:31,4,./perfexp--upp-upp--queue-insfirst-remelem,661000000,5.002903,7.568688
     1462023-04-03 15:51:36,2,./perfexp--lq-tailq--queue-insfirst-inselem,432000000,5.003819,11.582914
     1472023-04-03 15:51:41,1,./perfexp--upp-upp--stack-insfirst-remelem,655000000,5.007278,7.644699
     1482023-04-03 15:51:46,3,./perfexp--lq-tailq--stack-insfirst-allhead,596000000,5.002249,8.393035
     1492023-04-03 15:51:51,5,./perfexp--upp-upp--stack-inslast-inselem,493000000,5.008268,10.158759
     1502023-04-03 15:51:56,5,./perfexp--cfa-cfa--queue-inslast-inselem,520000000,5.008160,9.631077
     1512023-04-03 15:52:01,2,./perfexp--cfa-cfa--queue-insfirst-allhead,509000000,5.001747,9.826615
     1522023-04-03 15:52:06,2,./perfexp--cfa-cfa--queue-insfirst-remelem,717000000,5.003431,6.978286
     1532023-04-03 15:52:11,5,./perfexp--cfa-cfa--stack-insfirst-inselem,548000000,5.005236,9.133642
     1542023-04-03 15:52:16,5,./perfexp--upp-upp--stack-insfirst-allhead,589000000,5.008330,8.503107
     1552023-04-03 15:52:21,3,./perfexp--upp-upp--queue-inslast-remelem,606000000,5.000791,8.252130
     1562023-04-03 15:52:26,2,./perfexp--cfa-cfa--queue-insfirst-inselem,509000000,5.005662,9.834306
     1572023-04-03 15:52:31,2,./perfexp--cpp-stlref--queue-insfirst-remelem,170000000,5.014890,29.499353
     1582023-04-03 15:52:36,4,./perfexp--upp-upp--stack-insfirst-inselem,526000000,5.008703,9.522249
     1592023-04-03 15:52:42,3,./perfexp--lq-list--stack-insfirst-inselem,442000000,5.009383,11.333446
     1602023-04-03 15:52:47,3,./perfexp--cfa-cfa--queue-inslast-inselem,520000000,5.007789,9.630363
     1612023-04-03 15:52:52,5,./perfexp--cpp-stlref--queue-insfirst-inselem,167000000,5.011863,30.011156
     1622023-04-03 15:52:57,3,./perfexp--cfa-cfa--stack-insfirst-remelem,761000000,5.004427,6.576120
     1632023-04-03 15:53:02,1,./perfexp--lq-tailq--queue-inslast-allhead,569000000,5.000007,8.787359
     1642023-04-03 15:53:07,4,./perfexp--cfa-cfa--stack-insfirst-remelem,755000000,5.006075,6.630563
     1652023-04-03 15:53:12,1,./perfexp--cfa-cfa--queue-insfirst-allhead,508000000,5.007775,9.857825
     1662023-04-03 15:53:17,3,./perfexp--upp-upp--queue-insfirst-remelem,662000000,5.003549,7.558231
     1672023-04-03 15:53:22,1,./perfexp--upp-upp--stack-insfirst-allhead,602000000,5.003572,8.311581
     1682023-04-03 15:53:27,5,./perfexp--lq-tailq--stack-inslast-allhead,617000000,5.001483,8.106131
     1692023-04-03 15:53:32,4,./perfexp--lq-list--stack-insfirst-inselem,442000000,5.010176,11.335240
     1702023-04-03 15:53:37,4,./perfexp--cpp-stlref--stack-insfirst-allhead,166000000,5.013545,30.202078
     1712023-04-03 15:53:42,5,./perfexp--cfa-cfa--stack-insfirst-allhead,552000000,5.000744,9.059319
     1722023-04-03 15:53:47,4,./perfexp--lq-tailq--queue-insfirst-remelem,765000000,5.002711,6.539492
     1732023-04-03 15:53:52,3,./perfexp--cfa-cfa--stack-insfirst-allhead,552000000,5.007654,9.071837
     1742023-04-03 15:53:57,1,./perfexp--upp-upp--queue-insfirst-remelem,660000000,5.001139,7.577483
     1752023-04-03 15:54:02,3,./perfexp--cpp-stlref--queue-insfirst-inselem,169000000,5.013091,29.663260
     1762023-04-03 15:54:07,2,./perfexp--lq-list--stack-insfirst-remelem,713000000,5.006786,7.022140
     1772023-04-03 15:54:12,1,./perfexp--lq-tailq--stack-inslast-inselem,606000000,5.002385,8.254761
     1782023-04-03 15:54:17,4,./perfexp--upp-upp--queue-inslast-inselem,487000000,5.003862,10.274871
     1792023-04-03 15:54:22,1,./perfexp--lq-list--stack-insfirst-allhead,593000000,5.002939,8.436659
     1802023-04-03 15:54:27,2,./perfexp--lq-tailq--queue-inslast-allhead,565000000,5.004251,8.857081
     1812023-04-03 15:54:32,5,./perfexp--lq-list--stack-insfirst-allhead,592000000,5.001007,8.447647
     1822023-04-03 15:54:37,3,./perfexp--upp-upp--queue-inslast-allhead,538000000,5.007986,9.308524
     1832023-04-03 15:54:42,4,./perfexp--lq-tailq--stack-inslast-allhead,617000000,5.004785,8.111483
     1842023-04-03 15:54:47,2,./perfexp--lq-tailq--queue-insfirst-allhead,537000000,5.000866,9.312600
     1852023-04-03 15:54:52,3,./perfexp--lq-tailq--stack-inslast-allhead,593000000,5.001259,8.433826
     1862023-04-03 15:54:57,5,./perfexp--lq-tailq--stack-inslast-inselem,607000000,5.008090,8.250560
     1872023-04-03 15:55:02,1,./perfexp--cfa-cfa--queue-inslast-inselem,520000000,5.007405,9.629625
     1882023-04-03 15:55:07,2,./perfexp--lq-list--stack-insfirst-allhead,590000000,5.000838,8.475997
     1892023-04-03 15:55:12,3,./perfexp--upp-upp--stack-insfirst-inselem,525000000,5.004319,9.532036
     1902023-04-03 15:55:17,5,./perfexp--cpp-stlref--queue-insfirst-remelem,170000000,5.018299,29.519406
     1912023-04-03 15:55:22,3,./perfexp--lq-tailq--queue-inslast-inselem,557000000,5.000287,8.977176
     1922023-04-03 15:55:28,1,./perfexp--lq-tailq--queue-inslast-inselem,550000000,5.002507,9.095467
     1932023-04-03 15:55:33,4,./perfexp--lq-tailq--queue-inslast-inselem,557000000,5.002020,8.980287
     1942023-04-03 15:55:38,1,./perfexp--cfa-cfa--queue-insfirst-inselem,507000000,5.001630,9.865148
     1952023-04-03 15:55:43,1,./perfexp--cpp-stlref--stack-inslast-inselem,166000000,5.029390,30.297530
     1962023-04-03 15:55:48,2,./perfexp--upp-upp--queue-inslast-inselem,486000000,5.003020,10.294280
     1972023-04-03 15:55:53,3,./perfexp--upp-upp--queue-insfirst-inselem,461000000,5.000073,10.846145
     1982023-04-03 15:55:58,5,./perfexp--cfa-cfa--stack-inslast-allhead,547000000,5.004262,9.148559
     1992023-04-03 15:56:03,1,./perfexp--lq-tailq--queue-inslast-remelem,546000000,5.005073,9.166800
     2002023-04-03 15:56:08,3,./perfexp--lq-list--stack-insfirst-allhead,591000000,5.003465,8.466100
     2012023-04-03 15:56:13,2,./perfexp--lq-tailq--stack-insfirst-remelem,716000000,5.001052,6.984709
     2022023-04-03 15:56:18,4,./perfexp--cfa-cfa--queue-inslast-allhead,516000000,5.003638,9.696973
     2032023-04-03 15:56:23,1,./perfexp--cpp-stlref--stack-insfirst-remelem,159000000,5.008347,31.499038
     2042023-04-03 15:56:28,4,./perfexp--lq-tailq--stack-insfirst-inselem,445000000,5.007219,11.252178
     2052023-04-03 15:56:33,2,./perfexp--lq-tailq--queue-insfirst-remelem,763000000,5.000451,6.553671
     2062023-04-03 15:56:38,1,./perfexp--upp-upp--queue-insfirst-inselem,461000000,5.002222,10.850807
     2072023-04-03 15:56:43,1,./perfexp--cpp-stlref--queue-insfirst-inselem,167000000,5.019099,30.054485
     2082023-04-03 15:56:48,4,./perfexp--cfa-cfa--stack-insfirst-allhead,553000000,5.005063,9.050747
     2092023-04-03 15:56:53,2,./perfexp--lq-tailq--queue-inslast-inselem,557000000,5.001068,8.978578
     2102023-04-03 15:56:58,3,./perfexp--upp-upp--stack-insfirst-remelem,644000000,5.005232,7.772099
     2112023-04-03 15:57:03,2,./perfexp--cfa-cfa--stack-inslast-inselem,538000000,5.004795,9.302593
     2122023-04-03 15:57:08,4,./perfexp--cpp-stlref--stack-inslast-remelem,158000000,5.004902,31.676595
     2132023-04-03 15:57:13,1,./perfexp--upp-upp--queue-inslast-allhead,539000000,5.002228,9.280571
     2142023-04-03 15:57:18,5,./perfexp--cpp-stlref--stack-inslast-remelem,159000000,5.019823,31.571214
     2152023-04-03 15:57:23,1,./perfexp--upp-upp--queue-insfirst-allhead,505000000,5.008103,9.917036
     2162023-04-03 15:57:29,5,./perfexp--lq-tailq--queue-insfirst-inselem,415000000,5.000368,12.049080
     2172023-04-03 15:57:34,3,./perfexp--cfa-cfa--queue-insfirst-inselem,509000000,5.003350,9.829764
     2182023-04-03 15:57:39,1,./perfexp--upp-upp--stack-inslast-remelem,687000000,5.005699,7.286316
     2192023-04-03 15:57:44,2,./perfexp--upp-upp--stack-insfirst-inselem,526000000,5.004338,9.513951
     2202023-04-03 15:57:49,1,./perfexp--upp-upp--queue-inslast-inselem,489000000,5.001246,10.227497
     2212023-04-03 15:57:54,3,./perfexp--cfa-cfa--queue-inslast-allhead,516000000,5.004492,9.698628
     2222023-04-03 15:57:59,5,./perfexp--cfa-cfa--stack-inslast-remelem,772000000,5.002201,6.479535
     2232023-04-03 15:58:04,5,./perfexp--lq-tailq--queue-insfirst-remelem,762000000,5.002834,6.565399
     2242023-04-03 15:58:09,1,./perfexp--lq-list--stack-insfirst-inselem,441000000,5.003211,11.345150
     2252023-04-03 15:58:14,1,./perfexp--cfa-cfa--queue-inslast-allhead,516000000,5.006598,9.702709
     2262023-04-03 15:58:19,2,./perfexp--upp-upp--stack-insfirst-allhead,602000000,5.000444,8.306385
     2272023-04-03 15:58:24,3,./perfexp--cfa-cfa--queue-inslast-remelem,702000000,5.005657,7.130566
     2282023-04-03 15:58:29,4,./perfexp--cpp-stlref--queue-inslast-inselem,166000000,5.026702,30.281337
     2292023-04-03 15:58:34,4,./perfexp--upp-upp--stack-insfirst-remelem,630000000,5.005706,7.945565
     2302023-04-03 15:58:39,1,./perfexp--cfa-cfa--stack-insfirst-remelem,759000000,5.004132,6.593059
     2312023-04-03 15:58:44,5,./perfexp--cpp-stlref--queue-inslast-remelem,167000000,5.024779,30.088497
     2322023-04-03 15:58:49,5,./perfexp--upp-upp--queue-inslast-inselem,485000000,5.001876,10.313146
     2332023-04-03 15:58:54,4,./perfexp--lq-tailq--stack-insfirst-allhead,595000000,5.003147,8.408650
     2342023-04-03 15:58:59,5,./perfexp--upp-upp--stack-inslast-remelem,680000000,5.001317,7.354878
     2352023-04-03 15:59:04,5,./perfexp--upp-upp--queue-insfirst-inselem,462000000,5.006965,10.837587
     2362023-04-03 15:59:09,3,./perfexp--cpp-stlref--queue-inslast-allhead,172000000,5.023178,29.204523
     2372023-04-03 15:59:14,4,./perfexp--cpp-stlref--queue-insfirst-allhead,173000000,5.020339,29.019301
     2382023-04-03 15:59:19,5,./perfexp--lq-list--stack-insfirst-remelem,712000000,5.002571,7.026083
     2392023-04-03 15:59:24,4,./perfexp--upp-upp--queue-insfirst-allhead,506000000,5.000700,9.882806
     2402023-04-03 15:59:29,4,./perfexp--cpp-stlref--queue-inslast-allhead,167000000,5.011863,30.011156
     2412023-04-03 15:59:34,2,./perfexp--cfa-cfa--stack-inslast-remelem,771000000,5.001426,6.486934
     2422023-04-03 15:59:39,4,./perfexp--cfa-cfa--stack-insfirst-inselem,550000000,5.005721,9.101311
     2432023-04-03 15:59:44,1,./perfexp--cfa-cfa--stack-insfirst-inselem,551000000,5.002555,9.079047
     2442023-04-03 15:59:49,4,./perfexp--cfa-cfa--stack-inslast-allhead,546000000,5.001532,9.160315
     2452023-04-03 15:59:54,2,./perfexp--cpp-stlref--queue-inslast-allhead,161000000,5.006152,31.094112
     2462023-04-03 15:59:59,3,./perfexp--cpp-stlref--stack-inslast-allhead,166000000,5.020481,30.243861
     2472023-04-03 16:00:04,1,./perfexp--cpp-stlref--stack-insfirst-inselem,165000000,5.020233,30.425655
     2482023-04-03 16:00:09,3,./perfexp--cfa-cfa--queue-insfirst-allhead,509000000,5.003864,9.830774
     2492023-04-03 16:00:14,4,./perfexp--lq-list--stack-insfirst-allhead,593000000,5.002670,8.436206
     2502023-04-03 16:00:19,1,./perfexp--cpp-stlref--queue-insfirst-allhead,170000000,5.005779,29.445759
     2512023-04-03 16:00:25,1,./perfexp--cpp-stlref--queue-inslast-allhead,168000000,5.021567,29.890280
     2522023-04-03 16:00:30,5,./perfexp--cpp-stlref--queue-insfirst-allhead,170000000,5.030049,29.588524
     2532023-04-03 16:00:35,5,./perfexp--upp-upp--queue-inslast-remelem,616000000,5.007578,8.129185
     2542023-04-03 16:00:40,4,./perfexp--lq-list--stack-insfirst-remelem,713000000,5.002819,7.016576
     2552023-04-03 16:00:45,3,./perfexp--upp-upp--queue-insfirst-allhead,501000000,5.007947,9.995902
  • driver/cfa.cc

    r6e1e2d0 ra50fdfb  
    1010// Created On       : Tue Aug 20 13:44:49 2002
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 10 21:16:00 2023
    13 // Update Count     : 476
     12// Last Modified On : Tue Feb 14 22:46:38 2023
     13// Update Count     : 470
    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.
    5046        if ( putenv( (char *)( *new string( string( __CFA_FLAGPREFIX__ + to_string( flags++ ) + "__=" ) + arg ) ).c_str() ) ) {
    5147                cerr << argv[0] << " error, cannot set environment variable." << endl;
     
    202198                                } // if
    203199                        } else if ( arg == "-CFA" ) {
    204                                 CFA_flag = true;                                                // strip -CFA flag
     200                                CFA_flag = true;                                                // strip the -CFA flag
    205201                                link = false;
    206202                                args[nargs++] = "-fsyntax-only";                // stop after stage 2
    207203                        } else if ( arg == "-debug" ) {
    208                                 debug = true;                                                   // strip debug flag
     204                                debug = true;                                                   // strip the debug flag
    209205                        } else if ( arg == "-nodebug" ) {
    210                                 debug = false;                                                  // strip nodebug flag
     206                                debug = false;                                                  // strip the nodebug flag
    211207                        } else if ( arg == "-quiet" ) {
    212                                 quiet = true;                                                   // strip quiet flag
     208                                quiet = true;                                                   // strip the quiet flag
    213209                        } else if ( arg == "-noquiet" ) {
    214                                 quiet = false;                                                  // strip noquiet flag
    215                         } else if ( arg == "-invariant" ) {
    216                                 Putenv( argv, "-" + arg );
    217                         } else if ( arg == "--invariant" ) {
    218                                 Putenv( argv, arg );
     210                                quiet = false;                                                  // strip the noquiet flag
    219211                        } else if ( arg == "-no-include-stdhdr" ) {
    220                                 noincstd_flag = true;                                   // strip no-include-stdhdr flag
     212                                noincstd_flag = true;                                   // strip the no-include-stdhdr flag
    221213                        } else if ( arg == "-nolib" ) {
    222                                 nolib = true;                                                   // strip nolib flag
     214                                nolib = true;                                                   // strip the nolib flag
    223215                        } else if ( arg == "-help" ) {
    224                                 help = true;                                                    // strip help flag
     216                                help = true;                                                    // strip the help flag
    225217                        } else if ( arg == "-nohelp" ) {
    226                                 help = false;                                                   // strip nohelp flag
     218                                help = false;                                                   // strip the nohelp flag
    227219                        } else if ( arg == "-cfalib") {
    228220                                compiling_libs = true;
     
    282274                                } // if
    283275                        } else if ( prefix( arg, "-B" ) ) {
    284                                 bprefix = arg.substr(2);                                // strip -B flag
     276                                bprefix = arg.substr(2);                                // strip the -B flag
    285277                        } else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) {
    286278                                args[nargs++] = argv[i];                                // pass flag along
  • src/AST/Attribute.hpp

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

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

    r6e1e2d0 ra50fdfb  
    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, ArgumentFlag isVarArgs )
     59        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool 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( isVarArgs );
     63        FunctionType * ftype = new FunctionType(static_cast<ArgumentFlag>(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, ArgumentFlag isVarArgs )
     83        std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool 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 );
     88        FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );
    8989        for ( auto & param : this->params ) {
    9090                type->params.emplace_back( param->get_type() );
  • src/AST/Decl.hpp

    r6e1e2d0 ra50fdfb  
    1010// Created On       : Thu May 9 10:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr  5 10:42:00 2023
    13 // Update Count     : 35
     12// Last Modified On : Thu Nov 24  9:44:00 2022
     13// Update Count     : 34
    1414//
    1515
     
    122122};
    123123
    124 /// Function variable arguments flag
    125 enum ArgumentFlag { FixedArgs, VariableArgs };
    126 
    127124/// Object declaration `int foo()`
    128125class FunctionDecl : public DeclWithType {
     
    147144                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    148145                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    149                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs );
     146                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
    150147
    151148        FunctionDecl( const CodeLocation & location, const std::string & name,
     
    153150                std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
    154151                CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
    155                 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, ArgumentFlag isVarArgs = FixedArgs );
     152                std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
    156153
    157154        const Type * get_type() const override;
     
    316313public:
    317314        bool isTyped; // isTyped indicated if the enum has a declaration like:
    318         // enum (type_optional) Name {...}
     315        // enum (type_optional) Name {...} 
    319316        ptr<Type> base; // if isTyped == true && base.get() == nullptr, it is a "void" type enum
    320317        enum class EnumHiding { Visible, Hide } hide;
     
    374371};
    375372
    376 /// Assembly declaration: `asm ... ( "..." : ... )`
    377373class AsmDecl : public Decl {
    378374public:
  • src/AST/Expr.hpp

    r6e1e2d0 ra50fdfb  
    254254};
    255255
    256 /// A name qualified by a namespace or type.
    257256class QualifiedNameExpr final : public Expr {
    258257public:
     
    260259        std::string name;
    261260
    262         QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n )
     261        QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n ) 
    263262        : Expr( loc ), type_decl( d ), name( n ) {}
    264263
     
    622621};
    623622
    624 /// A name that refers to a generic dimension parameter.
    625623class DimensionExpr final : public Expr {
    626624public:
     
    912910};
    913911
     912
    914913}
    915914
  • src/AST/Init.hpp

    r6e1e2d0 ra50fdfb  
    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

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

    r6e1e2d0 ra50fdfb  
    1010// Created On       : Fri Jun 24 13:16:31 2022
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Apr 14 15:09:00 2023
    13 // Update Count     : 3
     12// Last Modified On : Thr Sep 22 13:44:00 2022
     13// Update Count     : 2
    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.
    41 bool isUnnamedBitfield( const ObjectDecl * obj );
    42 
    4340}
  • src/AST/Pass.impl.hpp

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

    r6e1e2d0 ra50fdfb  
    766766        virtual const ast::Stmt * visit( const ast::SuspendStmt * node ) override final {
    767767                os << "Suspend Statement";
    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;
     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;
    772772                }
    773773                os << endl;
  • src/AST/Stmt.hpp

    r6e1e2d0 ra50fdfb  
    1010// Created On       : Wed May  8 13:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Wed Apr  5 10:34:00 2023
    13 // Update Count     : 37
     12// Last Modified On : Wed Apr 20 14:34:00 2022
     13// Update Count     : 36
    1414//
    1515
     
    205205};
    206206
    207 // A while loop or a do-while loop:
    208 enum WhileDoKind { While, DoWhile };
    209 
    210207// While loop: while (...) ... else ... or do ... while (...) else ...;
    211208class WhileDoStmt final : public Stmt {
     
    215212        ptr<Stmt> else_;
    216213        std::vector<ptr<Stmt>> inits;
    217         WhileDoKind isDoWhile;
     214        bool isDoWhile;
    218215
    219216        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body,
    220                                  const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
     217                                 const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
    221218                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(nullptr), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    222219
    223220        WhileDoStmt( const CodeLocation & loc, const Expr * cond, const Stmt * body, const Stmt * else_,
    224                                  const std::vector<ptr<Stmt>> && inits, WhileDoKind isDoWhile = While, const std::vector<Label> && labels = {} )
     221                                 const std::vector<ptr<Stmt>> && inits, bool isDoWhile = false, const std::vector<Label> && labels = {} )
    225222                : Stmt(loc, std::move(labels)), cond(cond), body(body), else_(else_), inits(std::move(inits)), isDoWhile(isDoWhile) {}
    226223
     
    367364  public:
    368365        ptr<CompoundStmt> then;
    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) {}
     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) {}
    373370
    374371        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     
    427424};
    428425
    429 // Clause in a waitfor statement: waitfor (..., ...) ...
    430426class WaitForClause final : public WhenClause {
    431427  public:
     
    531527        MUTATE_FRIEND
    532528};
    533 
    534529} // namespace ast
    535530
  • src/AST/SymbolTable.cpp

    r6e1e2d0 ra50fdfb  
    260260void SymbolTable::addId( const DeclWithType * decl, const Expr * baseExpr ) {
    261261        // default handling of conflicts is to raise an error
    262         addIdCommon( decl, OnConflict::error(), baseExpr, decl->isDeleted ? decl : nullptr );
     262        addId( 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         addIdCommon( decl, OnConflict::error(), nullptr, deleter );
     267        addId( decl, OnConflict::error(), nullptr, deleter );
    268268}
    269269
     
    677677}
    678678
    679 void SymbolTable::addIdCommon(
    680                 const DeclWithType * decl, SymbolTable::OnConflict handleConflicts,
    681                 const Expr * baseExpr, const Decl * deleter ) {
     679void SymbolTable::addId(
     680                const DeclWithType * decl, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
     681                const Decl * deleter ) {
    682682        SpecialFunctionKind kind = getSpecialFunctionKind(decl->name);
    683683        if (kind == NUMBER_OF_KINDS) { // not a special decl
    684                 addIdToTable(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
     684                addId(decl, decl->name, idTable, handleConflicts, baseExpr, deleter);
    685685        }
    686686        else {
     
    695695                        assertf(false, "special decl with non-function type");
    696696                }
    697                 addIdToTable(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
    698         }
    699 }
    700 
    701 void SymbolTable::addIdToTable(
    702                 const DeclWithType * decl, const std::string & lookupKey,
    703                 IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts,
    704                 const Expr * baseExpr, const Decl * deleter ) {
     697                addId(decl, key, specialFunctionTable[kind], handleConflicts, baseExpr, deleter);
     698        }
     699}
     700
     701void SymbolTable::addId(
     702                const DeclWithType * decl, const std::string & lookupKey, IdTable::Ptr & table, SymbolTable::OnConflict handleConflicts, const Expr * baseExpr,
     703                const Decl * deleter ) {
    705704        ++*stats().add_calls;
    706705        const std::string &name = decl->name;
     
    779778void SymbolTable::addMembers(
    780779                const AggregateDecl * aggr, const Expr * expr, SymbolTable::OnConflict handleConflicts ) {
    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 );
     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                        }
    799798                }
    800799        }
  • src/AST/SymbolTable.hpp

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

    r6e1e2d0 ra50fdfb  
    1010// Created On       : Mon May 13 15:00:00 2019
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Apr  6 15:59:00 2023
    13 // Update Count     : 7
     12// Last Modified On : Thu Nov 24  9:49:00 2022
     13// Update Count     : 6
    1414//
    1515
     
    199199
    200200TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
    201 : Type( q ), types( std::move(ts) ) {}
     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}
    202220
    203221bool isUnboundType(const Type * type) {
  • src/AST/Type.hpp

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

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

    r6e1e2d0 ra50fdfb  
    2020#include <iterator>
    2121
    22 // Returns an iterator that is it advanced n times.
     22// it's nice to actually be able to increment iterators by an arbitrary amount
    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 
    5652template< typename T >
    5753struct enumerate_t {
     
    113109
    114110// -----------------------------------------------------------------------------
    115 // Helper function to transform one iterable container into another.
    116 
    117111template< typename OutType, typename Range, typename Functor >
    118112OutType map_range( const Range& range, Functor&& functor ) {
     
    212206// Helper struct and function to support
    213207// for ( val : lazy_map( container1, f ) ) {}
    214 // syntax to have a for each that iterates a container,
    215 // mapping each element by applying f.
    216 
     208// syntax to have a for each that iterates a container, mapping each element by applying f
    217209template< typename T, typename Func >
    218210struct lambda_iterate_t {
  • src/CompilationState.cc

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

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

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

    r6e1e2d0 ra50fdfb  
    1414#include <utility>                     // for pair
    1515
    16 #include "AST/DeclReplacer.hpp"
    17 #include "AST/Expr.hpp"
    1816#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"
    2417#include "CodeGen/GenType.h"           // for genPrettyType
    2518#include "CodeGen/OperatorTable.h"
     19#include "Common/CodeLocationTools.hpp"
    2620#include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
    2721#include "Common/SemanticError.h"      // for SemanticError
     
    3428#include "ResolvExpr/Unify.h"          // for typesCompatible
    3529#include "SymTab/Autogen.h"            // for genImplicitCall
    36 #include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
    3730#include "SymTab/Indexer.h"            // for Indexer
    3831#include "SymTab/Mangler.h"            // for Mangler
     
    5245#include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
    5346
     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
    5455extern bool ctordtorp; // print all debug
    5556extern bool ctorp; // print ctor debug
     
    6263namespace InitTweak {
    6364namespace {
    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 
    10265        struct SelfAssignChecker {
    10366                void previsit( const ast::ApplicationExpr * appExpr );
     
    158121                void previsit( const ast::FunctionDecl * ) { visit_children = false; }
    159122
    160         protected:
     123          protected:
    161124                ObjectSet curVars;
    162125        };
     
    239202
    240203                SemanticErrorException errors;
    241         private:
     204          private:
    242205                template< typename... Params >
    243206                void emit( CodeLocation, const Params &... params );
     
    325288                static UniqueName dtorNamer( "__cleanup_dtor" );
    326289                std::string name = dtorNamer.newName();
    327                 ast::FunctionDecl * dtorFunc = genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
     290                ast::FunctionDecl * dtorFunc = SymTab::genDefaultFunc( loc, name, objDecl->type->stripReferences(), false );
    328291                stmtsToAdd.push_back( new ast::DeclStmt(loc, dtorFunc ) );
    329292
     
    11171080        void InsertDtors::previsit( const ast::BranchStmt * stmt ) {
    11181081                switch( stmt->kind ) {
    1119                 case ast::BranchStmt::Continue:
    1120                 case ast::BranchStmt::Break:
     1082                  case ast::BranchStmt::Continue:
     1083                  case ast::BranchStmt::Break:
    11211084                        // could optimize the break/continue case, because the S_L-S_G check is unnecessary (this set should
    11221085                        // always be empty), but it serves as a small sanity check.
    1123                 case ast::BranchStmt::Goto:
     1086                  case ast::BranchStmt::Goto:
    11241087                        handleGoto( stmt );
    11251088                        break;
    1126                 default:
     1089                  default:
    11271090                        assert( false );
    11281091                } // switch
     
    13491312                // xxx - functions returning ast::ptr seems wrong...
    13501313                auto res = ResolvExpr::findVoidExpression( untypedExpr, { symtab, transUnit().global } );
    1351                 return res.release();
     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 );
    13521317        }
    13531318
  • src/InitTweak/GenInit.cc

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

    r6e1e2d0 ra50fdfb  
    1010// Created On       : Sat May 16 12:34:05 2015
    1111// Last Modified By : Andrew Beach
    12 // Last Modified On : Thr Apr 20 11:46:00 2023
    13 // Update Count     : 1393
     12// Last Modified On : Tue Apr  4 10:28:00 2023
     13// Update Count     : 1392
    1414//
    15 
    16 #include "DeclarationNode.h"
    1715
    1816#include <cassert>                 // for assert, assertf, strict_dynamic_cast
     
    3634#include "Common/UniqueName.h"     // for UniqueName
    3735#include "Common/utility.h"        // for maybeClone
    38 #include "Parser/ExpressionNode.h" // for ExpressionNode
    39 #include "Parser/InitializerNode.h"// for InitializerNode
    40 #include "Parser/StatementNode.h"  // for StatementNode
     36#include "Parser/ParseNode.h"      // for DeclarationNode, ExpressionNode
    4137#include "TypeData.h"              // for TypeData, TypeData::Aggregate_t
    4238#include "TypedefTable.h"          // for TypedefTable
     
    1003999}
    10041000
    1005 // If a typedef wraps an anonymous declaration, name the inner declaration
    1006 // so it has a consistent name across translation units.
    1007 static 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.
    1051 static 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.
    1076 static 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 
    1087 void buildList( DeclarationNode * firstNode,
     1001void buildList( const DeclarationNode * firstNode,
    10881002                std::vector<ast::ptr<ast::Decl>> & outputList ) {
    10891003        SemanticErrorException errors;
    10901004        std::back_insert_iterator<std::vector<ast::ptr<ast::Decl>>> out( outputList );
    10911005
    1092         for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
     1006        for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
    10931007                try {
    1094                         bool extracted_named = false;
    1095                         ast::UnionDecl * unionDecl = nullptr;
     1008                        bool extracted = false, anon = false;
     1009                        ast::AggregateDecl * unionDecl = nullptr;
    10961010
    10971011                        if ( DeclarationNode * extr = cur->extractAggregate() ) {
     1012                                // Handle the case where a SUE declaration is contained within an object or type declaration.
     1013
    10981014                                assert( cur->type );
    1099                                 nameTypedefedDecl( extr, cur );
    1100 
    1101                                 if ( ast::Decl * decl = extr->build() ) {
     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 ) {
    11021048                                        // Remember the declaration if it is a union aggregate ?
    11031049                                        unionDecl = dynamic_cast<ast::UnionDecl *>( decl );
    11041050
     1051                                        decl->location = cur->location;
    11051052                                        *out++ = decl;
    11061053
    11071054                                        // need to remember the cases where a declaration contains an anonymous aggregate definition
     1055                                        extracted = true;
    11081056                                        assert( extr->type );
    11091057                                        if ( extr->type->kind == TypeData::Aggregate ) {
    11101058                                                // typedef struct { int A } B is the only case?
    1111                                                 extracted_named = !extr->type->aggregate.anon;
     1059                                                anon = extr->type->aggregate.anon;
    11121060                                        } else if ( extr->type->kind == TypeData::Enum ) {
    11131061                                                // typedef enum { A } B is the only case?
    1114                                                 extracted_named = !extr->type->enumeration.anon;
    1115                                         } else {
    1116                                                 extracted_named = true;
     1062                                                anon = extr->type->enumeration.anon;
    11171063                                        }
    11181064                                } // if
     
    11201066                        } // if
    11211067
    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                                         }
     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
    11421097                                } // if
    1143                                 *out++ = decl;
     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
    11441122                        } // if
    1145                 } catch ( SemanticErrorException & e ) {
     1123                } catch( SemanticErrorException & e ) {
    11461124                        errors.append( e );
    11471125                } // try
     
    11541132
    11551133// currently only builds assertions, function parameters, and return values
    1156 void buildList( DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
     1134void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList ) {
    11571135        SemanticErrorException errors;
    11581136        std::back_insert_iterator<std::vector<ast::ptr<ast::DeclWithType>>> out( outputList );
    11591137
    1160         for ( const DeclarationNode * cur = firstNode; cur; cur = strict_next( cur ) ) {
     1138        for ( const DeclarationNode * cur = firstNode; cur; cur = dynamic_cast< DeclarationNode * >( cur->get_next() ) ) {
    11611139                try {
    11621140                        ast::Decl * decl = cur->build();
    1163                         assertf( decl, "buildList: build for ast::DeclWithType." );
     1141                        assert( decl );
    11641142                        if ( ast::DeclWithType * dwt = dynamic_cast<ast::DeclWithType *>( decl ) ) {
    11651143                                dwt->location = cur->location;
     
    11901168                                );
    11911169                                *out++ = obj;
    1192                         } else {
    1193                                 assertf( false, "buildList: Could not convert to ast::DeclWithType." );
    11941170                        } // if
    1195                 } catch ( SemanticErrorException & e ) {
     1171                } catch( SemanticErrorException & e ) {
    11961172                        errors.append( e );
    11971173                } // try
     
    12071183        SemanticErrorException errors;
    12081184        std::back_insert_iterator<std::vector<ast::ptr<ast::Type>>> out( outputList );
    1209 
    1210         for ( const DeclarationNode * cur = firstNode ; cur ; cur = strict_next( cur ) ) {
     1185        const DeclarationNode * cur = firstNode;
     1186
     1187        while ( cur ) {
    12111188                try {
    12121189                        * out++ = cur->buildType();
    1213                 } catch ( SemanticErrorException & e ) {
     1190                } catch( SemanticErrorException & e ) {
    12141191                        errors.append( e );
    12151192                } // try
    1216         } // for
     1193                cur = dynamic_cast< DeclarationNode * >( cur->get_next() );
     1194        } // while
    12171195
    12181196        if ( ! errors.isEmpty() ) {
  • src/Parser/ExpressionNode.cc

    r6e1e2d0 ra50fdfb  
    1313// Update Count     : 1083
    1414//
    15 
    16 #include "ExpressionNode.h"
    1715
    1816#include <cassert>                 // for assert
     
    2725#include "Common/SemanticError.h"  // for SemanticError
    2826#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild, CodeLo...
    29 #include "DeclarationNode.h"       // for DeclarationNode
    30 #include "InitializerNode.h"       // for InitializerNode
     27#include "ParseNode.h"             // for ExpressionNode, maybeMoveBuildType
    3128#include "parserutility.h"         // for notZeroExpr
    3229
     
    702699} // build_binary_val
    703700
     701ast::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
    704708ast::Expr * build_cond( const CodeLocation & location,
    705709                ExpressionNode * expr_node1,
  • src/Parser/InitializerNode.cc

    r6e1e2d0 ra50fdfb  
    1414//
    1515
    16 #include "InitializerNode.h"
    17 
    1816#include <iostream>                // for operator<<, ostream, basic_ostream
    1917#include <list>                    // for list
    2018#include <string>                  // for operator<<, string
     19
     20using 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 "ExpressionNode.h"        // for ExpressionNode
    27 #include "DeclarationNode.h"       // for buildList
    28 
    29 using namespace std;
     26#include "ParseNode.h"             // for InitializerNode, ExpressionNode
    3027
    3128static ast::ConstructFlag toConstructFlag( bool maybeConstructed ) {
  • src/Parser/ParseNode.h

    r6e1e2d0 ra50fdfb  
    3838class DeclarationWithType;
    3939class Initializer;
    40 class InitializerNode;
    4140class ExpressionNode;
    4241struct StatementNode;
     
    8079        CodeLocation location = yylloc;
    8180}; // ParseNode
     81
     82//##############################################################################
     83
     84class 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
     119class 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
    82152
    83153// Must harmonize with OperName.
     
    99169};
    100170
     171// These 4 routines modify the string:
     172ast::Expr * build_constantInteger( const CodeLocation &, std::string & );
     173ast::Expr * build_constantFloat( const CodeLocation &, std::string & );
     174ast::Expr * build_constantChar( const CodeLocation &, std::string & );
     175ast::Expr * build_constantStr( const CodeLocation &, std::string & );
     176ast::Expr * build_field_name_FLOATING_FRACTIONconstant( const CodeLocation &, const std::string & str );
     177ast::Expr * build_field_name_FLOATING_DECIMALconstant( const CodeLocation &, const std::string & str );
     178ast::Expr * build_field_name_FLOATINGconstant( const CodeLocation &, const std::string & str );
     179ast::Expr * build_field_name_fraction_constants( const CodeLocation &, ast::Expr * fieldName, ExpressionNode * fracts );
     180
     181ast::NameExpr * build_varref( const CodeLocation &, const std::string * name );
     182ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const DeclarationNode * decl_node, const ast::NameExpr * name );
     183ast::QualifiedNameExpr * build_qualified_expr( const CodeLocation &, const ast::EnumDecl * decl, const ast::NameExpr * name );
     184ast::DimensionExpr * build_dimensionref( const CodeLocation &, const std::string * name );
     185
     186ast::Expr * build_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
     187ast::Expr * build_keyword_cast( const CodeLocation &, ast::AggregateDecl::Aggregate target, ExpressionNode * expr_node );
     188ast::Expr * build_virtual_cast( const CodeLocation &, DeclarationNode * decl_node, ExpressionNode * expr_node );
     189ast::Expr * build_fieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );
     190ast::Expr * build_pfieldSel( const CodeLocation &, ExpressionNode * expr_node, ast::Expr * member );
     191ast::Expr * build_offsetOf( const CodeLocation &, DeclarationNode * decl_node, ast::NameExpr * member );
     192ast::Expr * build_and( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
     193ast::Expr * build_and_or( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ast::LogicalFlag flag );
     194ast::Expr * build_unary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node );
     195ast::Expr * build_binary_val( const CodeLocation &, OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
     196ast::Expr * build_binary_ptr( const CodeLocation &, OperKinds op, ExpressionNode * expr_node1, ExpressionNode * expr_node2 );
     197ast::Expr * build_cond( const CodeLocation &, ExpressionNode * expr_node1, ExpressionNode * expr_node2, ExpressionNode * expr_node3 );
     198ast::Expr * build_tuple( const CodeLocation &, ExpressionNode * expr_node = nullptr );
     199ast::Expr * build_func( const CodeLocation &, ExpressionNode * function, ExpressionNode * expr_node );
     200ast::Expr * build_compoundLiteral( const CodeLocation &, DeclarationNode * decl_node, InitializerNode * kids );
     201
     202//##############################################################################
     203
     204struct TypeData;
     205
     206struct 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
     353ast::Type * buildType( TypeData * type );
     354
     355static 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
     363struct 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
     399ast::Stmt * build_expr( CodeLocation const &, ExpressionNode * ctl );
     400
     401struct 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
     409struct 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
     418ast::Stmt * build_if( const CodeLocation &, CondCtl * ctl, StatementNode * then, StatementNode * else_ );
     419ast::Stmt * build_switch( const CodeLocation &, bool isSwitch, ExpressionNode * ctl, StatementNode * stmt );
     420ast::CaseClause * build_case( ExpressionNode * ctl );
     421ast::CaseClause * build_default( const CodeLocation & );
     422ast::Stmt * build_while( const CodeLocation &, CondCtl * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
     423ast::Stmt * build_do_while( const CodeLocation &, ExpressionNode * ctl, StatementNode * stmt, StatementNode * else_ = nullptr );
     424ast::Stmt * build_for( const CodeLocation &, ForCtrl * forctl, StatementNode * stmt, StatementNode * else_ = nullptr );
     425ast::Stmt * build_branch( const CodeLocation &, ast::BranchStmt::Kind kind );
     426ast::Stmt * build_branch( const CodeLocation &, std::string * identifier, ast::BranchStmt::Kind kind );
     427ast::Stmt * build_computedgoto( ExpressionNode * ctl );
     428ast::Stmt * build_return( const CodeLocation &, ExpressionNode * ctl );
     429ast::Stmt * build_throw( const CodeLocation &, ExpressionNode * ctl );
     430ast::Stmt * build_resume( const CodeLocation &, ExpressionNode * ctl );
     431ast::Stmt * build_resume_at( ExpressionNode * ctl , ExpressionNode * target );
     432ast::Stmt * build_try( const CodeLocation &, StatementNode * try_, StatementNode * catch_, StatementNode * finally_ );
     433ast::CatchClause * build_catch( const CodeLocation &, ast::ExceptionKind kind, DeclarationNode * decl, ExpressionNode * cond, StatementNode * body );
     434ast::FinallyClause * build_finally( const CodeLocation &, StatementNode * stmt );
     435ast::Stmt * build_compound( const CodeLocation &, StatementNode * first );
     436StatementNode * maybe_build_compound( const CodeLocation &, StatementNode * first );
     437ast::Stmt * build_asm( const CodeLocation &, bool voltile, ast::Expr * instruction, ExpressionNode * output = nullptr, ExpressionNode * input = nullptr, ExpressionNode * clobber = nullptr, LabelNode * gotolabels = nullptr );
     438ast::Stmt * build_directive( const CodeLocation &, std::string * directive );
     439ast::SuspendStmt * build_suspend( const CodeLocation &, StatementNode *, ast::SuspendStmt::Type );
     440ast::WaitForStmt * build_waitfor( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
     441ast::WaitForStmt * build_waitfor_else( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt );
     442ast::WaitForStmt * build_waitfor_timeout( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
     443ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
     444ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt );
     445ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation &, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
     446ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root );
     447ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
     448ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
     449
     450//##############################################################################
     451
     452template<typename AstType, typename NodeType,
     453        template<typename, typename...> class Container, typename... Args>
     454void 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
     484void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Decl>> & outputList );
     485void buildList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::DeclWithType>> & outputList );
     486void buildTypeList( const DeclarationNode * firstNode, std::vector<ast::ptr<ast::Type>> & outputList );
     487
     488template<typename AstType, typename NodeType,
     489        template<typename, typename...> class Container, typename... Args>
     490void 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
    101497std::ostream & operator<<( std::ostream & out, const ParseNode * node );
    102498
  • src/Parser/RunParser.cpp

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

    r6e1e2d0 ra50fdfb  
    1111// Created On       : Sat May 16 14:59:41 2015
    1212// Last Modified By : Andrew Beach
    13 // Last Modified On : Tue Apr 11 10:16:00 2023
    14 // Update Count     : 428
     13// Last Modified On : Tue Apr  4 11:40:00 2023
     14// Update Count     : 427
    1515//
    16 
    17 #include "StatementNode.h"
    1816
    1917#include <cassert>                 // for assert, strict_dynamic_cast, assertf
     
    2523#include "Common/SemanticError.h"  // for SemanticError
    2624#include "Common/utility.h"        // for maybeMoveBuild, maybeBuild
    27 #include "DeclarationNode.h"       // for DeclarationNode
    28 #include "ExpressionNode.h"        // for ExpressionNode
     25#include "ParseNode.h"             // for StatementNode, ExpressionNode, bui...
    2926#include "parserutility.h"         // for notZeroExpr
    3027
     
    3229
    3330using namespace std;
    34 
    35 // Some helpers for cases that really want a single node but check for lists.
    36 static 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 
    43 static 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 }
    4931
    5032StatementNode::StatementNode( DeclarationNode * decl ) {
     
    7153} // StatementNode::StatementNode
    7254
    73 StatementNode * 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 
    86 ClauseNode * ClauseNode::append_last_case( StatementNode * stmt ) {
    87         ClauseNode * prev = this;
     55StatementNode * StatementNode::append_last_case( StatementNode * stmt ) {
     56        StatementNode * prev = this;
    8857        // find end of list and maintain previous pointer
    89         for ( ClauseNode * curr = prev; curr != nullptr; curr = (ClauseNode *)curr->get_next() ) {
    90                 ClauseNode * node = strict_dynamic_cast< ClauseNode * >(curr);
     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() );
    9161                assert( dynamic_cast<ast::CaseClause *>( node->clause.get() ) );
    9262                prev = curr;
    9363        } // for
    94         ClauseNode * node = dynamic_cast< ClauseNode * >(prev);
    9564        // convert from StatementNode list to Statement list
     65        StatementNode * node = dynamic_cast< StatementNode * >(prev);
    9666        std::vector<ast::ptr<ast::Stmt>> stmts;
    9767        buildMoveList( stmt, stmts );
     
    10373        stmts.clear();
    10474        return this;
    105 } // ClauseNode::append_last_case
     75} // StatementNode::append_last_case
    10676
    10777ast::Stmt * build_expr( CodeLocation const & location, ExpressionNode * ctl ) {
     
    12797                for ( ast::ptr<ast::Stmt> & stmt : inits ) {
    12898                        // build the && of all of the declared variables compared against 0
     99                        //auto declStmt = strict_dynamic_cast<ast::DeclStmt *>( stmt );
    129100                        auto declStmt = stmt.strict_as<ast::DeclStmt>();
     101                        //ast::DeclWithType * dwt = strict_dynamic_cast<ast::DeclWithType *>( declStmt->decl );
    130102                        auto dwt = declStmt->decl.strict_as<ast::DeclWithType>();
    131103                        ast::Expr * nze = notZeroExpr( new ast::VariableExpr( dwt->location, dwt ) );
     
    141113        ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    142114
    143         ast::Stmt const * astthen = buildMoveSingle( then );
    144         ast::Stmt const * astelse = buildMoveOptional( else_ );
     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
    145127
    146128        return new ast::IfStmt( location, astcond, astthen, astelse,
     
    149131} // build_if
    150132
    151 ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, ClauseNode * stmt ) {
     133// Temporary work around. Split StmtClause off from StatementNode.
     134template<typename clause_t>
     135static 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
     168ast::Stmt * build_switch( const CodeLocation & location, bool isSwitch, ExpressionNode * ctl, StatementNode * stmt ) {
    152169        std::vector<ast::ptr<ast::CaseClause>> aststmt;
    153         buildMoveList( stmt, aststmt );
     170        buildMoveClauseList( stmt, aststmt );
    154171        // If it is not a switch it is a choose statement.
    155172        if ( ! isSwitch ) {
     
    173190} // build_switch
    174191
    175 ast::CaseClause * build_case( const CodeLocation & location, ExpressionNode * ctl ) {
     192ast::CaseClause * build_case( ExpressionNode * ctl ) {
    176193        // stmt starts empty and then added to
    177194        auto expr = maybeMoveBuild( ctl );
    178         return new ast::CaseClause( location, expr, {} );
     195        return new ast::CaseClause( expr->location, expr, {} );
    179196} // build_case
    180197
     
    188205        ast::Expr * astcond = build_if_control( ctl, astinit ); // ctl deleted, cond/init set
    189206
     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
    190215        return new ast::WhileDoStmt( location,
    191216                astcond,
    192                 buildMoveSingle( stmt ),
    193                 buildMoveOptional( else_ ),
     217                aststmt.front(),
     218                astelse.empty() ? nullptr : astelse.front().release(),
    194219                std::move( astinit ),
    195                 ast::While
     220                false
    196221        );
    197222} // build_while
    198223
    199224ast::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
    200233        // do-while cannot have declarations in the contitional, so init is always empty
    201234        return new ast::WhileDoStmt( location,
    202235                notZeroExpr( maybeMoveBuild( ctl ) ),
    203                 buildMoveSingle( stmt ),
    204                 buildMoveOptional( else_ ),
     236                aststmt.front(),
     237                astelse.empty() ? nullptr : astelse.front().release(),
    205238                {},
    206                 ast::DoWhile
     239                true
    207240        );
    208241} // build_do_while
     
    218251        astincr = maybeMoveBuild( forctl->change );
    219252        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 );
    220261
    221262        return new ast::ForStmt( location,
     
    223264                astcond,
    224265                astincr,
    225                 buildMoveSingle( stmt ),
    226                 buildMoveOptional( else_ )
     266                aststmt.front(),
     267                astelse.empty() ? nullptr : astelse.front().release()
    227268        );
    228269} // build_for
     
    285326} // build_resume_at
    286327
    287 ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, ClauseNode * catch_, ClauseNode * finally_ ) {
     328ast::Stmt * build_try( const CodeLocation & location, StatementNode * try_, StatementNode * catch_, StatementNode * finally_ ) {
    288329        std::vector<ast::ptr<ast::CatchClause>> aststmt;
    289         buildMoveList( catch_, aststmt );
     330        buildMoveClauseList( catch_, aststmt );
    290331        ast::CompoundStmt * tryBlock = strict_dynamic_cast<ast::CompoundStmt *>( maybeMoveBuild( try_ ) );
    291332        ast::FinallyClause * finallyBlock = nullptr;
     
    301342
    302343ast::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 );
    303347        return new ast::CatchClause( location,
    304348                kind,
    305349                maybeMoveBuild( decl ),
    306350                maybeMoveBuild( cond ),
    307                 buildMoveSingle( body )
     351                aststmt.front().release()
    308352        );
    309353} // build_catch
    310354
    311355ast::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 );
    312359        return new ast::FinallyClause( location,
    313                 strict_dynamic_cast<const ast::CompoundStmt *>(
    314                         buildMoveSingle( stmt )
    315                 )
     360                aststmt.front().strict_as<ast::CompoundStmt>()
    316361        );
    317362} // build_finally
    318363
    319 ast::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         );
     364ast::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;
    326375} // build_suspend
    327376
     
    476525
    477526// Question
    478 ast::Stmt * build_asm( const CodeLocation & location, bool is_volatile, ExpressionNode * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
     527ast::Stmt * build_asm( const CodeLocation & location, bool voltile, ast::Expr * instruction, ExpressionNode * output, ExpressionNode * input, ExpressionNode * clobber, LabelNode * gotolabels ) {
    479528        std::vector<ast::ptr<ast::Expr>> out, in;
    480529        std::vector<ast::ptr<ast::ConstantExpr>> clob;
     
    484533        buildMoveList( clobber, clob );
    485534        return new ast::AsmStmt( location,
    486                 is_volatile,
    487                 maybeMoveBuild( instruction ),
     535                voltile,
     536                instruction,
    488537                std::move( out ),
    489538                std::move( in ),
  • src/Parser/TypeData.cc

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

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

    r6e1e2d0 ra50fdfb  
    1616
    1717#include "TypedefTable.h"
    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 
     18#include <cassert>                                                                              // for assert
     19#include <iostream>
    2920using namespace std;
    3021
    3122#if 0
    3223#define debugPrint( code ) code
    33 
    34 static 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
    4524#else
    4625#define debugPrint( code )
    4726#endif
     27
     28using namespace std;                                                                    // string, iostream
     29
     30debugPrint(
     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);
    4843
    4944TypedefTable::~TypedefTable() {
     
    8378                typedefTable.addToEnclosingScope( name, kind, "MTD" );
    8479        } // if
    85 } // TypedefTable::makeTypedef
    86 
    87 void TypedefTable::makeTypedef( const string & name ) {
    88         return makeTypedef( name, TYPEDEFname );
    8980} // TypedefTable::makeTypedef
    9081
  • src/Parser/TypedefTable.h

    r6e1e2d0 ra50fdfb  
    1919
    2020#include "Common/ScopedMap.h"                                                   // for ScopedMap
     21#include "ParserTypes.h"
     22#include "parser.hh"                                                                    // for IDENTIFIER, TYPEDEFname, TYPEGENname
    2123
    2224class TypedefTable {
    2325        struct Note { size_t level; bool forall; };
    2426        typedef ScopedMap< std::string, int, Note > KindTable;
    25         KindTable kindTable;
     27        KindTable kindTable;   
    2628        unsigned int level = 0;
    2729  public:
     
    3133        bool existsCurr( const std::string & identifier ) const;
    3234        int isKind( const std::string & identifier ) const;
    33         void makeTypedef( const std::string & name, int kind );
    34         void makeTypedef( const std::string & name );
     35        void makeTypedef( const std::string & name, int kind = TYPEDEFname );
    3536        void addToScope( const std::string & identifier, int kind, const char * );
    3637        void addToEnclosingScope( const std::string & identifier, int kind, const char * );
  • src/Parser/lex.ll

    r6e1e2d0 ra50fdfb  
    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
    4946#include "ParseNode.h"
    50 #include "ParserTypes.h"                                // for Token
    51 #include "StatementNode.h"                              // for CondCtl, ForCtrl
    5247#include "TypedefTable.h"
    53 // This (generated) header must come late as it is missing includes.
    54 #include "parser.hh"                                    // generated info
    5548
    5649string * build_postfix_name( string * name );
  • src/Parser/module.mk

    r6e1e2d0 ra50fdfb  
    2121SRC += \
    2222       Parser/DeclarationNode.cc \
    23        Parser/DeclarationNode.h \
    2423       Parser/ExpressionNode.cc \
    25        Parser/ExpressionNode.h \
    2624       Parser/InitializerNode.cc \
    27        Parser/InitializerNode.h \
    2825       Parser/lex.ll \
    2926       Parser/ParseNode.cc \
     
    3633       Parser/RunParser.hpp \
    3734       Parser/StatementNode.cc \
    38        Parser/StatementNode.h \
    3935       Parser/TypeData.cc \
    4036       Parser/TypeData.h \
  • src/Parser/parser.yy

    r6e1e2d0 ra50fdfb  
    99// Author           : Peter A. Buhr
    1010// Created On       : Sat Sep  1 20:22:55 2001
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 26 16:45:37 2023
    13 // Update Count     : 6330
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Tue Apr  4 14:02:00 2023
     13// Update Count     : 6329
    1414//
    1515
     
    4848using namespace std;
    4949
    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_...
     50#include "SynTree/Declaration.h"
     51#include "ParseNode.h"
    5652#include "TypedefTable.h"
    5753#include "TypeData.h"
     54#include "SynTree/LinkageSpec.h"
    5855#include "Common/SemanticError.h"                                               // error_str
    5956#include "Common/utility.h"                                                             // for maybeMoveBuild, maybeBuild, CodeLo...
     
    300297%union {
    301298        Token tok;
    302         ExpressionNode * expr;
     299        ParseNode * pn;
     300        ExpressionNode * en;
    303301        DeclarationNode * decl;
    304302        ast::AggregateDecl::Aggregate aggKey;
    305303        ast::TypeDecl::Kind tclass;
    306         StatementNode * stmt;
    307         ClauseNode * clause;
     304        StatementNode * sn;
    308305        ast::WaitForStmt * wfs;
    309     ast::WaitUntilStmt::ClauseNode * wucn;
     306    ast::WaitUntilStmt::ClauseNode * wuscn;
     307        ast::Expr * constant;
    310308        CondCtl * ifctl;
    311         ForCtrl * forctl;
    312         LabelNode * labels;
    313         InitializerNode * init;
    314         OperKinds oper;
     309        ForCtrl * fctl;
     310        OperKinds compop;
     311        LabelNode * label;
     312        InitializerNode * in;
     313        OperKinds op;
    315314        std::string * str;
    316         bool is_volatile;
    317         EnumHiding enum_hiding;
    318         ast::ExceptionKind except_kind;
     315        bool flag;
     316        EnumHiding hide;
     317        ast::ExceptionKind catch_kind;
    319318        ast::GenericExpr * genexpr;
    320319}
     
    382381%type<tok> identifier                                   identifier_at                           identifier_or_type_name         attr_name
    383382%type<tok> quasi_keyword
    384 %type<expr> string_literal
     383%type<constant> string_literal
    385384%type<str> string_literal_list
    386385
    387 %type<enum_hiding> hide_opt                                     visible_hide_opt
     386%type<hide> hide_opt                                    visible_hide_opt
    388387
    389388// expressions
    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
     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
    401400%type<ifctl> conditional_declaration
    402 %type<forctl> for_control_expression            for_control_expression_list
    403 %type<oper> upupeq updown updowneq downupdowneq
    404 %type<expr> subrange
     401%type<fctl> for_control_expression              for_control_expression_list
     402%type<compop> upupeq updown updowneq downupdowneq
     403%type<en> subrange
    405404%type<decl> asm_name_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
     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
    411410%type<genexpr> generic_association              generic_assoc_list
    412411
    413412// statements
    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
     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
    430428%type<wfs> wor_waitfor_clause
    431 %type<wucn> waituntil_clause                    wand_waituntil_clause       wor_waituntil_clause
     429%type<wuscn> waituntil_clause                   wand_waituntil_clause       wor_waituntil_clause
    432430
    433431// declarations
     
    441439%type<decl> assertion assertion_list assertion_list_opt
    442440
    443 %type<expr> bit_subrange_size_opt bit_subrange_size
     441%type<en> bit_subrange_size_opt bit_subrange_size
    444442
    445443%type<decl> basic_declaration_specifier basic_type_name basic_type_specifier direct_type indirect_type
     
    454452
    455453%type<decl> enumerator_list enum_type enum_type_nobody
    456 %type<init> enumerator_value_opt
     454%type<in> enumerator_value_opt
    457455
    458456%type<decl> external_definition external_definition_list external_definition_list_opt
     
    461459
    462460%type<decl> field_declaration_list_opt field_declaration field_declaring_list_opt field_declarator field_abstract_list_opt field_abstract
    463 %type<expr> field field_name_list field_name fraction_constants_opt
     461%type<en> field field_name_list field_name fraction_constants_opt
    464462
    465463%type<decl> external_function_definition function_definition function_array function_declarator function_no_ptr function_ptr
     
    510508%type<decl> type_parameter type_parameter_list type_initializer_opt
    511509
    512 %type<expr> type_parameters_opt type_list array_type_list
     510%type<en> type_parameters_opt type_list array_type_list
    513511
    514512%type<decl> type_qualifier type_qualifier_name forall type_qualifier_list_opt type_qualifier_list
     
    521519
    522520// initializers
    523 %type<init>  initializer initializer_list_opt initializer_opt
     521%type<in>  initializer initializer_list_opt initializer_opt
    524522
    525523// designators
    526 %type<expr>  designator designator_list designation
     524%type<en>  designator designator_list designation
    527525
    528526
     
    646644
    647645string_literal:
    648         string_literal_list                                                     { $$ = new ExpressionNode( build_constantStr( yylloc, *$1 ) ); }
     646        string_literal_list                                                     { $$ = build_constantStr( yylloc, *$1 ); }
    649647        ;
    650648
     
    741739                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
    742740        | string_literal '[' assignment_expression ']'          // "abc"[3], 3["abc"]
    743                 { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, $1, $3 ) ); }
     741                { $$ = new ExpressionNode( build_binary_val( yylloc, OperKinds::Index, new ExpressionNode( $1 ), $3 ) ); }
    744742        | postfix_expression '{' argument_expression_list_opt '}' // CFA, constructor call
    745743                {
     
    759757                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
    760758        | string_literal '`' identifier                                         // CFA, postfix call
    761                 { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), $1 ) ); }
     759                { $$ = new ExpressionNode( build_func( yylloc, new ExpressionNode( build_varref( yylloc, build_postfix_name( $3 ) ) ), new ExpressionNode( $1 ) ) ); }
    762760        | postfix_expression '.' identifier
    763761                { $$ = new ExpressionNode( build_fieldSel( yylloc, $1, build_varref( yylloc, $3 ) ) ); }
     
    859857        | constant
    860858        | string_literal
    861                 { $$ = $1; }
     859                { $$ = new ExpressionNode( $1 ); }
    862860        | EXTENSION cast_expression                                                     // GCC
    863861                { $$ = $2->set_extension( true ); }
     
    12621260
    12631261case_value_list:                                                                                // CFA
    1264         case_value                                                                      { $$ = new ClauseNode( build_case( yylloc, $1 ) ); }
     1262        case_value                                                                      { $$ = new StatementNode( build_case( $1 ) ); }
    12651263                // convert case list, e.g., "case 1, 3, 5:" into "case 1: case 3: case 5"
    1266         | case_value_list ',' case_value                        { $$ = $1->set_last( new ClauseNode( build_case( yylloc, $3 ) ) ); }
     1264        | case_value_list ',' case_value                        { $$ = (StatementNode *)($1->set_last( new StatementNode( build_case( $3 ) ) ) ); }
    12671265        ;
    12681266
     
    12731271        | CASE case_value_list error                                            // syntax error
    12741272                { SemanticError( yylloc, "Missing colon after case list." ); $$ = nullptr; }
    1275         | DEFAULT ':'                                                           { $$ = new ClauseNode( build_default( yylloc ) ); }
     1273        | DEFAULT ':'                                                           { $$ = new StatementNode( build_default( yylloc ) ); }
    12761274                // A semantic check is required to ensure only one default clause per switch/choose statement.
    12771275        | DEFAULT error                                                                         //  syntax error
     
    12811279case_label_list:                                                                                // CFA
    12821280        case_label
    1283         | case_label_list case_label                            { $$ = $1->set_last( $2 ); }
     1281        | case_label_list case_label                            { $$ = (StatementNode *)( $1->set_last( $2 )); }
    12841282        ;
    12851283
     
    12981296                { $$ = $1->append_last_case( new StatementNode( build_compound( yylloc, $2 ) ) ); }
    12991297        | switch_clause_list case_label_list statement_list_nodecl
    1300                 { $$ = $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 ) ) ) ); }
     1298                { $$ = (StatementNode *)( $1->set_last( $2->append_last_case( new StatementNode( build_compound( yylloc, $3 ) ) ) ) ); }
    13011299        ;
    13021300
     
    16811679
    16821680waituntil:
    1683         WAITUNTIL '(' comma_expression ')'
     1681        WAITUNTIL '(' cast_expression ')'
    16841682                { $$ = $3; }
    16851683        ;
     
    17381736handler_clause:
    17391737        handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1740                 { $$ = new ClauseNode( build_catch( yylloc, $1, $4, $6, $8 ) ); }
     1738                { $$ = new StatementNode( build_catch( yylloc, $1, $4, $6, $8 ) ); }
    17411739        | handler_clause handler_key '(' push exception_declaration pop handler_predicate_opt ')' compound_statement
    1742                 { $$ = $1->set_last( new ClauseNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); }
     1740                { $$ = (StatementNode *)$1->set_last( new StatementNode( build_catch( yylloc, $2, $5, $7, $9 ) ) ); }
    17431741        ;
    17441742
     
    17571755
    17581756finally_clause:
    1759         FINALLY compound_statement                                      { $$ = new ClauseNode( build_finally( yylloc, $2 ) ); }
     1757        FINALLY compound_statement                                      { $$ = new StatementNode( build_finally( yylloc, $2 ) ); }
    17601758        ;
    17611759
     
    18151813asm_operand:                                                                                    // GCC
    18161814        string_literal '(' constant_expression ')'
    1817                 { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", maybeMoveBuild( $1 ), maybeMoveBuild( $3 ) ) ); }
     1815                { $$ = new ExpressionNode( new ast::AsmExpr( yylloc, "", $1, maybeMoveBuild( $3 ) ) ); }
    18181816        | '[' IDENTIFIER ']' string_literal '(' constant_expression ')'
    18191817                {
    1820                         $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, maybeMoveBuild( $4 ), maybeMoveBuild( $6 ) ) );
     1818                        $$ = new ExpressionNode( new ast::AsmExpr( yylloc, *$2.str, $4, maybeMoveBuild( $6 ) ) );
    18211819                        delete $2.str;
    18221820                }
     
    18271825                { $$ = nullptr; }                                                               // use default argument
    18281826        | string_literal
    1829                 { $$ = $1; }
     1827                { $$ = new ExpressionNode( $1 ); }
    18301828        | asm_clobbers_list_opt ',' string_literal
    1831                 { $$ = (ExpressionNode *)( $1->set_last( $3 ) ); }
     1829                { $$ = (ExpressionNode *)($1->set_last( new ExpressionNode( $3 ) )); }
    18321830        ;
    18331831
     
    19011899static_assert:
    19021900        STATICASSERT '(' constant_expression ',' string_literal ')' ';' // C11
    1903                 { $$ = DeclarationNode::newStaticAssert( $3, maybeMoveBuild( $5 ) ); }
     1901                { $$ = DeclarationNode::newStaticAssert( $3, $5 ); }
    19041902        | STATICASSERT '(' constant_expression ')' ';'          // CFA
    19051903                { $$ = DeclarationNode::newStaticAssert( $3, build_constantStr( yylloc, *new string( "\"\"" ) ) ); }
     
    33313329                {
    33323330                        DeclarationNode * name = new DeclarationNode();
    3333                         name->asmName = maybeMoveBuild( $3 );
     3331                        name->asmName = $3;
    33343332                        $$ = name->addQualifiers( $5 );
    33353333                }
  • src/Parser/parserutility.h

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

    r6e1e2d0 ra50fdfb  
    5555namespace ResolvExpr {
    5656
    57 /// Unique identifier for matching expression resolutions to their requesting expression
    58 UniqueId globalResnSlot = 0;
    59 
    60 namespace {
    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 
    1701 bool 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 
    1810 void 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 
    1917 std::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 
    193557const ast::Expr * referenceToRvalueConversion( const ast::Expr * expr, Cost & cost ) {
    193658        if ( expr->result.as< ast::ReferenceType >() ) {
     
    194264        return expr;
    194365}
     66
     67/// Unique identifier for matching expression resolutions to their requesting expression
     68UniqueId globalResnSlot = 0;
    194469
    194570Cost computeConversionCost(
     
    196893}
    196994
     95namespace {
     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
     1674bool 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
     1783void 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
     1890std::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
    19701908} // namespace ResolvExpr
    19711909
  • src/ResolvExpr/CurrentObject.cc

    r6e1e2d0 ra50fdfb  
    99// Author           : Rob Schluntz
    1010// Created On       : Tue Jun 13 15:28:32 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Mon Apr 10  9:40:00 2023
    13 // Update Count     : 18
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Jul  1 09:16:01 2022
     13// Update Count     : 15
    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 
    634595        /// create a new MemberIterator that traverses a type correctly
    635596        MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
     
    671632        };
    672633
    673         /// Iterates over an indexed type:
    674         class IndexIterator : public MemberIterator {
    675         protected:
     634        /// Iterates array types
     635        class ArrayIterator final : public MemberIterator {
    676636                CodeLocation location;
     637                const ArrayType * array = nullptr;
     638                const Type * base = nullptr;
    677639                size_t index = 0;
    678640                size_t size = 0;
    679                 std::unique_ptr<MemberIterator> memberIter;
    680         public:
    681                 IndexIterator( const CodeLocation & loc, size_t size ) :
    682                         location( loc ), size( size )
    683                 {}
     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                }
    684660
    685661                void setPosition( const Expr * expr ) {
     
    690666                        auto arg = eval( expr );
    691667                        index = arg.first;
     668                        return;
    692669
    693670                        // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
     
    707684
    708685                void setPosition(
    709                         std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
    710                         std::deque<ast::ptr<ast::Expr>>::const_iterator end
     686                        std::deque< ptr< Expr > >::const_iterator begin,
     687                        std::deque< ptr< Expr > >::const_iterator end
    711688                ) override {
    712689                        if ( begin == end ) return;
     
    719696
    720697                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                 }
    746698
    747699                ArrayIterator & bigStep() override {
     
    882834
    883835                const Type * getNext() final {
    884                         bool hasMember = memberIter && *memberIter;
    885                         return hasMember ? memberIter->getType() : nullptr;
     836                        return ( memberIter && *memberIter ) ? memberIter->getType() : nullptr;
    886837                }
    887838
     
    947898        };
    948899
    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() ) );
     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);
    963909                }
    964910
    965911                TupleIterator & bigStep() override {
    966                         ++index;
    967                         memberIter.reset( index < size ?
    968                                 createMemberIterator( location, typeAtIndex() ) : nullptr );
     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                        }
    969920                        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 {};
    1004921                }
    1005922        };
  • src/ResolvExpr/CurrentObject.h

    r6e1e2d0 ra50fdfb  
    99// Author           : Rob Schluntz
    1010// Created On       : Thu Jun  8 11:07:25 2017
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Thu Apr  6 16:14:00 2023
    13 // Update Count     : 4
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Sat Jul 22 09:36:48 2017
     13// Update Count     : 3
    1414//
    1515
     
    6565
    6666        /// Iterates members of a type by initializer
    67         class MemberIterator;
     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        };
    68104
    69105        /// Builds initializer lists in resolution
  • src/ResolvExpr/ExplodedArg.hpp

    r6e1e2d0 ra50fdfb  
    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

    r6e1e2d0 ra50fdfb  
    1010// Created On       : Thu Mar 03 15:45:56 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Apr 14 15:03:00 2023
    13 // Update Count     : 64
     12// Last Modified On : Fri Apr 27 14:39:06 2018
     13// Update Count     : 63
    1414//
    1515
     
    211211        }
    212212
     213        bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
     214                return obj && obj->name.empty() && obj->bitfieldWidth;
     215        }
     216
    213217        /// inserts a forward declaration for functionDecl into declsToAdd
    214218        void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
     
    230234        }
    231235
     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
    232247        /// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
    233248        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic ) {
     
    241256                ftype->parameters.push_back( dstParam );
    242257                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);
    243266        }
    244267
  • src/SymTab/Autogen.h

    r6e1e2d0 ra50fdfb  
    99// Author           : Rob Schluntz
    1010// Created On       : Sun May 17 21:53:34 2015
    11 // Last Modified By : Andrew Beach
    12 // Last Modified On : Fri Apr 14 15:06:00 2023
    13 // Update Count     : 17
     11// Last Modified By : Peter A. Buhr
     12// Last Modified On : Fri Dec 13 16:38:06 2019
     13// Update Count     : 16
    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 );
    4748
    4849        /// generate the type of an assignment function for paramType.
     
    5455        FunctionType * genDefaultType( Type * paramType, bool maybePolymorphic = true );
    5556
     57        ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic = true);
     58
    5659        /// generate the type of a copy constructor for paramType.
    5760        /// maybePolymorphic is true if the resulting FunctionType is allowed to be polymorphic
     
    6467        template< typename OutputIterator >
    6568        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 );
    6675
    6776        /// inserts into out a generated call expression to function fname with arguments dstParam and srcParam. Should only be called with non-array types.
     
    112121
    113122                *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 };
    114180
    115181                srcParam.clearArrayIndices();
     
    182248        }
    183249
     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
    184320        template< typename OutputIterator >
    185321        Statement * genCall( InitTweak::InitExpander_old & srcParam, Expression * dstParam, const std::string & fname, OutputIterator out, Type * type, Type * addCast, bool forward ) {
     
    189325                } else {
    190326                        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 );
    191344                }
    192345        }
     
    226379        }
    227380
     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        }
    228414} // namespace SymTab
    229415
  • src/SymTab/module.mk

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

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

    r6e1e2d0 ra50fdfb  
    99// Author           : Peter Buhr and Rob Schluntz
    1010// Created On       : Fri May 15 23:12:02 2015
    11 // Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 10 21:12:17 2023
    13 // Update Count     : 682
     11// Last Modified By : Andrew Beach
     12// Last Modified On : Thr Feb 16 10:08:00 2023
     13// Update Count     : 680
    1414//
    1515
     
    3232
    3333#include "AST/Convert.hpp"
    34 #include "AST/Util.hpp"                     // for checkInvariants
    3534#include "CompilationState.h"
    3635#include "../config.h"                      // for CFA_LIBDIR
     
    103102}
    104103
    105 // Helpers for checkInvariant:
    106 void checkInvariants( std::list< Declaration * > & ) {}
    107 using ast::checkInvariants;
    108 
    109 #define PASS( name, pass, unit, ... )       \
     104#define PASS( name, pass )                  \
    110105        if ( errorp ) { cerr << name << endl; } \
    111106        NewPass(name);                          \
    112107        Stats::Time::StartBlock(name);          \
    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         }
     108        pass;                                   \
     109        Stats::Time::StopBlock();
    124110
    125111static bool waiting_for_gdb = false;                                    // flag to set cfa-cpp to wait for gdb on start
     
    312298                transUnit = buildUnit();
    313299
    314                 DUMP( astp, std::move( transUnit ) );
     300                if ( astp ) {
     301                        dump( std::move( transUnit ) );
     302                        return EXIT_SUCCESS;
     303                } // if
    315304
    316305                Stats::Time::StopBlock();
     
    321310                }
    322311
    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 );
     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 ) );
    356353
    357354                if ( symtabp ) {
     
    364361                } // if
    365362
    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 );
     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 ) );
    373373
    374374                if ( libcfap ) {
     
    382382                } // if
    383383
    384                 DUMP( bresolvep, std::move( transUnit ) );
     384                if ( bresolvep ) {
     385                        dump( std::move( transUnit ) );
     386                        return EXIT_SUCCESS;
     387                } // if
    385388
    386389                if ( resolvprotop ) {
     
    389392                } // if
    390393
    391                 PASS( "Resolve", ResolvExpr::resolve, transUnit );
    392                 DUMP( exprp, std::move( transUnit ) );
    393 
    394                 PASS( "Fix Init", InitTweak::fix, transUnit, buildingLibrary() );
     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()));
    395403
    396404                // fix ObjectDecl - replaces ConstructorInit nodes
    397                 DUMP( ctorinitp, std::move( transUnit ) );
     405                if ( ctorinitp ) {
     406                        dump( std::move( transUnit ) );
     407                        return EXIT_SUCCESS;
     408                } // if
    398409
    399410                // Currently not working due to unresolved issues with UniqueExpr
    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 );
     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 ) );
    404415
    405416                // Needs to happen before tuple types are expanded.
    406                 PASS( "Convert Specializations",  GenPoly::convertSpecializations, transUnit );
    407 
    408                 PASS( "Expand Tuples", Tuples::expandTuples, transUnit );
    409                 DUMP( tuplep, std::move( transUnit ) );
     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
    410425
    411426                // Must come after Translate Tries.
    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 );
     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 ) );
    418436
    419437                translationUnit = convert( std::move( transUnit ) );
    420438
    421                 DUMP( bboxp, translationUnit );
    422                 PASS( "Box", GenPoly::box, translationUnit );
    423 
    424                 PASS( "Link-Once", CodeGen::translateLinkOnce, translationUnit );
     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 ) );
    425446
    426447                // Code has been lowered to C, now we can start generation.
    427448
    428                 DUMP( bcodegenp, translationUnit );
     449                if ( bcodegenp ) {
     450                        dump( translationUnit );
     451                        return EXIT_SUCCESS;
     452                } // if
    429453
    430454                if ( optind < argc ) {                                                  // any commands after the flags and input file ? => output file name
     
    433457
    434458                CodeTools::fillLocations( translationUnit );
    435                 PASS( "Code Gen", CodeGen::generate, translationUnit, *output, ! genproto, prettycodegenp, true, linemarks );
     459                PASS( "Code Gen", CodeGen::generate( translationUnit, *output, ! genproto, prettycodegenp, true, linemarks ) );
    436460
    437461                CodeGen::FixMain::fix( translationUnit, *output,
     
    481505
    482506
    483 static const char optstring[] = ":c:ghilLmNnpdP:S:twW:D:";
     507static const char optstring[] = ":c:ghlLmNnpdP:S:twW:D:";
    484508
    485509enum { PreludeDir = 128 };
     
    488512        { "gdb", no_argument, nullptr, 'g' },
    489513        { "help", no_argument, nullptr, 'h' },
    490         { "invariant", no_argument, nullptr, 'i' },
    491514        { "libcfa", no_argument, nullptr, 'l' },
    492515        { "linemarks", no_argument, nullptr, 'L' },
    493         { "no-main", no_argument, nullptr, 'm' },
     516        { "no-main", no_argument, 0, 'm' },
    494517        { "no-linemarks", no_argument, nullptr, 'N' },
    495518        { "no-prelude", no_argument, nullptr, 'n' },
     
    510533        "wait for gdb to attach",                                                       // -g
    511534        "print translator help message",                                        // -h
    512         "invariant checking during AST passes",                         // -i
    513535        "generate libcfa.c",                                                            // -l
    514536        "generate line marks",                                                          // -L
     
    604626                        usage( argv );                                                          // no return
    605627                        break;
    606                   case 'i':                                                                             // invariant checking
    607                         invariant = true;
    608                         break;
    609628                  case 'l':                                                                             // generate libcfa.c
    610629                        libcfap = true;
  • tests/.expect/PRNG.x64.txt

    r6e1e2d0 ra50fdfb  
    1 
    2 CFA xoshiro256pp
    31
    42                    PRNG()     PRNG(5)   PRNG(0,5)
     
    5856
    5957Sequential
    60 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     58trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    6159
    6260Concurrent
    63 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    64 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    65 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
    66 trials 20000000 buckets 100000 min 139 max 265 avg 200.0 std 14.1 rstd 7.0%
     61trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     62trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     63trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
     64trials 100000000 buckets 100000 min 875 max 1146 avg 1000.0 std 31.6 rstd 3.2%
    6765
    6866                   prng(t)   prng(t,5) prng(t,0,5)
  • tests/.expect/PRNG.x86.txt

    r6e1e2d0 ra50fdfb  
    1 
    2 CFA xoshiro128pp
    31
    42                    PRNG()     PRNG(5)   PRNG(0,5)
     
    5856
    5957Sequential
    60 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     58trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    6159
    6260Concurrent
    63 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    64 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    65 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
    66 trials 20000000 buckets 100000 min 144 max 270 avg 200.0 std 14.1 rstd 7.1%
     61trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     62trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     63trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
     64trials 100000000 buckets 100000 min 858 max 1147 avg 1000.0 std 31.5 rstd 3.2%
    6765
    6866                   prng(t)   prng(t,5) prng(t,0,5)
  • tests/Makefile.am

    r6e1e2d0 ra50fdfb  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon Apr 10 23:24:02 2023
    14 ## Update Count     : 96
     13## Last Modified On : Fri Feb  3 23:06:44 2023
     14## Update Count     : 94
    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 concurrent/waitfor/parse
     186        init1 limits nested-types cast labelledExit array quasiKeyword include/stdincludes include/includes builtins/sync warnings/self-assignment
    187187$(SYNTAX_ONLY_CODE): % : %.cfa $(CFACCBIN)
    188188        $(CFACOMPILE_SYNTAX)
  • tests/PRNG.cfa

    r6e1e2d0 ra50fdfb  
    88// Created On       : Wed Dec 29 09:38:12 2021
    99// Last Modified By : Peter A. Buhr
    10 // Last Modified On : Sun Apr 23 22:02:09 2023
    11 // Update Count     : 420
     10// Last Modified On : Wed Dec 21 20:39:59 2022
     11// Update Count     : 406
    1212//
    1313
     
    1515#include <stdlib.hfa>                                                                   // PRNG
    1616#include <clock.hfa>
     17#include <thread.hfa>
    1718#include <limits.hfa>                                                                   // MAX
    1819#include <math.hfa>                                                                             // sqrt
    1920#include <malloc.h>                                                                             // malloc_stats
    2021#include <locale.h>                                                                             // setlocale
    21 #include <thread.hfa>
    2222#include <mutex_stmt.hfa>
    2323
    24 #define xstr(s) str(s)
    25 #define str(s) #s
    26 
    27 #if defined( __x86_64__ ) || defined( __aarch64__ )             // 64-bit architecture
     24#ifdef __x86_64__                                                                               // 64-bit architecture
    2825#define PRNG PRNG64
    2926#else                                                                                                   // 32-bit architecture
    3027#define PRNG PRNG32
    3128#endif // __x86_64__
    32 
    33 //#define TIME
    3429
    3530#ifdef TIME                                                                                             // use -O2 -nodebug
     
    4338#endif // TIME
    4439
    45 static void avgstd( size_t trials, size_t buckets[] ) {
    46         size_t min = MAX, max = 0;
     40void avgstd( unsigned int buckets[] ) {
     41        unsigned int min = MAX, max = 0;
    4742        double sum = 0.0, diff;
    4843        for ( i; BUCKETS ) {
     
    5954        } // for
    6055        double std = sqrt( sum / BUCKETS );
    61         mutex( sout ) sout | "trials"  | trials | "buckets" | BUCKETS
     56        mutex( sout ) sout | "trials"  | TRIALS | "buckets" | BUCKETS
    6257                | "min" | min | "max" | max
    6358                | "avg" | wd(0,1, avg) | "std" | wd(0,1, std) | "rstd" | wd(0,1, (avg == 0 ? 0.0 : std / avg * 100)) | "%";
     
    6964thread T1 {};
    7065void main( T1 & ) {
    71         size_t * buckets = calloc( BUCKETS );                           // too big for task stack
    72         for ( TRIALS / 50 ) {
     66        unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
     67        for ( TRIALS / 100 ) {
    7368                buckets[rand() % BUCKETS] += 1;                                 // concurrent
    7469        } // for
    75         avgstd( TRIALS / 50, buckets );
     70        avgstd( buckets );
    7671        free( buckets );
    7772} // main
     
    8176        PRNG prng;
    8277        if ( seed != 0 ) set_seed( prng, seed );
    83         size_t * buckets = calloc( BUCKETS );                           // too big for task stack
     78        unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
    8479        for ( TRIALS ) {
    8580                buckets[prng( prng ) % BUCKETS] += 1;                   // concurrent
    8681        } // for
    87         avgstd( TRIALS, buckets );
     82        avgstd( buckets );
    8883        free( buckets );
    8984} // main
     
    9186thread T3 {};
    9287void main( T3 & th ) {
    93         size_t * buckets = calloc( BUCKETS );                           // too big for task stack
    94         for ( TRIALS / 5 ) {
     88        unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
     89        for ( TRIALS ) {
    9590                buckets[prng() % BUCKETS] += 1;                                 // concurrent
    9691        } // for
    97         avgstd( TRIALS / 5, buckets );
     92        avgstd( buckets );
    9893        free( buckets );
    9994} // main
     
    10196thread T4 {};
    10297void main( T4 & th ) {
    103         size_t * buckets = calloc( BUCKETS );                           // too big for task stack
     98        unsigned int * buckets = calloc( BUCKETS );                     // too big for task stack
    10499        for ( TRIALS ) {
    105                 buckets[prng( th ) % BUCKETS] += 1;                             // concurrent
    106         } // for
    107         avgstd( TRIALS, buckets );
     100                buckets[prng( th ) % BUCKETS] += 1;     // concurrent
     101        } // for
     102        avgstd( buckets );
    108103        free( buckets );
    109104} // main
     
    113108static void dummy( thread$ & th ) __attribute__(( noinline ));
    114109static void dummy( thread$ & th ) {
    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 ) {
     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 ) {
    117112                buckets[prng( th ) % BUCKETS] += 1;                             // sequential
    118113        } // for
    119         avgstd( TRIALS, buckets );
     114        avgstd( buckets );
    120115        free( buckets );
    121116} // dummy
     
    123118
    124119int main() {
    125         // setlocale( LC_NUMERIC, getenv( "LANG" ) );           // causes leaked storage message
    126 
    127         // only works on the current pthread thread
     120        // causes leaked storage message
     121        // setlocale( LC_NUMERIC, getenv( "LANG" ) );                   // print digit separator
    128122        // locale_t loc = newlocale( LC_NUMERIC_MASK, getenv( "LANG" ), (locale_t)0p );
    129123        // if ( loc == (locale_t)0p ) abort( "newlocale" );
     
    132126        enum { TASKS = 4 };
    133127        Time start;
    134 
    135128#ifdef TIME                                                                                             // too slow for test and generates non-repeatable results
    136129#if 1
    137         sout | "glib rand" | nl | nl;
    138 
    139         size_t rseed;
     130        unsigned int rseed;
    140131        if ( seed != 0 ) rseed = seed;
    141132        else rseed = rdtscl();
     
    143134
    144135        sout | sepDisable;
    145         sout | nl | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
     136        sout | wd(26, "rand()" ) | wd(12, "rand(5)") | wd(12, "rand(0,5)" );
    146137        for ( 20 ) {
    147138                sout | wd(26, rand()) | nonl;
     
    155146        STARTTIME;
    156147        {
    157                 size_t * buckets = calloc( BUCKETS );                   // too big for task stack
    158                 for ( i; TRIALS / 5 ) {
     148                unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
     149                for ( i; TRIALS / 10 ) {
    159150                        buckets[rand() % BUCKETS] += 1;                         // sequential
    160151                } // for
    161                 avgstd( TRIALS / 5, buckets );
     152                avgstd( buckets );
    162153                free( buckets );
    163154        }
    164         ENDTIME( " x 5 " );
     155        ENDTIME( " x 10 " );
    165156
    166157        sout | nl | "Concurrent";
     
    172163                } // wait for threads to complete
    173164        }
    174         ENDTIME( " x 50 " );
     165        ENDTIME( " x 100 " );
    175166#endif // 0
    176167#endif // TIME
    177 
    178         sout | nl | "CFA " xstr(PRNG_NAME);
    179 
    180168#if 1
    181169        PRNG prng;
     
    196184        STARTTIME;
    197185        {
    198                 size_t * buckets = calloc( BUCKETS );                   // too big for task stack
     186                unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
    199187                for ( TRIALS ) {
    200188                        buckets[prng( prng ) % BUCKETS] += 1;           // sequential
    201189                } // for
    202                 avgstd( TRIALS, buckets );
     190                avgstd( buckets );
    203191                free( buckets );
    204192        }
     
    231219        STARTTIME;
    232220        {
    233                 size_t * buckets = calloc( BUCKETS );                   // too big for task stack
    234                 for ( TRIALS / 5 ) {
     221                unsigned int * buckets = calloc( BUCKETS );             // too big for task stack
     222                for ( TRIALS ) {
    235223                        buckets[prng() % BUCKETS] += 1;
    236224                } // for
    237                 avgstd( TRIALS / 5, buckets );
     225                avgstd( buckets );
    238226                free( buckets );
    239227        }
    240         ENDTIME( " x 5 " );
     228        ENDTIME();
    241229
    242230        sout | nl | "Concurrent";
     
    248236                } // wait for threads to complete
    249237        }
    250         ENDTIME( " x 5 " );
     238        ENDTIME();
    251239#endif // 0
    252240#if 1
  • tests/concurrent/waitfor/parse.cfa

    r6e1e2d0 ra50fdfb  
    1 // 
    2 // Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
     1//----------------------------------------------------------------------------------------
     2//----------------------------------------------------------------------------------------
    33//
    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 //
     4//              DEPRECATED TEST
     5//              DIFFERS BETWEEN DEBUG AND RELEASE
     6//
     7//----------------------------------------------------------------------------------------
     8//----------------------------------------------------------------------------------------
    159
    1610#include <monitor.hfa>
     
    1812monitor M {};
    1913
    20 void notcalled( M & mutex m1, M & mutex m2 ) {
    21         abort();
    22 }
    23 void or( M & mutex m ) {
    24         abort();
    25 }
    26 void timeout( M & mutex m ) {
    27         abort();
     14M a;
     15
     16void f1( M & mutex a );
     17void f2( M & mutex a );
     18void f2( M & mutex a, M & mutex b );
     19void f3( M & mutex a );
     20void f3( M & mutex a, M & mutex b );
     21void f3( M & mutex a, M & mutex b, M & mutex c );
     22
     23void 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        }
     50        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        }
     72        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        }
    28100}
    29101
    30 void 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 );
    98         or else {
    99         }
    100 
    101         when( true ) waitfor( notcalled : m, m );
    102         or else {
    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
    254 int 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: //
     102int main() {}
  • tests/pybin/settings.py

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

    r6e1e2d0 ra50fdfb  
    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')
    117116        parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=180)
    118117        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)
     
    173172        test.prepare()
    174173
    175         # extra flags for cfa to pass through make.
    176         cfa_flags = 'CFAFLAGS=--invariant' if settings.invariant else None
    177 
    178174        # ----------
    179175        # MAKE
     
    181177        # build, skipping to next test on error
    182178        with Timed() as comp_dur:
    183                 make_ret, _, _ = make(test.target(), flags=cfa_flags, output_file=subprocess.DEVNULL, error=out_file, error_file=err_file)
     179                make_ret, _, _ = make( test.target(), output_file=subprocess.DEVNULL, error=out_file, error_file = err_file )
    184180
    185181        # ----------
Note: See TracChangeset for help on using the changeset viewer.